- b toggles boing for center star
- w toggles whir for center star
- p toggles phase for center star
- G go
- S stop
- A copy center to all
- R reset All
- W toggle whir for entire scene.
The HTML file:
<head>
<script type="text/javascript" src="star.js"> </script>
<script type="text/javascript" src="UI.js"> </script>
</head>
<body>
<canvas id="canvas" width=500 height=500 style="border:2px solid"></canvas>
<p>
<ul>
</ul>
<script>
'use strict'
var canvas = document.getElementById('canvas');
canvas.tabIndex=0;
canvas.addEventListener("keypress", Keypress);
var items = [];
items.push(new Star(canvas.width/2, canvas.height/2));
items.push(new Star(canvas.width/4, canvas.height/4));
items.push(new Star(3*canvas.width/4, canvas.height/4));
items.push(new Star(3*canvas.width/4, 3*canvas.height/4));
items.push(new Star(canvas.width/4, 3*canvas.height/4));
var animation = false;
var rotation = 0;
var doRotation = false;
var ctx = canvas.getContext('2d');
ctx.transform(1,0,0,-1,0,canvas.height);
DrawScene(items);
</script>
<ul>
<li> <b>b</b> toggles boing for center star
<lI> <b>w</b> toggles whir for center star
<lI> <b>p</b> toggles phase for center star
<li> <b>G</b> go
<li> <b>S</b> stop
<lI> <b>A</b> copy center to all
<lI> <b>R</b> reset All
<li> <b>W</b> toggle whir for entire scene.
</ul>
</body>
UI.js
'use strict'
function Keypress(evnt) {
switch(event.key) {
case 'A':
for (let i=1;i<items.length;i++) {
items[i].Copy(items[0]);
}
break;
case 'G':
// don't want to start a second one if we are already animating
if (animation != true) {
animation = true;
setTimeout(DoAnimation, 20);
}
break;
case 'S':
animation = false;
break;
case 'R':
for (let i=0;i<items.length;i++) {
items[i].Reset();
}
animation = false;
break;
case 'W':
doRotation = !doRotation;
break;
case 'b':
items[0].FlipScale()
break;
case 'p':
items[0].FlipPhase();
break;
case 'w':
items[0].FlipSpin();
break;
}
DrawScene();
}
function DoAnimation() {
if (doRotation) {
rotation -= 1;
rotation %= 360;
}
DrawScene();
if (animation) {
setTimeout(DoAnimation, 20);
}
}
function DrawScene(){
ctx.clearRect(0,0, canvas.height, canvas.width);
ctx.save();
ctx.translate(canvas.width/2, canvas.height/2);
ctx.rotate(rotation*Math.PI/180);
ctx.translate(-canvas.width/2, -canvas.height/2);
for(let i = 0; i < items.length; i++) {
items[i].Next();
items[i].Display(ctx);
}
ctx.restore();
}
star.js
'use strict'
const SCALE_MIN = 20;
const SCALE_MAX = 100;
function MakePoints() {
let pts = [];
for(let i = 0; i < 5; i++) {
let angle = i*Math.PI*2/5;
let x = Math.cos(angle);
let y = Math.sin(angle);
pts.push([x,y]);
}
return pts;
}
class Star{
constructor(cx = 0, cy = 0 ){
this.points = MakePoints();
this.orderB = [0,1,2,3,4];
this.orderA = [3,1,4,2,0];
this.cx = cx;
this.cy = cy;
this.Reset();
}
Copy (master) {
this.scale = master.scale;
this.scaling = master.scaling;
this.scaleDir = master.scaleDir;
this.rotation = master.rotation;
this.spinning = master.spinning;
this.spinDown = master.spinDown;
this.phasing = master.phasing;
this.phaseDir = master.phaseDir;
this.phaseStep = master.phaseStep;
}
Reset() {
this.scale = SCALE_MIN;
this.scaling = false;
this.scaleDir = 1;
this.rotation = 0;
this.spinning = false;
this.spinDown = false;
this.phasing = false;
this.phaseDir = 1;
this.phaseStep = 0;
}
FlipSpin() {
this.spinning = !this.spinning;
if (this.spinning == false ) {
this.spinDown = true;
} else {
this.spinDown = false;
}
}
FlipScale() {
this.scaling = !this.scaling;
}
FlipPhase() {
this.phasing = !this.phasing;
}
Next() {
if (this.spinning || (this.spinDown && this.rotation != 0)) {
this.rotation += 1;
this.rotation %= 360;
}
if(this.spinDown && this.rotation == 0) {
this.spinDown = false;
}
if (this.scaling) {
this.scale += this.scaleDir;
if (this.scale <= SCALE_MIN) {
this.scaleDir = 1;
}
if (this.scale >= SCALE_MAX) {
this.scaleDir = -1;
}
}
if (this.phasing) {
this.phaseStep += .01 * this.phaseDir;
if (this.phaseStep <= 0) {
this.phaseDir = 1;
}
if (this.phaseStep >= 1) {
this.phaseDir = -1;
}
}
}
TruePoint(pt) {
let idx1 = this.orderA[pt];
let idx2 = this.orderB[pt];
let x = this.points[idx1][0] * (1-this.phaseStep)
+ this.points[idx2][0]*this.phaseStep;
let y = this.points[idx1][1] * (1-this.phaseStep)
+ this.points[idx2][1]*this.phaseStep;
return [x,y];
}
Display(ctx) {
let scale = this.scale;
ctx.save();
ctx.translate(this.cx, this.cy)
ctx.rotate(this.rotation*Math.PI/180);
let last = this.points.length-1;
ctx.beginPath();
let pt = this.TruePoint(last);
ctx.fillStyle = "red";
ctx.arc(pt[0]*scale,pt[1]*scale, 4, 0, Math.PI*2);
ctx.fill();
ctx.strokeStyle = "blue";
ctx.moveTo(pt[0]*scale,pt[1]*scale);
for(let i=0; i<=last; i++) {
let pt = this.TruePoint(i);
ctx.lineTo(pt[0]*scale,pt[1]*scale);
}
ctx.stroke();
ctx.closePath();
ctx.restore();
}
}