Seperated state controller, working drag to draw example
This commit is contained in:
parent
1feea9778c
commit
34a91e97c5
|
@ -1,14 +1,14 @@
|
||||||
/**
|
/**
|
||||||
* Handles user input events and modifies state.
|
* Handles user input events and modifies state.
|
||||||
* Core logic comes through this class.
|
|
||||||
*/
|
*/
|
||||||
goog.provide('ascii.Controller');
|
goog.provide('ascii.Controller');
|
||||||
|
|
||||||
|
goog.require('ascii.StateController');
|
||||||
goog.require('ascii.Vector');
|
goog.require('ascii.Vector');
|
||||||
goog.require('ascii.View');
|
goog.require('ascii.View');
|
||||||
|
|
||||||
/** @const */ var DRAG_LATENCY = 200; // Milliseconds.
|
/** @const */ var DRAG_LATENCY = 100; // Milliseconds.
|
||||||
/** @const */ var DRAG_ACCURACY = 5; // Pixels.
|
/** @const */ var DRAG_ACCURACY = 0.1; // Pixels.
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @constructor
|
* @constructor
|
||||||
|
@ -17,22 +17,37 @@ ascii.Controller = function(view, state) {
|
||||||
/** @type {ascii.View} */ this.view = view;
|
/** @type {ascii.View} */ this.view = view;
|
||||||
/** @type {ascii.State} */ this.state = state;
|
/** @type {ascii.State} */ this.state = state;
|
||||||
|
|
||||||
|
/** @type {ascii.StateController} */ this.stateController =
|
||||||
|
new ascii.StateController(state);
|
||||||
|
|
||||||
/** @type {ascii.Vector} */ this.dragOrigin;
|
/** @type {ascii.Vector} */ this.dragOrigin;
|
||||||
/** @type {ascii.Vector} */ this.pressVector;
|
/** @type {ascii.Vector} */ this.pressVector;
|
||||||
/** @type {number} */ this.pressTimestamp;
|
/** @type {number} */ this.pressTimestamp;
|
||||||
|
|
||||||
|
// TODO: Setup different bindings for tablet/mobile.
|
||||||
this.installDesktopBindings();
|
this.installDesktopBindings();
|
||||||
};
|
};
|
||||||
|
|
||||||
ascii.Controller.prototype.handlePress = function(x, y) {
|
ascii.Controller.prototype.handlePress = function(x, y) {
|
||||||
|
var position = new ascii.Vector(x, y);
|
||||||
|
|
||||||
this.pressVector = new ascii.Vector(x, y);
|
this.pressVector = new ascii.Vector(x, y);
|
||||||
this.pressTimestamp = $.now();
|
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) {
|
ascii.Controller.prototype.handleMove = function(x, y) {
|
||||||
var position = new ascii.Vector(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.
|
// Initiate a drag if we have moved enough, quickly enough.
|
||||||
if (this.dragOrigin == null &&
|
if (this.dragOrigin == null &&
|
||||||
|
@ -41,6 +56,12 @@ ascii.Controller.prototype.handleMove = function(x, y) {
|
||||||
this.dragOrigin = this.view.offset;
|
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.
|
// Drag in progress, update the view origin.
|
||||||
if (this.dragOrigin != null) {
|
if (this.dragOrigin != null) {
|
||||||
this.view.offset = this.dragOrigin.add(
|
this.view.offset = this.dragOrigin.add(
|
||||||
|
@ -48,21 +69,15 @@ ascii.Controller.prototype.handleMove = function(x, y) {
|
||||||
.subtract(new ascii.Vector(x, y))
|
.subtract(new ascii.Vector(x, y))
|
||||||
.scale(1/this.view.zoom));
|
.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) {
|
ascii.Controller.prototype.handleRelease = function(x, y) {
|
||||||
var position = new ascii.Vector(x, y);
|
var position = new ascii.Vector(x, y);
|
||||||
|
|
||||||
// Drag wasn't initiated in time, treat this as a drawing event.
|
// Drag wasn't initiated in time, treat this as a drawing event.
|
||||||
if (this.dragOrigin == null &&
|
if (this.dragOrigin == null &&
|
||||||
($.now() - this.pressTimestamp) >= DRAG_LATENCY &&
|
($.now() - this.pressTimestamp) >= DRAG_LATENCY) {
|
||||||
position.subtract(this.pressVector).length() > DRAG_ACCURACY) {
|
this.stateController.handleDrawingRelease(this.view.screenToCell(position));
|
||||||
// TODO: Draw stuff.
|
|
||||||
}
|
}
|
||||||
this.pressVector = null;
|
this.pressVector = null;
|
||||||
this.pressTimestamp = 0;
|
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);
|
this.view.zoom = Math.max(Math.min(this.view.zoom, 5), 0.2);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
ascii.Controller.prototype.installDesktopBindings = function() {
|
ascii.Controller.prototype.installDesktopBindings = function() {
|
||||||
var controller = this;
|
var controller = this;
|
||||||
$(this.view.canvas).bind('mousewheel', function(e) {
|
$(this.view.canvas).bind('mousewheel', function(e) {
|
||||||
|
|
|
@ -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';
|
||||||
|
};
|
|
@ -3,7 +3,7 @@
|
||||||
*/
|
*/
|
||||||
goog.provide('ascii.State');
|
goog.provide('ascii.State');
|
||||||
|
|
||||||
/** @const */ ascii.MAX_GRID_SIZE = 1000;
|
/** @const */ var MAX_GRID_SIZE = 1000;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @constructor
|
* @constructor
|
||||||
|
@ -22,10 +22,10 @@ ascii.Cell.prototype.setValue = function(value) {
|
||||||
*/
|
*/
|
||||||
ascii.State = function() {
|
ascii.State = function() {
|
||||||
/** @type {Array.<Array.<ascii.Cell>>} */
|
/** @type {Array.<Array.<ascii.Cell>>} */
|
||||||
this.cells = new Array(ascii.MAX_GRID_SIZE);
|
this.cells = new Array(MAX_GRID_SIZE);
|
||||||
|
|
||||||
for (var i = 0; i < this.cells.length; i++) {
|
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++) {
|
for (var j = 0; j < this.cells[i].length; j++) {
|
||||||
this.cells[i][j] = new ascii.Cell();
|
this.cells[i][j] = new ascii.Cell();
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@ goog.provide('ascii.View');
|
||||||
|
|
||||||
goog.require('ascii.Vector');
|
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();
|
this.context.beginPath();
|
||||||
for (var i = 0; i < this.state.cells.length; i++) {
|
for (var i = 0; i < this.state.cells.length; i++) {
|
||||||
this.context.moveTo(
|
this.context.moveTo(
|
||||||
i*ascii.CHARACTER_PIXELS - this.offset.x,
|
i*CHARACTER_PIXELS - this.offset.x,
|
||||||
0 - this.offset.y);
|
0 - this.offset.y);
|
||||||
this.context.lineTo(
|
this.context.lineTo(
|
||||||
i*ascii.CHARACTER_PIXELS - this.offset.x,
|
i*CHARACTER_PIXELS - this.offset.x,
|
||||||
ascii.MAX_GRID_SIZE*ascii.CHARACTER_PIXELS - this.offset.y);
|
this.state.cells.length*CHARACTER_PIXELS - this.offset.y);
|
||||||
}
|
}
|
||||||
for (var j = 0; j < this.state.cells[0].length; j++) {
|
for (var j = 0; j < this.state.cells[0].length; j++) {
|
||||||
this.context.moveTo(
|
this.context.moveTo(
|
||||||
0 - this.offset.x,
|
0 - this.offset.x,
|
||||||
j*ascii.CHARACTER_PIXELS - this.offset.y);
|
j*CHARACTER_PIXELS - this.offset.y);
|
||||||
this.context.lineTo(
|
this.context.lineTo(
|
||||||
ascii.MAX_GRID_SIZE*ascii.CHARACTER_PIXELS - this.offset.x,
|
this.state.cells.length*CHARACTER_PIXELS - this.offset.x,
|
||||||
j*ascii.CHARACTER_PIXELS - this.offset.y);
|
j*CHARACTER_PIXELS - this.offset.y);
|
||||||
}
|
}
|
||||||
this.context.stroke();
|
this.context.stroke();
|
||||||
|
|
||||||
|
@ -73,8 +73,8 @@ ascii.View.prototype.render = function() {
|
||||||
for (var j = 0; j < this.state.cells[i].length; j++) {
|
for (var j = 0; j < this.state.cells[i].length; j++) {
|
||||||
if (this.state.cells[i][j].value != null) {
|
if (this.state.cells[i][j].value != null) {
|
||||||
this.context.fillText(this.state.cells[i][j].value,
|
this.context.fillText(this.state.cells[i][j].value,
|
||||||
i*ascii.CHARACTER_PIXELS - this.offset.x + 3,
|
i*CHARACTER_PIXELS - this.offset.x + 3,
|
||||||
j*ascii.CHARACTER_PIXELS - this.offset.y - 2);
|
j*CHARACTER_PIXELS - this.offset.y - 2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -108,7 +108,9 @@ ascii.View.prototype.frameToScreen = function(vector) {
|
||||||
* @return {ascii.Vector}
|
* @return {ascii.Vector}
|
||||||
*/
|
*/
|
||||||
ascii.View.prototype.frameToCell = function(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));
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Reference in New Issue