Created
October 21, 2015 09:59
-
-
Save jamespantalones/67a222ca4da465a14dc4 to your computer and use it in GitHub Desktop.
Canvas State
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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