Added box drawing and made this the default action
This commit is contained in:
parent
d2c6e799a8
commit
dda36a9a7f
|
@ -42,6 +42,7 @@ ascii.Controller.prototype.handlePress = function(position) {
|
|||
window.setTimeout(function() {
|
||||
if (this.dragOrigin == null) {
|
||||
this.stateController.handleDrawingPress(this.view.screenToCell(position));
|
||||
this.view.dirty = true;
|
||||
}
|
||||
// TODO: Skip this if release happens before timeout.
|
||||
}.bind(this), DRAG_LATENCY);
|
||||
|
@ -68,6 +69,7 @@ ascii.Controller.prototype.handleMove = function(position) {
|
|||
!this.view.screenToCell(position)
|
||||
.equals(this.view.screenToCell(this.lastMoveCell)))) {
|
||||
this.stateController.handleDrawingMove(this.view.screenToCell(position));
|
||||
this.view.dirty = true;
|
||||
this.lastMoveCell = position;
|
||||
}
|
||||
|
||||
|
@ -88,6 +90,7 @@ ascii.Controller.prototype.handleRelease = function(position) {
|
|||
if (this.dragOrigin == null &&
|
||||
($.now() - this.pressTimestamp) >= DRAG_LATENCY) {
|
||||
this.stateController.handleDrawingRelease(this.view.screenToCell(position));
|
||||
this.view.dirty = true;
|
||||
}
|
||||
this.pressVector = null;
|
||||
this.pressTimestamp = 0;
|
||||
|
@ -118,6 +121,9 @@ ascii.Controller.prototype.installDesktopBindings = function() {
|
|||
$(this.view.canvas).mouseup(function(e) {
|
||||
controller.handleRelease(new ascii.Vector(e.clientX, e.clientY));
|
||||
});
|
||||
$(this.view.canvas).mouseleave(function(e) {
|
||||
controller.handleRelease(new ascii.Vector(e.clientX, e.clientY));
|
||||
});
|
||||
$(this.view.canvas).mousemove(function(e) {
|
||||
controller.handleMove(new ascii.Vector(e.clientX, e.clientY));
|
||||
});
|
||||
|
|
|
@ -2,6 +2,86 @@ goog.provide('ascii.StateController');
|
|||
|
||||
goog.require('ascii.Vector');
|
||||
|
||||
/**
|
||||
* Common interface for different drawing functions, e.g. box, line, etc.
|
||||
* @interface
|
||||
*/
|
||||
function DrawFunction() {}
|
||||
/** Start of drawing. @param {ascii.Vector} position */
|
||||
DrawFunction.prototype.start = function(position) {};
|
||||
/** Drawing move. @param {ascii.Vector} position */
|
||||
DrawFunction.prototype.move = function(position) {};
|
||||
/** End of drawing. @param {ascii.Vector} position */
|
||||
DrawFunction.prototype.end = function(position) {};
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
* @implements {DrawFunction}
|
||||
* @param {ascii.State} state
|
||||
*/
|
||||
function DrawBox(state) {
|
||||
this.state = state;
|
||||
/** @type {ascii.Vector} */ this.startPosition = null;
|
||||
/** @type {ascii.Vector} */ this.endPosition = null;
|
||||
}
|
||||
|
||||
DrawBox.prototype.start = function(position) {
|
||||
this.startPosition = position;
|
||||
this.endPosition = position;
|
||||
this.draw();
|
||||
};
|
||||
DrawBox.prototype.move = function(position) {
|
||||
this.endPosition = position;
|
||||
this.state.clearDraw();
|
||||
this.draw();
|
||||
};
|
||||
DrawBox.prototype.end = function(position) {
|
||||
this.state.commitDraw();
|
||||
};
|
||||
|
||||
/** Draws the currently dragged out box. */
|
||||
DrawBox.prototype.draw = function() {
|
||||
var x1 = Math.min(this.startPosition.x, this.endPosition.x);
|
||||
var y1 = Math.min(this.startPosition.y, this.endPosition.y);
|
||||
var x2 = Math.max(this.startPosition.x, this.endPosition.x);
|
||||
var y2 = Math.max(this.startPosition.y, this.endPosition.y);
|
||||
|
||||
this.state.drawValue(new ascii.Vector(x1, y1), '+');
|
||||
this.state.drawValue(new ascii.Vector(x1, y2), '+');
|
||||
this.state.drawValue(new ascii.Vector(x2, y1), '+');
|
||||
this.state.drawValue(new ascii.Vector(x2, y2), '+');
|
||||
|
||||
|
||||
for (var x = x1 + 1; x < x2; x++) {
|
||||
this.state.drawValue(new ascii.Vector(x, y1), '\u2014');
|
||||
this.state.drawValue(new ascii.Vector(x, y2), '\u2014');
|
||||
}
|
||||
for (var y = y1 + 1; y < y2; y++) {
|
||||
this.state.drawValue(new ascii.Vector(x1, y), '|');
|
||||
this.state.drawValue(new ascii.Vector(x2, y), '|');
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
* @implements {DrawFunction}
|
||||
* @param {ascii.State} state
|
||||
*/
|
||||
function DrawFreeform(state) {
|
||||
this.state = state;
|
||||
}
|
||||
|
||||
DrawFreeform.prototype.start = function(position) {
|
||||
this.state.drawValue(position, 'O');
|
||||
};
|
||||
DrawFreeform.prototype.move = function(position) {
|
||||
this.state.drawValue(position, 'O');
|
||||
};
|
||||
|
||||
DrawFreeform.prototype.end = function(position) {
|
||||
this.state.commitDraw();
|
||||
};
|
||||
|
||||
/**
|
||||
* Handles management of the diagram state. Input events are cleaned in the
|
||||
* parent controller and passed down to this class for dealing with drawing.
|
||||
|
@ -11,6 +91,7 @@ goog.require('ascii.Vector');
|
|||
*/
|
||||
ascii.StateController = function(state) {
|
||||
/** @type {ascii.State} */ this.state = state;
|
||||
/** @type {DrawFunction} */ this.drawFunction = new DrawBox(state);
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -18,7 +99,7 @@ ascii.StateController = function(state) {
|
|||
* @param {ascii.Vector} position
|
||||
*/
|
||||
ascii.StateController.prototype.handleDrawingPress = function(position) {
|
||||
this.state.setValue(position, 'O');
|
||||
this.drawFunction.start(position);
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -26,6 +107,7 @@ ascii.StateController.prototype.handleDrawingPress = function(position) {
|
|||
* @param {ascii.Vector} position
|
||||
*/
|
||||
ascii.StateController.prototype.handleDrawingRelease = function(position) {
|
||||
this.drawFunction.end(position);
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -33,6 +115,5 @@ ascii.StateController.prototype.handleDrawingRelease = function(position) {
|
|||
* @param {ascii.Vector} position
|
||||
*/
|
||||
ascii.StateController.prototype.handleDrawingMove = function(position) {
|
||||
this.state.setValue(position, 'O');
|
||||
this.drawFunction.move(position);
|
||||
};
|
||||
|
||||
|
|
|
@ -9,6 +9,12 @@ goog.provide('ascii.State');
|
|||
*/
|
||||
ascii.Cell = function() {
|
||||
/** @type {?string} */ this.value = null;
|
||||
/** @type {?string} */ this.scratchValue = null;
|
||||
};
|
||||
|
||||
/** @return {?string} */
|
||||
ascii.Cell.prototype.getDrawValue = function() {
|
||||
return (this.scratchValue != null ? this.scratchValue : this.value);
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -19,7 +25,8 @@ ascii.Cell = function() {
|
|||
ascii.State = function() {
|
||||
/** @type {Array.<Array.<ascii.Cell>>} */
|
||||
this.cells = new Array(MAX_GRID_SIZE);
|
||||
/** @type {boolean} */ this.dirty = true;
|
||||
/** @type {Array.<ascii.Cell>} */
|
||||
this.scratchCells = new Array();
|
||||
|
||||
for (var i = 0; i < this.cells.length; i++) {
|
||||
this.cells[i] = new Array(MAX_GRID_SIZE);
|
||||
|
@ -40,12 +47,45 @@ ascii.State.prototype.getCell = function(vector) {
|
|||
};
|
||||
|
||||
/**
|
||||
* Sets the cells value at the given position.
|
||||
* Sets the cells value at the given position. Probably shouldn't
|
||||
* be used directly in many cases. Used drawValue instead.
|
||||
*
|
||||
* @param {ascii.Vector} position
|
||||
* @param {string} value
|
||||
*/
|
||||
ascii.State.prototype.setValue = function(position, value) {
|
||||
this.getCell(position).value = value;
|
||||
this.dirty = true;
|
||||
};
|
||||
|
||||
/**
|
||||
* Sets the cells scratch (uncommitted) value at the given position.
|
||||
*
|
||||
* @param {ascii.Vector} position
|
||||
* @param {string} value
|
||||
*/
|
||||
ascii.State.prototype.drawValue = function(position, value) {
|
||||
var cell = this.getCell(position);
|
||||
this.scratchCells.push(cell);
|
||||
cell.scratchValue = value;
|
||||
};
|
||||
|
||||
/**
|
||||
* Clears the current drawing scratchpad.
|
||||
*/
|
||||
ascii.State.prototype.clearDraw = function() {
|
||||
for (var i in this.scratchCells) {
|
||||
this.scratchCells[i].scratchValue = null;
|
||||
}
|
||||
this.scratchCells.length = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* Ends the current draw, commiting anything currently drawn the scratchpad.
|
||||
*/
|
||||
ascii.State.prototype.commitDraw = function() {
|
||||
for (var i in this.scratchCells) {
|
||||
this.scratchCells[i].value = this.scratchCells[i].getDrawValue();
|
||||
this.scratchCells[i].scratchValue = null;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -37,9 +37,8 @@ ascii.View.prototype.resizeCanvas = function() {
|
|||
* Starts the animation loop for the canvas. Should only be called once.
|
||||
*/
|
||||
ascii.View.prototype.animate = function() {
|
||||
if (this.dirty || this.state.dirty) {
|
||||
if (this.dirty) {
|
||||
this.dirty = false;
|
||||
this.state.dirty = false;
|
||||
this.render();
|
||||
}
|
||||
var view = this;
|
||||
|
@ -48,6 +47,8 @@ ascii.View.prototype.animate = function() {
|
|||
|
||||
/**
|
||||
* Renders the given state to the canvas.
|
||||
* TODO: Room for efficiency here still. Drawing should be incremental,
|
||||
* however performance is currently very acceptable on test devices.
|
||||
*/
|
||||
ascii.View.prototype.render = function() {
|
||||
var context = this.context;
|
||||
|
@ -95,8 +96,9 @@ ascii.View.prototype.render = function() {
|
|||
this.context.font = '15px Courier New';
|
||||
for (var i = startOffset.x; i < endOffset.x; i++) {
|
||||
for (var j = startOffset.y; j < endOffset.y; j++) {
|
||||
if (this.state.cells[i][j].value != null) {
|
||||
context.fillText(this.state.cells[i][j].value,
|
||||
var cellValue = this.state.cells[i][j].getDrawValue();
|
||||
if (cellValue != null) {
|
||||
context.fillText(cellValue,
|
||||
i * CHARACTER_PIXELS - this.offset.x + 3,
|
||||
j * CHARACTER_PIXELS - this.offset.y - 2);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue