diff --git a/Gruntfile.js b/Gruntfile.js index 07680eff..cd453635 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -10,16 +10,24 @@ * If you run this task locally, it may require some env set up first. */ -module.exports = function (grunt) { +module.exports = function(grunt) { grunt.initConfig({ - jshint : { + jshint: { /*options: { - "evil": true, - "asi": true, - "smarttabs": true, - "eqnull": true - },*/ - files : [ + "evil": true, + "asi": true, + "smarttabs": true, + "eqnull": true + },*/ + options: { + indent:2, + undef : true, + latedef : true, + browser : true, + jquery : true, + globals : {'pskl':true, 'Events':true, 'Constants':true, 'console' : true, 'module':true, 'require':true} + }, + files: [ 'Gruntfile.js', 'package.json', 'js/**/*.js', @@ -69,13 +77,23 @@ module.exports = function (grunt) { } }); + grunt.config.set('leadingIndent.indentation', 'spaces'); + grunt.config.set('leadingIndent.jsFiles', { + src: ['js/**/*.js','!js/lib/**/*.js'] + }); + grunt.config.set('leadingIndent.cssFiles', { + src: ['css/**/*.css'] + }); + grunt.loadNpmTasks('grunt-contrib-connect'); grunt.loadNpmTasks('grunt-contrib-jshint'); grunt.loadNpmTasks('grunt-contrib-concat'); grunt.loadNpmTasks('grunt-contrib-uglify'); grunt.loadNpmTasks('grunt-ghost'); + grunt.loadNpmTasks('grunt-leading-indent'); + + grunt.registerTask('lint', ['leadingIndent:jsFiles', 'leadingIndent:cssFiles', 'jshint']); + grunt.registerTask('test', ['leadingIndent:jsFiles', 'leadingIndent:cssFiles', 'jshint', 'connect', 'ghost']); grunt.registerTask('default', ['jshint', 'concat', 'uglify']); - grunt.registerTask('lint', ['jshint']); - grunt.registerTask('test', ['jshint', 'connect', 'ghost']); }; diff --git a/js/Constants.js b/js/Constants.js index c7abf94a..5b333e5c 100644 --- a/js/Constants.js +++ b/js/Constants.js @@ -1,36 +1,38 @@ // TODO(grosbouddha): put under pskl namespace. var Constants = { - DEFAULT_SIZE : { - height : 32, - width : 32 - }, + DEFAULT_SIZE : { + height : 32, + width : 32 + }, - MAX_HEIGHT : 128, - MAX_WIDTH : 128, + MAX_HEIGHT : 128, + MAX_WIDTH : 128, - DEFAULT_PEN_COLOR : '#000000', - TRANSPARENT_COLOR : 'TRANSPARENT', - - /* - * Fake semi-transparent color used to highlight transparent - * strokes and rectangles: - */ - SELECTION_TRANSPARENT_COLOR: 'rgba(255, 255, 255, 0.6)', + PREVIEW_FILM_SIZE : 120, - /* - * When a tool is hovering the drawing canvas, we highlight the eventual - * pixel target with this color: - */ - TOOL_TARGET_HIGHLIGHT_COLOR: 'rgba(255, 255, 255, 0.2)', - - /* - * Default entry point for piskel web service: - */ - PISKEL_SERVICE_URL: 'http://3.piskel-app.appspot.com', + DEFAULT_PEN_COLOR : '#000000', + TRANSPARENT_COLOR : 'TRANSPARENT', + + /* + * Fake semi-transparent color used to highlight transparent + * strokes and rectangles: + */ + SELECTION_TRANSPARENT_COLOR: 'rgba(255, 255, 255, 0.6)', - GRID_STROKE_WIDTH: 1, - GRID_STROKE_COLOR: "lightgray", + /* + * When a tool is hovering the drawing canvas, we highlight the eventual + * pixel target with this color: + */ + TOOL_TARGET_HIGHLIGHT_COLOR: 'rgba(255, 255, 255, 0.2)', + + /* + * Default entry point for piskel web service: + */ + PISKEL_SERVICE_URL: 'http://3.piskel-app.appspot.com', - LEFT_BUTTON : "left_button_1", - RIGHT_BUTTON : "right_button_2" + GRID_STROKE_WIDTH: 1, + GRID_STROKE_COLOR: "lightgray", + + LEFT_BUTTON : "left_button_1", + RIGHT_BUTTON : "right_button_2" }; \ No newline at end of file diff --git a/js/Events.js b/js/Events.js index 34283d0d..06e2dda2 100644 --- a/js/Events.js +++ b/js/Events.js @@ -1,64 +1,64 @@ // TODO(grosbouddha): put under pskl namespace. Events = { - - TOOL_SELECTED : "TOOL_SELECTED", - TOOL_RELEASED : "TOOL_RELEASED", - PRIMARY_COLOR_SELECTED: "PRIMARY_COLOR_SELECTED", - PRIMARY_COLOR_UPDATED: "PRIMARY_COLOR_UPDATED", - SECONDARY_COLOR_SELECTED: "SECONDARY_COLOR_SELECTED", - SECONDARY_COLOR_UPDATED: "SECONDARY_COLOR_UPDATED", + + TOOL_SELECTED : "TOOL_SELECTED", + TOOL_RELEASED : "TOOL_RELEASED", + PRIMARY_COLOR_SELECTED: "PRIMARY_COLOR_SELECTED", + PRIMARY_COLOR_UPDATED: "PRIMARY_COLOR_UPDATED", + SECONDARY_COLOR_SELECTED: "SECONDARY_COLOR_SELECTED", + SECONDARY_COLOR_UPDATED: "SECONDARY_COLOR_UPDATED", - /** - * When this event is emitted, a request is sent to the localstorage - * Service to save the current framesheet. The storage service - * may not immediately store data (internal throttling of requests). - */ - LOCALSTORAGE_REQUEST: "LOCALSTORAGE_REQUEST", + /** + * When this event is emitted, a request is sent to the localstorage + * Service to save the current framesheet. The storage service + * may not immediately store data (internal throttling of requests). + */ + LOCALSTORAGE_REQUEST: "LOCALSTORAGE_REQUEST", - CANVAS_RIGHT_CLICKED: "CANVAS_RIGHT_CLICKED", + CANVAS_RIGHT_CLICKED: "CANVAS_RIGHT_CLICKED", - /** - * Event to request a refresh of the display. - * A bit overkill but, it's just workaround in our current drawing system. - * TODO: Remove or rework when redraw system is refactored. - */ - REFRESH: "REFRESH", + /** + * Event to request a refresh of the display. + * A bit overkill but, it's just workaround in our current drawing system. + * TODO: Remove or rework when redraw system is refactored. + */ + 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", + /** + * 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", - /** - * Fired each time a user setting change. - * The payload will be: - * 1st argument: Name of the settings - * 2nd argument: New value - */ - USER_SETTINGS_CHANGED: "USER_SETTINGS_CHANGED", - - /** - * The framesheet was reseted and is now probably drastically different. - * Number of frames, content of frames, color used for the palette may have changed. - */ - FRAMESHEET_RESET: "FRAMESHEET_RESET", + /** + * Fired each time a user setting change. + * The payload will be: + * 1st argument: Name of the settings + * 2nd argument: New value + */ + USER_SETTINGS_CHANGED: "USER_SETTINGS_CHANGED", + + /** + * The framesheet was reseted and is now probably drastically different. + * Number of frames, content of frames, color used for the palette may have changed. + */ + FRAMESHEET_RESET: "FRAMESHEET_RESET", - FRAME_SIZE_CHANGED : "FRAME_SIZE_CHANGED", + FRAME_SIZE_CHANGED : "FRAME_SIZE_CHANGED", - CURRENT_FRAME_SET: "CURRENT_FRAME_SET", + CURRENT_FRAME_SET: "CURRENT_FRAME_SET", - SELECTION_CREATED: "SELECTION_CREATED", - SELECTION_MOVE_REQUEST: "SELECTION_MOVE_REQUEST", - SELECTION_DISMISSED: "SELECTION_DISMISSED", - - SHOW_NOTIFICATION: "SHOW_NOTIFICATION", - HIDE_NOTIFICATION: "HIDE_NOTIFICATION", + SELECTION_CREATED: "SELECTION_CREATED", + SELECTION_MOVE_REQUEST: "SELECTION_MOVE_REQUEST", + SELECTION_DISMISSED: "SELECTION_DISMISSED", + + SHOW_NOTIFICATION: "SHOW_NOTIFICATION", + HIDE_NOTIFICATION: "HIDE_NOTIFICATION", - UNDO: "UNDO", - REDO: "REDO", - CUT: "CUT", - COPY: "COPY", - PASTE: "PASTE" + UNDO: "UNDO", + REDO: "REDO", + CUT: "CUT", + COPY: "COPY", + PASTE: "PASTE" }; \ No newline at end of file diff --git a/js/controller/AnimatedPreviewController.js b/js/controller/AnimatedPreviewController.js index bcec77e3..9b50961a 100644 --- a/js/controller/AnimatedPreviewController.js +++ b/js/controller/AnimatedPreviewController.js @@ -1,67 +1,67 @@ (function () { - var ns = $.namespace("pskl.controller"); - ns.AnimatedPreviewController = function (framesheet, container, dpi) { - this.framesheet = framesheet; - this.container = container; + var ns = $.namespace("pskl.controller"); + ns.AnimatedPreviewController = function (framesheet, container, dpi) { + this.framesheet = framesheet; + this.container = container; - this.elapsedTime = 0; + this.elapsedTime = 0; + this.currentIndex = 0; + + this.fps = parseInt($("#preview-fps")[0].value, 10); + + var renderingOptions = { + "dpi": this.calculateDPI_() + }; + this.renderer = new pskl.rendering.FrameRenderer(this.container, renderingOptions); + + $.subscribe(Events.FRAME_SIZE_CHANGED, this.updateDPI_.bind(this)); + }; + + ns.AnimatedPreviewController.prototype.init = function () { + // the oninput event won't work on IE10 unfortunately, but at least will provide a + // consistent behavior across all other browsers that support the input type range + // see https://bugzilla.mozilla.org/show_bug.cgi?id=853670 + $("#preview-fps")[0].addEventListener('change', this.onFPSSliderChange.bind(this)); + }; + + ns.AnimatedPreviewController.prototype.onFPSSliderChange = function (evt) { + this.setFPS(parseInt($("#preview-fps")[0].value, 10)); + }; + + ns.AnimatedPreviewController.prototype.setFPS = function (fps) { + this.fps = fps; + $("#preview-fps").val(this.fps); + $("#display-fps").html(this.fps + " FPS"); + }; + + ns.AnimatedPreviewController.prototype.render = function (delta) { + this.elapsedTime += delta; + var index = Math.floor(this.elapsedTime / (1000/this.fps)); + if (index != this.currentIndex) { + this.currentIndex = index; + if (!this.framesheet.hasFrameAtIndex(this.currentIndex)) { this.currentIndex = 0; + this.elapsedTime = 0; + } + this.renderer.render(this.framesheet.getFrameByIndex(this.currentIndex)); + } + }; - this.fps = parseInt($("#preview-fps")[0].value, 10); - - var renderingOptions = { - "dpi": this.calculateDPI_() - }; - this.renderer = new pskl.rendering.FrameRenderer(this.container, renderingOptions); + /** + * Calculate the preview DPI depending on the framesheet size + */ + ns.AnimatedPreviewController.prototype.calculateDPI_ = function () { + var previewSize = 200, + framePixelHeight = this.framesheet.getCurrentFrame().getHeight(), + framePixelWidth = this.framesheet.getCurrentFrame().getWidth(); + // TODO (julz) : should have a utility to get a Size from framesheet easily (what about empty framesheets though ?) + + //return pskl.PixelUtils.calculateDPIForContainer($(".preview-container"), framePixelHeight, framePixelWidth); + return pskl.PixelUtils.calculateDPI(previewSize, previewSize, framePixelHeight, framePixelWidth); + }; - $.subscribe(Events.FRAME_SIZE_CHANGED, this.updateDPI_.bind(this)); - }; - - ns.AnimatedPreviewController.prototype.init = function () { - // the oninput event won't work on IE10 unfortunately, but at least will provide a - // consistent behavior across all other browsers that support the input type range - // see https://bugzilla.mozilla.org/show_bug.cgi?id=853670 - $("#preview-fps")[0].addEventListener('change', this.onFPSSliderChange.bind(this)); - }; - - ns.AnimatedPreviewController.prototype.onFPSSliderChange = function (evt) { - this.setFPS(parseInt($("#preview-fps")[0].value, 10)); - }; - - ns.AnimatedPreviewController.prototype.setFPS = function (fps) { - this.fps = fps; - $("#preview-fps").val(this.fps); - $("#display-fps").html(this.fps + " FPS"); - }; - - ns.AnimatedPreviewController.prototype.render = function (delta) { - this.elapsedTime += delta; - var index = Math.floor(this.elapsedTime / (1000/this.fps)); - if (index != this.currentIndex) { - this.currentIndex = index; - if (!this.framesheet.hasFrameAtIndex(this.currentIndex)) { - this.currentIndex = 0; - this.elapsedTime = 0; - } - this.renderer.render(this.framesheet.getFrameByIndex(this.currentIndex)); - } - }; - - /** - * Calculate the preview DPI depending on the framesheet size - */ - ns.AnimatedPreviewController.prototype.calculateDPI_ = function () { - var previewSize = 200, - framePixelHeight = this.framesheet.getCurrentFrame().getHeight(), - framePixelWidth = this.framesheet.getCurrentFrame().getWidth(); - // TODO (julz) : should have a utility to get a Size from framesheet easily (what about empty framesheets though ?) - - //return pskl.PixelUtils.calculateDPIForContainer($(".preview-container"), framePixelHeight, framePixelWidth); - return pskl.PixelUtils.calculateDPI(previewSize, previewSize, framePixelHeight, framePixelWidth); - }; - - ns.AnimatedPreviewController.prototype.updateDPI_ = function () { - this.dpi = this.calculateDPI_(); - this.renderer.updateDPI(this.dpi); - }; + ns.AnimatedPreviewController.prototype.updateDPI_ = function () { + this.dpi = this.calculateDPI_(); + this.renderer.updateDPI(this.dpi); + }; })(); \ No newline at end of file diff --git a/js/controller/DrawingController.js b/js/controller/DrawingController.js index 76201a11..fdedeb2c 100644 --- a/js/controller/DrawingController.js +++ b/js/controller/DrawingController.js @@ -25,8 +25,6 @@ this.renderer = new pskl.rendering.FrameRenderer(this.container, renderingOptions, "drawing-canvas"); this.overlayRenderer = new pskl.rendering.FrameRenderer(this.container, renderingOptions, "canvas-overlay"); - this.renderer.init(framesheet.getCurrentFrame()); - this.overlayRenderer.init(this.overlayFrame); // State of drawing controller: this.isClicked = false; @@ -35,12 +33,18 @@ this.currentToolBehavior = null; this.primaryColor = Constants.DEFAULT_PEN_COLOR; this.secondaryColor = Constants.TRANSPARENT_COLOR; + }; + ns.DrawingController.prototype.init = function () { + this.renderer.render(this.framesheet.getCurrentFrame()); + this.overlayRenderer.render(this.overlayFrame); + this.initMouseBehavior(); $.subscribe(Events.TOOL_SELECTED, $.proxy(function(evt, toolBehavior) { console.log("Tool selected: ", toolBehavior); this.currentToolBehavior = toolBehavior; + this.overlayFrame.clear(); }, this)); /** @@ -68,21 +72,21 @@ 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: - body.contextmenu(this.onCanvasContextMenu_); + this.container.mousedown($.proxy(this.onMousedown_, this)); + this.container.mousemove($.proxy(this.onMousemove_, this)); + body.mouseup($.proxy(this.onMouseup_, this)); + + // Deactivate right click: + body.contextmenu(this.onCanvasContextMenu_); }; ns.DrawingController.prototype.startDPIUpdateTimer_ = function () { - if (this.dpiUpdateTimer) { - window.clearInterval(this.dpiUpdateTimer); - } - this.dpiUpdateTimer = window.setTimeout($.proxy(this.updateDPI_, this), 200); + if (this.dpiUpdateTimer) { + window.clearInterval(this.dpiUpdateTimer); + } + this.dpiUpdateTimer = window.setTimeout($.proxy(this.updateDPI_, this), 200); }, /** @@ -98,144 +102,144 @@ * @private */ ns.DrawingController.prototype.onMousedown_ = function (event) { - this.isClicked = true; - - if(event.button == 2) { // right click - this.isRightClicked = true; - $.publish(Events.CANVAS_RIGHT_CLICKED); - } + this.isClicked = true; + + if(event.button == 2) { // right click + this.isRightClicked = true; + $.publish(Events.CANVAS_RIGHT_CLICKED); + } - var coords = this.getSpriteCoordinates(event); + var coords = this.getSpriteCoordinates(event); + + this.currentToolBehavior.applyToolAt( + coords.col, coords.row, + this.getCurrentColor_(), + this.framesheet.getCurrentFrame(), + this.overlayFrame, + this.wrapEvtInfo_(event) + ); - this.currentToolBehavior.applyToolAt( - coords.col, coords.row, - this.getCurrentColor_(), - this.framesheet.getCurrentFrame(), - this.overlayFrame, - this.wrapEvtInfo_(event) - ); - - $.publish(Events.LOCALSTORAGE_REQUEST); - }; + $.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 coords = this.getSpriteCoordinates(event); - if (this.isClicked) { - - this.currentToolBehavior.moveToolAt( - coords.col, coords.row, - this.getCurrentColor_(), - this.framesheet.getCurrentFrame(), - this.overlayFrame, - this.wrapEvtInfo_(event) - ); - - // 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 { - - this.currentToolBehavior.moveUnactiveToolAt( - coords.col, coords.row, - this.getCurrentColor_(), - this.framesheet.getCurrentFrame(), - this.overlayFrame, - this.wrapEvtInfo_(event) - ); - } - 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. - - this.isClicked = false; - this.isRightClicked = false; - - var coords = this.getSpriteCoordinates(event); - //console.log("mousemove: col: " + spriteCoordinate.col + " - row: " + spriteCoordinate.row); - this.currentToolBehavior.releaseToolAt( + ns.DrawingController.prototype.onMousemove_ = function (event) { + var currentTime = new Date().getTime(); + // Throttling of the mousemove event: + if ((currentTime - this.previousMousemoveTime) > 40 ) { + var coords = this.getSpriteCoordinates(event); + if (this.isClicked) { + + this.currentToolBehavior.moveToolAt( coords.col, coords.row, this.getCurrentColor_(), this.framesheet.getCurrentFrame(), this.overlayFrame, this.wrapEvtInfo_(event) ); - - $.publish(Events.TOOL_RELEASED); - } - }, - - /** - * @private - */ - ns.DrawingController.prototype.wrapEvtInfo_ = function (event) { - var evtInfo = {}; - if (event.button === 0) { - evtInfo.button = Constants.LEFT_BUTTON; - } else if (event.button == 2) { - evtInfo.button = Constants.RIGHT_BUTTON; - } - return evtInfo; - }, - - /** - * @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.getSpriteCoordinates = function(event) { - var coords = this.getRelativeCoordinates(event.clientX, event.clientY); - return this.renderer.convertPixelCoordinatesIntoSpriteCoordinate(coords); - }; - - /** - * @private - */ - ns.DrawingController.prototype.getCurrentColor_ = function () { - if(this.isRightClicked) { - return this.secondaryColor; + + // 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 { - return this.primaryColor; - } - }; - /** - * @private - */ - ns.DrawingController.prototype.onCanvasContextMenu_ = function (event) { - if ($(event.target).closest('#drawing-canvas-container').length) { - // Deactivate right click on drawing canvas only. - event.preventDefault(); - event.stopPropagation(); - event.cancelBubble = true; - return false; - } + this.currentToolBehavior.moveUnactiveToolAt( + coords.col, coords.row, + this.getCurrentColor_(), + this.framesheet.getCurrentFrame(), + this.overlayFrame, + this.wrapEvtInfo_(event) + ); + } + 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. + + this.isClicked = false; + this.isRightClicked = false; + + var coords = this.getSpriteCoordinates(event); + //console.log("mousemove: col: " + spriteCoordinate.col + " - row: " + spriteCoordinate.row); + this.currentToolBehavior.releaseToolAt( + coords.col, coords.row, + this.getCurrentColor_(), + this.framesheet.getCurrentFrame(), + this.overlayFrame, + this.wrapEvtInfo_(event) + ); + + $.publish(Events.TOOL_RELEASED); + } + }; + + /** + * @private + */ + ns.DrawingController.prototype.wrapEvtInfo_ = function (event) { + var evtInfo = {}; + if (event.button === 0) { + evtInfo.button = Constants.LEFT_BUTTON; + } else if (event.button == 2) { + evtInfo.button = Constants.RIGHT_BUTTON; + } + return evtInfo; + }; + + /** + * @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.getSpriteCoordinates = function(event) { + var coords = this.getRelativeCoordinates(event.clientX, event.clientY); + return this.renderer.convertPixelCoordinatesIntoSpriteCoordinate(coords); + }; + + /** + * @private + */ + ns.DrawingController.prototype.getCurrentColor_ = function () { + if(this.isRightClicked) { + return this.secondaryColor; + } else { + return this.primaryColor; + } + }; + + /** + * @private + */ + ns.DrawingController.prototype.onCanvasContextMenu_ = function (event) { + if ($(event.target).closest('#drawing-canvas-container').length) { + // Deactivate right click on drawing canvas only. + event.preventDefault(); + event.stopPropagation(); + event.cancelBubble = true; + return false; + } + }; ns.DrawingController.prototype.render = function () { this.renderFrame(); @@ -271,11 +275,11 @@ */ ns.DrawingController.prototype.calculateDPI_ = function() { var availableViewportHeight = $('#main-wrapper').height(), - leftSectionWidth = $('.left-column').outerWidth(true), - rightSectionWidth = $('.right-column').outerWidth(true), - availableViewportWidth = $('#main-wrapper').width() - leftSectionWidth - rightSectionWidth, - framePixelHeight = this.framesheet.getCurrentFrame().getHeight(), - framePixelWidth = this.framesheet.getCurrentFrame().getWidth(); + leftSectionWidth = $('.left-column').outerWidth(true), + rightSectionWidth = $('.right-column').outerWidth(true), + availableViewportWidth = $('#main-wrapper').width() - leftSectionWidth - rightSectionWidth, + framePixelHeight = this.framesheet.getCurrentFrame().getHeight(), + framePixelWidth = this.framesheet.getCurrentFrame().getWidth(); if (pskl.UserSettings.get(pskl.UserSettings.SHOW_GRID)) { availableViewportWidth = availableViewportWidth - (framePixelWidth * Constants.GRID_STROKE_WIDTH); @@ -299,7 +303,7 @@ var currentFrameHeight = this.framesheet.getCurrentFrame().getHeight(); var canvasHeight = currentFrameHeight * dpi; if (pskl.UserSettings.get(pskl.UserSettings.SHOW_GRID)) { - canvasHeight += Constants.GRID_STROKE_WIDTH * currentFrameHeight; + canvasHeight += Constants.GRID_STROKE_WIDTH * currentFrameHeight; } var verticalGapInPixel = Math.floor(($('#main-wrapper').height() - canvasHeight) / 2); diff --git a/js/controller/PreviewFilmController.js b/js/controller/PreviewFilmController.js index 456f6c9b..b4e6f0f5 100644 --- a/js/controller/PreviewFilmController.js +++ b/js/controller/PreviewFilmController.js @@ -1,217 +1,220 @@ (function () { - var ns = $.namespace("pskl.controller"); - ns.PreviewFilmController = function (framesheet, container, dpi) { + var ns = $.namespace("pskl.controller"); + ns.PreviewFilmController = function (framesheet, container, dpi) { - this.framesheet = framesheet; - this.container = container; - this.dpi = this.calculateDPI_(); + this.framesheet = framesheet; + this.container = container; + this.dpi = this.calculateDPI_(); - this.redrawFlag = true; + this.redrawFlag = true; + }; - $.subscribe(Events.TOOL_RELEASED, this.flagForRedraw_.bind(this)); - $.subscribe(Events.FRAMESHEET_RESET, this.flagForRedraw_.bind(this)); - $.subscribe(Events.FRAMESHEET_RESET, this.refreshDPI_.bind(this)); + ns.PreviewFilmController.prototype.init = function() { + $.subscribe(Events.TOOL_RELEASED, this.flagForRedraw_.bind(this)); + $.subscribe(Events.FRAMESHEET_RESET, this.flagForRedraw_.bind(this)); + $.subscribe(Events.FRAMESHEET_RESET, this.refreshDPI_.bind(this)); - $('#preview-list-scroller').scroll(this.updateScrollerOverflows.bind(this)); - this.updateScrollerOverflows(); - }; + $('#preview-list-scroller').scroll(this.updateScrollerOverflows.bind(this)); + this.updateScrollerOverflows(); + }; - ns.PreviewFilmController.prototype.init = function() {}; + ns.PreviewFilmController.prototype.addFrame = function () { + this.framesheet.addEmptyFrame(); + this.framesheet.setCurrentFrameIndex(this.framesheet.getFrameCount() - 1); + this.updateScrollerOverflows(); + }; - ns.PreviewFilmController.prototype.addFrame = function () { - this.framesheet.addEmptyFrame(); - this.framesheet.setCurrentFrameIndex(this.framesheet.getFrameCount() - 1); - this.updateScrollerOverflows(); - }; + ns.PreviewFilmController.prototype.flagForRedraw_ = function () { + this.redrawFlag = true; + }; - ns.PreviewFilmController.prototype.flagForRedraw_ = function () { - this.redrawFlag = true; - }; + ns.PreviewFilmController.prototype.refreshDPI_ = function () { + this.dpi = this.calculateDPI_(); + }; - ns.PreviewFilmController.prototype.refreshDPI_ = function () { - this.dpi = this.calculateDPI_(); - }; + ns.PreviewFilmController.prototype.render = function () { + if (this.redrawFlag) { + // TODO(vincz): Full redraw on any drawing modification, optimize. + this.createPreviews_(); + this.redrawFlag = false; + } + }; - ns.PreviewFilmController.prototype.render = function () { - if (this.redrawFlag) { - // TODO(vincz): Full redraw on any drawing modification, optimize. - this.createPreviews_(); - this.redrawFlag = false; - } - }; + ns.PreviewFilmController.prototype.updateScrollerOverflows = function () { + var scroller = $('#preview-list-scroller'); + var scrollerHeight = scroller.height(); + var scrollTop = scroller.scrollTop(); + var scrollerContentHeight = $('#preview-list').height(); + var treshold = $('.top-overflow').height(); + var overflowTop = false, + overflowBottom = false; + if (scrollerHeight < scrollerContentHeight) { + if (scrollTop > treshold) { + overflowTop = true; + } + var scrollBottom = (scrollerContentHeight - scrollTop) - scrollerHeight; + if (scrollBottom > treshold) { + overflowBottom = true; + } + } + var wrapper = $('#preview-list-wrapper'); + wrapper.toggleClass('top-overflow-visible', overflowTop); + wrapper.toggleClass('bottom-overflow-visible', overflowBottom); + }; - ns.PreviewFilmController.prototype.updateScrollerOverflows = function () { - var scroller = $('#preview-list-scroller'); - var scrollerHeight = scroller.height(); - var scrollTop = scroller.scrollTop(); - var scrollerContentHeight = $('#preview-list').height(); - var treshold = $('.top-overflow').height(); - var overflowTop = false, - overflowBottom = false; - if (scrollerHeight < scrollerContentHeight) { - if (scrollTop > treshold) { - overflowTop = true; - } - var scrollBottom = (scrollerContentHeight - scrollTop) - scrollerHeight; - if (scrollBottom > treshold) { - overflowBottom = true; - } - } - var wrapper = $('#preview-list-wrapper'); - wrapper.toggleClass('top-overflow-visible', overflowTop); - wrapper.toggleClass('bottom-overflow-visible', overflowBottom); - }; + ns.PreviewFilmController.prototype.createPreviews_ = function () { + + this.container.html(""); + // Manually remove tooltips since mouseout events were shortcut by the DOM refresh: + $(".tooltip").remove(); - ns.PreviewFilmController.prototype.createPreviews_ = function () { - - this.container.html(""); - // Manually remove tooltips since mouseout events were shortcut by the DOM refresh: - $(".tooltip").remove(); + var frameCount = this.framesheet.getFrameCount(); - var frameCount = this.framesheet.getFrameCount(); + for (var i = 0, l = frameCount; i < l ; i++) { + this.container.append(this.createPreviewTile_(i)); + } + // Append 'new empty frame' button + var newFrameButton = document.createElement("div"); + newFrameButton.id = "add-frame-action"; + newFrameButton.className = "add-frame-action"; + newFrameButton.innerHTML = "
Add new frame
"; + this.container.append(newFrameButton); - for (var i = 0, l = frameCount; i < l ; i++) { - this.container.append(this.createPreviewTile_(i)); - } - // Append 'new empty frame' button - var newFrameButton = document.createElement("div"); - newFrameButton.id = "add-frame-action"; - newFrameButton.className = "add-frame-action"; - newFrameButton.innerHTML = "Add new frame
"; - this.container.append(newFrameButton); + $(newFrameButton).click(this.addFrame.bind(this)); - $(newFrameButton).click(this.addFrame.bind(this)); - - var needDragndropBehavior = (frameCount > 1); - if(needDragndropBehavior) { - this.initDragndropBehavior_(); - } - this.updateScrollerOverflows(); - }; + var needDragndropBehavior = (frameCount > 1); + if(needDragndropBehavior) { + this.initDragndropBehavior_(); + } + this.updateScrollerOverflows(); + }; - /** - * @private - */ - ns.PreviewFilmController.prototype.initDragndropBehavior_ = function () { - - $("#preview-list").sortable({ - placeholder: "preview-tile-drop-proxy", - update: $.proxy(this.onUpdate_, this), - items: ".preview-tile" - }); - $("#preview-list").disableSelection(); - }; + /** + * @private + */ + ns.PreviewFilmController.prototype.initDragndropBehavior_ = function () { + + $("#preview-list").sortable({ + placeholder: "preview-tile-drop-proxy", + update: $.proxy(this.onUpdate_, this), + items: ".preview-tile" + }); + $("#preview-list").disableSelection(); + }; - /** - * @private - */ - ns.PreviewFilmController.prototype.onUpdate_ = function( event, ui ) { - var originFrameId = parseInt(ui.item.data("tile-number"), 10); - var targetInsertionId = $('.preview-tile').index(ui.item); + /** + * @private + */ + ns.PreviewFilmController.prototype.onUpdate_ = function( event, ui ) { + var originFrameId = parseInt(ui.item.data("tile-number"), 10); + var targetInsertionId = $('.preview-tile').index(ui.item); - this.framesheet.moveFrame(originFrameId, targetInsertionId); - this.framesheet.setCurrentFrameIndex(targetInsertionId); + this.framesheet.moveFrame(originFrameId, targetInsertionId); + this.framesheet.setCurrentFrameIndex(targetInsertionId); - // TODO(grosbouddha): move localstorage request to the model layer? - $.publish(Events.LOCALSTORAGE_REQUEST); - }; + // TODO(grosbouddha): move localstorage request to the model layer? + $.publish(Events.LOCALSTORAGE_REQUEST); + }; - /** - * @private - * TODO(vincz): clean this giant rendering function & remove listeners. - */ - ns.PreviewFilmController.prototype.createPreviewTile_ = function(tileNumber) { - var currentFrame = this.framesheet.getFrameByIndex(tileNumber); - - var previewTileRoot = document.createElement("li"); - var classname = "preview-tile"; - previewTileRoot.setAttribute("data-tile-number", tileNumber); + /** + * @private + * TODO(vincz): clean this giant rendering function & remove listeners. + */ + ns.PreviewFilmController.prototype.createPreviewTile_ = function(tileNumber) { + var currentFrame = this.framesheet.getFrameByIndex(tileNumber); + + var previewTileRoot = document.createElement("li"); + var classname = "preview-tile"; + previewTileRoot.setAttribute("data-tile-number", tileNumber); - if (this.framesheet.getCurrentFrame() == currentFrame) { - classname += " selected"; - } - previewTileRoot.className = classname; + if (this.framesheet.getCurrentFrame() == currentFrame) { + classname += " selected"; + } + previewTileRoot.className = classname; - var canvasContainer = document.createElement("div"); - canvasContainer.className = "canvas-container"; - - var canvasBackground = document.createElement("div"); - canvasBackground.className = "canvas-background"; - canvasContainer.appendChild(canvasBackground); - - previewTileRoot.addEventListener('click', this.onPreviewClick_.bind(this, tileNumber)); + var canvasContainer = document.createElement("div"); + canvasContainer.className = "canvas-container"; + + var canvasBackground = document.createElement("div"); + canvasBackground.className = "canvas-background"; + canvasContainer.appendChild(canvasBackground); + + previewTileRoot.addEventListener('click', this.onPreviewClick_.bind(this, tileNumber)); - var cloneFrameButton = document.createElement("button"); - cloneFrameButton.setAttribute('rel', 'tooltip'); - cloneFrameButton.setAttribute('data-placement', 'right'); - cloneFrameButton.setAttribute('title', 'Duplicate this frame'); - cloneFrameButton.className = "tile-overlay duplicate-frame-action"; - previewTileRoot.appendChild(cloneFrameButton); - cloneFrameButton.addEventListener('click', this.onAddButtonClick_.bind(this, tileNumber)); + var cloneFrameButton = document.createElement("button"); + cloneFrameButton.setAttribute('rel', 'tooltip'); + cloneFrameButton.setAttribute('data-placement', 'right'); + cloneFrameButton.setAttribute('title', 'Duplicate this frame'); + cloneFrameButton.className = "tile-overlay duplicate-frame-action"; + previewTileRoot.appendChild(cloneFrameButton); + cloneFrameButton.addEventListener('click', this.onAddButtonClick_.bind(this, tileNumber)); - // 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"); - currentFrameRenderer.init(currentFrame); - - previewTileRoot.appendChild(canvasContainer); + // 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"); + currentFrameRenderer.render(currentFrame); + + previewTileRoot.appendChild(canvasContainer); - if(tileNumber > 0 || this.framesheet.getFrameCount() > 1) { - // Add 'remove frame' button. - var deleteButton = document.createElement("button"); - deleteButton.setAttribute('rel', 'tooltip'); - deleteButton.setAttribute('data-placement', 'right'); - deleteButton.setAttribute('title', 'Delete this frame'); - deleteButton.className = "tile-overlay delete-frame-action"; - deleteButton.addEventListener('click', this.onDeleteButtonClick_.bind(this, tileNumber)); - previewTileRoot.appendChild(deleteButton); + if(tileNumber > 0 || this.framesheet.getFrameCount() > 1) { + // Add 'remove frame' button. + var deleteButton = document.createElement("button"); + deleteButton.setAttribute('rel', 'tooltip'); + deleteButton.setAttribute('data-placement', 'right'); + deleteButton.setAttribute('title', 'Delete this frame'); + deleteButton.className = "tile-overlay delete-frame-action"; + deleteButton.addEventListener('click', this.onDeleteButtonClick_.bind(this, tileNumber)); + previewTileRoot.appendChild(deleteButton); - // Add 'dragndrop handle'. - var dndHandle = document.createElement("div"); - dndHandle.className = "tile-overlay dnd-action"; - previewTileRoot.appendChild(dndHandle); - } - var tileCount = document.createElement("div"); - tileCount.className = "tile-overlay tile-count"; - tileCount.innerHTML = tileNumber; - previewTileRoot.appendChild(tileCount); - + // Add 'dragndrop handle'. + var dndHandle = document.createElement("div"); + dndHandle.className = "tile-overlay dnd-action"; + previewTileRoot.appendChild(dndHandle); + } + var tileCount = document.createElement("div"); + tileCount.className = "tile-overlay tile-count"; + tileCount.innerHTML = tileNumber; + previewTileRoot.appendChild(tileCount); + - return previewTileRoot; - }; + return previewTileRoot; + }; - ns.PreviewFilmController.prototype.onPreviewClick_ = function (index, evt) { - // has not class tile-action: - if(!evt.target.classList.contains('tile-overlay')) { - this.framesheet.setCurrentFrameIndex(index); - } - }; + ns.PreviewFilmController.prototype.onPreviewClick_ = function (index, evt) { + // has not class tile-action: + if(!evt.target.classList.contains('tile-overlay')) { + this.framesheet.setCurrentFrameIndex(index); + } + }; - ns.PreviewFilmController.prototype.onDeleteButtonClick_ = function (index, evt) { - this.framesheet.removeFrameByIndex(index); - $.publish(Events.LOCALSTORAGE_REQUEST); // Should come from model - this.updateScrollerOverflows(); - }; + ns.PreviewFilmController.prototype.onDeleteButtonClick_ = function (index, evt) { + this.framesheet.removeFrameByIndex(index); + $.publish(Events.LOCALSTORAGE_REQUEST); // Should come from model + this.updateScrollerOverflows(); + }; - ns.PreviewFilmController.prototype.onAddButtonClick_ = function (index, evt) { - this.framesheet.duplicateFrameByIndex(index); - $.publish(Events.LOCALSTORAGE_REQUEST); // Should come from model - this.framesheet.setCurrentFrameIndex(index + 1); - this.updateScrollerOverflows(); - }; + ns.PreviewFilmController.prototype.onAddButtonClick_ = function (index, evt) { + this.framesheet.duplicateFrameByIndex(index); + $.publish(Events.LOCALSTORAGE_REQUEST); // Should come from model + this.framesheet.setCurrentFrameIndex(index + 1); + this.updateScrollerOverflows(); + }; - /** - * Calculate the preview DPI depending on the framesheet size - */ - ns.PreviewFilmController.prototype.calculateDPI_ = function () { - var previewSize = 120, - framePixelHeight = this.framesheet.getCurrentFrame().getHeight(), - framePixelWidth = this.framesheet.getCurrentFrame().getWidth(); - // TODO (julz) : should have a utility to get a Size from framesheet easily (what about empty framesheets though ?) + /** + * Calculate the preview DPI depending on the framesheet size + */ + ns.PreviewFilmController.prototype.calculateDPI_ = function () { + var curFrame = this.framesheet.getCurrentFrame(), + frameHeight = curFrame.getHeight(), + frameWidth = curFrame.getWidth(), + maxFrameDim = Math.max(frameWidth, frameHeight); - return pskl.PixelUtils.calculateDPI(previewSize, previewSize, framePixelHeight, framePixelWidth); - }; + var previewHeight = Constants.PREVIEW_FILM_SIZE * frameHeight / maxFrameDim; + var previewWidth = Constants.PREVIEW_FILM_SIZE * frameWidth / maxFrameDim; + + return pskl.PixelUtils.calculateDPI(previewHeight, previewWidth, frameHeight, frameWidth) || 1; + }; })(); \ No newline at end of file diff --git a/js/controller/SettingsController.js b/js/controller/SettingsController.js index 7c54903d..3e7c237d 100644 --- a/js/controller/SettingsController.js +++ b/js/controller/SettingsController.js @@ -1,45 +1,45 @@ (function () { - var ns = $.namespace("pskl.controller"); + var ns = $.namespace("pskl.controller"); - ns.SettingsController = function () {}; + ns.SettingsController = function () {}; - /** - * @public - */ - ns.SettingsController.prototype.init = function() { + /** + * @public + */ + ns.SettingsController.prototype.init = function() { - // Highlight selected background picker: - var backgroundClass = pskl.UserSettings.get(pskl.UserSettings.CANVAS_BACKGROUND); - $('#background-picker-wrapper') - .find('.background-picker[data-background-class=' + backgroundClass + ']') - .addClass('selected'); + // Highlight selected background picker: + var backgroundClass = pskl.UserSettings.get(pskl.UserSettings.CANVAS_BACKGROUND); + $('#background-picker-wrapper') + .find('.background-picker[data-background-class=' + backgroundClass + ']') + .addClass('selected'); - // Initial state for grid display: - var show_grid = pskl.UserSettings.get(pskl.UserSettings.SHOW_GRID); - $('#show-grid').prop('checked', show_grid); + // Initial state for grid display: + var show_grid = pskl.UserSettings.get(pskl.UserSettings.SHOW_GRID); + $('#show-grid').prop('checked', show_grid); - // Expand drawer when clicking 'Settings' tab. - $('#settings').click(function(evt) { - $('.right-sticky-section').toggleClass('expanded'); - $('#settings').toggleClass('has-expanded-drawer'); - }); + // Expand drawer when clicking 'Settings' tab. + $('#settings').click(function(evt) { + $('.right-sticky-section').toggleClass('expanded'); + $('#settings').toggleClass('has-expanded-drawer'); + }); - // Handle grid display changes: - $('#show-grid').change($.proxy(function(evt) { - var checked = $('#show-grid').prop('checked'); - pskl.UserSettings.set(pskl.UserSettings.SHOW_GRID, checked); - }, this)); + // Handle grid display changes: + $('#show-grid').change($.proxy(function(evt) { + var checked = $('#show-grid').prop('checked'); + pskl.UserSettings.set(pskl.UserSettings.SHOW_GRID, checked); + }, this)); - // Handle canvas background changes: - $('#background-picker-wrapper').click(function(evt) { - var target = $(evt.target).closest('.background-picker'); - if (target.length) { - var backgroundClass = target.data('background-class'); - pskl.UserSettings.set(pskl.UserSettings.CANVAS_BACKGROUND, backgroundClass); + // Handle canvas background changes: + $('#background-picker-wrapper').click(function(evt) { + var target = $(evt.target).closest('.background-picker'); + if (target.length) { + var backgroundClass = target.data('background-class'); + pskl.UserSettings.set(pskl.UserSettings.CANVAS_BACKGROUND, backgroundClass); - $('.background-picker').removeClass('selected'); - target.addClass('selected'); - } - }); - }; + $('.background-picker').removeClass('selected'); + target.addClass('selected'); + } + }); + }; })(); \ No newline at end of file diff --git a/js/controller/ToolController.js b/js/controller/ToolController.js index aa48685e..4b38b2f9 100644 --- a/js/controller/ToolController.js +++ b/js/controller/ToolController.js @@ -1,99 +1,107 @@ (function () { - var ns = $.namespace("pskl.controller"); + var ns = $.namespace("pskl.controller"); - - ns.ToolController = function () { - - this.toolInstances = { - "simplePen" : new pskl.drawingtools.SimplePen(), - "verticalMirrorPen" : new pskl.drawingtools.VerticalMirrorPen(), - "eraser" : new pskl.drawingtools.Eraser(), - "paintBucket" : new pskl.drawingtools.PaintBucket(), - "stroke" : new pskl.drawingtools.Stroke(), - "rectangle" : new pskl.drawingtools.Rectangle(), - "circle" : new pskl.drawingtools.Circle(), - "move" : new pskl.drawingtools.Move(), - "rectangleSelect" : new pskl.drawingtools.RectangleSelect(), - "shapeSelect" : new pskl.drawingtools.ShapeSelect(), - "colorPicker" : new pskl.drawingtools.ColorPicker() - }; - - this.currentSelectedTool = this.toolInstances.simplePen; - this.previousSelectedTool = this.toolInstances.simplePen; + + ns.ToolController = function () { + + this.toolInstances = { + "simplePen" : new pskl.drawingtools.SimplePen(), + "verticalMirrorPen" : new pskl.drawingtools.VerticalMirrorPen(), + "eraser" : new pskl.drawingtools.Eraser(), + "paintBucket" : new pskl.drawingtools.PaintBucket(), + "stroke" : new pskl.drawingtools.Stroke(), + "rectangle" : new pskl.drawingtools.Rectangle(), + "circle" : new pskl.drawingtools.Circle(), + "move" : new pskl.drawingtools.Move(), + "rectangleSelect" : new pskl.drawingtools.RectangleSelect(), + "shapeSelect" : new pskl.drawingtools.ShapeSelect(), + "colorPicker" : new pskl.drawingtools.ColorPicker() }; - /** - * @private - */ - ns.ToolController.prototype.activateToolOnStage_ = function(tool) { - var stage = $("body"); - var previousSelectedToolClass = stage.data("selected-tool-class"); - if(previousSelectedToolClass) { - stage.removeClass(previousSelectedToolClass); - } - stage.addClass(tool.toolId); - stage.data("selected-tool-class", tool.toolId); - }; + this.currentSelectedTool = this.toolInstances.simplePen; + this.previousSelectedTool = this.toolInstances.simplePen; + }; - /** - * @private - */ - ns.ToolController.prototype.selectTool_ = function(tool) { - console.log("Selecting Tool:" , this.currentSelectedTool); - this.currentSelectedTool = tool; - this.activateToolOnStage_(this.currentSelectedTool); - $.publish(Events.TOOL_SELECTED, [tool]); - }; + /** + * @public + */ + ns.ToolController.prototype.init = function() { + this.createToolMarkup_(); - /** - * @private - */ - ns.ToolController.prototype.onToolIconClicked_ = function(evt) { - var target = $(evt.target); - var clickedTool = target.closest(".tool-icon"); + // Initialize tool: + // Set SimplePen as default selected tool: + this.selectTool_(this.toolInstances.simplePen); + // Activate listener on tool panel: + $("#tool-section").click($.proxy(this.onToolIconClicked_, this)); + }; - if(clickedTool.length) { - for(var tool in this.toolInstances) { - if (this.toolInstances[tool].toolId == clickedTool.data().toolId) { - this.selectTool_(this.toolInstances[tool]); + /** + * @private + */ + ns.ToolController.prototype.activateToolOnStage_ = function(tool) { + var stage = $("body"); + var previousSelectedToolClass = stage.data("selected-tool-class"); + if(previousSelectedToolClass) { + stage.removeClass(previousSelectedToolClass); + } + stage.addClass(tool.toolId); + stage.data("selected-tool-class", tool.toolId); + }; - // Show tool as selected: - $('#tool-section .tool-icon.selected').removeClass('selected'); - clickedTool.addClass('selected'); - } - } - } - }; + /** + * @private + */ + ns.ToolController.prototype.selectTool_ = function(tool) { + console.log("Selecting Tool:" , this.currentSelectedTool); + this.currentSelectedTool = tool; + this.activateToolOnStage_(this.currentSelectedTool); + $.publish(Events.TOOL_SELECTED, [tool]); + }; - /** - * @private - */ - ns.ToolController.prototype.createToolMarkup_ = function() { - var currentTool, toolMarkup = '', extraClass; - // TODO(vincz): Tools rendering order is not enforced by the data stucture (this.toolInstances), fix that. - for (var toolKey in this.toolInstances) { - currentTool = this.toolInstances[toolKey]; - extraClass = currentTool.toolId; - if (this.currentSelectedTool == currentTool) { - extraClass = extraClass + " selected"; - } - toolMarkup += ''; - } - $('#tools-container').html(toolMarkup); - }; + /** + * @private + */ + ns.ToolController.prototype.onToolIconClicked_ = function(evt) { + var target = $(evt.target); + var clickedTool = target.closest(".tool-icon"); - /** - * @public - */ - ns.ToolController.prototype.init = function() { + if(clickedTool.length) { + var toolId = clickedTool.data().toolId; + var tool = this.getToolById_(toolId); + if (tool) { + this.selectTool_(tool); - this.createToolMarkup_(); + // Show tool as selected: + $('#tool-section .tool-icon.selected').removeClass('selected'); + clickedTool.addClass('selected'); + } + } + }; - // Initialize tool: - // Set SimplePen as default selected tool: - this.selectTool_(this.toolInstances.simplePen); - // Activate listener on tool panel: - $("#tool-section").click($.proxy(this.onToolIconClicked_, this)); - }; + ns.ToolController.prototype.getToolById_ = function (toolId) { + for(var key in this.toolInstances) { + if (this.toolInstances[key].toolId == toolId) { + return this.toolInstances[key]; + } + } + return null; + }; + + /** + * @private + */ + ns.ToolController.prototype.createToolMarkup_ = function() { + var currentTool, toolMarkup = '', extraClass; + // TODO(vincz): Tools rendering order is not enforced by the data stucture (this.toolInstances), fix that. + for (var toolKey in this.toolInstances) { + currentTool = this.toolInstances[toolKey]; + extraClass = currentTool.toolId; + if (this.currentSelectedTool == currentTool) { + extraClass = extraClass + " selected"; + } + toolMarkup += ''; + } + $('#tools-container').html(toolMarkup); + }; })(); \ No newline at end of file diff --git a/js/drawingtools/BaseTool.js b/js/drawingtools/BaseTool.js index 32524b68..f1d77ad0 100644 --- a/js/drawingtools/BaseTool.js +++ b/js/drawingtools/BaseTool.js @@ -4,69 +4,69 @@ * @require pskl.utils */ (function() { - var ns = $.namespace("pskl.drawingtools"); + var ns = $.namespace("pskl.drawingtools"); - ns.BaseTool = function() {}; + ns.BaseTool = function() {}; - ns.BaseTool.prototype.applyToolAt = function(col, row, color, frame, overlay) {}; - - ns.BaseTool.prototype.moveToolAt = function(col, row, color, frame, overlay) {}; + ns.BaseTool.prototype.applyToolAt = function(col, row, color, frame, overlay) {}; + + ns.BaseTool.prototype.moveToolAt = function(col, row, color, frame, overlay) {}; - ns.BaseTool.prototype.moveUnactiveToolAt = function(col, row, color, frame, overlay) { - if (overlay.containsPixel(col, row)) { - if (!isNaN(this.highlightedPixelCol) && - !isNaN(this.highlightedPixelRow) && - (this.highlightedPixelRow != row || - this.highlightedPixelCol != col)) { + ns.BaseTool.prototype.moveUnactiveToolAt = function(col, row, color, frame, overlay) { + if (overlay.containsPixel(col, row)) { + if (!isNaN(this.highlightedPixelCol) && + !isNaN(this.highlightedPixelRow) && + (this.highlightedPixelRow != row || + this.highlightedPixelCol != col)) { - // Clean the previously highlighted pixel: - overlay.clear(); - } + // Clean the previously highlighted pixel: + overlay.clear(); + } - // Show the current pixel targeted by the tool: - overlay.setPixel(col, row, Constants.TOOL_TARGET_HIGHLIGHT_COLOR); + // Show the current pixel targeted by the tool: + overlay.setPixel(col, row, Constants.TOOL_TARGET_HIGHLIGHT_COLOR); - this.highlightedPixelCol = col; - this.highlightedPixelRow = row; - } - }; + this.highlightedPixelCol = col; + this.highlightedPixelRow = row; + } + }; - ns.BaseTool.prototype.releaseToolAt = function(col, row, color, frame, overlay) {}; + ns.BaseTool.prototype.releaseToolAt = function(col, row, color, frame, overlay) {}; - /** - * Bresenham line algorihtm: Get an array of pixels from - * start and end coordinates. - * - * http://en.wikipedia.org/wiki/Bresenham's_line_algorithm - * http://stackoverflow.com/questions/4672279/bresenham-algorithm-in-javascript - * - * @private - */ - ns.BaseTool.prototype.getLinePixels_ = function(x0, x1, y0, y1) { - - var pixels = []; - var dx = Math.abs(x1-x0); - var dy = Math.abs(y1-y0); - var sx = (x0 < x1) ? 1 : -1; - var sy = (y0 < y1) ? 1 : -1; - var err = dx-dy; + /** + * Bresenham line algorihtm: Get an array of pixels from + * start and end coordinates. + * + * http://en.wikipedia.org/wiki/Bresenham's_line_algorithm + * http://stackoverflow.com/questions/4672279/bresenham-algorithm-in-javascript + * + * @private + */ + ns.BaseTool.prototype.getLinePixels_ = function(x0, x1, y0, y1) { + + var pixels = []; + var dx = Math.abs(x1-x0); + var dy = Math.abs(y1-y0); + var sx = (x0 < x1) ? 1 : -1; + var sy = (y0 < y1) ? 1 : -1; + var err = dx-dy; - while(true){ + while(true){ - // Do what you need to for this - pixels.push({"col": x0, "row": y0}); + // Do what you need to for this + pixels.push({"col": x0, "row": y0}); - if ((x0==x1) && (y0==y1)) break; - var e2 = 2*err; - if (e2>-dy){ - err -= dy; - x0 += sx; - } - if (e2 < dx) { - err += dx; - y0 += sy; - } - } - return pixels; - }; + if ((x0==x1) && (y0==y1)) break; + var e2 = 2*err; + if (e2>-dy){ + err -= dy; + x0 += sx; + } + if (e2 < dx) { + err += dx; + y0 += sy; + } + } + return pixels; + }; })(); diff --git a/js/drawingtools/Circle.js b/js/drawingtools/Circle.js index e9a7c5e6..a665dc96 100644 --- a/js/drawingtools/Circle.js +++ b/js/drawingtools/Circle.js @@ -4,82 +4,82 @@ * @require pskl.utils */ (function() { - var ns = $.namespace("pskl.drawingtools"); + var ns = $.namespace("pskl.drawingtools"); - ns.Circle = function() { - this.toolId = "tool-circle"; - this.helpText = "Circle tool"; - - // Circle's first point coordinates (set in applyToolAt) - this.startCol = null; - this.startRow = null; - }; + ns.Circle = function() { + this.toolId = "tool-circle"; + this.helpText = "Circle tool"; + + // Circle's first point coordinates (set in applyToolAt) + this.startCol = null; + this.startRow = null; + }; - pskl.utils.inherit(ns.Circle, ns.BaseTool); - - /** - * @override - */ - ns.Circle.prototype.applyToolAt = function(col, row, color, frame, overlay) { - this.startCol = col; - this.startRow = row; - - // Drawing the first point of the rectangle in the fake overlay canvas: - overlay.setPixel(col, row, color); - }; + pskl.utils.inherit(ns.Circle, ns.BaseTool); + + /** + * @override + */ + ns.Circle.prototype.applyToolAt = function(col, row, color, frame, overlay) { + this.startCol = col; + this.startRow = row; + + // Drawing the first point of the rectangle in the fake overlay canvas: + overlay.setPixel(col, row, color); + }; - ns.Circle.prototype.moveToolAt = function(col, row, color, frame, overlay) { - overlay.clear(); - if(color == Constants.TRANSPARENT_COLOR) { - color = Constants.SELECTION_TRANSPARENT_COLOR; - } + ns.Circle.prototype.moveToolAt = function(col, row, color, frame, overlay) { + overlay.clear(); + if(color == Constants.TRANSPARENT_COLOR) { + color = Constants.SELECTION_TRANSPARENT_COLOR; + } - // draw in overlay - this.drawCircle_(col, row, color, overlay); - }; + // draw in overlay + this.drawCircle_(col, row, color, overlay); + }; - /** - * @override - */ - ns.Circle.prototype.releaseToolAt = function(col, row, color, frame, overlay) { - overlay.clear(); - if(frame.containsPixel(col, row)) { // cancel if outside of canvas - // draw in frame to finalize - this.drawCircle_(col, row, color, frame); - } - }; + /** + * @override + */ + ns.Circle.prototype.releaseToolAt = function(col, row, color, frame, overlay) { + overlay.clear(); + if(frame.containsPixel(col, row)) { // cancel if outside of canvas + // draw in frame to finalize + this.drawCircle_(col, row, color, frame); + } + }; - ns.Circle.prototype.drawCircle_ = function (col, row, color, targetFrame) { - var circlePoints = this.getCirclePixels_(this.startCol, this.startRow, col, row); - for(var i = 0; i< circlePoints.length; i++) { - // Change model: - targetFrame.setPixel(circlePoints[i].col, circlePoints[i].row, color); - } - }; + ns.Circle.prototype.drawCircle_ = function (col, row, color, targetFrame) { + var circlePoints = this.getCirclePixels_(this.startCol, this.startRow, col, row); + for(var i = 0; i< circlePoints.length; i++) { + // Change model: + targetFrame.setPixel(circlePoints[i].col, circlePoints[i].row, color); + } + }; - ns.Circle.prototype.getCirclePixels_ = function (x0, y0, x1, y1) { - var coords = pskl.PixelUtils.getOrderedRectangleCoordinates(x0, y0, x1, y1); - var xC = (coords.x0 + coords.x1)/2; - var yC = (coords.y0 + coords.y1)/2; - - var rX = coords.x1 - xC; - var rY = coords.y1 - yC; + ns.Circle.prototype.getCirclePixels_ = function (x0, y0, x1, y1) { + var coords = pskl.PixelUtils.getOrderedRectangleCoordinates(x0, y0, x1, y1); + var xC = (coords.x0 + coords.x1)/2; + var yC = (coords.y0 + coords.y1)/2; + + var rX = coords.x1 - xC; + var rY = coords.y1 - yC; - var pixels = []; - var x, y, angle; - for (x = coords.x0 ; x < coords.x1 ; x++) { - angle = Math.acos((x - xC)/rX); - y = Math.round(rY * Math.sin(angle) + yC); - pixels.push({"col": x, "row": y}); - pixels.push({"col": 2*xC - x, "row": 2*yC - y}); - } + var pixels = []; + var x, y, angle; + for (x = coords.x0 ; x < coords.x1 ; x++) { + angle = Math.acos((x - xC)/rX); + y = Math.round(rY * Math.sin(angle) + yC); + pixels.push({"col": x, "row": y}); + pixels.push({"col": 2*xC - x, "row": 2*yC - y}); + } - for (y = coords.y0 ; y < coords.y1 ; y++) { - angle = Math.asin((y - yC)/rY); - x = Math.round(rX * Math.cos(angle) + xC); - pixels.push({"col": x, "row": y}); - pixels.push({"col": 2*xC - x, "row": 2*yC - y}); - } - return pixels; - }; + for (y = coords.y0 ; y < coords.y1 ; y++) { + angle = Math.asin((y - yC)/rY); + x = Math.round(rX * Math.cos(angle) + xC); + pixels.push({"col": x, "row": y}); + pixels.push({"col": 2*xC - x, "row": 2*yC - y}); + } + return pixels; + }; })(); diff --git a/js/drawingtools/ColorPicker.js b/js/drawingtools/ColorPicker.js index f204afc4..9c5d72c6 100644 --- a/js/drawingtools/ColorPicker.js +++ b/js/drawingtools/ColorPicker.js @@ -4,26 +4,26 @@ * @require pskl.utils */ (function() { - var ns = $.namespace("pskl.drawingtools"); + var ns = $.namespace("pskl.drawingtools"); - ns.ColorPicker = function() { - this.toolId = "tool-colorpicker"; - this.helpText = "Color picker"; - }; + ns.ColorPicker = function() { + this.toolId = "tool-colorpicker"; + this.helpText = "Color picker"; + }; - pskl.utils.inherit(ns.ColorPicker, ns.BaseTool); - - /** - * @override - */ - ns.ColorPicker.prototype.applyToolAt = function(col, row, color, frame, overlay, context) { - if (frame.containsPixel(col, row)) { - var sampledColor = frame.getPixel(col, row); - if (context.button == Constants.LEFT_BUTTON) { - $.publish(Events.PRIMARY_COLOR_SELECTED, [sampledColor]); - } else if (context.button == Constants.RIGHT_BUTTON) { - $.publish(Events.SECONDARY_COLOR_SELECTED, [sampledColor]); - } - } - }; + pskl.utils.inherit(ns.ColorPicker, ns.BaseTool); + + /** + * @override + */ + ns.ColorPicker.prototype.applyToolAt = function(col, row, color, frame, overlay, context) { + if (frame.containsPixel(col, row)) { + var sampledColor = frame.getPixel(col, row); + if (context.button == Constants.LEFT_BUTTON) { + $.publish(Events.PRIMARY_COLOR_SELECTED, [sampledColor]); + } else if (context.button == Constants.RIGHT_BUTTON) { + $.publish(Events.SECONDARY_COLOR_SELECTED, [sampledColor]); + } + } + }; })(); diff --git a/js/drawingtools/Eraser.js b/js/drawingtools/Eraser.js index 2db273c4..fd3cb7e3 100644 --- a/js/drawingtools/Eraser.js +++ b/js/drawingtools/Eraser.js @@ -4,20 +4,20 @@ * @require Constants * @require pskl.utils */ - (function() { - var ns = $.namespace("pskl.drawingtools"); +(function() { + var ns = $.namespace("pskl.drawingtools"); - ns.Eraser = function() { - this.toolId = "tool-eraser"; - this.helpText = "Eraser tool"; - }; + ns.Eraser = function() { + this.toolId = "tool-eraser"; + this.helpText = "Eraser tool"; + }; - pskl.utils.inherit(ns.Eraser, ns.SimplePen); + pskl.utils.inherit(ns.Eraser, ns.SimplePen); - /** - * @override - */ - ns.Eraser.prototype.applyToolAt = function(col, row, color, frame, overlay) { - this.superclass.applyToolAt.call(this, col, row, Constants.TRANSPARENT_COLOR, frame, overlay); - }; + /** + * @override + */ + ns.Eraser.prototype.applyToolAt = function(col, row, color, frame, overlay) { + this.superclass.applyToolAt.call(this, col, row, Constants.TRANSPARENT_COLOR, frame, overlay); + }; })(); \ No newline at end of file diff --git a/js/drawingtools/Move.js b/js/drawingtools/Move.js index 914123ce..e561b91a 100644 --- a/js/drawingtools/Move.js +++ b/js/drawingtools/Move.js @@ -4,51 +4,51 @@ * @require pskl.utils */ (function() { - var ns = $.namespace("pskl.drawingtools"); + var ns = $.namespace("pskl.drawingtools"); - ns.Move = function() { - this.toolId = "tool-move"; - this.helpText = "Move tool"; - - // Stroke's first point coordinates (set in applyToolAt) - this.startCol = null; - this.startRow = null; - }; + ns.Move = function() { + this.toolId = "tool-move"; + this.helpText = "Move tool"; + + // Stroke's first point coordinates (set in applyToolAt) + this.startCol = null; + this.startRow = null; + }; - pskl.utils.inherit(ns.Move, ns.BaseTool); - - /** - * @override - */ - ns.Move.prototype.applyToolAt = function(col, row, color, frame, overlay) { - this.startCol = col; - this.startRow = row; - this.frameClone = frame.clone(); - }; + pskl.utils.inherit(ns.Move, ns.BaseTool); + + /** + * @override + */ + ns.Move.prototype.applyToolAt = function(col, row, color, frame, overlay) { + this.startCol = col; + this.startRow = row; + this.frameClone = frame.clone(); + }; - ns.Move.prototype.moveToolAt = function(col, row, color, frame, overlay) { - var colDiff = col - this.startCol, rowDiff = row - this.startRow; - this.shiftFrame(colDiff, rowDiff, frame, this.frameClone); - }; + ns.Move.prototype.moveToolAt = function(col, row, color, frame, overlay) { + var colDiff = col - this.startCol, rowDiff = row - this.startRow; + this.shiftFrame(colDiff, rowDiff, frame, this.frameClone); + }; - ns.Move.prototype.shiftFrame = function (colDiff, rowDiff, frame, reference) { - var color; - for (var col = 0 ; col < frame.getWidth() ; col++) { - for (var row = 0 ; row < frame.getHeight() ; row++) { - if (reference.containsPixel(col - colDiff, row - rowDiff)) { - color = reference.getPixel(col - colDiff, row - rowDiff); - } else { - color = Constants.TRANSPARENT_COLOR; - } - frame.setPixel(col, row, color); - } - } - }; + ns.Move.prototype.shiftFrame = function (colDiff, rowDiff, frame, reference) { + var color; + for (var col = 0 ; col < frame.getWidth() ; col++) { + for (var row = 0 ; row < frame.getHeight() ; row++) { + if (reference.containsPixel(col - colDiff, row - rowDiff)) { + color = reference.getPixel(col - colDiff, row - rowDiff); + } else { + color = Constants.TRANSPARENT_COLOR; + } + frame.setPixel(col, row, color); + } + } + }; - /** - * @override - */ - ns.Move.prototype.releaseToolAt = function(col, row, color, frame, overlay) { - this.moveToolAt(col, row, color, frame, overlay); - }; + /** + * @override + */ + ns.Move.prototype.releaseToolAt = function(col, row, color, frame, overlay) { + this.moveToolAt(col, row, color, frame, overlay); + }; })(); diff --git a/js/drawingtools/PaintBucket.js b/js/drawingtools/PaintBucket.js index b42d94a4..428596e0 100644 --- a/js/drawingtools/PaintBucket.js +++ b/js/drawingtools/PaintBucket.js @@ -4,22 +4,22 @@ * @require pskl.utils */ (function() { - var ns = $.namespace("pskl.drawingtools"); + var ns = $.namespace("pskl.drawingtools"); - ns.PaintBucket = function() { - this.toolId = "tool-paint-bucket"; - this.helpText = "Paint bucket tool"; - }; + ns.PaintBucket = function() { + this.toolId = "tool-paint-bucket"; + this.helpText = "Paint bucket tool"; + }; - pskl.utils.inherit(ns.PaintBucket, ns.BaseTool); + pskl.utils.inherit(ns.PaintBucket, ns.BaseTool); - /** - * @override - */ - ns.PaintBucket.prototype.applyToolAt = function(col, row, color, frame, overlay) { + /** + * @override + */ + ns.PaintBucket.prototype.applyToolAt = function(col, row, color, frame, overlay) { - pskl.PixelUtils.paintSimilarConnectedPixelsFromFrame(frame, col, row, color); - }; + pskl.PixelUtils.paintSimilarConnectedPixelsFromFrame(frame, col, row, color); + }; })(); diff --git a/js/drawingtools/Rectangle.js b/js/drawingtools/Rectangle.js index 686a7786..532afd35 100644 --- a/js/drawingtools/Rectangle.js +++ b/js/drawingtools/Rectangle.js @@ -4,56 +4,56 @@ * @require pskl.utils */ (function() { - var ns = $.namespace("pskl.drawingtools"); + var ns = $.namespace("pskl.drawingtools"); - ns.Rectangle = function() { - this.toolId = "tool-rectangle"; - this.helpText = "Rectangle tool"; - - // Rectangle's first point coordinates (set in applyToolAt) - this.startCol = null; - this.startRow = null; - }; + ns.Rectangle = function() { + this.toolId = "tool-rectangle"; + this.helpText = "Rectangle tool"; + + // Rectangle's first point coordinates (set in applyToolAt) + this.startCol = null; + this.startRow = null; + }; - pskl.utils.inherit(ns.Rectangle, ns.BaseTool); - - /** - * @override - */ - ns.Rectangle.prototype.applyToolAt = function(col, row, color, frame, overlay) { - this.startCol = col; - this.startRow = row; - - // Drawing the first point of the rectangle in the fake overlay canvas: - overlay.setPixel(col, row, color); - }; + pskl.utils.inherit(ns.Rectangle, ns.BaseTool); + + /** + * @override + */ + ns.Rectangle.prototype.applyToolAt = function(col, row, color, frame, overlay) { + this.startCol = col; + this.startRow = row; + + // Drawing the first point of the rectangle in the fake overlay canvas: + overlay.setPixel(col, row, color); + }; - ns.Rectangle.prototype.moveToolAt = function(col, row, color, frame, overlay) { - overlay.clear(); - if(color == Constants.TRANSPARENT_COLOR) { - color = Constants.SELECTION_TRANSPARENT_COLOR; - } + ns.Rectangle.prototype.moveToolAt = function(col, row, color, frame, overlay) { + overlay.clear(); + if(color == Constants.TRANSPARENT_COLOR) { + color = Constants.SELECTION_TRANSPARENT_COLOR; + } - // draw in overlay - this.drawRectangle_(col, row, color, overlay); - }; + // draw in overlay + this.drawRectangle_(col, row, color, overlay); + }; - /** - * @override - */ - ns.Rectangle.prototype.releaseToolAt = function(col, row, color, frame, overlay) { - overlay.clear(); - if(frame.containsPixel(col, row)) { // cancel if outside of canvas - // draw in frame to finalize - this.drawRectangle_(col, row, color, frame); - } - }; + /** + * @override + */ + ns.Rectangle.prototype.releaseToolAt = function(col, row, color, frame, overlay) { + overlay.clear(); + if(frame.containsPixel(col, row)) { // cancel if outside of canvas + // draw in frame to finalize + this.drawRectangle_(col, row, color, frame); + } + }; - ns.Rectangle.prototype.drawRectangle_ = function (col, row, color, targetFrame) { - var strokePoints = pskl.PixelUtils.getBoundRectanglePixels(this.startCol, this.startRow, col, row); - for(var i = 0; i< strokePoints.length; i++) { - // Change model: - targetFrame.setPixel(strokePoints[i].col, strokePoints[i].row, color); - } - }; + ns.Rectangle.prototype.drawRectangle_ = function (col, row, color, targetFrame) { + var strokePoints = pskl.PixelUtils.getBoundRectanglePixels(this.startCol, this.startRow, col, row); + for(var i = 0; i< strokePoints.length; i++) { + // Change model: + targetFrame.setPixel(strokePoints[i].col, strokePoints[i].row, color); + } + }; })(); diff --git a/js/drawingtools/SimplePen.js b/js/drawingtools/SimplePen.js index dcbd89fa..1f7d482a 100644 --- a/js/drawingtools/SimplePen.js +++ b/js/drawingtools/SimplePen.js @@ -4,46 +4,46 @@ * @require pskl.utils */ (function() { - var ns = $.namespace("pskl.drawingtools"); + var ns = $.namespace("pskl.drawingtools"); - ns.SimplePen = function() { - this.toolId = "tool-pen"; - this.helpText = "Pen tool"; + ns.SimplePen = function() { + this.toolId = "tool-pen"; + this.helpText = "Pen tool"; - this.previousCol = null; - this.previousRow = null; + this.previousCol = null; + this.previousRow = null; - }; + }; - pskl.utils.inherit(ns.SimplePen, ns.BaseTool); - - /** - * @override - */ - ns.SimplePen.prototype.applyToolAt = function(col, row, color, frame, overlay) { - if (frame.containsPixel(col, row)) { - frame.setPixel(col, row, color); - } - this.previousCol = col; - this.previousRow = row; - }; + pskl.utils.inherit(ns.SimplePen, ns.BaseTool); + + /** + * @override + */ + ns.SimplePen.prototype.applyToolAt = function(col, row, color, frame, overlay) { + if (frame.containsPixel(col, row)) { + frame.setPixel(col, row, color); + } + this.previousCol = col; + this.previousRow = row; + }; - ns.SimplePen.prototype.moveToolAt = function(col, row, color, frame, overlay) { - if((Math.abs(col - this.previousCol) > 1) || (Math.abs(row - this.previousRow) > 1)) { - // The pen movement is too fast for the mousemove frequency, there is a gap between the - // current point and the previously drawn one. - // We fill the gap by calculating missing dots (simple linear interpolation) and draw them. - var interpolatedPixels = this.getLinePixels_(col, this.previousCol, row, this.previousRow); - for(var i=0, l=interpolatedPixels.length; i