Add zooming in both directions

This commit is contained in:
Florine W. Dekker 2021-10-31 17:01:50 +01:00
parent c5969362ad
commit c5e9d763ce
Signed by: FWDekker
GPG Key ID: D3DCFAA8A4560BE0
1 changed files with 44 additions and 31 deletions

View File

@ -53,6 +53,16 @@ class LineSegment {
} }
/**
* Returns the angle formed by this `LineSegment` in radians.
*
* @return the angle formed by this `LineSegment` in radians
*/
angle(): number {
return Math.atan2(this.y, this.x);
}
/** /**
* Returns `true` if and only if this `LineSegment` is exactly the same as `other`. * Returns `true` if and only if this `LineSegment` is exactly the same as `other`.
* *
@ -117,6 +127,7 @@ const settings = {
fillGoal: 0.3, fillGoal: 0.3,
stepTime: 250, stepTime: 250,
stepsPerLevel: 5, stepsPerLevel: 5,
zoomSpeed: 1 / 30,
}; };
@ -131,41 +142,37 @@ doAfterLoad(() => {
// Model // Model
// TODO: Dynamic thickness calculation
const lines: Line[] = [new Line(1), new Line(5)]; const lines: Line[] = [new Line(1), new Line(5)];
let step = 0; let step = 0;
let lastStepTime = Date.now();
setInterval(() => { setInterval(() => {
const stepLine = Math.floor(step / (settings.stepsPerLevel ** 2)); const currentLevel = lines.findIndex(it => it.segments.length !== 25);
const inductionLine = stepLine + 1;
const superInductionLine = stepLine + 2;
// Add new low-level segment // Add low-level segment
const length = settings.stepsPerLevel ** (2 + stepLine); const length = settings.stepsPerLevel ** (2 + currentLevel);
// TODO: Accumulate angles let angle: number;
const angle = (random_normal() - 0.5) * Math.PI * 2; if (lines[currentLevel].segments.length > 0)
lines[stepLine].segments.push(new LineSegment(Math.cos(angle) * length, Math.sin(angle) * length)); angle = lines[currentLevel].segments.slice(-1)[0].angle() + (random_normal() - 0.5) * Math.PI * 2;
else
angle = Math.random() * Math.PI * 2;
lines[currentLevel].segments.push(new LineSegment(Math.cos(angle) * length, Math.sin(angle) * length));
// Add first-level induction line // Add induction segments
if ((step + 1) % settings.stepsPerLevel === 0) { for (const level of [1, 2]) {
if (lines.length <= inductionLine) { const inductionLevel = currentLevel + level;
lines[inductionLine] = new Line(5 ** inductionLine); const lowerLines = lines[inductionLevel - 1];
if (lowerLines.segments.length !== 0 && lowerLines.segments.length % 5 === 0) {
if (lines.length <= inductionLevel) {
lines[inductionLevel] = new Line(5 ** inductionLevel);
}
lines[inductionLevel].segments.push(lowerLines.sumSegmentsSlice(-settings.stepsPerLevel));
} }
lines[inductionLine].segments.push(lines[stepLine].sumSegmentsSlice(-settings.stepsPerLevel));
}
// Add second-level induction line
if ((step + 1) % (settings.stepsPerLevel ** 2) === 0) {
if (lines.length <= superInductionLine) {
lines[superInductionLine] = new Line(5 ** superInductionLine);
}
lines[superInductionLine].segments.push(lines[inductionLine].sumSegmentsSlice(-settings.stepsPerLevel));
} }
// Update shared info
step++; step++;
lastStepTime = Date.now();
}, settings.stepTime); }, settings.stepTime);
@ -179,8 +186,7 @@ doAfterLoad(() => {
// Draw // Draw
const startTime = Date.now(); let maxPoint = new Point(0, 0);
let maxX = 0;
let zoomFactor = 1; let zoomFactor = 1;
const draw = () => { const draw = () => {
ctx.restore(); ctx.restore();
@ -201,8 +207,12 @@ doAfterLoad(() => {
ctx.stroke(); ctx.stroke();
// Zoom // Zoom
if ((1 / zoomFactor) * maxX > canvas.width * settings.fillGoal) { const excessFactor = Math.max(
zoomFactor *= (((1 / zoomFactor) * maxX) / (canvas.width * settings.fillGoal)) ** (1 / 60); ((1 / zoomFactor) * maxPoint.x) / (canvas.width * settings.fillGoal),
((1 / zoomFactor) * maxPoint.y) / (canvas.height * settings.fillGoal)
);
if (excessFactor > 1) {
zoomFactor *= excessFactor ** settings.zoomSpeed;
} }
ctx.scale(1 / zoomFactor, 1 / zoomFactor); ctx.scale(1 / zoomFactor, 1 / zoomFactor);
@ -218,7 +228,10 @@ doAfterLoad(() => {
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);
maxX = Math.max(maxX, lastPos.x); maxPoint = new Point(
Math.max(maxPoint.x, Math.abs(lastPos.x)),
Math.max(maxPoint.y, Math.abs(lastPos.y))
);
} }
ctx.stroke(); ctx.stroke();