Compare commits
2 Commits
d71b18dbcc
...
e53d88c991
Author | SHA1 | Date |
---|---|---|
Ladd Hoffman | e53d88c991 | |
Ladd Hoffman | 2a75359997 |
86
draw.js
86
draw.js
|
@ -9,34 +9,46 @@ class Drawing {
|
||||||
this.stopButton.onclick = () => this.stop();
|
this.stopButton.onclick = () => this.stop();
|
||||||
this.stopButton.innerHTML = "Stop";
|
this.stopButton.innerHTML = "Stop";
|
||||||
this.canvas = document.createElement('canvas');
|
this.canvas = document.createElement('canvas');
|
||||||
this.canvas.width = 200;
|
|
||||||
this.canvas.height = 200;
|
|
||||||
buttonsDiv.appendChild(this.startButton);
|
buttonsDiv.appendChild(this.startButton);
|
||||||
buttonsDiv.appendChild(this.stopButton);
|
buttonsDiv.appendChild(this.stopButton);
|
||||||
div.appendChild(buttonsDiv);
|
div.appendChild(buttonsDiv);
|
||||||
div.appendChild(this.canvas);
|
div.appendChild(this.canvas);
|
||||||
document.body.appendChild(div);
|
document.body.appendChild(div);
|
||||||
this.ctx = this.canvas.getContext('2d');
|
this.ctx = this.canvas.getContext('2d');
|
||||||
this.offset = {x: 0, y: 0};
|
|
||||||
this.sequence = [];
|
this.sequence = [];
|
||||||
this.t = 0;
|
this.t = 0;
|
||||||
this.rt = 0;
|
this.rt = 0;
|
||||||
this.dt = 0;
|
this.dt = 0;
|
||||||
this.points = {};
|
this.points = {};
|
||||||
this.stopped = true;
|
this.stopped = true;
|
||||||
|
this.frame = [[-50, -50], [150, 150]];
|
||||||
|
this.scale = 1.0;
|
||||||
|
this.canvas.width = (this.frame[1][0] - this.frame[0][0]) * this.scale;
|
||||||
|
this.canvas.height = (this.frame[1][1] - this.frame[0][1]) * this.scale;
|
||||||
|
this.speed = 1.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
pixel([x, y]) {
|
pixel([x, y]) {
|
||||||
return [
|
return [
|
||||||
this.offset.x + x,
|
(x - this.frame[0][0]) * this.scale,
|
||||||
this.canvas.height - this.offset.y - y
|
this.canvas.height - (y - this.frame[0][1]) * this.scale
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
setOffset([x, y]) {
|
setSpeed(speed) {
|
||||||
this.sequence.push(() => {
|
this.speed = speed;
|
||||||
this.offset = {x, y};
|
}
|
||||||
});
|
|
||||||
|
setFrame([x1, y1], [x2, y2]) {
|
||||||
|
this.frame = [[x1, y1], [x2, y2]];
|
||||||
|
this.canvas.width = (this.frame[1][0] - this.frame[0][0]) * this.scale;
|
||||||
|
this.canvas.height = (this.frame[1][1] - this.frame[0][1]) * this.scale;
|
||||||
|
}
|
||||||
|
|
||||||
|
setScale(zoom) {
|
||||||
|
this.scale = zoom;
|
||||||
|
this.canvas.width = (this.frame[1][0] - this.frame[0][0]) * this.scale;
|
||||||
|
this.canvas.height = (this.frame[1][1] - this.frame[0][1]) * this.scale;
|
||||||
}
|
}
|
||||||
|
|
||||||
setStroke(style, width) {
|
setStroke(style, width) {
|
||||||
|
@ -72,8 +84,10 @@ class Drawing {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
oscillatingValue(x1, x2, period) {
|
oscillatingValue(x1, x2, period, initialPhase = 0) {
|
||||||
return x1 + (x2 - x1) * Math.sin(2*Math.PI*this.t/period);
|
const center = (x1 + x2) / 2;
|
||||||
|
const amplitude = (x2 - x1) / 2;
|
||||||
|
return center + amplitude * Math.sin(2*Math.PI*this.t/period + initialPhase);
|
||||||
}
|
}
|
||||||
|
|
||||||
oscillatingPoint([x1, y1], [x2, y2], period) {
|
oscillatingPoint([x1, y1], [x2, y2], period) {
|
||||||
|
@ -82,19 +96,55 @@ class Drawing {
|
||||||
return [x, y];
|
return [x, y];
|
||||||
}
|
}
|
||||||
|
|
||||||
square(p) {
|
object(p, opts, fn) {
|
||||||
|
let history = [];
|
||||||
|
const maxAge = opts?.trace?.age ?? 0;
|
||||||
|
const dashLength = 5;
|
||||||
|
let distance = 0;
|
||||||
this.sequence.push(() => {
|
this.sequence.push(() => {
|
||||||
const [x, y] = this.getPoint(p);
|
const [x, y] = this.getPoint(p);
|
||||||
this.ctx.fillRect(...this.pixel([x - 5, y - 5]), 10, 10);
|
let ds = 0;
|
||||||
|
if (history.length) {
|
||||||
|
const dx = x - history[history.length - 1].p[0];
|
||||||
|
const dy = y - history[history.length - 1].p[1];
|
||||||
|
ds = Math.sqrt(dx**2 + dy**2);
|
||||||
|
}
|
||||||
|
distance += ds;
|
||||||
|
history.push({t: this.t, p: [x, y], distance});
|
||||||
|
const oldest = history.findIndex(({t}) => this.t - t <= maxAge);
|
||||||
|
if (oldest >= 0) {
|
||||||
|
history = history.slice(oldest);
|
||||||
|
}
|
||||||
|
this.ctx.strokeStyle = 'black';
|
||||||
|
this.ctx.lineWidth = 1;
|
||||||
|
this.ctx.beginPath();
|
||||||
|
this.ctx.moveTo(...this.pixel(history[0].p));
|
||||||
|
for (let i = 1; i < history.length; i++) {
|
||||||
|
if (Math.floor(history[i].distance / dashLength) % 2) {
|
||||||
|
this.ctx.moveTo(...this.pixel(history[i].p));
|
||||||
|
} else {
|
||||||
|
this.ctx.lineTo(...this.pixel(history[i].p));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.ctx.stroke();
|
||||||
|
fn(x, y);
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
circle(p) {
|
square(p, opts) {
|
||||||
this.sequence.push(() => {
|
const size = opts?.size ?? 10;
|
||||||
|
this.object(p, opts, (x, y) => {
|
||||||
|
this.ctx.fillRect(...this.pixel([x - size / 2, y + size / 2]), size * this.scale, size * this.scale);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
circle(p, opts) {
|
||||||
|
const radius = opts?.radius ?? 5;
|
||||||
|
this.object(p, opts, (x, y) => {
|
||||||
this.ctx.beginPath();
|
this.ctx.beginPath();
|
||||||
this.ctx.ellipse(...this.pixel(this.getPoint(p)), 5, 5, 0, 0, 2*Math.PI);
|
this.ctx.ellipse(...this.pixel([x, y]), radius * this.scale, radius * this.scale, 0, 0, 2*Math.PI);
|
||||||
this.ctx.fill();
|
this.ctx.fill();
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
definePoint(name, fn) {
|
definePoint(name, fn) {
|
||||||
|
@ -132,7 +182,7 @@ class Drawing {
|
||||||
this.dt = 0;
|
this.dt = 0;
|
||||||
this.elideInterval = false;
|
this.elideInterval = false;
|
||||||
} else {
|
} else {
|
||||||
this.dt = rt - this.rt + elapsed;
|
this.dt = (rt - this.rt + elapsed) * this.speed;
|
||||||
}
|
}
|
||||||
this.t += this.dt;
|
this.t += this.dt;
|
||||||
this.rt = rt;
|
this.rt = rt;
|
||||||
|
|
10
test.html
10
test.html
|
@ -10,19 +10,17 @@
|
||||||
<body>
|
<body>
|
||||||
<script>
|
<script>
|
||||||
const d = new Drawing();
|
const d = new Drawing();
|
||||||
console.log('drawing', d);
|
|
||||||
d.setOffset([50, 50]);
|
|
||||||
d.setStroke('black', 4);
|
d.setStroke('black', 4);
|
||||||
d.polyline([0, 100], [0, 0], [100, 0]);
|
d.polyline([0, 100], [0, 0], [100, 0]);
|
||||||
d.definePoint('p1', () => d.oscillatingPoint([75, 125], [125, 125], 5000));
|
d.definePoint('p1', () => d.oscillatingPoint([25, 50], [100, 100], 5000));
|
||||||
d.setStroke('red', 2);
|
d.setStroke('red', 2);
|
||||||
d.line([0, 0], 'p1');
|
d.line([0, 0], 'p1');
|
||||||
d.setFill('blue');
|
|
||||||
d.definePoint('p2', () => {
|
d.definePoint('p2', () => {
|
||||||
const [x, y] = d.getPoint('p1');
|
const [x, y] = d.getPoint('p1');
|
||||||
return [x, y - 25];
|
return [x, y - d.oscillatingValue(10, 40, 5000 / 3, Math.PI / 2)];
|
||||||
});
|
});
|
||||||
d.square('p2');
|
d.setFill('blue');
|
||||||
|
d.square('p2', {trace: {age: 5000}});
|
||||||
d.setFill('cyan');
|
d.setFill('cyan');
|
||||||
d.circle('p1');
|
d.circle('p1');
|
||||||
d.start();
|
d.start();
|
||||||
|
|
Loading…
Reference in New Issue