diff --git a/js/Events.js b/js/Events.js index 2a1545b8..df4dfb89 100644 --- a/js/Events.js +++ b/js/Events.js @@ -22,6 +22,13 @@ Events = { */ REFRESH: "REFRESH", + /** + * Temporary event to bind the redraw of right preview film to the canvas. + * This redraw should be driven by model updates. + * TODO(vincz): Remove. + */ + REDRAW_PREVIEWFILM: "REDRAW_PREVIEWFILM", + /** * The framesheet was reseted and is now probably drastically different. * Number of frames, content of frames, color used for the palette may have changed. diff --git a/js/controller/DrawingController.js b/js/controller/DrawingController.js index f6043669..66559fc1 100644 --- a/js/controller/DrawingController.js +++ b/js/controller/DrawingController.js @@ -19,8 +19,175 @@ this.renderer.init(this.frame); this.overlayRenderer.init(this.frame); + + // State of drawing controller: + this.isClicked = false; + this.isRightClicked = false; + this.previousMousemoveTime = 0; + this.currentToolBehavior = null; + this.primaryColor = Constants.DEFAULT_PEN_COLOR; + this.secondaryColor = Constants.TRANSPARENT_COLOR; + + this.initMouseBehavior(); + + $.subscribe(Events.TOOL_SELECTED, $.proxy(function(evt, toolBehavior) { + + console.log("Tool selected: ", toolBehavior); + this.currentToolBehavior = toolBehavior; + }, this)); + + $.subscribe(Events.COLOR_SELECTED, $.proxy(function(evt, color, isPrimary) { + console.log("Color selected: ", color); + if (isPrimary) { + this.primaryColor = color; + } else { + this.secondaryColor = color; + } + }, this)); }; + ns.DrawingController.prototype.initMouseBehavior = function() { + var body = $('body'); + this.container.mousedown($.proxy(this.onMousedown_, this)); + this.container.mousemove($.proxy(this.onMousemove_, this)); + body.mouseup($.proxy(this.onMouseup_, this)); + + // Deactivate right click: + this.container.contextmenu(this.onCanvasContextMenu_); + }; + + /** + * @private + */ + ns.DrawingController.prototype.onMousedown_ = function (event) { + this.isClicked = true; + + if(event.button == 2) { // right click + this.isRightClicked = true; + $.publish(Events.CANVAS_RIGHT_CLICKED); + } + + var spriteCoordinate = this.getSpriteCoordinate(event); + //console.log("mousedown: col: " + spriteCoordinate.col + " - row: " + spriteCoordinate.row); + + this.currentToolBehavior.applyToolAt( + spriteCoordinate.col, + spriteCoordinate.row, + this.getCurrentColor_(), + this + ); + + $.publish(Events.LOCALSTORAGE_REQUEST); + }; + + /** + * @private + */ + ns.DrawingController.prototype.onMousemove_ = function (event) { + var currentTime = new Date().getTime(); + // Throttling of the mousemove event: + if ((currentTime - this.previousMousemoveTime) > 40 ) { + var spriteCoordinate = this.getSpriteCoordinate(event); + if (this.isClicked) { + + this.currentToolBehavior.moveToolAt( + spriteCoordinate.col, + spriteCoordinate.row, + this.getCurrentColor_(), + this + ); + + //console.log("mousemove: col: " + spriteCoordinate.col + " - row: " + spriteCoordinate.row); + + // TODO(vincz): Find a way to move that to the model instead of being at the interaction level. + // Eg when drawing, it may make sense to have it here. However for a non drawing tool, + // you don't need to draw anything when mousemoving and you request useless localStorage. + $.publish(Events.LOCALSTORAGE_REQUEST); + } else { + // debug mode to see the selected pixel + // this.clearOverlay(); + // this.overlayFrame.setPixel( spriteCoordinate.col,spriteCoordinate.row, "#ff0000"); + // this.renderOverlay(); + } + this.previousMousemoveTime = currentTime; + } + }; + + /** + * @private + */ + ns.DrawingController.prototype.onMouseup_ = function (event) { + if(this.isClicked || this.isRightClicked) { + // A mouse button was clicked on the drawing canvas before this mouseup event, + // the user was probably drawing on the canvas. + // Note: The mousemove movement (and the mouseup) may end up outside + // of the drawing canvas. + if(this.isRightClicked) { + $.publish(Events.CANVAS_RIGHT_CLICK_RELEASED); + } + + + this.isClicked = false; + this.isRightClicked = false; + var spriteCoordinate = this.getSpriteCoordinate(event); + console.log("mousemove: col: " + spriteCoordinate.col + " - row: " + spriteCoordinate.row); + this.currentToolBehavior.releaseToolAt( + spriteCoordinate.col, + spriteCoordinate.row, + this.getCurrentColor_(), + this + ); + + $.publish(Events.TOOL_RELEASED); + + // TODO: Remove that when we have the centralized redraw loop + $.publish(Events.REDRAW_PREVIEWFILM); + } + }, + + /** + * @private + */ + ns.DrawingController.prototype.getRelativeCoordinates = function (clientX, clientY) { + var canvasPageOffset = this.container.offset(); + return { + x : clientX - canvasPageOffset.left, + y : clientY - canvasPageOffset.top + } + }; + + /** + * @private + */ + ns.DrawingController.prototype.getSpriteCoordinate = function(event) { + var coords = this.getRelativeCoordinates(event.clientX, event.clientY); + return { + "col" : (coords.x - coords.x % this.dpi) / this.dpi, + "row" : (coords.y - coords.y % this.dpi) / this.dpi + } + }; + + /** + * @private + */ + ns.DrawingController.prototype.getCurrentColor_ = function () { + if(this.isRightClicked) { + return this.secondaryColor; + } else { + return this.primaryColor; + } + }; + + /** + * @private + */ + ns.DrawingController.prototype.onCanvasContextMenu_ = function (event) { + event.preventDefault(); + event.stopPropagation(); + event.cancelBubble = true; + return false; + }; + ns.DrawingController.prototype.updateDPI = function (newDPI) { this.renderer.updateDPI(newDPI); this.overlayRenderer.updateDPI(newDPI); diff --git a/js/controller/PreviewFilmController.js b/js/controller/PreviewFilmController.js index 75383df0..7d7a2fe6 100644 --- a/js/controller/PreviewFilmController.js +++ b/js/controller/PreviewFilmController.js @@ -5,6 +5,10 @@ this.dpi = dpi; this.framesheet = framesheet; this.container = container; + + $.subscribe(Events.REDRAW_PREVIEWFILM, $.proxy(function(evt) { + this.createPreviews() + }, this)); }; ns.PreviewFilmController.prototype.init = function() { @@ -28,7 +32,7 @@ for (var i = 0, l = frameCount; i < l ; i++) { this.container.append(this.createInterstitialTile_(i)); - this.container.append(this.createPreviewTile_(i)); + this.container.append(this.createPreviewTile_(i, this.framesheet)); } this.container.append(this.createInterstitialTile_(frameCount)); @@ -142,7 +146,7 @@ * @private * TODO(vincz): clean this giant rendering function & remove listeners. */ - ns.PreviewFilmController.prototype.createPreviewTile_ = function(tileNumber) { + ns.PreviewFilmController.prototype.createPreviewTile_ = function(tileNumber, framesheet) { var currentFrame = this.framesheet.getFrameByIndex(tileNumber); //var width = frame.getWidth() * this.dpi, // height = frame.getHeight() * this.dpi; @@ -183,7 +187,8 @@ canvasPreviewDuplicateAction.innerHTML = "dup" canvasPreviewDuplicateAction.addEventListener('click', function(evt) { - piskel.duplicateFrame(tileNumber); + framesheet.duplicateFrameByIndex(tileNumber); + $.publish('SET_ACTIVE_FRAME', [tileNumber + 1]); }); //this.renderer.render(this.framesheet.getFrameByIndex(tileNumber), canvasPreview); @@ -191,7 +196,7 @@ // TODO(vincz): Eventually optimize this part by not recreating a FrameRenderer. Note that the real optim // is to make this update function (#createPreviewTile) less aggressive. var renderingOptions = {"dpi": this.dpi }; - var currentFrameRenderer = new pskl.rendering.FrameRenderer(canvasContainer, renderingOptions, "tile-view"); + var currentFrameRenderer = new pskl.rendering.FrameRenderer($(canvasContainer), renderingOptions, "tile-view"); currentFrameRenderer.init(currentFrame); previewTileRoot.appendChild(canvasContainer); diff --git a/js/piskel.js b/js/piskel.js index af4f7a79..fde522b4 100644 --- a/js/piskel.js +++ b/js/piskel.js @@ -24,23 +24,8 @@ $.namespace("pskl"); // Animated canvas preview: previewAnimationCanvasDpi = 8, - // DOM references: - drawingAreaContainer, - drawingAreaCanvas, - previewCanvas, - - // States: - isClicked = false, - isRightClicked = false, - activeFrameIndex = -1, - animIndex = 0, - - primaryColor = Constants.DEFAULT_PEN_COLOR, - secondaryColor = Constants.TRANSPARENT_COLOR, - + activeFrameIndex = -1, currentFrame = null; - currentToolBehavior = null, - previousMousemoveTime = 0; /** * Main application controller @@ -56,7 +41,7 @@ $.namespace("pskl"); this.drawingController = new pskl.controller.DrawingController( frameSheet.getFrameByIndex(0), - $('#drawing-canvas-container')[0], + $('#drawing-canvas-container'), drawingCanvasDpi ); @@ -64,7 +49,7 @@ $.namespace("pskl"); this.animationController = new pskl.controller.AnimatedPreviewController( frameSheet, - $('#preview-canvas-container')[0], + $('#preview-canvas-container'), previewAnimationCanvasDpi ); @@ -91,6 +76,10 @@ $.namespace("pskl"); this.finishInit(); pskl.LocalStorageService.displayRestoreNotification(); } + + $.subscribe('SET_ACTIVE_FRAME', function(evt, frameId) { + piskel.setActiveFrameAndRedraw(frameId); + }); }, /** @@ -118,27 +107,12 @@ $.namespace("pskl"); finishInit : function () { - $.subscribe(Events.TOOL_SELECTED, function(evt, toolBehavior) { - console.log("Tool selected: ", toolBehavior); - currentToolBehavior = toolBehavior; - }); - - $.subscribe(Events.COLOR_SELECTED, function(evt, color, isPrimary) { - console.log("Color selected: ", color); - if (isPrimary) { - primaryColor = color; - } else { - secondaryColor = color; - } - }); + $.subscribe(Events.REFRESH, function() { piskel.setActiveFrameAndRedraw(0); }); - // TODO: Move this into their service or behavior files: - this.initDrawingArea(); - pskl.ToolSelector.init(); pskl.Palette.init(frameSheet); }, @@ -202,132 +176,6 @@ $.namespace("pskl"); return frameSheet.getFrameByIndex(activeFrameIndex); }, - initDrawingArea : function() { - drawingAreaContainer = $('#drawing-canvas-container')[0]; - document.body.addEventListener('mouseup', this.onMouseup.bind(this)); - drawingAreaContainer.addEventListener('mousedown', this.onMousedown.bind(this)); - drawingAreaContainer.addEventListener('mousemove', this.onMousemove.bind(this)); - document.body.addEventListener('contextmenu', this.onCanvasContextMenu); - }, - - removeFrame: function(frameIndex) { - frameSheet.removeFrameByIndex(frameIndex); - var activeFrameIndex = frameIndex ? frameIndex - 1 : 0; - this.setActiveFrameAndRedraw(activeFrameIndex); - }, - - duplicateFrame: function(frameIndex) { - frameSheet.duplicateFrameByIndex(frameIndex); - this.setActiveFrameAndRedraw(frameIndex + 1); - }, - - getCurrentColor : function () { - if(isRightClicked) { - return secondaryColor; - } else { - return primaryColor; - } - }, - - onMousedown : function (event) { - isClicked = true; - - if(event.button == 2) { // right click - isRightClicked = true; - $.publish(Events.CANVAS_RIGHT_CLICKED); - } - - var spriteCoordinate = this.getSpriteCoordinate(event); - currentToolBehavior.applyToolAt( - spriteCoordinate.col, - spriteCoordinate.row, - this.getCurrentColor(), - this.drawingController - ); - - $.publish(Events.LOCALSTORAGE_REQUEST); - }, - - onMousemove : function (event) { - var currentTime = new Date().getTime(); - // Throttling of the mousemove event: - if ((currentTime - previousMousemoveTime) > 40 ) { - var spriteCoordinate = this.getSpriteCoordinate(event); - if (isClicked) { - - currentToolBehavior.moveToolAt( - spriteCoordinate.col, - spriteCoordinate.row, - this.getCurrentColor(), - this.drawingController - ); - - // TODO(vincz): Find a way to move that to the model instead of being at the interaction level. - // Eg when drawing, it may make sense to have it here. However for a non drawing tool, - // you don't need to draw anything when mousemoving and you request useless localStorage. - $.publish(Events.LOCALSTORAGE_REQUEST); - } else { - // debug mode to see the selected pixel - // this.drawingController.clearOverlay(); - // this.drawingController.overlay.setPixel( spriteCoordinate.col,spriteCoordinate.row, "#ff0000"); - // this.drawingController.renderOverlay(); - } - previousMousemoveTime = currentTime; - } - }, - - onMouseup : function (event) { - if(isClicked || isRightClicked) { - // A mouse button was clicked on the drawing canvas before this mouseup event, - // the user was probably drawing on the canvas. - // Note: The mousemove movement (and the mouseup) may end up outside - // of the drawing canvas. - if(isRightClicked) { - $.publish(Events.CANVAS_RIGHT_CLICK_RELEASED); - } - - - isClicked = false; - isRightClicked = false; - var spriteCoordinate = this.getSpriteCoordinate(event); - currentToolBehavior.releaseToolAt( - spriteCoordinate.col, - spriteCoordinate.row, - this.getCurrentColor(), - this.drawingController - ); - - - $.publish(Events.TOOL_RELEASED); - // TODO: Remove that when we have the centralized redraw loop - this.previewsController.createPreviews(); - } - }, - - onCanvasContextMenu : function (event) { - event.preventDefault(); - event.stopPropagation(); - event.cancelBubble = true; - return false; - }, - - getRelativeCoordinates : function (x, y) { - var canvasRect = $(".drawing-canvas")[0].getBoundingClientRect(); - return { - x : x - canvasRect.left, - y : y - canvasRect.top - } - }, - - getSpriteCoordinate : function(event) { - var coord = this.getRelativeCoordinates(event.x, event.y); - var coords = this.getRelativeCoordinates(event.clientX, event.clientY); - return { - "col" : (coords.x - coords.x%drawingCanvasDpi) / drawingCanvasDpi, - "row" : (coords.y - coords.y%drawingCanvasDpi) / drawingCanvasDpi - } - }, - // TODO(julz): Create package ? storeSheet : function (event) { // TODO Refactor using jquery ? diff --git a/js/rendering/FrameRenderer.js b/js/rendering/FrameRenderer.js index 63b96533..6dbe9bc0 100644 --- a/js/rendering/FrameRenderer.js +++ b/js/rendering/FrameRenderer.js @@ -80,7 +80,7 @@ canvas.setAttribute("class", canvasClassname); this.canvas = canvas; - this.container.appendChild(this.canvas); + this.container.append(this.canvas); this.canvasConfigDirty = false; }