chaos/scripts/index.js

118 lines
2.9 KiB
JavaScript

'use strict';
import { html } from 'the-dom';
import { applyChaos } from './chaos';
import { barnsley } from './ifs';
const { body } = html(document);
const content = body.find('#content');
const plotting = body.find('#plotting').node;
const ctx = plotting.getContext('2d');
let dragging = false;
let center, zoom = 200;
let width, height;
/**
* Re-render the scene from scratch
*
* @return {null}
*/
const render = () => {
plotting.width = width;
plotting.height = height;
// do not plot (very) small sizes
if (width < 1) {
return;
}
// do the chaos game
const image = ctx.getImageData(0, 0, width, height);
const color = [0, 0, 0];
let skip = 50;
applyChaos(image, [0, 0], 500000, ...barnsley, point => {
const x = Math.floor(point[0] * zoom + center[0]);
const y = height - Math.floor(point[1] * zoom + center[1]);
if (x >= 0 && x < width && y >= 0 && y < height && skip <= 0) {
const i = (y * width + x) * 4;
image.data[i] = color[0];
image.data[i + 1] = color[1];
image.data[i + 2] = color[2];
image.data[i + 3] = 255;
}
skip -= 1;
});
ctx.putImageData(image, 0, 0);
};
/**
* Update the scene when the window has been resized
*
* @return {null}
*/
const resize = () => {
width = content.node.clientWidth;
height = content.node.clientHeight;
center = [Math.floor(width / 2), Math.floor(height / 2)];
render();
};
/**
* Zoom on the cursor position when using mouse wheel
*/
content.on('wheel', event => {
const delta = event.deltaMode === 0 ? event.deltaY / 53 : event.deltaY;
const newZoom = zoom * (1 - delta * .035);
// which (unprojected) point does the mouse point on?
const mouse = [
(event.offsetX - center[0]) / zoom,
(height - event.offsetY - center[1]) / zoom
];
// we need to set the center so that `mouse` stays at
// the same position on screen, i.e (vectorially):
// mouse * newZoom + newCenter = mouse * zoom + center
// => newCenter = mouse * zoom - mouse * newZoom + center
center = [
mouse[0] * zoom - mouse[0] * newZoom + center[0],
mouse[1] * zoom - mouse[1] * newZoom + center[1]
];
zoom = newZoom;
render();
event.preventDefault();
});
/**
* Pan the content with click-drag action
*/
content.on('mousedown', event => dragging = [event.offsetX, event.offsetY]);
content.on('mouseup', () => dragging = false);
content.on('mousemove', event => {
if (dragging !== false) {
const newMouse = [event.offsetX, event.offsetY];
const movement = [newMouse[0] - dragging[0], newMouse[1] - dragging[1]];
center[0] += movement[0];
center[1] -= movement[1];
render();
dragging = newMouse;
event.preventDefault();
}
});
window.onresize = resize;
resize();