Für diese Seite benötigte ich einige Zahnräder, welche ich als Logo und als Hintergrund verwendete. Die Zahnräder sollten sich bei bedarf drehen und dynamisch erzeugt werden.
Was wir benötigen ist erst einmal ein Zahnrad welches folgende Eigenschaften hat:
- Position (x, y),
- Modulo (m),
- Zähnezahl (z),
- Farbe (color_gear),
- Drehung (angle),
- Rotationsgeschwindigkeit (speed),
- Richtung (dir).
Übersetzt in eine Klasse sieht das dann folgendermaßen aus:
/* Class Gear */
function Gear(x, y, m, z, color_gear, start_angle, speed, dir) {
this.angle = start_angle; // Start angle
this.speed = speed; // Speed
this.dir = dir; // Direction
this.x = x; // Position X
this.y = y; // Position Y
this.m = m; // Modulo
this.z = z; // Teeth Number
this.color_gear = color_gear; // Color
if(this.angle == 0 && dir == true) {// Zentrieren des Zahnrads
this.angle = Math.PI/this.z;
}
}
Dabei kann jede Funktion als Klasse fungieren. Mit Hilfe von prototype werden Getter und Setter zu der Klasse hinzugefügt:
/* Getter and Setter for the Class Gear */
Gear.prototype.getX = function() { return this.x; }
Gear.prototype.getY = function() { return this.y; }
Gear.prototype.getModulo = function() { return this.m; }
Gear.prototype.getTeeth = function() { return this.z; }
Gear.prototype.getColor = function() { return this.color_gear; }
Gear.prototype.getAngle = function() { return this.angle; }
Gear.prototype.setAngle = function(a) { return this.angle = a; }
Gear.prototype.getDirection = function() { return this.dir; }
Gear.prototype.getSpeed = function() { return this.speed; }
Nun besteht ein Getriebe nicht nur aus einem Zahnrad sondern aus mehreren, deshalb wird eine Getriebe Klasse benötigt. Welche auch die Zahnräder zeichnet und animiert. Diese Klasse hat folgende Eigenschaften:
- Array von Zahnräder (allGears),
- Context des Canvas Elements (ctx),
- Abmessungen des Canvas Elements (width, height).
/* Class Gears This Class holds the all the gears and methods to draw */
function Gears(canvas) {
this.ctx = canvas.getContext("2d");;
this.allGears = [];
this.width = canvas.width;
this.height = canvas.height;
this.timer;
var _this = this;
// Funktionen..
}
Als Funktionen benötigen wir:
- eine zum zeichnen der Zahnräder (drawGear),
- zum zeichnen eines Zahnrades (draw),
- zum löschen der Zeichenfläche (clear),
- Hinzufügen eines Zahnrades (AddGear),
- Die Animation starten (StartAnimation),
- Die Zahnräder nur Statisch zeichnen (DrawStatic),
- Die Animation wieder zu stoppen (StopAnimation).
Die Öffentlichen Funktion, welche als Benutzer zur Verfügung stehen sind schnell geschrieben.
Gears.prototype.AddGear = function(gear) {
this.allGears.push(gear);
}
Gears.prototype.StartAnimation = function() {
this.timer = setInterval(function() {_this.draw();}, 25);
}
Gears.prototype.DrawStatic = function() {
this.draw();
}
Gears.prototype.StopAnimation = function() {
clearTimeout(this.timer);
}
Es fehlen noch draw() und clear():
this.clear = function() {
this.ctx.clearRect(0 ,0 ,this.width, this.height);
}
this.draw = function() {
this.clear();
for (var i = 0; i < this.allGears.length; i++) {
var g = this.allGears[i];
this.drawGear(g);
}
}
Und zuletzt noch die drawGear():
this.drawGear = function(gear) {
var z = gear.getTeeth();
var m = gear.getModulo();
var df = (z - 2.5) * m; // Innenradius
var d = z * m; // Radius
var dk = (z + 2) * m; // Außenradius
var tooth_angle = Math.PI/ z;
var d_i_big = (z - 7) * m;
var d_i_black = 8 * m;
var rect_w = (z - 3) * m * 2;
var rect_h = 6 * m;
var x = gear.getX();
var y = gear.getY();
var angle = gear.getAngle();
//Drehung neu berechnen
if(gear.getDirection()) gear.setAngle(angle - gear.getSpeed()/40);
else gear.setAngle(angle + gear.getSpeed()/40);
angle = gear.getAngle();
this.ctx.beginPath();
this.ctx.moveTo(x + Math.sin(angle - tooth_angle/1.5) * df, y - Math.cos(angle - tooth_angle/1.5) * df);
for (var phi = angle; phi < angle + 2*Math.PI; phi = phi + 2*Math.PI/z) {
//linke Seite des Zahns
this.ctx.lineTo(x + Math.sin(phi - tooth_angle/4) * dk, y - Math.cos(phi - tooth_angle/4) * dk);
//oberer Teil des Zahns
this.ctx.arc(x, y, dk, phi - tooth_angle/4 - Math.PI / 2, phi + tooth_angle/4 - Math.PI / 2);
//rechte Seite des Zahns
this.ctx.lineTo(x + Math.sin(phi + tooth_angle/1.5) * df, y - Math.cos(phi + tooth_angle/1.5) * df);
//Der untere Teil des Zahns
this.ctx.arc(x, y, df, phi + tooth_angle/1.5 - Math.PI / 2, phi + 2 * tooth_angle/1.5 - Math.PI / 2);
}
//Das Innenloch ausschneiden
this.ctx.moveTo(x+d_i_big, y);
this.ctx.arc(x, y, d_i_big, 0, 2*Math.PI, true);
//this.ctx.closePath();
this.ctx.fillStyle=gear.getColor();
this.ctx.fill();
//Das Fleisch um das Innenloch
this.ctx.fillStyle=gear.getColor();
this.ctx.arc(x, y, d_i_black, 0, 2*Math.PI, false);
this.ctx.arc(x, y, 2.5*m, 2*Math.PI, 0, true);
this.ctx.closePath();
this.ctx.fill();
//die Speichen des Zahnrads
this.ctx.beginPath();
this.ctx.translate(x, y);
this.ctx.rotate(angle);
this.ctx.fillStyle=gear.getColor();
this.ctx.fillRect(-rect_w/2, -rect_h/2, rect_w, rect_h);
this.ctx.rotate(Math.PI / 2);
this.ctx.fillStyle=gear.getColor();
this.ctx.fillRect(-rect_w/2, -rect_h/2, rect_w, rect_h);
// zurück rotieren
//this.ctx.beginPath();
this.ctx.rotate(-angle);
this.ctx.rotate(-Math.PI / 2);
this.ctx.translate(-x, -y);
this.ctx.globalCompositeOperation = "destination-out";
//this.ctx.beginPath();
this.ctx.fillStyle=gear.getColor();
this.ctx.arc(x, y, 2.5*m, 2*Math.PI, 0, false);
this.ctx.closePath();
this.ctx.fill();
this.ctx.globalCompositeOperation = "source-over";
}
Und fertig ist der Javascript Teil. Für die Verwendung in Html ist im Folgenden ein kleines Beispiel gezeigt:
<!DOCTPYE html>
<html>
<head>
<title>Canvas Gears</title>
<script language="javascript" type="text/javascript" src="Gears.js"></script>
</head>
<body>
<canvas id="myCanvas" width="300" height="160" style="border:1px solid #000000; ">
</canvas>
</body>
<script>
var speed = Math.PI / 16;
var m = 2;
var z1 = 36;
var z2 = 24;
var z3 = 12;
var canvas = document.getElementById('myCanvas');
if (canvas && canvas.getContext) {
var ctx = canvas.getContext("2d");
var gears = new Gears(canvas1);
var g1 = new Gear((z1+2)*m, (z1+2)*m, m, z1, "rgba(0, 0, 0, 1)", 0, speed, false);
var g2 = new Gear((z1+2)*m + (z1+z2)*m, (z1+2)*m, m, z2, "rgba(0, 0, 0, 1)", 0, speed * 1.5, true);
var g3 = new Gear((z1+2)*m + (z1+z2)*m + (z2+z3)*m, (z1+2)*m, m, z3, "rgba(0, 0, 0, 1)", 0, speed * 3, false);
gears.AddGear(g1);
gears.AddGear(g2);
gears.AddGear(g3);
gears.StartAnimation();
}
</script>
</html>
Wie das ganze aussehen kann seht ihr im Logo dieser Seite und im Hintergrund.