Skip to content

Instantly share code, notes, and snippets.

@jamespantalones
Created October 21, 2015 09:59
Show Gist options
  • Save jamespantalones/67a222ca4da465a14dc4 to your computer and use it in GitHub Desktop.
Save jamespantalones/67a222ca4da465a14dc4 to your computer and use it in GitHub Desktop.
Canvas State
angular.module('progApp').factory('canvasState', function (drawService, Shapes) {
var clickzone = document.getElementById('clickzone');
var controls = document.getElementById('controls');
function CanvasState(canvas) {
this.canvas = canvas;
this.width = canvas.width;
this.height = canvas.height;
this.ctx = canvas.getContext('2d');
var stylePaddingLeft;
var stylePaddingTop;
var styleBorderLeft;
var styleBorderTop;
var html;
var currentState;
var i;
if (document.defaultView && document.defaultView.getComputedStyle) {
this.stylePaddingLeft = parseInt(document.defaultView.getComputedStyle(canvas, null).paddingLeft, 10) || 0;
this.stylePaddingTop = parseInt(document.defaultView.getComputedStyle(canvas, null).paddingTop, 10) || 0;
this.styleBorderLeft = parseInt(document.defaultView.getComputedStyle(canvas, null).borderLeftWidth, 10) || 0;
this.styleBorderTop = parseInt(document.defaultView.getComputedStyle(canvas, null).borderTopWidth, 10) || 0;
}
html = document.body.parentNode;
this.htmlTop = html.offsetTop;
this.htmlLeft = html.offsetLeft;
// ------------------------------------------------
// Keep track of state
//
this.valid = false;
this.shapes = [];
this.dragging = false;
this.resizeDragging = false;
this.expectResize = -1;
this.selection = null;
this.dragoffx = 0;
this.dragoffy = 0;
this.selectionHandles = [];
for (i = 0; i < 8; i += 1) {
var shape = Shapes.newShape(this);
this.selectionHandles.push(shape);
}
// ------------------------------------------------
// Make reference
//
currentState = this;
//fixes a problem where double clicking causes text to get selected on the canvas
canvas.addEventListener('selectstart', function(e) {
e.preventDefault();
return false;
}, false);
// ------------------------------------------------
// Listen for clicks on body and deselect items
//
clickzone.addEventListener('mousedown', function(e){
console.log('click');
var shapes = currentState.shapes;
for (var i = 0; i < shapes.length; i++ ){
currentState.selection = null;
currentState.valid = false;
}
}, true);
// ------------------------------------------------
// Listen for D keypress to remove item
//
document.addEventListener('keypress', function(e){
if (e.charCode === 100){
if (currentState.selection !== null){
console.log(currentState.shapes);
console.log(currentState.selection);
// ------------------------------------------------
// Loop through each image and find one matching currentstate
//
for (var i = 0; i < currentState.shapes.length; i++ ){
var src = currentState.shapes[i].image.image.src;
var current = currentState.selection.image.image.src;
var pos = i;
if (src === current){
currentState.shapes.splice(pos, 1);
currentState.selection = null;
currentState.valid = false;
}
console.log(src, current);
}
// delete currentState.selection;
//need redraw
}
}
});
// ------------------------------------------------
// Mouse Down
//
canvas.addEventListener('mousedown', function(e) {
e.preventDefault();
var mouse, mx, my, shapes, l, i, mySel;
if (currentState.expectResize !== -1) {
currentState.resizeDragging = true;
return;
}
mouse = currentState.getMouse(e);
mx = mouse.x;
my = mouse.y;
// ------------------------------------------------
// Array of all objects tied to ctx
//
shapes = currentState.shapes;
l = shapes.length;
for (i = l-1; i >= 0; i -= 1) {
if (shapes[i].contains(mx, my)) {
mySel = shapes[i];
// Keep track of where in the object we clicked
// so we can move it smoothly (see mousemove)
currentState.dragoffx = mx - mySel.x;
currentState.dragoffy = my - mySel.y;
currentState.dragging = true;
currentState.selection = mySel;
currentState.valid = false;
return;
}
}
// deselect object if selected
if (currentState.selection) {
currentState.selection = null;
currentState.valid = false;
}
}, true);
// ------------------------------------------------
// Mousemove
//
canvas.addEventListener('mousemove', function(e) {
var mouse = currentState.getMouse(e);
var mx = mouse.x;
var my = mouse.y;
var oldx;
var oldy;
var i;
var cur;
if (currentState.dragging){
mouse = currentState.getMouse(e);
// ------------------------------------------------
// Drag from where object was clicked
//
currentState.selection.x = mouse.x - currentState.dragoffx;
currentState.selection.y = mouse.y - currentState.dragoffy;
currentState.valid = false;
}
else if (currentState.resizeDragging) {
oldx = currentState.selection.x;
oldy = currentState.selection.y;
switch (currentState.expectResize) {
case 0:
currentState.selection.x = mx;
currentState.selection.y = my;
currentState.selection.w += oldx - mx;
currentState.selection.h += oldy - my;
break;
case 1:
currentState.selection.y = my;
currentState.selection.h += oldy - my;
break;
case 2:
currentState.selection.y = my;
currentState.selection.w = mx - oldx;
currentState.selection.h += oldy - my;
break;
case 3:
currentState.selection.x = mx;
currentState.selection.w += oldx - mx;
break;
case 4:
currentState.selection.w = mx - oldx;
break;
case 5:
currentState.selection.x = mx;
currentState.selection.w += oldx - mx;
currentState.selection.h = my - oldy;
break;
case 6:
currentState.selection.h = my - oldy;
break;
case 7:
currentState.selection.w = mx - oldx;
currentState.selection.h = my - oldy;
break;
}
currentState.valid = false;
}
// Check for grabbing handles
if (currentState.selection !== null && !currentState.resizeDragging) {
for (i = 0; i < 8; i += 1) {
// 0 1 2
// 3 4
// 5 6 7
cur = currentState.selectionHandles[i];
if (mx >= cur.x && mx <= cur.x + currentState.selectionBoxSize &&
my >= cur.y && my <= cur.y + currentState.selectionBoxSize) {
currentState.expectResize = i;
currentState.valid = false;
switch (i) {
case 0:
this.style.cursor='nw-resize';
break;
case 1:
this.style.cursor='n-resize';
break;
case 2:
this.style.cursor='ne-resize';
break;
case 3:
this.style.cursor='w-resize';
break;
case 4:
this.style.cursor='e-resize';
break;
case 5:
this.style.cursor='sw-resize';
break;
case 6:
this.style.cursor='s-resize';
break;
case 7:
this.style.cursor='se-resize';
break;
}
return;
}
}
// not over a selection box, return to normal
currentState.resizeDragging = false;
currentState.expectResize = -1;
this.style.cursor = 'auto';
}
}, true);
// ------------------------------------------------
// Mouseup
//
canvas.addEventListener('mouseup', function(e) {
currentState.dragging = false;
currentState.resizeDragging = false;
currentState.expectResize = -1;
if (currentState.selection !== null) {
if (currentState.selection.w < 0) {
currentState.selection.w = -currentState.selection.w;
currentState.selection.x -= currentState.selection.w;
}
if (currentState.selection.h < 0) {
currentState.selection.h = -currentState.selection.h;
currentState.selection.y -= currentState.selection.h;
}
}
}, true);
// ------------------------------------------------
// Double click adds new image
//
canvas.addEventListener('dblclick', function(e) {
var mouse = currentState.getMouse(e);
var randomImage = drawService.addNewImage();
var shape = Shapes.newShape(currentState, randomImage, mouse.x - 100, mouse.y - 100, randomImage.w, randomImage.h);
currentState.addShape(shape);
}, true);
this.selectionColor = 'blue';
this.selectionWidth = 1;
this.selectionBoxSize = 6;
this.selectionBoxColor = 'blue';
this.interval = 30;
// requestAnimationFrame(currentState.draw);
setInterval(function() {currentState.draw(); }, currentState.interval);
}
// -------------------------------------------------
//
// Canvas prototype methods
//
// -------------------------------------------------
CanvasState.prototype = {
addShape: function(shape){
this.shapes.push(shape);
this.valid = false;
},
clear: function(){
this.ctx.clearRect(0, 0, this.width, this.height);
},
draw: function(){
var ctx;
var shapes;
var shape;
var mySel;
if (!this.valid) {
ctx = this.ctx;
shapes = this.shapes;
this.clear();
// ------------------------------------------------
// Background draw functions GO HERE
//
for (var i = 0; i < shapes.length; i ++) {
shape = shapes[i];
// We can skip the drawing of elements that have moved off the screen:
if (shape.x <= this.width && shape.y <= this.height &&
shape.x + shape.w >= 0 && shape.y + shape.h >= 0) {
shapes[i].draw(ctx);
}
}
if (this.selection !== null) {
ctx.strokeStyle = this.selectionColor;
ctx.lineWidth = this.selectionWidth;
mySel = this.selection;
ctx.strokeRect(mySel.x,mySel.y,mySel.w,mySel.h);
}
// ------------------------------------------------
// Stuff to draw on top GOES HERE
//
this.valid = true;
}
},
getMouse: function(e){
var element = this.canvas, offsetX = 0, offsetY = 0, mx, my;
// Compute the total offset
if (element.offsetParent !== undefined) {
do {
offsetX += element.offsetLeft;
offsetY += element.offsetTop;
element = element.offsetParent;
}
while (element);
}
offsetX += this.stylePaddingLeft + this.styleBorderLeft + this.htmlLeft;
offsetY += this.stylePaddingTop + this.styleBorderTop + this.htmlTop;
mx = e.pageX - offsetX;
my = e.pageY - offsetY;
return {
x: mx,
y: my
};
}
};
return {
newCanvas: function (canvas) {
return new CanvasState(canvas);
}
};
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment