💡 Performance: only calculate points once

This commit is contained in:
Mattéo Delabre 2015-12-23 19:01:47 +01:00
parent 41c3ce8b17
commit 7019b4c40a
3 changed files with 70 additions and 46 deletions

View File

@ -491,18 +491,18 @@ function _typeof(obj) { return obj && typeof Symbol !== "undefined" && obj.const
}; };
/** /**
* Apply the chaos game: starting from `start`, we plot * Starting from the last point in `points`, add
* the next `n` points. To get to the next point, we apply * `iterations` number of point generated by applying
* a random transformation among given ones * transformations chosen at random among `transforms`
* *
* @param {Array} start Starting point * @param {Array} points Initial set of points
* @param {number} iterations Number of points to plot * @param {number} iterations Number of points to plot
* @param {Array} transforms List of available transforms * @param {Array} transforms List of available transforms
* @param {Array} weights Probability weights for each transform * @param {Array} weights Probability weights for each transform
* @return {null} * @return {null}
*/ */
var applyChaos = exports.applyChaos = function applyChaos(start, iterations, transforms, weights, cb) { var applyChaos = exports.applyChaos = function applyChaos(points, iterations, transforms, weights) {
var point = start; var point = points[points.length - 1];
if (weights === undefined) { if (weights === undefined) {
weights = Array.apply(null, Array(transforms.length)).map(function () { weights = Array.apply(null, Array(transforms.length)).map(function () {
@ -513,8 +513,7 @@ function _typeof(obj) { return obj && typeof Symbol !== "undefined" && obj.const
while (iterations--) { while (iterations--) {
var index = chooseIndex(weights); var index = chooseIndex(weights);
point = transforms[index](point); point = transforms[index](point);
points.push(point);
cb(point);
} }
}; };
}, {}], 7: [function (require, module, exports) { }, {}], 7: [function (require, module, exports) {
@ -571,6 +570,8 @@ function _typeof(obj) { return obj && typeof Symbol !== "undefined" && obj.const
var width = undefined, var width = undefined,
height = undefined; height = undefined;
var points = [[0, 0]];
/** /**
* Re-render the scene from scratch * Re-render the scene from scratch
* *
@ -587,24 +588,22 @@ function _typeof(obj) { return obj && typeof Symbol !== "undefined" && obj.const
// do the chaos game // do the chaos game
var image = ctx.getImageData(0, 0, width, height); var image = ctx.getImageData(0, 0, width, height);
var length = points.length;
var color = [0, 0, 0]; var color = [0, 0, 0];
var skip = 50;
_chaos.applyChaos.apply(undefined, [[0, 0], 200000].concat(_toConsumableArray(_ifs.barnsley), [function (point) { for (var i = 50; i < length; i += 1) {
var x = Math.floor(point[0] * zoom + center[0]); var x = Math.floor(points[i][0] * zoom + center[0]);
var y = height - Math.floor(point[1] * zoom + center[1]); var y = height - Math.floor(points[i][1] * zoom + center[1]);
if (x >= 0 && x < width && y >= 0 && y < height && skip <= 0) { if (x >= 0 && x < width && y >= 0 && y < height) {
var i = (y * width + x) * 4; var index = (y * width + x) * 4;
image.data[i] = color[0]; image.data[index] = color[0];
image.data[i + 1] = color[1]; image.data[index + 1] = color[1];
image.data[i + 2] = color[2]; image.data[index + 2] = color[2];
image.data[i + 3] = 255; image.data[index + 3] = 255;
} }
}
skip -= 1;
}]));
ctx.putImageData(image, 0, 0); ctx.putImageData(image, 0, 0);
}; };
@ -627,7 +626,7 @@ function _typeof(obj) { return obj && typeof Symbol !== "undefined" && obj.const
*/ */
content.on('wheel', function (event) { content.on('wheel', function (event) {
var delta = event.deltaMode === 0 ? event.deltaY / 53 : event.deltaY; var delta = event.deltaMode === 0 ? event.deltaY / 53 : event.deltaY;
var newZoom = zoom * (1 - delta * .035); var newZoom = zoom * Math.max(0, 1 - delta * .035);
// which (unprojected) point does the mouse point on? // which (unprojected) point does the mouse point on?
var mouse = [(event.offsetX - center[0]) / zoom, (height - event.offsetY - center[1]) / zoom]; var mouse = [(event.offsetX - center[0]) / zoom, (height - event.offsetY - center[1]) / zoom];
@ -638,9 +637,33 @@ function _typeof(obj) { return obj && typeof Symbol !== "undefined" && obj.const
// => newCenter = mouse * zoom - mouse * newZoom + center // => newCenter = mouse * zoom - mouse * newZoom + center
center = [mouse[0] * zoom - mouse[0] * newZoom + center[0], mouse[1] * zoom - mouse[1] * newZoom + center[1]]; center = [mouse[0] * zoom - mouse[0] * newZoom + center[0], mouse[1] * zoom - mouse[1] * newZoom + center[1]];
zoom = newZoom; if (newZoom > zoom) {
render(); _chaos.applyChaos.apply(undefined, [points, Math.floor((newZoom - zoom) * 1000)].concat(_toConsumableArray(_ifs.sierpinski)));
} else {
// points = points.slice(0, points.length + Math.floor((newZoom - zoom) * 1000));
}
zoom = newZoom;
// time for some GC
if (points.length > 1000000) {
var length = points.length;
var newPoints = [];
var i = 0;
for (i = 0; i < length; i += 1) {
var x = Math.floor(points[i][0] * zoom + center[0]);
var y = height - Math.floor(points[i][1] * zoom + center[1]);
if (x >= 0 && x < width && y >= 0 && y < height) {
newPoints.push(points[i]);
}
}
points = newPoints;
}
render();
event.preventDefault(); event.preventDefault();
}); });
@ -668,6 +691,7 @@ function _typeof(obj) { return obj && typeof Symbol !== "undefined" && obj.const
} }
}); });
_chaos.applyChaos.apply(undefined, [points, 200000].concat(_toConsumableArray(_ifs.sierpinski)));
window.onresize = resize; window.onresize = resize;
resize(); resize();
}, { "./chaos": 6, "./ifs": 7, "the-dom": 1 }] }, {}, [8]); }, { "./chaos": 6, "./ifs": 7, "the-dom": 1 }] }, {}, [8]);

View File

@ -20,18 +20,18 @@ const chooseIndex = weights => {
}; };
/** /**
* Apply the chaos game: starting from `start`, we plot * Starting from the last point in `points`, add
* the next `n` points. To get to the next point, we apply * `iterations` number of point generated by applying
* a random transformation among given ones * transformations chosen at random among `transforms`
* *
* @param {Array} start Starting point * @param {Array} points Initial set of points
* @param {number} iterations Number of points to plot * @param {number} iterations Number of points to plot
* @param {Array} transforms List of available transforms * @param {Array} transforms List of available transforms
* @param {Array} weights Probability weights for each transform * @param {Array} weights Probability weights for each transform
* @return {null} * @return {null}
*/ */
export const applyChaos = (start, iterations, transforms, weights, cb) => { export const applyChaos = (points, iterations, transforms, weights) => {
let point = start; let point = points[points.length - 1];
if (weights === undefined) { if (weights === undefined) {
weights = Array.apply(null, Array(transforms.length)).map( weights = Array.apply(null, Array(transforms.length)).map(
@ -42,7 +42,6 @@ export const applyChaos = (start, iterations, transforms, weights, cb) => {
while (iterations--) { while (iterations--) {
const index = chooseIndex(weights); const index = chooseIndex(weights);
point = transforms[index](point); point = transforms[index](point);
points.push(point);
cb(point);
} }
}; };

View File

@ -14,6 +14,8 @@ let dragging = false;
let center, zoom = 200; let center, zoom = 200;
let width, height; let width, height;
let points = [[0, 0]];
/** /**
* Re-render the scene from scratch * Re-render the scene from scratch
* *
@ -30,24 +32,22 @@ const render = () => {
// do the chaos game // do the chaos game
const image = ctx.getImageData(0, 0, width, height); const image = ctx.getImageData(0, 0, width, height);
const length = points.length;
const color = [0, 0, 0]; const color = [0, 0, 0];
let skip = 50;
applyChaos([0, 0], 200000, ...barnsley, point => { for (let i = 50; i < length; i += 1) {
const x = Math.floor(point[0] * zoom + center[0]); const x = Math.floor(points[i][0] * zoom + center[0]);
const y = height - Math.floor(point[1] * zoom + center[1]); const y = height - Math.floor(points[i][1] * zoom + center[1]);
if (x >= 0 && x < width && y >= 0 && y < height && skip <= 0) { if (x >= 0 && x < width && y >= 0 && y < height) {
const i = (y * width + x) * 4; const index = (y * width + x) * 4;
image.data[i] = color[0]; image.data[index] = color[0];
image.data[i + 1] = color[1]; image.data[index + 1] = color[1];
image.data[i + 2] = color[2]; image.data[index + 2] = color[2];
image.data[i + 3] = 255; image.data[index + 3] = 255;
} }
}
skip -= 1;
});
ctx.putImageData(image, 0, 0); ctx.putImageData(image, 0, 0);
}; };
@ -70,7 +70,7 @@ const resize = () => {
*/ */
content.on('wheel', event => { content.on('wheel', event => {
const delta = event.deltaMode === 0 ? event.deltaY / 53 : event.deltaY; const delta = event.deltaMode === 0 ? event.deltaY / 53 : event.deltaY;
const newZoom = zoom * (1 - delta * .035); const newZoom = zoom * Math.max(0, 1 - delta * .035);
// which (unprojected) point does the mouse point on? // which (unprojected) point does the mouse point on?
const mouse = [ const mouse = [
@ -113,5 +113,6 @@ content.on('mousemove', event => {
} }
}); });
applyChaos(points, 200000, ...barnsley);
window.onresize = resize; window.onresize = resize;
resize(); resize();