Add basic non-adaptive zooming
This commit is contained in:
parent
480d9b899d
commit
df8e29c6e3
|
@ -109,47 +109,62 @@ class Line {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Global constants.
|
||||||
|
*/
|
||||||
|
const settings = {
|
||||||
|
dotRadius: 10,
|
||||||
|
stepTime: 250,
|
||||||
|
stepsPerLevel: 5,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// Unhide main element
|
||||||
doAfterLoad(() => $("main").classList.remove("hidden"));
|
doAfterLoad(() => $("main").classList.remove("hidden"));
|
||||||
|
|
||||||
|
|
||||||
|
// Application loop(s)
|
||||||
doAfterLoad(() => {
|
doAfterLoad(() => {
|
||||||
const canvas = $("#art");
|
const canvas = $("#art");
|
||||||
const ctx = canvas.getContext("2d");
|
const ctx = canvas.getContext("2d");
|
||||||
|
|
||||||
// State
|
|
||||||
const lines: Line[] = [new Line(1), new Line(2)];
|
// Model
|
||||||
|
const lines: Line[] = [new Line(1), new Line(5)];
|
||||||
|
|
||||||
let step = 0;
|
let step = 0;
|
||||||
setInterval(() => {
|
setInterval(() => {
|
||||||
const stepLine = Math.floor(step / 25);
|
const stepLine = Math.floor(step / (settings.stepsPerLevel ** 2));
|
||||||
const inductionLine = stepLine + 1;
|
const inductionLine = stepLine + 1;
|
||||||
const superInductionLine = stepLine + 2;
|
const superInductionLine = stepLine + 2;
|
||||||
|
|
||||||
// Add new low-level segment
|
// Add new low-level segment
|
||||||
const length = 5 ** (2 + stepLine);
|
const length = settings.stepsPerLevel ** (2 + stepLine);
|
||||||
|
// TODO: Accumulate angles
|
||||||
const angle = (random_normal() - 0.5) * Math.PI * 2;
|
const angle = (random_normal() - 0.5) * Math.PI * 2;
|
||||||
lines[stepLine].segments.push(new LineSegment(Math.cos(angle) * length, Math.sin(angle) * length));
|
lines[stepLine].segments.push(new LineSegment(Math.cos(angle) * length, Math.sin(angle) * length));
|
||||||
|
|
||||||
// Add first-level induction line
|
// Add first-level induction line
|
||||||
if ((step + 1) % 5 === 0) {
|
if ((step + 1) % settings.stepsPerLevel === 0) {
|
||||||
if (lines.length <= inductionLine) {
|
if (lines.length <= inductionLine) {
|
||||||
lines[inductionLine] = new Line(inductionLine + 1);
|
lines[inductionLine] = new Line(5 ** inductionLine);
|
||||||
}
|
}
|
||||||
|
|
||||||
lines[inductionLine].segments.push(lines[stepLine].sumSegmentsSlice(-5));
|
lines[inductionLine].segments.push(lines[stepLine].sumSegmentsSlice(-settings.stepsPerLevel));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add second-level induction line
|
// Add second-level induction line
|
||||||
if ((step + 1) % 25 === 0) {
|
if ((step + 1) % (settings.stepsPerLevel ** 2) === 0) {
|
||||||
if (lines.length <= superInductionLine) {
|
if (lines.length <= superInductionLine) {
|
||||||
lines[superInductionLine] = new Line(superInductionLine + 1);
|
lines[superInductionLine] = new Line(5 ** superInductionLine);
|
||||||
}
|
}
|
||||||
|
|
||||||
lines[superInductionLine].segments.push(lines[inductionLine].sumSegmentsSlice(-5));
|
lines[superInductionLine].segments.push(lines[inductionLine].sumSegmentsSlice(-settings.stepsPerLevel));
|
||||||
}
|
}
|
||||||
|
|
||||||
step++;
|
step++;
|
||||||
}, 250);
|
}, settings.stepTime);
|
||||||
|
|
||||||
|
|
||||||
// Resize
|
// Resize
|
||||||
const resize = () => {
|
const resize = () => {
|
||||||
|
@ -159,28 +174,42 @@ doAfterLoad(() => {
|
||||||
window.addEventListener("resize", resize, false);
|
window.addEventListener("resize", resize, false);
|
||||||
resize();
|
resize();
|
||||||
|
|
||||||
|
|
||||||
// Draw
|
// Draw
|
||||||
|
const startTime = Date.now();
|
||||||
const draw = () => {
|
const draw = () => {
|
||||||
const center = new Point(canvas.width / 2, canvas.height / 2);
|
ctx.restore();
|
||||||
|
ctx.save();
|
||||||
|
|
||||||
// Background
|
// Background
|
||||||
ctx.fillStyle = "#000000";
|
ctx.fillStyle = "#000000";
|
||||||
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
||||||
|
|
||||||
|
// Draw from center
|
||||||
|
const center = new Point(canvas.width / 2, canvas.height / 2);
|
||||||
|
ctx.translate(center.x, center.y);
|
||||||
|
|
||||||
// Center dot
|
// Center dot
|
||||||
ctx.beginPath();
|
ctx.beginPath();
|
||||||
ctx.fillStyle = "#ffffff";
|
ctx.strokeStyle = "#ffffff";
|
||||||
ctx.arc(center.x - 5, center.y - 5, 10, 0, 2 * Math.PI);
|
ctx.arc(0, 0, settings.dotRadius, 0, 2 * Math.PI);
|
||||||
ctx.fill();
|
ctx.stroke();
|
||||||
|
|
||||||
|
// Zoom
|
||||||
|
// TODO: Adaptive zoom
|
||||||
|
const nowTime = Date.now();
|
||||||
|
const factor = settings.stepsPerLevel **
|
||||||
|
((nowTime - startTime) / (settings.stepsPerLevel ** 2 * settings.stepTime));
|
||||||
|
ctx.scale(1 / factor, 1 / factor);
|
||||||
|
|
||||||
// Lines
|
// Lines
|
||||||
ctx.strokeStyle = "#ffffff";
|
ctx.strokeStyle = "#ffffff";
|
||||||
for (const line of lines) {
|
for (const line of lines) {
|
||||||
ctx.lineWidth = line.thickness;
|
ctx.lineWidth = line.thickness;
|
||||||
ctx.beginPath();
|
ctx.beginPath();
|
||||||
ctx.moveTo(center.x, center.y);
|
ctx.moveTo(0, 0);
|
||||||
|
|
||||||
let lastPos = new Point(center.x, center.y);
|
let lastPos = new Point(0, 0);
|
||||||
for (const segment of line.segments) {
|
for (const segment of line.segments) {
|
||||||
lastPos = new Point(lastPos.x + segment.x, lastPos.y + segment.y);
|
lastPos = new Point(lastPos.x + segment.x, lastPos.y + segment.y);
|
||||||
ctx.lineTo(lastPos.x, lastPos.y);
|
ctx.lineTo(lastPos.x, lastPos.y);
|
||||||
|
@ -189,6 +218,7 @@ doAfterLoad(() => {
|
||||||
ctx.stroke();
|
ctx.stroke();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Repeat
|
||||||
window.requestAnimationFrame(draw);
|
window.requestAnimationFrame(draw);
|
||||||
};
|
};
|
||||||
window.requestAnimationFrame(draw);
|
window.requestAnimationFrame(draw);
|
||||||
|
|
Loading…
Reference in New Issue