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`.
*
@ -117,6 +127,7 @@ const settings = {
fillGoal: 0.3,
stepTime: 250,
stepsPerLevel: 5,
zoomSpeed: 1 / 30,
};
@ -131,41 +142,37 @@ doAfterLoad(() => {
// Model
// TODO: Dynamic thickness calculation
const lines: Line[] = [new Line(1), new Line(5)];
let step = 0;
let lastStepTime = Date.now();
setInterval(() => {
const stepLine = Math.floor(step / (settings.stepsPerLevel ** 2));
const inductionLine = stepLine + 1;
const superInductionLine = stepLine + 2;
const currentLevel = lines.findIndex(it => it.segments.length !== 25);
// Add new low-level segment
const length = settings.stepsPerLevel ** (2 + stepLine);
// TODO: Accumulate angles
const angle = (random_normal() - 0.5) * Math.PI * 2;
lines[stepLine].segments.push(new LineSegment(Math.cos(angle) * length, Math.sin(angle) * length));
// Add low-level segment
const length = settings.stepsPerLevel ** (2 + currentLevel);
let angle: number;
if (lines[currentLevel].segments.length > 0)
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
if ((step + 1) % settings.stepsPerLevel === 0) {
if (lines.length <= inductionLine) {
lines[inductionLine] = new Line(5 ** inductionLine);
// Add induction segments
for (const level of [1, 2]) {
const inductionLevel = currentLevel + level;
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++;
lastStepTime = Date.now();
}, settings.stepTime);
@ -179,8 +186,7 @@ doAfterLoad(() => {
// Draw
const startTime = Date.now();
let maxX = 0;
let maxPoint = new Point(0, 0);
let zoomFactor = 1;
const draw = () => {
ctx.restore();
@ -201,8 +207,12 @@ doAfterLoad(() => {
ctx.stroke();
// Zoom
if ((1 / zoomFactor) * maxX > canvas.width * settings.fillGoal) {
zoomFactor *= (((1 / zoomFactor) * maxX) / (canvas.width * settings.fillGoal)) ** (1 / 60);
const excessFactor = Math.max(
((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);
@ -218,7 +228,10 @@ doAfterLoad(() => {
lastPos = new Point(lastPos.x + segment.x, lastPos.y + segment.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();