#1 Schneeflocken vom Bildschirm von toggodamian 04.12.2012 18:02

avatar

Hallo Florian,
Ich hoffe ich drücke mich jetzt korrekt aus. Ich habe jetzt kein richtiges Beispiel dafür, versuche es dir aber mal zu erklären:
Es gibt ja Schneeflocken die von oben des Bildschirmes nach Unten fallen. Jetzt hatte ich die Idee, zumindest setze ich das so in meinem Forum um, das dass Forum von der Vogelprespektive gesehen wird. Wäre es auch möglich so die Schneeflocken runter fallen zu lassen, sprich die Grafik ist erst Groß und wird dann klein bis 0px? Das kenne ich so von einem Spiel, und würde es auch sehr begrüßen sowas für die Schneeflocken realisieren zu können, bisschen hin und her Schaukeln sollte ja eigentlich Standart sein, denke ich Wäre für dieses Jahr für mich nicht schlecht es so realisieren zu können, eine etwas andere Art von aufbau des Forums eben
Schön wäre natürlich auch, eine gewisse Position feststellen zu können, wo sie genau von oben kommen können und auch hinfallen, den ich wollte das nicht über den ganzen Bildschirm haben, sondern eigentlich nur oben. Wäre das machbar für dich?

ich weiß, hört sich komisch der Wunsch an, isst er auch, wäre nur eine andere Art von Schneeflocken fall am Bildschirm

Ich danke dir jetzt schon für die Klasse umsetzung und bin drauf gespannt

#2 RE: Schneeflocken vom Bildschirm von florian-zier 14.12.2012 23:20

avatar

Hallo toggo,
ich habe nun ein neues Skript erstellt.
Um alles zu realisieren ist es etwas länger geworden, deswegen habe ich aber auch alle Einstellungen, die vorgenommen werden können, nach oben ausgelagert.
Ohne die Auslagerung wären die Einstellungen sonst nicht mehr gut zu finden oder man bräuchte eine lange Parameter-Liste beim Funktionsaufruf.
Ansonsten habe ich versucht alles so gut es geht objektorientiert umzusetzen und zu kapseln.

Ich lade alles auch nochmal als fertige HTML-Seite in den Anhang, um ggf. nochmals das genaue Zusammenspiel zeigen zu können.
Aber am besten fange ich gleich mit dem Skript an, welches die Funktionalität bereitstellt:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
 
var snowProperties = {
// Adresse der Schneeflocken-Grafik:
flakeImage : 'http://files.homepagemodules.de/b123484/a_47_4cadcb5d.png',
// Alternativ-Text, falls Grafik nicht gefunden:
flakeText : '*',
 
// maximale Abweichung von der Standard-Bildgröße in Prozent [0..1]
// z.B.: 0 = keine, 50 = +-50%, 100 = +-100% (doppelt so groß bzw. nicht mehr zu sehen)
deviation : 50,
 
flakeWidth : 20, // Breite einer Schneeflocke
flakeHeight : 23, // Höhe einer Schneeflocke
 
animSpeed : 75, // Intervall für Ausführung der Animations-Schritte in ms
stepDown : 2, // Pixel nach unten pro Animations-Schritt
amplitude : 10, // maximale Pendelbewegungen seitwärts in Pixeln
period : 12.5, // Länge für eine komplette Pendelbewegung nach links und rechts
 
amountStart : Math.ceil(window.innerWidth*0.0025), // Anzahl der zu ladenden Schneeflocken pro Zeile (Anzeigebreite => window.innerHeight)
snowLine : Math.round(window.innerHeight * 0.8), // maximale Höhe, welche die Schneeflocken zurücklegen (Anzeigehöhe => window.innerHeight)
sizeBottom : 2 // minimale Größe einer Schneeflocke am Ende in Prozent
}
 
function snowFlake() {
var that = this;
 
this.deviation = ((Math.random() * 2) - 1) * (snowProperties.deviation/100);
this.width = snowProperties.flakeWidth * (1 + this.deviation);
this.height = snowProperties.flakeHeight * (1 + this.deviation);

this.posX = Math.floor((Math.random() * (window.innerWidth - this.width - Math.abs(this.deviation) ) ) + 1);
this.posY = ((-1) * this.height) - Math.floor((Math.random() * (2*this.height) ) + 1);
 
this.decrWidth = ( this.width - ( this.width * (snowProperties.sizeBottom/100) ) ) // (Anfangsbreite - Endbreite)
/ (snowProperties.snowLine - (this.height * 3));
this.decrHeight = ( this.height - ( this.height * (snowProperties.sizeBottom/100) ) ) // (Anfangshöhe - Endhöhe)
/ (snowProperties.snowLine - (this.height * 3));
 
this.flake;
this.init = function() {
// HTML-Element für Schneeflocke erzeugen:
this.flake = document.createElement('img');
// Attribute des HTML-Elementes initialisieren:
this.flake.setAttribute( 'name', 'snowflake');
this.flake.setAttribute( 'alt', snowProperties.flakeText);
this.flake.setAttribute( 'class', 'snowflake');
this.flake.setAttribute( 'src', snowProperties.flakeImage);
// Element in Seite einbinden:
document.getElementsByTagName('body')[0].appendChild(this.flake);
 
this.flake.style.width = this.width + 'px';
this.flake.style.height = this.height + 'px';
this.flake.style.top = this.posY + 'px';
this.flake.style.left = this.posX + 'px';
}
this.init();
 
this.remove = function() {
document.getElementsByTagName('body')[0].removeChild(this.flake);
}
 

this.fallDown = function() {
this.posY += snowProperties.stepDown;
this.flake.style.top = this.posY + 'px';
 
var newPosition = parseFloat(this.posX) +
snowProperties.amplitude *
Math.sin( (1/snowProperties.period) * (this.posY - this.deviation) );
this.flake.style.left = newPosition + 'px';
 
this.width -= this.decrWidth;
this.height -= this.decrHeight;
this.flake.style.width = this.width + 'px';
this.flake.style.height = this.height + 'px';
}
}
 

function snowFall() {
var that = this;
 
this.flakes;
 
var interval;
var timeout;
 
var loadRange;
var loadTimer;
var totalAmount;
var countLoaded = 0; // Anzahl geladener Schneeflocken
 
this.init = function() {
totalAmount = snowProperties.amountStart *
Math.round( snowProperties.snowLine / (snowProperties.flakeHeight * 1.5 * 2) );
 
this.flakes = new Array(totalAmount);
loadRange = snowProperties.amountStart; // this.flakes.length * (snowProperties.amountStart/100);
 
for (var i = 0; i < loadRange; i++) {
this.flakes[i] = new snowFlake();
this.flakes[i].flake.style.display = 'none';
countLoaded = i + 1;
}
 
// (Durchschnittliche Fallhöhe bis Bildrand) * (Zeitschritte, die bis dahin vergingen):
loadTimer = (snowProperties.flakeHeight * 1.5 * 2) * (snowProperties.animSpeed / snowProperties.stepDown);
timeout = window.setTimeout( function() { that.loadAsync(); }, loadTimer);
}
this.init();
 
this.loadAsync = function() {
var loadMore = false;
for (var i = 0; i < loadRange; i++) {
if ( (countLoaded < this.flakes.length) && (this.flakes[countLoaded] == null) ) {
this.flakes[countLoaded++] = new snowFlake();
}
else {
break;
}
loadMore = true;
}
if (loadMore) {
timeout = window.setTimeout( function() { that.loadAsync(); }, loadTimer);
}
}
 
this.show = function() {
for (var i = 0; i < this.flakes.length; i++) {
if (this.flakes[i] != null) {
this.flakes[i].flake.style.display = 'block';
}
}
}
this.hide = function() {
for (var i = 0; i < this.flakes.length; i++) {
if (this.flakes[i] != null) {
this.flakes[i].flake.style.display = 'none';
}
}
}
 
this.startAnimation = function() {
interval = window.setInterval( function() { that.play(); } , snowProperties.animSpeed);
this.show();
}
this.stopAnimation = function() {
window.clearInterval(interval);
this.hide();
}
 
this.play = function() {
for (var i = 0; i < this.flakes.length; i++) {
if (this.flakes[i] != null) {
if (this.flakes[i].posY > snowProperties.snowLine) {
this.flakes[i].remove(); // alte Schneeflocke entfernen
this.flakes[i] = new snowFlake(); // neue Schneeflocke generieren
}
this.flakes[i].fallDown();
}
}
}
}
 



Änderungen sind soweit nur bei Bedarf in dem snowProperties -Objekt nötig.
Dort steht alles bereit, um die Intensität und Genauigkeit des Schneefalls zu regeln.
Außerdem lassen sich da auch die Pendelbewegung, das untere Ende und die Endgröße einer Schneeflocke im Verhältnis zu vorher festlegen.

Das Skript hat einen kleinen netten Nebeneffekt, falls das gewünschte Bild einmal nicht angezeigt werden könnte.
Die Variable flakeText bestimmt den Text welcher in so einem Fall dann angezeigt werden würde.
Sofern ein "*" darin steht, sieht es auch ohne geladenes Bildchen so aus, als würden kleine Schneeflöckchen fallen.

Die Variable deviation stellt eine kleine Abweichung von den Standard-Vorgaben dar.
So können bei dem Wert "50" z.B. auch Schneeflocken um bis zu 50% größer oder kleiner als durch die Vorgabe-Größe angegeben generiert werden.
Das dient nur dazu, dass nicht alle Schneeflocken gleich groß sind.
Beachte dass bei 100% theoretisch ein paar Schneeflocken doppelt so groß werden können, aber eben auch unsichtbar, da sie ja um 100% verkleinert werden könnten.
Bei 0% Abweichung sind eben alle Schneeflocken gleich groß.
Möchtest du Größen aus einem gewissen Bereich, dann müsstest du die Breite und Höhe in der Mitte zwischen der kleinsten und größten Schneeflocke bestimmen.
Mit einer geeigneten Abweichung dazu werden dann Schneeflocken zwischen deiner gewünschten Mindest- und Maximal-Größe generiert.

sizeBottom bestimmt dann noch, wie groß (bzw. klein) eine Schneeflocke am Ende sein wird.
Die Angabe bezieht sich auf die Anfangs-Größe, "20" bedeutet dann z.B. 20% von der Ursprungs-Größe, wenn die Schneeflocke unten angekommen ist.
Ob sie als "angekommen" gewertet wird, bestimmt die Angabe in snowLine.
Natürlich kannst du da eine beliebige Zahl eintragen, ich habe mich im Beispiel aber einfach mal für 80% der Anzeigehöhe entschieden.
D.h. also, dass die Schneeflocke ausgeblendet wird, wenn unten noch 20% von der Seite übrig sind.

amountStart gibt hingegen an, wieviele Schneeflocken gleichzeitig nebeneinander generiert werden.
Sie unterscheiden sich trotzdem etwas in der Anfangshöhe, damit nicht alle auf der gleichen Ebene herunterfallen.
Auch hier wäre ein fest eingetragener Wert möglich.
Doch ich habe auch hier eine Berechnung verwendet, nämlich 0,25% der Bildschirmbreite.
Die Zahl wird absichtlich so kleingerechnet, bedingt durch heutige Monitorgrößen, ansonsten wären es unmengen an Schneeflocken auf dem Bildschirm.


Welche Werte für dein Forum am besten geeignet sind, musst du am besten einfach ausprobieren.
Letztendlich kommt es ja auch noch auf das persönliche Gefühl an.
Passe aber auf, dass du die Zeit zwischen den Animations-Schritten (animSpeed) nicht zu kurz setzst, ansonsten sind sehr viele Berechnungen nötig.
Ebenso sollte die Anzahl der zu ladenden Schneeflocken in einer Zeile (amountStart) nicht zu hoch sein, da sich die Gesamtzahl der Schneeflocken mithilfe der Höhe der Anzeige letztlich danach richtet.
Nebenbei sollte man ja auch noch genügend Sicht auf das Forum haben können.

Ich hoffe, du findest eine für dich passende Einstellung.


Da das Skript damit weitestgehend abgehakt wäre, bleiben im Prinzip nur noch die Style-Anweisungen für die Schneeflocken-Bilder:

1
2
3
4
5
6
7
8
9
 
<style type="text/css">
.snowflake {
position:absolute;
top:0px;
left:0px;
 
color:#CCC; /* Farbe für Alternativtext */
}
</style>
 



Abgesehen von der nötigen absoluten Positionierung empfiehlt es sich hier, eine Schriftfarbe anzugeben.
Sie wird wahrscheinlich (hoffentlich) nicht gebraucht, gibt aber die Farbe des Alternativ-Textes an, falls die Grafik nicht geladen werden konnte.
In einem schicken Grau sieht ein "*" dann ziemlich gut aus als Ersatz-Schneeflocke.
Wenn du im Skript statt dem Stern einen leeren Text-String verwendest, dann sieht man natürlich nichts mehr statt der Grafik.
Somit würdest du vermeiden, dass das Skript bei fehlender Grafik überhaupt auffällt.
Allerdings würde ich hier zur trotzdem noch ansehnlichen Stern-Alternative raten.



Jetzt müsste alles wichtige eingestellt und vom Design her angepasst sein.
Allerdings wirst du bis jetzt noch nicht viel sehen.
Es fehlt also noch der Aufruf des Skriptes, nachdem die Seite geladen wurde.

Du startest den Wintertraum, indem du ein neues Objekt für das Schneefall-Skript anlegst und dann die Methode startAnimation() aufrufst:

1
2
 
var fallingSnow = new snowFall();
fallingSnow.startAnimation();
 



Dies sollte nicht vor dem Onload-Event geschehen, da die Seite komplett geladen sein muss.
Im Beispiel-Skript habe ich den Start einfach in eine Methode gepackt, die ich beim Onload-Event schließlich aufrufe.

Bei bereits vorhandenen automatisch aufgerufen Skripten empfehle ich, dieses Skript dann weiter hinten in der Onload-Hierarchie einzureihen.
Einfach nur, damit andere Skripte nicht evtl. etwas verzögert werden.


Dann wünsche ich dir noch einen schönen Abend in deiner neuen Schneelandschaft.
Viel Spaß damit!

#3 RE: Schneeflocken vom Bildschirm von toggodamian 28.12.2012 02:25

avatar

Tut mir leid Florian das ich dich so lange warten lasse mit einer antwort.
Ich kann nun mit Großem Stolz meinen Usern den Winterraum zeigen, denn du für uns Programmiert hast. Das Script ist Spitze, zwar hab ich es mir vom Optischen etwas anders vorgestellt, aber so wie es ist, finde ich es auch Perfekt. Was mich aber noch stört, ist das auch manche Schneeflocken etwas außer den Bildschrimrand gelangen und dadurch den Scrollbalken der nach Recht geht auslösen tut. Ich kann es ausblenden, hab aber dann im Forum in anderen Teilen davon dann Probleme zu große Bilder noch dann ganz Betrachten zu können, weil die dann Rechts abgeschnitten sind und ich nicht da rein Scrollen kann. Hab schon versucht was zu machen, habe es nur noch nicht geschafft. Wo muss ich da etwas ändern um den Inneren Raum des Fensters etwas den Raum verkleinern zu können, damit er mir nicht den Scrollbalken anzeigt?

Aber ansonsten ist das ganze einfach nur zu perfekt, vielen Herzlichen Dank Florian für die Meisterleistung, du beeindruckst mich jedesmal mit deinen Scipten

Hier zusehen: http://197007.homepagemodules.de/

#4 RE: Schneeflocken vom Bildschirm von Wolfgang 28.12.2012 12:41

avatar

Hallo Florian,
super Script. Habe es bei mir auch eingebaut!

Besonders gut finde ich die Begrenzung der Fallzeit.
Diese Einstellungsvariante hast Du allerdings nur auf dem Script im Anhang!





Gruß
Wolfgang

#5 RE: Schneeflocken vom Bildschirm von florian-zier 31.12.2012 18:32

avatar

Hallo ihr beiden,
schön, dass es euch gefällt.


@Damian:
Ich habe das Skript einfach mal so erstellt, wie sich in meinem Kopf die Vorstellung ergeben hat.
Die Kurven werden mithilfe der Sinus-Funktion berechnet, das war die für mich am besten scheinende Lösung, ich lass es ja sonst nicht so oft schneien.

Das Problem mit dem Überschreiten des Randes ist in der Tat wohl etwas unschön.
Eigentlich soll genau dies schon während der Generierung vermieden werden.
Bei mir kam das dann nicht mehr vor, hatte wohl leider die falschen zufälligen Start-Positionen zum Testen.
Aber du müsstest es mit einer Änderung in der Funktion snowFlake() beheben können, bei mir ist es bisher nicht mehr aufgetreten.
Ziehe beim Festlegen der Start-Position am Ende einfach noch die Amplitude ab, dass sollte dann die Auslenkung berücksichtigen:

1
 
this.posX = Math.floor((Math.random() * (window.innerWidth - this.width - Math.abs(this.deviation) ) ) + 1) - snowProperties.amplitude;
 


Sollte das evtl. um einen Pixel oder so nicht ausreichen, ziehst du einfach nochmal ein paar Pixel danach ab.
Ich hoffe, dass das die Lösung des Problemes sein wird.


@Wolfgang:
Die Begrenzung der Fallzeit habe ich nicht mehr erwähnt, da nicht explizit danach gefragt wurde und die Schneeflocken in der Regel ja auch dauerhaft fallen sollen.
Wenn das aber gerne verwendet wird, dann kann ich das hier auch nochmals für alle erwähnen.
Also mit einem Timeout der stopAnimation()-Methode kann z.B. nach 15s die Animation beendet werden.

1
 
window.setTimeout( function(){ fallingSnow.stopAnimation(); },	15000);
 


Mit der startAnimation()-Methode wird sie dementsprechend wiederaufgenommen.
Beim stoppen werden die Schneeflocken nur ausgeblendet, deswegen ist eine wiederaufnahme der Animation möglich.
Ich habe die entsprechende Stelle im Skript nochmals mit Kommentaren versehen und um eine Vorlage für die Wiederaufnahme ergänzt.


Der Vollständigkeit wegen packe ich auch noch die Schneeflocken-Grafik in den Anhang.
Da ich das Skript mit komplett weißem Hintergrund getestet habe, war dies in etwa eine für mich ansehnliche Farbe für die Schneeflocken.
Die jeweils beste Farbmischung für das eigene Forum / die eigenen Website kann man sich ja aber jederzeit selbst zusammenstellen.
Immerhin kann die gewünschte Grafik ja jederzeit in den Script-Properties geändert werden.

Als Vorlage für eine Schneeflocken-Grafik habe ich mir einfach mal die folgende herausgesucht:
http://www.papierprofi.de/Motivlocher-fu...N-4005329107559
Diese habe ich dann mit Inkscape in ein Vektorbild verwandelt.
Das tat ich hauptsächlich, um die pixeligen Stellen zu entfernen und die Grafik dann verlustfrei skalieren zu können.

Letztendlich besteht die Grafik nun nur noch aus einem einzigen Umriss.
Für diesen Umriss habe ich dann nur noch die Rand-Dicke und -Farbe, sowie die Füllfarbe mit Verlauf eingestellt.
Das ist eben der Vorteil von Vektorgrafiken, die Grundstruktur bildet nach wie vor immer noch der gleiche Umriss.

Am Ende habe ich das ganze dann noch in einer ziemlich kleinen Größe als Pixelbild exportiert.
Das sieht auf jeden Fall besser aus, als das riesige Original als Rastergrafik runter zu skalieren, da dabei meistens die falschen Pixel beibehalten werden.

Das Skript, sowie Original-Bild und Vektor-Grafik und das daraus exportierte PNG habe ich alle zusammen nochmals hier in den Anhang gepackt.
Falls es jemanden interessiert, die aktuell verwendete Grafik habe ich einfach in die Bilder-Sammlung im Admin-Bereich des Forums hochgeladen, somit habe ich es immer schön in der Liste der Grafik-Übersicht des Forums dabei.



Ansonsten bleibt mir nur noch, euch und allen anderen Usern ein frohes Neujahr zu wünschen.
Immerhin haben wir den Welt-Untergang überlebt, da gibt es genügend zu feiern.
Also...
Happy New Year

Xobor Forum Software von Xobor
Einfach ein eigenes Forum erstellen
Datenschutz