From d126023c4a49c27234e2f4069398e7490dd4e77f Mon Sep 17 00:00:00 2001 From: jdescottes Date: Mon, 30 Jun 2014 20:38:14 +0200 Subject: [PATCH 1/5] temp --- src/js/controller/PreviewFilmController.js | 33 +++++++++++++++++--- src/js/controller/piskel/PiskelController.js | 10 ++++-- src/js/drawingtools/SimplePen.js | 15 +++++++-- src/js/rendering/frame/TiledFrameRenderer.js | 26 +++++++++++++-- src/js/utils/CanvasUtils.js | 10 ++++++ 5 files changed, 82 insertions(+), 12 deletions(-) diff --git a/src/js/controller/PreviewFilmController.js b/src/js/controller/PreviewFilmController.js index bbca4eda..5366b7bb 100644 --- a/src/js/controller/PreviewFilmController.js +++ b/src/js/controller/PreviewFilmController.js @@ -1,6 +1,8 @@ (function () { var ns = $.namespace("pskl.controller"); + var CACHE_RESET_INTERVAL = 1000 * 60 * 10; + var ACTION = { SELECT : 'select', CLONE : 'clone', @@ -15,6 +17,9 @@ this.refreshZoom_(); this.redrawFlag = true; + + this.cache_ = {}; + window.setInterval(function () {this.cache_ = {};}.bind(this), CACHE_RESET_INTERVAL); }; ns.PreviewFilmController.prototype.init = function() { @@ -175,11 +180,8 @@ cloneFrameButton.className = "tile-overlay duplicate-frame-action"; previewTileRoot.appendChild(cloneFrameButton); - var canvasRenderer = new pskl.rendering.CanvasRenderer(currentFrame, this.zoom); - canvasRenderer.drawTransparentAs(Constants.TRANSPARENT_COLOR); - var canvas = canvasRenderer.render(); - canvas.classList.add('tile-view', 'canvas'); - canvasContainer.appendChild(canvas); + + canvasContainer.appendChild(this.getCanvasForFrame(currentFrame)); previewTileRoot.appendChild(canvasContainer); if(tileNumber > 0 || this.piskelController.getFrameCount() > 1) { @@ -206,6 +208,27 @@ return previewTileRoot; }; + ns.PreviewFilmController.prototype.getCanvasForFrame = function (frame) { + var canvas = null; + var cacheKey = frame.getHash() + this.zoom; + if (this.cache_[cacheKey]) { + canvas = this.cache_[cacheKey]; + } else { + var frameAsString = JSON.stringify(frame.getPixels()); + if (this.cache_[frameAsString]) { + canvas = pskl.CanvasUtils.clone(this.cache_[frameAsString]); + } else { + var canvasRenderer = new pskl.rendering.CanvasRenderer(frame, this.zoom); + canvasRenderer.drawTransparentAs(Constants.TRANSPARENT_COLOR); + canvas = canvasRenderer.render(); + this.cache_[frameAsString] = canvas; + } + canvas.classList.add('tile-view', 'canvas'); + this.cache_[cacheKey] = canvas; + } + return canvas; + }; + /** * Calculate the preview zoom depending on the piskel size */ diff --git a/src/js/controller/piskel/PiskelController.js b/src/js/controller/piskel/PiskelController.js index a66a5875..b337866e 100644 --- a/src/js/controller/piskel/PiskelController.js +++ b/src/js/controller/piskel/PiskelController.js @@ -77,10 +77,16 @@ }; ns.PiskelController.prototype.getFrameAt = function (index) { + var hash = []; var frames = this.getLayers().map(function (l) { - return l.getFrameAt(index); + var frame = l.getFrameAt(index); + hash.push(frame.getHash()); + return frame; }); - return pskl.utils.FrameUtils.merge(frames); + var mergedFrame = pskl.utils.FrameUtils.merge(frames); + mergedFrame.id = hash.join('-'); + mergedFrame.version = 0; + return mergedFrame; }; ns.PiskelController.prototype.hasFrameAt = function (index) { diff --git a/src/js/drawingtools/SimplePen.js b/src/js/drawingtools/SimplePen.js index dd9ab9ce..41f1c28f 100644 --- a/src/js/drawingtools/SimplePen.js +++ b/src/js/drawingtools/SimplePen.js @@ -22,7 +22,7 @@ * @override */ ns.SimplePen.prototype.applyToolAt = function(col, row, color, frame, overlay, event) { - frame.setPixel(col, row, color); + overlay.setPixel(col, row, color); this.previousCol = col; this.previousRow = row; this.pixels.push({ @@ -55,17 +55,26 @@ ns.SimplePen.prototype.releaseToolAt = function(col, row, color, frame, overlay, event) { + // apply on real frame + this.setPixelsToFrame_(frame, this.pixels, color); + + // save state this.raiseSaveStateEvent({ pixels : this.pixels.slice(0), color : color }); + + // reset this.pixels = []; }; ns.SimplePen.prototype.replay = function (frame, replayData) { - var pixels = replayData.pixels; + this.setPixelsToFrame_(frame, replayData.pixels, replayData.color); + }; + + ns.SimplePen.prototype.setPixelsToFrame_ = function (frame, pixels, color) { pixels.forEach(function (pixel) { - frame.setPixel(pixel.col, pixel.row, replayData.color); + frame.setPixel(pixel.col, pixel.row, color); }); }; })(); diff --git a/src/js/rendering/frame/TiledFrameRenderer.js b/src/js/rendering/frame/TiledFrameRenderer.js index 4b41bb1d..ce8a3c9a 100644 --- a/src/js/rendering/frame/TiledFrameRenderer.js +++ b/src/js/rendering/frame/TiledFrameRenderer.js @@ -1,6 +1,8 @@ (function () { var ns = $.namespace('pskl.rendering.frame'); + var CACHE_RESET_INTERVAL = 1000 * 60 * 10; + ns.TiledFrameRenderer = function (container, zoom) { this.container = container; this.setZoom(zoom); @@ -8,11 +10,31 @@ this.displayContainer = document.createElement('div'); this.displayContainer.classList.add('tiled-frame-container'); container.get(0).appendChild(this.displayContainer); + + this.cache_ = {}; + window.setInterval(function () {this.cache_ = {};}.bind(this), CACHE_RESET_INTERVAL); }; ns.TiledFrameRenderer.prototype.render = function (frame) { - var canvas = new pskl.utils.FrameUtils.toImage(frame, this.zoom); - this.displayContainer.style.backgroundImage = 'url(' + canvas.toDataURL('image/png') + ')'; + var frameData = null; + + var hash = frame.getHash(); + if (this.cache_[hash]) { + frameData = this.cache_[hash]; + } else { + var frameAsString = JSON.stringify(frame.getPixels()); + if (this.cache_[frameAsString]) { + frameData = this.cache_[frameAsString]; + } else { + var canvas = new pskl.utils.FrameUtils.toImage(frame, this.zoom); + frameData = canvas.toDataURL('image/png'); + this.cache_[frameAsString] = frameData; + } + + this.cache_[hash] = frameData; + } + + this.displayContainer.style.backgroundImage = 'url(' + frameData + ')'; }; ns.TiledFrameRenderer.prototype.show = function () { diff --git a/src/js/utils/CanvasUtils.js b/src/js/utils/CanvasUtils.js index a6eca20e..8ef9d161 100644 --- a/src/js/utils/CanvasUtils.js +++ b/src/js/utils/CanvasUtils.js @@ -48,6 +48,16 @@ } }, + clone : function (canvas) { + var clone = pskl.CanvasUtils.createCanvas(canvas.width, canvas.height); + + //apply the old canvas to the new one + clone.getContext('2d').drawImage(canvas, 0, 0); + + //return the new canvas + return clone; + }, + getImageDataFromCanvas : function (canvas) { var sourceContext = canvas.getContext('2d'); return sourceContext.getImageData(0, 0, canvas.width, canvas.height).data; From 8a70943b09a47f453b3048e4e83036afdb7902d0 Mon Sep 17 00:00:00 2001 From: jdescottes Date: Wed, 2 Jul 2014 07:34:07 +0200 Subject: [PATCH 2/5] Fix : fix classes extending simplePen --- src/js/controller/settings/SaveController.js | 27 ++++++++++++-------- src/js/drawingtools/Lighten.js | 8 +++++- src/js/drawingtools/SimplePen.js | 11 +++++--- src/js/service/BackupService.js | 2 +- 4 files changed, 33 insertions(+), 15 deletions(-) diff --git a/src/js/controller/settings/SaveController.js b/src/js/controller/settings/SaveController.js index d0cfc38a..4d84b481 100644 --- a/src/js/controller/settings/SaveController.js +++ b/src/js/controller/settings/SaveController.js @@ -42,18 +42,25 @@ evt.stopPropagation(); var name = this.getName(); - var description = this.getDescription(); - var isPublic = !!this.isPublicCheckbox.prop('checked'); - var descriptor = new pskl.model.piskel.Descriptor(name, description, isPublic); - this.piskelController.getPiskel().setDescriptor(descriptor); + if (!name) { + name = window.prompt('Please specify a name', 'New piskel'); + } - this.beforeSaving_(); - pskl.app.storageService.store({ - success : this.onSaveSuccess_.bind(this), - error : this.onSaveError_.bind(this), - after : this.afterSaving_.bind(this) - }); + if (name) { + var description = this.getDescription(); + var isPublic = !!this.isPublicCheckbox.prop('checked'); + + var descriptor = new pskl.model.piskel.Descriptor(name, description, isPublic); + this.piskelController.getPiskel().setDescriptor(descriptor); + + this.beforeSaving_(); + pskl.app.storageService.store({ + success : this.onSaveSuccess_.bind(this), + error : this.onSaveError_.bind(this), + after : this.afterSaving_.bind(this) + }); + } }; ns.SaveController.prototype.onSaveLocalClick_ = function (evt) { diff --git a/src/js/drawingtools/Lighten.js b/src/js/drawingtools/Lighten.js index 78a3a7ed..fc897a2e 100644 --- a/src/js/drawingtools/Lighten.js +++ b/src/js/drawingtools/Lighten.js @@ -27,7 +27,9 @@ * @override */ ns.Lighten.prototype.applyToolAt = function(col, row, color, frame, overlay, event, mouseButton) { - var pixelColor = frame.getPixel(col, row); + var overlayColor = overlay.getPixel(col, row); + var frameColor = frame.getPixel(col, row); + var pixelColor = overlayColor === Constants.TRANSPARENT_COLOR ? frameColor : overlayColor; var isDarken = event.ctrlKey || event.cmdKey; var isSinglePass = event.shiftKey; @@ -55,7 +57,11 @@ }; ns.Lighten.prototype.releaseToolAt = function(col, row, color, frame, overlay, event) { + // apply on real frame + this.setPixelsToFrame_(frame, this.pixels); + this.resetUsedPixels_(); + $.publish(Events.PISKEL_SAVE_STATE, { type : pskl.service.HistoryService.SNAPSHOT }); diff --git a/src/js/drawingtools/SimplePen.js b/src/js/drawingtools/SimplePen.js index 41f1c28f..f36ec667 100644 --- a/src/js/drawingtools/SimplePen.js +++ b/src/js/drawingtools/SimplePen.js @@ -23,11 +23,16 @@ */ ns.SimplePen.prototype.applyToolAt = function(col, row, color, frame, overlay, event) { overlay.setPixel(col, row, color); + + if (color === Constants.TRANSPARENT_COLOR) { + frame.setPixel(col, row, color); + } this.previousCol = col; this.previousRow = row; this.pixels.push({ col : col, - row : row + row : row, + color : color }); }; @@ -56,7 +61,7 @@ ns.SimplePen.prototype.releaseToolAt = function(col, row, color, frame, overlay, event) { // apply on real frame - this.setPixelsToFrame_(frame, this.pixels, color); + this.setPixelsToFrame_(frame, this.pixels); // save state this.raiseSaveStateEvent({ @@ -74,7 +79,7 @@ ns.SimplePen.prototype.setPixelsToFrame_ = function (frame, pixels, color) { pixels.forEach(function (pixel) { - frame.setPixel(pixel.col, pixel.row, color); + frame.setPixel(pixel.col, pixel.row, pixel.color); }); }; })(); diff --git a/src/js/service/BackupService.js b/src/js/service/BackupService.js index 8b884fbc..59e9a23a 100644 --- a/src/js/service/BackupService.js +++ b/src/js/service/BackupService.js @@ -1,6 +1,6 @@ (function () { var ns = $.namespace('pskl.service'); - var BACKUP_INTERVAL = 1000 * 30; + var BACKUP_INTERVAL = 1000 * 60; ns.BackupService = function (piskelController) { this.piskelController = piskelController; From a2e2459169dd00bdfe34bf65f9da0b3e433b6384 Mon Sep 17 00:00:00 2001 From: jdescottes Date: Thu, 3 Jul 2014 00:09:47 +0200 Subject: [PATCH 3/5] cleanup of performance improvement --- src/js/controller/PreviewFilmController.js | 41 +++++++------ src/js/model/frame/CachedFrameProcessor.js | 60 ++++++++++++++++++++ src/js/rendering/frame/TiledFrameRenderer.js | 32 +++-------- src/piskel-script-list.js | 1 + 4 files changed, 89 insertions(+), 45 deletions(-) create mode 100644 src/js/model/frame/CachedFrameProcessor.js diff --git a/src/js/controller/PreviewFilmController.js b/src/js/controller/PreviewFilmController.js index 5366b7bb..86ff0b1f 100644 --- a/src/js/controller/PreviewFilmController.js +++ b/src/js/controller/PreviewFilmController.js @@ -1,8 +1,6 @@ (function () { var ns = $.namespace("pskl.controller"); - var CACHE_RESET_INTERVAL = 1000 * 60 * 10; - var ACTION = { SELECT : 'select', CLONE : 'clone', @@ -18,8 +16,9 @@ this.redrawFlag = true; - this.cache_ = {}; - window.setInterval(function () {this.cache_ = {};}.bind(this), CACHE_RESET_INTERVAL); + this.cachedImageProcessor = new pskl.model.frame.CachedFrameProcessor(); + this.cachedImageProcessor.setFrameProcessor(this.frameToPreviewCanvas_.bind(this)); + this.cachedImageProcessor.setOutputCloner(this.clonePreviewCanvas_.bind(this)); }; ns.PreviewFilmController.prototype.init = function() { @@ -44,7 +43,6 @@ ns.PreviewFilmController.prototype.render = function () { if (this.redrawFlag) { - // TODO(vincz): Full redraw on any drawing modification, optimize. this.createPreviews_(); this.redrawFlag = false; } @@ -209,26 +207,25 @@ }; ns.PreviewFilmController.prototype.getCanvasForFrame = function (frame) { - var canvas = null; - var cacheKey = frame.getHash() + this.zoom; - if (this.cache_[cacheKey]) { - canvas = this.cache_[cacheKey]; - } else { - var frameAsString = JSON.stringify(frame.getPixels()); - if (this.cache_[frameAsString]) { - canvas = pskl.CanvasUtils.clone(this.cache_[frameAsString]); - } else { - var canvasRenderer = new pskl.rendering.CanvasRenderer(frame, this.zoom); - canvasRenderer.drawTransparentAs(Constants.TRANSPARENT_COLOR); - canvas = canvasRenderer.render(); - this.cache_[frameAsString] = canvas; - } - canvas.classList.add('tile-view', 'canvas'); - this.cache_[cacheKey] = canvas; - } + var canvas = this.cachedImageProcessor.get(frame, this.zoom); + canvas.classList.add('tile-view', 'canvas'); return canvas; }; + ns.PreviewFilmController.prototype.frameToPreviewCanvas_ = function (frame) { + var canvasRenderer = new pskl.rendering.CanvasRenderer(frame, this.zoom); + canvasRenderer.drawTransparentAs(Constants.TRANSPARENT_COLOR); + var canvas = canvasRenderer.render(); + canvas.classList.add('tile-view', 'canvas'); + return canvas; + }; + + ns.PreviewFilmController.prototype.clonePreviewCanvas_ = function (canvas) { + var clone = pskl.CanvasUtils.clone(canvas); + clone.classList.add('tile-view', 'canvas'); + return clone; + }; + /** * Calculate the preview zoom depending on the piskel size */ diff --git a/src/js/model/frame/CachedFrameProcessor.js b/src/js/model/frame/CachedFrameProcessor.js new file mode 100644 index 00000000..cb44e8af --- /dev/null +++ b/src/js/model/frame/CachedFrameProcessor.js @@ -0,0 +1,60 @@ +(function () { + var ns = $.namespace('pskl.model.frame'); + + var DEFAULT_RESET_INTERVAL = 10 * 60 *1000; + + var DEFAULT_FRAME_PROCESSOR = function (frame) { + return pskl.utils.FrameUtils.toImage(frame); + }; + + var DEFAULT_OUTPUT_CLONER = function (o) {return o;}; + + var DEFAULT_NAMESPACE = '__cache_default__'; + + ns.CachedFrameProcessor = function (cacheResetInterval) { + this.cache_ = {}; + this.cacheResetInterval = cacheResetInterval || DEFAULT_RESET_INTERVAL; + this.frameProcessor = DEFAULT_FRAME_PROCESSOR; + this.outputCloner = DEFAULT_OUTPUT_CLONER; + + window.setInterval(this.clear.bind(this), this.cacheResetInterval); + }; + + ns.CachedFrameProcessor.prototype.clear = function () { + this.cache_ = {}; + }; + + ns.CachedFrameProcessor.prototype.setFrameProcessor = function (frameProcessor) { + this.frameProcessor = frameProcessor; + }; + + ns.CachedFrameProcessor.prototype.setOutputCloner = function (outputCloner) { + this.outputCloner = outputCloner; + }; + + ns.CachedFrameProcessor.prototype.get = function (frame, namespace) { + var processedFrame = null; + namespace = namespace || DEFAULT_NAMESPACE; + + if (!this.cache_[namespace]) { + this.cache_[namespace] = {}; + } + + var cache = this.cache_[namespace]; + + var cacheKey = frame.getHash(); + if (this.cache_[cacheKey]) { + processedFrame = this.cache_[cacheKey]; + } else { + var frameAsString = JSON.stringify(frame.getPixels()); + if (this.cache_[frameAsString]) { + processedFrame = this.outputCloner(this.cache_[frameAsString]); + } else { + processedFrame = this.frameProcessor(frame); + this.cache_[frameAsString] = processedFrame; + } + this.cache_[cacheKey] = processedFrame; + } + return processedFrame; + }; +})(); \ No newline at end of file diff --git a/src/js/rendering/frame/TiledFrameRenderer.js b/src/js/rendering/frame/TiledFrameRenderer.js index ce8a3c9a..637c1ba1 100644 --- a/src/js/rendering/frame/TiledFrameRenderer.js +++ b/src/js/rendering/frame/TiledFrameRenderer.js @@ -1,8 +1,6 @@ (function () { var ns = $.namespace('pskl.rendering.frame'); - var CACHE_RESET_INTERVAL = 1000 * 60 * 10; - ns.TiledFrameRenderer = function (container, zoom) { this.container = container; this.setZoom(zoom); @@ -11,30 +9,18 @@ this.displayContainer.classList.add('tiled-frame-container'); container.get(0).appendChild(this.displayContainer); - this.cache_ = {}; - window.setInterval(function () {this.cache_ = {};}.bind(this), CACHE_RESET_INTERVAL); + this.cachedImageProcessor = new pskl.model.frame.CachedFrameProcessor(); + this.cachedImageProcessor.setFrameProcessor(this.frameToDataUrl_.bind(this)); + }; + + ns.TiledFrameRenderer.prototype.frameToDataUrl_ = function (frame) { + var canvas = new pskl.utils.FrameUtils.toImage(frame, this.zoom); + return canvas.toDataURL('image/png'); }; ns.TiledFrameRenderer.prototype.render = function (frame) { - var frameData = null; - - var hash = frame.getHash(); - if (this.cache_[hash]) { - frameData = this.cache_[hash]; - } else { - var frameAsString = JSON.stringify(frame.getPixels()); - if (this.cache_[frameAsString]) { - frameData = this.cache_[frameAsString]; - } else { - var canvas = new pskl.utils.FrameUtils.toImage(frame, this.zoom); - frameData = canvas.toDataURL('image/png'); - this.cache_[frameAsString] = frameData; - } - - this.cache_[hash] = frameData; - } - - this.displayContainer.style.backgroundImage = 'url(' + frameData + ')'; + var imageSrc = this.cachedImageProcessor.get(frame, this.zoom); + this.displayContainer.style.backgroundImage = 'url(' + imageSrc + ')'; }; ns.TiledFrameRenderer.prototype.show = function () { diff --git a/src/piskel-script-list.js b/src/piskel-script-list.js index 12a8e832..8891340f 100644 --- a/src/piskel-script-list.js +++ b/src/piskel-script-list.js @@ -47,6 +47,7 @@ "js/model/Frame.js", "js/model/Layer.js", "js/model/piskel/Descriptor.js", + "js/model/frame/CachedFrameProcessor.js", "js/model/Piskel.js", // Selection From fa626532bac1ba621b58207d5ea72614811d072c Mon Sep 17 00:00:00 2001 From: jdescottes Date: Thu, 3 Jul 2014 00:48:49 +0200 Subject: [PATCH 4/5] cleanup of performance improvement --- src/js/Constants.js | 2 + src/js/controller/PalettesListController.js | 5 +-- src/js/controller/PreviewFilmController.js | 8 ++-- src/js/rendering/frame/TiledFrameRenderer.js | 6 +-- src/js/service/CurrentColorsService.js | 41 +++++++++++--------- 5 files changed, 34 insertions(+), 28 deletions(-) diff --git a/src/js/Constants.js b/src/js/Constants.js index 65b00fe7..713724d0 100644 --- a/src/js/Constants.js +++ b/src/js/Constants.js @@ -11,6 +11,8 @@ var Constants = { MAX_HEIGHT : 1024, MAX_WIDTH : 1024, + MAX_CURRENT_COLORS_DISPLAYED : 100, + MINIMUM_ZOOM : 1, PREVIEW_FILM_SIZE : 96, diff --git a/src/js/controller/PalettesListController.js b/src/js/controller/PalettesListController.js index 29ea5821..0901d3df 100644 --- a/src/js/controller/PalettesListController.js +++ b/src/js/controller/PalettesListController.js @@ -10,7 +10,6 @@ // I apologize to my future self for this one. var NO_SCROLL_MAX_COLORS = 20; - var MAX_COLORS = 100; ns.PalettesListController = function (paletteController, usedColorService) { this.usedColorService = usedColorService; @@ -80,8 +79,8 @@ } } - if (colors.length > MAX_COLORS) { - colors = colors.slice(0, MAX_COLORS); + if (colors.length > Constants.MAX_CURRENT_COLORS_DISPLAYED) { + colors = colors.slice(0, Constants.MAX_CURRENT_COLORS_DISPLAYED); } return colors; diff --git a/src/js/controller/PreviewFilmController.js b/src/js/controller/PreviewFilmController.js index 86ff0b1f..fc0bf192 100644 --- a/src/js/controller/PreviewFilmController.js +++ b/src/js/controller/PreviewFilmController.js @@ -16,9 +16,9 @@ this.redrawFlag = true; - this.cachedImageProcessor = new pskl.model.frame.CachedFrameProcessor(); - this.cachedImageProcessor.setFrameProcessor(this.frameToPreviewCanvas_.bind(this)); - this.cachedImageProcessor.setOutputCloner(this.clonePreviewCanvas_.bind(this)); + this.cachedFrameProcessor = new pskl.model.frame.CachedFrameProcessor(); + this.cachedFrameProcessor.setFrameProcessor(this.frameToPreviewCanvas_.bind(this)); + this.cachedFrameProcessor.setOutputCloner(this.clonePreviewCanvas_.bind(this)); }; ns.PreviewFilmController.prototype.init = function() { @@ -207,7 +207,7 @@ }; ns.PreviewFilmController.prototype.getCanvasForFrame = function (frame) { - var canvas = this.cachedImageProcessor.get(frame, this.zoom); + var canvas = this.cachedFrameProcessor.get(frame, this.zoom); canvas.classList.add('tile-view', 'canvas'); return canvas; }; diff --git a/src/js/rendering/frame/TiledFrameRenderer.js b/src/js/rendering/frame/TiledFrameRenderer.js index 637c1ba1..9eabb8dc 100644 --- a/src/js/rendering/frame/TiledFrameRenderer.js +++ b/src/js/rendering/frame/TiledFrameRenderer.js @@ -9,8 +9,8 @@ this.displayContainer.classList.add('tiled-frame-container'); container.get(0).appendChild(this.displayContainer); - this.cachedImageProcessor = new pskl.model.frame.CachedFrameProcessor(); - this.cachedImageProcessor.setFrameProcessor(this.frameToDataUrl_.bind(this)); + this.cachedFrameProcessor = new pskl.model.frame.CachedFrameProcessor(); + this.cachedFrameProcessor.setFrameProcessor(this.frameToDataUrl_.bind(this)); }; ns.TiledFrameRenderer.prototype.frameToDataUrl_ = function (frame) { @@ -19,7 +19,7 @@ }; ns.TiledFrameRenderer.prototype.render = function (frame) { - var imageSrc = this.cachedImageProcessor.get(frame, this.zoom); + var imageSrc = this.cachedFrameProcessor.get(frame, this.zoom); this.displayContainer.style.backgroundImage = 'url(' + imageSrc + ')'; }; diff --git a/src/js/service/CurrentColorsService.js b/src/js/service/CurrentColorsService.js index e8f282cf..4aed52e7 100644 --- a/src/js/service/CurrentColorsService.js +++ b/src/js/service/CurrentColorsService.js @@ -4,6 +4,9 @@ ns.CurrentColorsService = function (piskelController) { this.piskelController = piskelController; this.currentColors = []; + this.cachedFrameProcessor = new pskl.model.frame.CachedFrameProcessor(); + this.cachedFrameProcessor.setFrameProcessor(this.frameToColors_.bind(this)); + this.framesColorsCache_ = {}; }; @@ -16,33 +19,35 @@ return this.currentColors; }; + ns.CurrentColorsService.prototype.frameToColors_ = function (frame) { + var frameColors = {}; + frame.forEachPixel(function (color, x, y) { + frameColors[color] = (frameColors[color] || 0) + 1; + }); + return frameColors; + }; + + ns.CurrentColorsService.prototype.onPiskelUpdated_ = function (evt) { var layers = this.piskelController.getLayers(); var frames = layers.map(function (l) {return l.getFrames();}).reduce(function (p, n) {return p.concat(n);}); var colors = {}; frames.forEach(function (f) { - var frameHash = f.getHash(); - if (!this.framesColorsCache_[frameHash]) { - var frameColors = {}; - f.forEachPixel(function (color, x, y) { - frameColors[color] = true; - }); - this.framesColorsCache_[frameHash] = frameColors; - } - Object.keys(this.framesColorsCache_[frameHash]).forEach(function (color) { - colors[color] = true; + var frameColors = this.cachedFrameProcessor.get(f); + Object.keys(frameColors).slice(0, Constants.MAX_CURRENT_COLORS_DISPLAYED).forEach(function (color) { + colors[color] = (colors[color] || 0) + frameColors[color]; }); }.bind(this)); + + // Remove transparent color from used colors delete colors[Constants.TRANSPARENT_COLOR]; - this.currentColors = Object.keys(colors); + + // limit the array to the max colors to display + this.currentColors = Object.keys(colors).slice(0, Constants.MAX_CURRENT_COLORS_DISPLAYED); + + // sort by most frequent color this.currentColors = this.currentColors.sort(function (c1, c2) { - if (c1 < c2) { - return -1; - } else if (c1 > c2) { - return 1; - } else { - return 0; - } + return colors[c2] - colors[c1]; }); // TODO : only fire if there was a change From fa4e96e7e500fe0c3b4695ced34cc9d6b75bb86c Mon Sep 17 00:00:00 2001 From: jdescottes Date: Thu, 3 Jul 2014 23:23:31 +0200 Subject: [PATCH 5/5] Added documentation in CachedFrameProcessor --- src/js/controller/PreviewFilmController.js | 1 - src/js/model/frame/CachedFrameProcessor.js | 25 +++++++++++++++++++--- 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/src/js/controller/PreviewFilmController.js b/src/js/controller/PreviewFilmController.js index fc0bf192..d61a80c6 100644 --- a/src/js/controller/PreviewFilmController.js +++ b/src/js/controller/PreviewFilmController.js @@ -208,7 +208,6 @@ ns.PreviewFilmController.prototype.getCanvasForFrame = function (frame) { var canvas = this.cachedFrameProcessor.get(frame, this.zoom); - canvas.classList.add('tile-view', 'canvas'); return canvas; }; diff --git a/src/js/model/frame/CachedFrameProcessor.js b/src/js/model/frame/CachedFrameProcessor.js index cb44e8af..3c0c07aa 100644 --- a/src/js/model/frame/CachedFrameProcessor.js +++ b/src/js/model/frame/CachedFrameProcessor.js @@ -1,7 +1,8 @@ (function () { var ns = $.namespace('pskl.model.frame'); - var DEFAULT_RESET_INTERVAL = 10 * 60 *1000; + + var DEFAULT_CLEAR_INTERVAL = 10 * 60 *1000; var DEFAULT_FRAME_PROCESSOR = function (frame) { return pskl.utils.FrameUtils.toImage(frame); @@ -13,7 +14,7 @@ ns.CachedFrameProcessor = function (cacheResetInterval) { this.cache_ = {}; - this.cacheResetInterval = cacheResetInterval || DEFAULT_RESET_INTERVAL; + this.cacheResetInterval = cacheResetInterval || DEFAULT_CLEAR_INTERVAL; this.frameProcessor = DEFAULT_FRAME_PROCESSOR; this.outputCloner = DEFAULT_OUTPUT_CLONER; @@ -24,14 +25,32 @@ this.cache_ = {}; }; + /** + * Set the processor function that will be called when there is a cache miss + * Function with 1 argument : pskl.model.Frame + * @param {Function} frameProcessor + */ ns.CachedFrameProcessor.prototype.setFrameProcessor = function (frameProcessor) { this.frameProcessor = frameProcessor; }; + /** + * Set the cloner that will be called when there is a miss on the 1st level cache + * but a hit on the 2nd level cache. + * Function with 2 arguments : cached value, frame + * @param {Function} outputCloner + */ ns.CachedFrameProcessor.prototype.setOutputCloner = function (outputCloner) { this.outputCloner = outputCloner; }; + /** + * Retrieve the processed frame from the cache, in the (optional) namespace + * If the first level cache is empty, attempt to clone it from 2nd level cache. If second level cache is empty process the frame. + * @param {pskl.model.Frame} frame + * @param {String} namespace + * @return {Object} the processed frame + */ ns.CachedFrameProcessor.prototype.get = function (frame, namespace) { var processedFrame = null; namespace = namespace || DEFAULT_NAMESPACE; @@ -48,7 +67,7 @@ } else { var frameAsString = JSON.stringify(frame.getPixels()); if (this.cache_[frameAsString]) { - processedFrame = this.outputCloner(this.cache_[frameAsString]); + processedFrame = this.outputCloner(this.cache_[frameAsString], frame); } else { processedFrame = this.frameProcessor(frame); this.cache_[frameAsString] = processedFrame;