From 7019b4c40afdc8f002f10ff2798e61879668ba1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matt=C3=A9o=20Delabre?= Date: Wed, 23 Dec 2015 19:01:47 +0100 Subject: [PATCH] :bulb: Performance: only calculate points once --- bundle.js | 72 ++++++++++++++++++++++++++++++++---------------- scripts/chaos.js | 15 +++++----- scripts/index.js | 29 +++++++++---------- 3 files changed, 70 insertions(+), 46 deletions(-) diff --git a/bundle.js b/bundle.js index 991dc3d..be856cb 100644 --- a/bundle.js +++ b/bundle.js @@ -491,18 +491,18 @@ function _typeof(obj) { return obj && typeof Symbol !== "undefined" && obj.const }; /** - * Apply the chaos game: starting from `start`, we plot - * the next `n` points. To get to the next point, we apply - * a random transformation among given ones + * Starting from the last point in `points`, add + * `iterations` number of point generated by applying + * 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 {Array} transforms List of available transforms * @param {Array} weights Probability weights for each transform * @return {null} */ - var applyChaos = exports.applyChaos = function applyChaos(start, iterations, transforms, weights, cb) { - var point = start; + var applyChaos = exports.applyChaos = function applyChaos(points, iterations, transforms, weights) { + var point = points[points.length - 1]; if (weights === undefined) { 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--) { var index = chooseIndex(weights); point = transforms[index](point); - - cb(point); + points.push(point); } }; }, {}], 7: [function (require, module, exports) { @@ -571,6 +570,8 @@ function _typeof(obj) { return obj && typeof Symbol !== "undefined" && obj.const var width = undefined, height = undefined; + var points = [[0, 0]]; + /** * Re-render the scene from scratch * @@ -587,24 +588,22 @@ function _typeof(obj) { return obj && typeof Symbol !== "undefined" && obj.const // do the chaos game var image = ctx.getImageData(0, 0, width, height); + var length = points.length; var color = [0, 0, 0]; - var skip = 50; - _chaos.applyChaos.apply(undefined, [[0, 0], 200000].concat(_toConsumableArray(_ifs.barnsley), [function (point) { - var x = Math.floor(point[0] * zoom + center[0]); - var y = height - Math.floor(point[1] * zoom + center[1]); + for (var i = 50; 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 && skip <= 0) { - var i = (y * width + x) * 4; + if (x >= 0 && x < width && y >= 0 && y < height) { + var index = (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; + image.data[index] = color[0]; + image.data[index + 1] = color[1]; + image.data[index + 2] = color[2]; + image.data[index + 3] = 255; } - - skip -= 1; - }])); + } ctx.putImageData(image, 0, 0); }; @@ -627,7 +626,7 @@ function _typeof(obj) { return obj && typeof Symbol !== "undefined" && obj.const */ content.on('wheel', function (event) { 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? 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 center = [mouse[0] * zoom - mouse[0] * newZoom + center[0], mouse[1] * zoom - mouse[1] * newZoom + center[1]]; - zoom = newZoom; - render(); + if (newZoom > zoom) { + _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(); }); @@ -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; resize(); }, { "./chaos": 6, "./ifs": 7, "the-dom": 1 }] }, {}, [8]); diff --git a/scripts/chaos.js b/scripts/chaos.js index adedbe8..d84a710 100644 --- a/scripts/chaos.js +++ b/scripts/chaos.js @@ -20,18 +20,18 @@ const chooseIndex = weights => { }; /** - * Apply the chaos game: starting from `start`, we plot - * the next `n` points. To get to the next point, we apply - * a random transformation among given ones + * Starting from the last point in `points`, add + * `iterations` number of point generated by applying + * 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 {Array} transforms List of available transforms * @param {Array} weights Probability weights for each transform * @return {null} */ -export const applyChaos = (start, iterations, transforms, weights, cb) => { - let point = start; +export const applyChaos = (points, iterations, transforms, weights) => { + let point = points[points.length - 1]; if (weights === undefined) { weights = Array.apply(null, Array(transforms.length)).map( @@ -42,7 +42,6 @@ export const applyChaos = (start, iterations, transforms, weights, cb) => { while (iterations--) { const index = chooseIndex(weights); point = transforms[index](point); - - cb(point); + points.push(point); } }; diff --git a/scripts/index.js b/scripts/index.js index 5c8579c..117dc0b 100644 --- a/scripts/index.js +++ b/scripts/index.js @@ -14,6 +14,8 @@ let dragging = false; let center, zoom = 200; let width, height; +let points = [[0, 0]]; + /** * Re-render the scene from scratch * @@ -30,24 +32,22 @@ const render = () => { // do the chaos game const image = ctx.getImageData(0, 0, width, height); + const length = points.length; const color = [0, 0, 0]; - let skip = 50; - applyChaos([0, 0], 200000, ...barnsley, point => { - const x = Math.floor(point[0] * zoom + center[0]); - const y = height - Math.floor(point[1] * zoom + center[1]); + for (let i = 50; i < length; i += 1) { + const x = Math.floor(points[i][0] * zoom + center[0]); + const y = height - Math.floor(points[i][1] * zoom + center[1]); - if (x >= 0 && x < width && y >= 0 && y < height && skip <= 0) { - const i = (y * width + x) * 4; + if (x >= 0 && x < width && y >= 0 && y < height) { + const index = (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; + image.data[index] = color[0]; + image.data[index + 1] = color[1]; + image.data[index + 2] = color[2]; + image.data[index + 3] = 255; } - - skip -= 1; - }); + } ctx.putImageData(image, 0, 0); }; @@ -70,7 +70,7 @@ const resize = () => { */ content.on('wheel', event => { 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? const mouse = [ @@ -113,5 +113,6 @@ content.on('mousemove', event => { } }); +applyChaos(points, 200000, ...barnsley); window.onresize = resize; resize();