diff --git a/index.html b/index.html
index 499e9821..256c5709 100644
--- a/index.html
+++ b/index.html
@@ -76,6 +76,8 @@
+
+
diff --git a/js/controller/AnimatedPreviewController.js b/js/controller/AnimatedPreviewController.js
new file mode 100644
index 00000000..1a1462bf
--- /dev/null
+++ b/js/controller/AnimatedPreviewController.js
@@ -0,0 +1,62 @@
+(function () {
+ var ns = $.namespace("pskl.controller");
+ ns.AnimatedPreviewController = function (framesheet, container, dpi) {
+ this.dpi = dpi;
+ this.framesheet = framesheet;
+ this.container = container;
+ this.animIndex = 0;
+
+ this.fps = parseInt($("#preview-fps")[0].value, 10);
+
+ this.renderer = new pskl.rendering.FrameRenderer();
+ };
+
+ ns.AnimatedPreviewController.prototype.init = function () {
+ this.initDom();
+ this.startAnimationTimer();
+ };
+
+ ns.AnimatedPreviewController.prototype.initDom = function () {
+ var frame = this.framesheet.getFrameByIndex(0);
+ var height = frame.getHeight() * this.dpi,
+ width = frame.getWidth() * this.dpi;
+
+ previewCanvas = document.createElement('canvas');
+ previewCanvas.className = 'canvas';
+
+ this.container.setAttribute('style', 'width:' + width + 'px; height:' + height + 'px;');
+ previewCanvas.setAttribute('width', width);
+ previewCanvas.setAttribute('height', height);
+
+ this.container.appendChild(previewCanvas);
+ this.previewCanvas = previewCanvas;
+
+ $("#preview-fps")[0].addEventListener('change', this.onFPSSliderChange.bind(this));
+ };
+
+ ns.AnimatedPreviewController.prototype.startAnimationTimer = function () {
+ this.stopAnimationTimer();
+ this.animationTimer = window.setTimeout(this.refreshAnimatedPreview.bind(this), 1000/this.fps);
+ };
+
+ ns.AnimatedPreviewController.prototype.stopAnimationTimer = function () {
+ if (this.animationTimer) {
+ window.clearInterval(this.animationTimer);
+ this.animationTimer = null;
+ }
+ };
+
+ ns.AnimatedPreviewController.prototype.onFPSSliderChange = function(evt) {
+ this.fps = parseInt($("#preview-fps")[0].value, 10);
+ };
+
+ ns.AnimatedPreviewController.prototype.refreshAnimatedPreview = function () {
+ this.renderer.render(this.framesheet.getFrameByIndex(this.animIndex), this.previewCanvas, this.dpi);
+ this.animIndex++;
+ if (this.animIndex == this.framesheet.getFrameCount()) {
+ this.animIndex = 0;
+ }
+ this.startAnimationTimer();
+ };
+
+})();
\ No newline at end of file
diff --git a/js/controller/PreviewFilmController.js b/js/controller/PreviewFilmController.js
new file mode 100644
index 00000000..9b5c2244
--- /dev/null
+++ b/js/controller/PreviewFilmController.js
@@ -0,0 +1,89 @@
+(function () {
+ var ns = $.namespace("pskl.controller");
+ ns.PreviewFilmController = function (framesheet, container, dpi) {
+
+ this.dpi = dpi;
+ this.framesheet = framesheet;
+ this.container = container;
+
+ this.renderer = new pskl.rendering.FrameRenderer();
+ };
+
+ ns.PreviewFilmController.prototype.init = function() {
+ var addFrameButton = $('#add-frame-button')[0];
+ addFrameButton.addEventListener('mousedown', this.addFrame.bind(this));
+ this.createPreviews();
+ };
+
+ ns.PreviewFilmController.prototype.addFrame = function () {
+ this.framesheet.addEmptyFrame();
+ piskel.setActiveFrameAndRedraw(this.framesheet.getFrameCount() - 1);
+ };
+
+ ns.PreviewFilmController.prototype.createPreviews = function () {
+ this.container.innerHTML = "";
+ for (var i = 0, l = this.framesheet.getFrameCount(); i < l ; i++) {
+ this.container.appendChild(this.createPreviewTile(i));
+ }
+ };
+
+ ns.PreviewFilmController.prototype.createPreviewTile = function(tileNumber) {
+ var frame = this.framesheet.getFrameByIndex(tileNumber);
+ var width = frame.getWidth() * this.dpi,
+ height = frame.getHeight() * this.dpi;
+
+ var previewTileRoot = document.createElement("li");
+ var classname = "preview-tile";
+
+ if (piskel.getActiveFrameIndex() == tileNumber) {
+ classname += " selected";
+ }
+ previewTileRoot.className = classname;
+
+ var canvasContainer = document.createElement("div");
+ canvasContainer.className = "canvas-container";
+ canvasContainer.setAttribute('style', 'width:' + width + 'px; height:' + height + 'px;');
+
+ var canvasBackground = document.createElement("div");
+ canvasBackground.className = "canvas-background";
+ canvasContainer.appendChild(canvasBackground);
+
+ var canvasPreview = document.createElement("canvas");
+ canvasPreview.className = "canvas tile-view"
+
+ canvasPreview.setAttribute('width', width);
+ canvasPreview.setAttribute('height', height);
+
+ previewTileRoot.addEventListener('click', function(evt) {
+ // has not class tile-action:
+ if(!evt.target.classList.contains('tile-action')) {
+ piskel.setActiveFrameAndRedraw(tileNumber);
+ }
+ });
+
+ var canvasPreviewDuplicateAction = document.createElement("button");
+ canvasPreviewDuplicateAction.className = "tile-action"
+ canvasPreviewDuplicateAction.innerHTML = "dup"
+
+ canvasPreviewDuplicateAction.addEventListener('click', function(evt) {
+ piskel.duplicateFrame(tileNumber);
+ });
+
+ this.renderer.render(this.framesheet.getFrameByIndex(tileNumber), canvasPreview, this.dpi);
+ canvasContainer.appendChild(canvasPreview);
+ previewTileRoot.appendChild(canvasContainer);
+ previewTileRoot.appendChild(canvasPreviewDuplicateAction);
+
+ if(tileNumber > 0 || this.framesheet.getFrameCount() > 1) {
+ var canvasPreviewDeleteAction = document.createElement("button");
+ canvasPreviewDeleteAction.className = "tile-action"
+ canvasPreviewDeleteAction.innerHTML = "del"
+ canvasPreviewDeleteAction.addEventListener('click', function(evt) {
+ piskel.removeFrame(tileNumber);
+ });
+ previewTileRoot.appendChild(canvasPreviewDeleteAction);
+ }
+
+ return previewTileRoot;
+ };
+})();
\ No newline at end of file
diff --git a/js/model/Frame.js b/js/model/Frame.js
index 2302c43d..552f6b93 100644
--- a/js/model/Frame.js
+++ b/js/model/Frame.js
@@ -1,5 +1,6 @@
(function () {
var ns = $.namespace("pskl.model");
+
ns.Frame = function (pixels) {
this.pixels = pixels;
};
@@ -30,6 +31,10 @@
return clone;
};
+ ns.Frame.prototype.serialize = function () {
+ return JSON.stringify(this.pixels);
+ };
+
ns.Frame.prototype.setPixel = function (col, row, color) {
this.pixels[col][row] = color;
};
diff --git a/js/model/FrameSheet.js b/js/model/FrameSheet.js
index 9e1bed9a..bb66a547 100644
--- a/js/model/FrameSheet.js
+++ b/js/model/FrameSheet.js
@@ -38,7 +38,11 @@
// Could be used to pass around model using long GET param (good enough for simple models) and
// do some temporary locastorage
ns.FrameSheet.prototype.serialize = function() {
- throw "FrameSheet.prototype.serialize not implemented"
+ var serializedFrames = [];
+ for (var i = 0 ; i < this.frames.length ; i++) {
+ serializedFrames.push(this.frames[i].serialize());
+ }
+ return '[' + serializedFrames.join(",") + ']';
//return JSON.stringify(frames);
};
@@ -48,13 +52,17 @@
* @param {String} serialized
*/
ns.FrameSheet.prototype.deserialize = function (serialized) {
- throw "FrameSheet.prototype.deserialize not implemented"
- // try {
- // frames = JSON.parse(serialized);
- // $.publish(Events.FRAMESHEET_RESET);
- // } catch (e) {
- // throw "Could not load serialized framesheet." + e.message
- // }
+ try {
+ var frameConfigurations = JSON.parse(serialized);
+ this.frames = [];
+ for (var i = 0 ; i < frameConfigurations.length ; i++) {
+ var frameCfg = frameConfigurations[i];
+ this.addFrame(new ns.Frame(frameCfg));
+ }
+ $.publish(Events.FRAMESHEET_RESET);
+ } catch (e) {
+ throw "Could not load serialized framesheet : " + e.message
+ }
};
ns.FrameSheet.prototype.getFrameByIndex = function(index) {
diff --git a/js/piskel.js b/js/piskel.js
index dcdc62b7..f8ea4b53 100644
--- a/js/piskel.js
+++ b/js/piskel.js
@@ -9,7 +9,7 @@ $.namespace("pskl");
/**
* FrameSheetModel instance.
*/
- var frameSheet, renderer = null,
+ var frameSheet,
// Temporary zoom implementation to easily get bigger canvases to
// see how good perform critical algorithms on big canvas.
@@ -52,17 +52,32 @@ $.namespace("pskl");
init : function () {
var emptyFrame = pskl.model.Frame.createEmpty(framePixelWidth, framePixelHeight);
+ frameSheet = new pskl.model.FrameSheet();
+ frameSheet.addFrame(emptyFrame);
+
this.drawingController = new pskl.controller.DrawingController(
emptyFrame,
$('#drawing-canvas-container')[0],
drawingCanvasDpi
);
- renderer = new pskl.rendering.FrameRenderer();
-
- frameSheet = new pskl.model.FrameSheet();
- frameSheet.addFrame(emptyFrame);
this.setActiveFrame(0);
+
+ this.animationController = new pskl.controller.AnimatedPreviewController(
+ frameSheet,
+ $('#preview-canvas-container')[0],
+ previewAnimationCanvasDpi
+ );
+
+
+ this.previewsController = new pskl.controller.PreviewFilmController(
+ frameSheet,
+ $('#preview-list')[0],
+ previewTileCanvasDpi
+ );
+
+ this.animationController.init();
+ this.previewsController.init();
pskl.NotificationService.init();
pskl.LocalStorageService.init(frameSheet);
@@ -96,9 +111,6 @@ $.namespace("pskl");
// TODO: Move this into their service or behavior files:
this.initDrawingArea();
- this.initPreviewSlideshow();
- this.initAnimationPreview();
- this.startAnimation();
pskl.ToolSelector.init();
pskl.Palette.init(frameSheet);
@@ -142,21 +154,19 @@ $.namespace("pskl");
setActiveFrameAndRedraw: function(index) {
this.setActiveFrame(index);
-
- // When redraw engine is refactored, remove the following crap and
- // trigger an event instead:
+ this.redraw();
+ },
+ redraw : function () {
// Update drawing canvas:
this.drawingController.renderFrame();
// Update slideshow:
- this.createPreviews();
- // Update animation preview:
- animIndex = 0;
+ this.previewsController.createPreviews();
},
getActiveFrameIndex: function() {
if(-1 == activeFrameIndex) {
- throw "Bad active frane initialization."
+ throw "Bad active frame initialization."
}
return activeFrameIndex;
},
@@ -171,128 +181,13 @@ $.namespace("pskl");
drawingAreaContainer.addEventListener('contextmenu', this.onCanvasContextMenu);
},
- initPreviewSlideshow: function() {
- var addFrameButton = $('#add-frame-button')[0];
- addFrameButton.addEventListener('mousedown', function() {
- frameSheet.addEmptyFrame();
- piskel.setActiveFrameAndRedraw(frameSheet.getFrameCount() - 1);
- });
- this.createPreviews();
- },
-
- initAnimationPreview : function() {
-
- var previewAnimationContainer = $('#preview-canvas-container')[0];
- previewCanvas = document.createElement('canvas');
- previewCanvas.className = 'canvas';
- previewAnimationContainer.setAttribute('style',
- 'width:' + framePixelWidth * previewAnimationCanvasDpi + 'px; height:' + framePixelHeight * previewAnimationCanvasDpi + 'px;');
- previewAnimationContainer.appendChild(previewCanvas);
- previewCanvas.setAttribute('width', framePixelWidth * previewAnimationCanvasDpi);
- previewCanvas.setAttribute('height', framePixelHeight * previewAnimationCanvasDpi);
- },
-
- startAnimation : function () {
- var scope = this;
- var animFPSTuner = $("#preview-fps")[0];
- var animPreviewFPS = parseInt(animFPSTuner.value, 10);
- var startPreviewRefresh = function() {
- return setInterval(scope.refreshAnimatedPreview, 1000/animPreviewFPS);
- };
- var refreshUpdater = startPreviewRefresh();
-
- animFPSTuner.addEventListener('change', function(evt) {
- window.clearInterval(refreshUpdater);
- animPreviewFPS = parseInt(animFPSTuner.value, 10);
- $("#display-fps").html(animPreviewFPS + " fps");
- refreshUpdater = startPreviewRefresh();
- });
- },
-
- createPreviews : function () {
- console.log("createPreviews");
- var container = $('#preview-list')[0], previewTile;
- container.innerHTML = "";
- for (var i = 0, l = frameSheet.getFrameCount(); i < l ; i++) {
- previewTile = this.createPreviewTile(i);
- container.appendChild(previewTile);
- }
- },
-
- createPreviewTile: function(tileNumber) {
- var previewTileRoot = document.createElement("li");
- var classname = "preview-tile";
-
- if (this.getActiveFrameIndex() == tileNumber) {
- classname += " selected";
- }
- previewTileRoot.className = classname;
-
- var canvasContainer = document.createElement("div");
- canvasContainer.className = "canvas-container";
- canvasContainer.setAttribute('style',
- 'width:' + framePixelWidth * previewTileCanvasDpi + 'px; height:' + framePixelHeight * previewTileCanvasDpi + 'px;');
-
- var canvasBackground = document.createElement("div");
- canvasBackground.className = "canvas-background";
- canvasContainer.appendChild(canvasBackground);
-
- var canvasPreview = document.createElement("canvas");
- canvasPreview.className = "canvas tile-view"
-
- canvasPreview.setAttribute('width', framePixelWidth * previewTileCanvasDpi);
- canvasPreview.setAttribute('height', framePixelHeight * previewTileCanvasDpi);
-
- previewTileRoot.addEventListener('click', function(evt) {
- // has not class tile-action:
- if(!evt.target.classList.contains('tile-action')) {
- piskel.setActiveFrameAndRedraw(tileNumber);
- }
- });
-
- var canvasPreviewDuplicateAction = document.createElement("button");
- canvasPreviewDuplicateAction.className = "tile-action"
- canvasPreviewDuplicateAction.innerHTML = "dup"
-
- canvasPreviewDuplicateAction.addEventListener('click', function(evt) {
- piskel.duplicateFrame(tileNumber);
- });
-
- renderer.render(frameSheet.getFrameByIndex(tileNumber), canvasPreview, previewTileCanvasDpi);
- canvasContainer.appendChild(canvasPreview);
- previewTileRoot.appendChild(canvasContainer);
- previewTileRoot.appendChild(canvasPreviewDuplicateAction);
-
- if(tileNumber > 0 || frameSheet.getFrameCount() > 1) {
- var canvasPreviewDeleteAction = document.createElement("button");
- canvasPreviewDeleteAction.className = "tile-action"
- canvasPreviewDeleteAction.innerHTML = "del"
- canvasPreviewDeleteAction.addEventListener('click', function(evt) {
- piskel.removeFrame(tileNumber);
- });
- previewTileRoot.appendChild(canvasPreviewDeleteAction);
- }
-
- return previewTileRoot;
- },
-
- refreshAnimatedPreview : function () {
- renderer.render(frameSheet.getFrameByIndex(animIndex), previewCanvas, previewAnimationCanvasDpi);
- animIndex++;
- if (animIndex == frameSheet.getFrameCount()) {
- animIndex = 0;
- }
- },
-
removeFrame: function(frameIndex) {
frameSheet.removeFrameByIndex(frameIndex);
-
this.setActiveFrameAndRedraw(frameIndex - 1);
},
duplicateFrame: function(frameIndex) {
frameSheet.duplicateFrameByIndex(frameIndex);
-
this.setActiveFrameAndRedraw(frameIndex + 1);
},
@@ -343,7 +238,7 @@ $.namespace("pskl");
// Note: The mousemove movement (and the mouseup) may end up outside
// of the drawing canvas.
// TODO: Remove that when we have the centralized redraw loop
- this.createPreviews();
+ this.previewsController.createPreviews();
}
if(isRightClicked) {