From 34a91e97c5233ad13114c4989c86f3dcd0a80baa Mon Sep 17 00:00:00 2001 From: Lewis Hemens Date: Sat, 11 Jan 2014 18:53:45 +0000 Subject: [PATCH] Seperated state controller, working drag to draw example --- js-lib/controller.js | 42 +++++++++++++++++++++++++------------- js-lib/state-controller.js | 25 +++++++++++++++++++++++ js-lib/state.js | 6 +++--- js-lib/view.js | 22 +++++++++++--------- 4 files changed, 68 insertions(+), 27 deletions(-) create mode 100644 js-lib/state-controller.js diff --git a/js-lib/controller.js b/js-lib/controller.js index 1f03830..9414379 100644 --- a/js-lib/controller.js +++ b/js-lib/controller.js @@ -1,14 +1,14 @@ /** * Handles user input events and modifies state. - * Core logic comes through this class. */ goog.provide('ascii.Controller'); +goog.require('ascii.StateController'); goog.require('ascii.Vector'); goog.require('ascii.View'); -/** @const */ var DRAG_LATENCY = 200; // Milliseconds. -/** @const */ var DRAG_ACCURACY = 5; // Pixels. +/** @const */ var DRAG_LATENCY = 100; // Milliseconds. +/** @const */ var DRAG_ACCURACY = 0.1; // Pixels. /** * @constructor @@ -17,22 +17,37 @@ ascii.Controller = function(view, state) { /** @type {ascii.View} */ this.view = view; /** @type {ascii.State} */ this.state = state; + /** @type {ascii.StateController} */ this.stateController = + new ascii.StateController(state); + /** @type {ascii.Vector} */ this.dragOrigin; /** @type {ascii.Vector} */ this.pressVector; /** @type {number} */ this.pressTimestamp; + // TODO: Setup different bindings for tablet/mobile. this.installDesktopBindings(); }; ascii.Controller.prototype.handlePress = function(x, y) { + var position = new ascii.Vector(x, y); + this.pressVector = new ascii.Vector(x, y); this.pressTimestamp = $.now(); + + // Check to see if a drag happened in the given allowed time. + window.setTimeout(function() { + if (this.dragOrigin == null) { + this.stateController.handleDrawingPress(this.view.screenToCell(position)); + } + // TODO: Skip this if release happens before timeout. + }.bind(this), DRAG_LATENCY); }; ascii.Controller.prototype.handleMove = function(x, y) { var position = new ascii.Vector(x, y); - if (this.pressVector == null) { return; } // No clicks, so just ignore. + // No clicks, so just ignore. + if (this.pressVector == null) { return; } // Initiate a drag if we have moved enough, quickly enough. if (this.dragOrigin == null && @@ -41,6 +56,12 @@ ascii.Controller.prototype.handleMove = function(x, y) { this.dragOrigin = this.view.offset; } + // Not dragging, so pass the mouse move on. + if (this.dragOrigin == null && + ($.now() - this.pressTimestamp) >= DRAG_LATENCY) { + this.stateController.handleDrawingMove(this.view.screenToCell(position)); + } + // Drag in progress, update the view origin. if (this.dragOrigin != null) { this.view.offset = this.dragOrigin.add( @@ -48,21 +69,15 @@ ascii.Controller.prototype.handleMove = function(x, y) { .subtract(new ascii.Vector(x, y)) .scale(1/this.view.zoom)); } - - // Drag wasn't initiated in time, treat this as a drawing event. - if (this.dragOrigin == null && ($.now() - this.pressTimestamp) >= DRAG_LATENCY) { - // TODO: Draw stuff. - this.state.getCell(this.view.screenToCell(position)).value = 'O'; - } }; ascii.Controller.prototype.handleRelease = function(x, y) { var position = new ascii.Vector(x, y); + // Drag wasn't initiated in time, treat this as a drawing event. if (this.dragOrigin == null && - ($.now() - this.pressTimestamp) >= DRAG_LATENCY && - position.subtract(this.pressVector).length() > DRAG_ACCURACY) { - // TODO: Draw stuff. + ($.now() - this.pressTimestamp) >= DRAG_LATENCY) { + this.stateController.handleDrawingRelease(this.view.screenToCell(position)); } this.pressVector = null; this.pressTimestamp = 0; @@ -74,7 +89,6 @@ ascii.Controller.prototype.handleZoom = function(delta) { this.view.zoom = Math.max(Math.min(this.view.zoom, 5), 0.2); }; - ascii.Controller.prototype.installDesktopBindings = function() { var controller = this; $(this.view.canvas).bind('mousewheel', function(e) { diff --git a/js-lib/state-controller.js b/js-lib/state-controller.js new file mode 100644 index 0000000..4f8afd5 --- /dev/null +++ b/js-lib/state-controller.js @@ -0,0 +1,25 @@ +/** + * Handles management of the diagram state. + */ +goog.provide('ascii.StateController'); + +goog.require('ascii.Vector'); + +/** + * @constructor + */ +ascii.StateController = function(state) { + /** @type {ascii.State} */ this.state = state; +}; + +ascii.StateController.prototype.handleDrawingPress = function(position) { + this.state.getCell(position).value = 'O'; +}; + +ascii.StateController.prototype.handleDrawingRelease = function(position) { +}; + + +ascii.StateController.prototype.handleDrawingMove = function(position) { + this.state.getCell(position).value = 'O'; +}; diff --git a/js-lib/state.js b/js-lib/state.js index 0df4421..1dff319 100644 --- a/js-lib/state.js +++ b/js-lib/state.js @@ -3,7 +3,7 @@ */ goog.provide('ascii.State'); -/** @const */ ascii.MAX_GRID_SIZE = 1000; +/** @const */ var MAX_GRID_SIZE = 1000; /** * @constructor @@ -22,10 +22,10 @@ ascii.Cell.prototype.setValue = function(value) { */ ascii.State = function() { /** @type {Array.>} */ - this.cells = new Array(ascii.MAX_GRID_SIZE); + this.cells = new Array(MAX_GRID_SIZE); for (var i = 0; i < this.cells.length; i++) { - this.cells[i] = new Array(ascii.MAX_GRID_SIZE); + this.cells[i] = new Array(MAX_GRID_SIZE); for (var j = 0; j < this.cells[i].length; j++) { this.cells[i][j] = new ascii.Cell(); } diff --git a/js-lib/view.js b/js-lib/view.js index b8e56e0..42f87e2 100644 --- a/js-lib/view.js +++ b/js-lib/view.js @@ -2,7 +2,7 @@ goog.provide('ascii.View'); goog.require('ascii.Vector'); -/** @const */ ascii.CHARACTER_PIXELS = 15; +/** @const */ var CHARACTER_PIXELS = 15; /** @@ -51,19 +51,19 @@ ascii.View.prototype.render = function() { this.context.beginPath(); for (var i = 0; i < this.state.cells.length; i++) { this.context.moveTo( - i*ascii.CHARACTER_PIXELS - this.offset.x, + i*CHARACTER_PIXELS - this.offset.x, 0 - this.offset.y); this.context.lineTo( - i*ascii.CHARACTER_PIXELS - this.offset.x, - ascii.MAX_GRID_SIZE*ascii.CHARACTER_PIXELS - this.offset.y); + i*CHARACTER_PIXELS - this.offset.x, + this.state.cells.length*CHARACTER_PIXELS - this.offset.y); } for (var j = 0; j < this.state.cells[0].length; j++) { this.context.moveTo( 0 - this.offset.x, - j*ascii.CHARACTER_PIXELS - this.offset.y); + j*CHARACTER_PIXELS - this.offset.y); this.context.lineTo( - ascii.MAX_GRID_SIZE*ascii.CHARACTER_PIXELS - this.offset.x, - j*ascii.CHARACTER_PIXELS - this.offset.y); + this.state.cells.length*CHARACTER_PIXELS - this.offset.x, + j*CHARACTER_PIXELS - this.offset.y); } this.context.stroke(); @@ -73,8 +73,8 @@ ascii.View.prototype.render = function() { for (var j = 0; j < this.state.cells[i].length; j++) { if (this.state.cells[i][j].value != null) { this.context.fillText(this.state.cells[i][j].value, - i*ascii.CHARACTER_PIXELS - this.offset.x + 3, - j*ascii.CHARACTER_PIXELS - this.offset.y - 2); + i*CHARACTER_PIXELS - this.offset.x + 3, + j*CHARACTER_PIXELS - this.offset.y - 2); } } } @@ -108,7 +108,9 @@ ascii.View.prototype.frameToScreen = function(vector) { * @return {ascii.Vector} */ ascii.View.prototype.frameToCell = function(vector) { - return new ascii.Vector(Math.round((vector.x-7.5)/15), Math.round((vector.y+7.5)/15)); + return new ascii.Vector( + Math.round((vector.x-CHARACTER_PIXELS/2)/CHARACTER_PIXELS), + Math.round((vector.y+CHARACTER_PIXELS/2)/CHARACTER_PIXELS)); }; /**