Add zooming in both directions
This commit is contained in:
parent
c5969362ad
commit
c5e9d763ce
|
@ -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();
|
||||
|
|
Loading…
Reference in New Issue