How to create an eraser in EaselJS? - javascript

I am developing a canvas paint but I want to have an eraser there. So I use this lines to erase de content but when I click is clear the whole canvas.
//undo tool
var undo = new createjs.Bitmap(app.loader.getResult('undo'));
undo.name = 'undo';
undo.x = brush.x + 90;
undo.y = brush.y;
undo.addEventListener('click', this.undoHandler);
this.toolsContainer.addChild(undo);
//trash tool
var clear = new createjs.Bitmap(app.loader.getResult('clear'));
clear.name = 'clear';
clear.x = undo.x + 90;
clear.y = undo.y;
clear.addEventListener('click', this.clearHandler);
this.toolsContainer.addChild(clear);
undoHandler:function(){
if(tools.undoArray.length){
var lastItem = tools.undoArray.pop();
app.container.removeChild(lastItem);
var lastItem2 = tools.undoArray2.pop();
app.container.removeChild(lastItem2);
var lastItem3 = tools.undoArray3.pop();
app.container.removeChild(lastItem3);
app.stage.update();
}
},
clearHandler:function(){
app.container.removeAllChildren();
app.container.updateCache(clearhandler?"destination-out":"source-over");;
app.stage.update();
},
I trying to develop something like this erase
http://jsfiddle.net/lannymcnie/ZNYPD/
any idea?

well here http://jsfiddle.net/lannymcnie/ZNYPD/, the key is this:
wrapper.updateCache(erase?"destination-out":"source-over");
so...
var stage, wrapper,erase;
function init() {
var stage = new createjs.Stage("canvas");
createjs.Ticker.addEventListener("tick", stage);
// Add some text to draw on top of (also instructions)
stage.addChild(new createjs.Text("Click and Drag to Draw", "40px Arial", "#000000").set({x:200,y:200}));
// Set up the container. We use it to draw in, and also to get mouse events.
var wrapper = new createjs.Container();
wrapper.hitArea = new createjs.Shape(new createjs.Graphics().f("#000").dr(0,0,800,600));
wrapper.cache(0,0,800,600); // Cache it.
stage.addChild(wrapper);
// Create the shape to draw into
var drawing = new createjs.Shape();
wrapper.addChild(drawing);
var lastPoint = new createjs.Point();
wrapper.addEventListener("mousedown", function(event) {
// Store the position. We have to do this because we clear the graphics later.
lastPoint.x = event.stageX;
lastPoint.y = event.stageY;
erase = Math.floor(Math.random()*2);
wrapper.addEventListener("pressmove", function(event){
// Draw a round line from the last position to the current one.
drawing.graphics.ss(20, "round").s("#ff0000");
drawing.graphics.mt(lastPoint.x, lastPoint.y);
drawing.graphics.lt(event.stageX, event.stageY);
// Update the last position for next move.
lastPoint.x = event.stageX;
lastPoint.y = event.stageY;
// Draw onto the canvas, and then update the container cache.
wrapper.updateCache(erase==1?"destination-out":"source-over");
drawing.graphics.clear();
});
// Listen for mousemove
});
}
$(function(){
init();
})
the only difference is that the drawing is based on a random from 0 to 1 because in my example the erase gets these values from here erase = Math.floor(Math.random()*2);

I have achieved this by maintaining a array of mid points and using the globalCompositeOperation as destination-out and source-over to make a transparent eraser trail .
Following is the code that you need to use with a mouse move function
`var handleMouseMove = function (event) {
midPt = new createjs.Point(oldPt.x + stage.mouseX>>1, oldPt.y+stage.mouseY>>1);
if(curTool.type=="eraser"){
var tempcanvas = document.getElementById('drawcanvas');
var tempctx=tempcanvas.getContext("2d");
tempctx.beginPath();
tempctx.globalCompositeOperation = "destination-out";
tempctx.arc(midPt.x, midPt.y, 20, 0, Math.PI * 2, false);
tempctx.fill();
tempctx.closePath();
tempctx.globalCompositeOperation = "source-over";
drawingCanvas.graphics.clear();
// keep updating the array for points
arrMidPtx.push(midPt.x);
arrMidPty.push(midPt.y);
stage.addChild(drawingCanvas);
stage.update();
}
else if ( curTool.type=="pen"){
drawingCanvas.graphics.clear().setStrokeStyle(stroke, 'round', 'round').beginStroke(color).moveTo(midPt.x, midPt.y).curveTo(oldPt.x, oldPt.y, oldMidPt.x, oldMidPt.y);
arrMidPtx.push(midPt.x);
arrMidPty.push(midPt.y);
arrOldPtx.push(oldPt.x);
arrOldPty.push(oldPt.y);
arrOldMidPtx.push(oldMidPt.x);
arrOldMidPty.push(oldMidPt.y);
oldPt.x = stage.mouseX;
oldPt.y = stage.mouseY;
oldMidPt.x = midPt.x;
oldMidPt.y = midPt.y;
stage.addChild(drawingCanvas);
stage.update();
}
};`

Related

How to make a canvas eraser for an Edit page?

I have made an edit form but this edit form also includes a drawing on a canvas. Everything is working okay except for the eraser I made for the canvas. The eraser works perfectly if you're making a drawing on a blank canvas but since this is for an edit page which means it already has a drawing on it. My main issue right now is that whenever I use the eraser, the previous drawing gets removed from the canvas leaving only the new marks you made. Can anyone help me with this one?
var stage, wrapper, erase=0;
function init(){
var stage = new createjs.Stage("canvas");
createjs.Ticker.addEventListener("tick", stage);
createjs.Touch.enable(stage);
stage.addChild(new createjs.Text("", "40px Arial", "#000000").set({x:200,y:200}));
// Set up the container. We use it to draw in, and also to get mouse events.
var wrapper = new createjs.Container();
wrapper.hitArea = new createjs.Shape(new createjs.Graphics().f("#000").dr(0,0,800,600));
wrapper.cache(0,0,800,600); // Cache it.
stage.addChild(wrapper);
// Create the shape to draw into
var drawing = new createjs.Shape();
wrapper.addChild(drawing);
var lastPoint = new createjs.Point();
// retrieves image url for previous drawing
var path = document.getElementById("hidden").value;
var prevDraw = new createjs.Bitmap(path);
prevDraw.image.onload = function(){
prevDraw.x = 0;
prevDraw.y = 0;
wrapper.addChild(prevDraw);
wrapper.updateCache();
stage.update();
}
wrapper.addEventListener("mousedown", function(event){
// Store the position. We have to do this because we clear the graphics later.
lastPoint.x = event.stageX;
lastPoint.y = event.stageY;
if(document.getElementById('toggle').checked){
erase = 1;
}else{
erase = 0;
}
wrapper.addEventListener("pressmove", function(event){
// Draw a round line from the last position to the current one.
drawing.graphics.ss(5, "round").s("#ff0000");
drawing.graphics.mt(lastPoint.x, lastPoint.y);
drawing.graphics.lt(event.stageX, event.stageY);
// Update the last position for next move.
lastPoint.x = event.stageX;
lastPoint.y = event.stageY;
// Draw onto the canvas, and then update the container cache.
wrapper.updateCache(erase==1?"destination-out":"source-over");
drawing.graphics.clear();
});
// Listen for mousemove
});
function clear(){
stage.removeAllChildren();
stage.update();
init2();
}
document.getElementById("clear").onclick = function(){
clear()
};
function reset(){
stage.removeAllChildren();
stage.update();
init();
}
document.getElementById("reset").onclick = function(){
reset()
};
}

Intersecting an isometric cube in Obelisk.js when mouse pointer intersects

I am using obelisk.js, which does not have a native way ( to my knowledge) of intersecting or raycasting for mouse picking, so I am trying to make my own methods, but I am not sure how to proceed.
Here's the code for a basic pen with a mouseover ( I want to detect when the mouse is on top of the cube):
Codepen sample
// Canvas & Scene Init:
var canvas = document.getElementById("canvas01");
var point = new obelisk.Point(210, 180);
var pixelView = new obelisk.PixelView(canvas, point);
// CUBE
var dimensionCube = new obelisk.CubeDimension(40, 40, 40);
var cubeColor = new obelisk.CubeColor();
var cube = new obelisk.Cube(dimensionCube, cubeColor);
var cubePos = new obelisk.Point3D(80, 80, 0);
pixelView.renderObject(cube, cubePos);
function getMousePos(canvas, evt) {
var rect = canvas.getBoundingClientRect();
return {
x: evt.clientX - rect.left,
y: evt.clientY - rect.top
};
}
// Listener
canvas.addEventListener('mousemove', function(evt) {
var mousePos = getMousePos(canvas, evt);
var message = 'Mouse position: ' + mousePos.x + ',' + mousePos.y ;
console.log(message);
}, false);
Thanks.
So after a bit of scratching my head I managed to add easel.js which has a handy hit area function and mouse event handling , the catch is that one has to crate a bitmap from the obelisk.js canvas and use that for the hit area without re-rendering.
I still need to figure out an efficient way of adding more than one primitive, here's the code so far:
And of course if you have a better,different or more native way that would be great as well:
// Canvas & Scene Init:
var canvas = document.getElementById("canvas01");
var ctx = canvas.getContext("2d");
var point = new obelisk.Point(210, 180);
var pixelView = new obelisk.PixelView(canvas, point);
var dimensionCube = new obelisk.CubeDimension(40, 40, 40);
var cubeColor = new obelisk.CubeColor();
var cube = new obelisk.Cube(dimensionCube, cubeColor);
var cubePos = new obelisk.Point3D(80, 80, 0);
pixelView.renderObject(cube, cubePos);
// Easel.JS glob:
var stage = new createjs.Stage("canvas01");
init();
function init() {
stage.enableMouseOver(10);
// we get the rendered canvas
var dataUrl = canvas.toDataURL();
// make a bitmap
var bitmap = new createjs.Bitmap(dataUrl);
// You could also add a hit area here
stage.addChild(bitmap);
// and the event handling we are after:
bitmap.on("mouseover", handleInteraction);
bitmap.on("mouseout", handleInteraction);
}
function handleInteraction(event) {
if (event.type === "mouseover") {
dimensionCube = new obelisk.CubeDimension(40, 40, 120);
cube = new obelisk.Cube(dimensionCube, cubeColor);
pixelView.clear();
pixelView.renderObject(cube, cubePos);
console.log("over");
} else {
dimensionCube = new obelisk.CubeDimension(40, 40, 40);
cube = new obelisk.Cube(dimensionCube, cubeColor);
pixelView.clear();
pixelView.renderObject(cube, cubePos);
console.log("out");
}
}
Pen: Obelisk.js + Easel.js basic Mouseover

Update canvas on mouse events

I've created a hexagonal grid using this JS library. The grid does get properly painted onto the Canvas. My issue is with trying to introduce events on mouse events. For instance, when I hover over a certain hexagon I want it's background color to change.
At the moment, only the last created hexagon will change on mouseover regardless of which hexagon the cursor is hovering over. How can I make the event listener update the specific hexagon over which the cursor exists?
If this is not possible due to painted objects becoming "rasterized" into the canvas, what alternate approach would be recommended?
The code is below:
<canvas id="stage"></canvas>
<script>
var element = document.getElementById("stage");
element.height = window.innerHeight;
element.width = window.innerWidth;
var stage = new createjs.Stage("stage");
stage.x = window.innerWidth/2;
stage.y = window.innerHeight/2;
stage.enableMouseOver();
var grid = new Grid();
grid.tileSize = 55;
var stageTransformer = new StageTransformer().initialize({ element: element, stage: stage });
stageTransformer.addEventListeners();
var tick = function (event) { stage.update(); };
var colorHexagon = function(hexagon, fill) {
hexagon.graphics
.beginFill(fill)
.beginStroke("rgba(50,50,50,1)")
.drawPolyStar(0, 0, grid.tileSize, 6, 0, 0);
};
var coordinates = grid.hexagon(0, 0, 3, true)
for (var i = 0; i < coordinates.length; i++) {
var q = coordinates[i].q,
r = coordinates[i].r,
center = grid.getCenterXY(q, r),
hexagon = new createjs.Shape();
hexagon.cursor = "pointer";
hexagon.addEventListener("mouseover", function() {
colorHexagon(hexagon, "rgba(50,150,0,1)")
});
hexagon.addEventListener("mouseout", function() {
colorHexagon(hexagon, "rgba(150,150,150,1)")
});
hexagon.q = q;
hexagon.r = r;
hexagon.x = center.x;
hexagon.y = center.y;
colorHexagon(hexagon, "rgba(150,150,150,1)");
stage.addChild(hexagon);
stage.update();
}
tick();
createjs.Ticker.setFPS(30);
createjs.Ticker.addEventListener("tick", tick);
</script>
This should work.
stage.addEventListener("mouseover", function(evt) {
colorHexagon(evt.target, "rgba(50,150,0,1)")
});
stage.addEventListener("mouseout", function(evt) {
colorHexagon(evt.target, "rgba(150,150,150,1)")
});
you can put them at the very bottom of your script. They don't have to be in a loop.
Bind your event handlers to the container of the hexagons instead of to each hexagon seperately and find the hexagon hovered over by using the coordinates of the mouse. And check the docs of the library, maybe they have a method for that included.

Saving Draw Canvas positions when user clicks

I have a canvas draw feature:
var sketcher = null;
var brush = null;
$(document).ready(function(e) {
brush = new Image();
brush.src = 'assets/brush2.png';
brush.onload = function(){
sketcher = new Sketcher( "sketch", brush );
}
});
That uses sketcher.js. This allows the user to stamp a pattern depending on what brush pattern is used.
I want to be able to save the users click positions to localstorage and recall them if possible.
Here is the positions I want to save on the image below you can see the orangey/yellow dots that a user has clicked. I want to be able to save them out and recall them.
Here's my dirty attempt, you'll have to clean it up a little bit:
http://jsfiddle.net/ACt6v/2/
var canvas = document.getElementById("the-canvas");
var ctx = canvas.getContext("2d");
var clicks = [];
var localStorageEnabled = typeof(Storage);
var loadLink = document.getElementById("load");
canvas.onmousedown = function(e) {
clicks.push({
x: e.clientX,
y: e.clientY
})
ctx.fillStyle="blue";
ctx.fillRect(e.clientX - 5, e.clientY - 5, 10, 10);
if( localStorageEnabled !=="undefined" ) {
localStorage["clicks"] = JSON.stringify(clicks);
}
}
loadLink.onmousedown = function(e) {
e.preventDefault();
console.log(localStorage["clicks"]); //view the console to see the clicks
var readClicks = JSON.parse(localStorage["clicks"]);
for (var i = 0 ; i < readClicks.length ; i++) {
ctx.fillStyle="red";
ctx.fillRect(readClicks[i].x - 5, readClicks[i].y - 5, 10, 10);
}
}
basically you save an array as a json string which contains all the coordinates of the points. This requires that the user clicks to create the dots. If you need to find the dots dynamically you will need another clean canvas.

Resize a draggable fill with EaselJS

I've got a project where I'm using EaselJS to create a fill (rectangle) and text over it inside a container. My objective is to make this rectangle and text draggable to move it over the canvas. This is already done and working well.
My problem is when I try to resize the rectangle using scaleX and scaleY using a onMouseOver handler. This is indeed done, BUT the rectangle just moves away from it's initial point to some other location.
I've read I need to use the regX and regY properties to override this, but in the context of my code I just can't. What am I doing wrong?
Here's my Javascript code:
(function(){
var stage, myCanvas;
var update = true;
this.init = function() {
myCanvas = document.getElementById("stageCanvas");
stage = new createjs.Stage(myCanvas);
stage.enableMouseOver();
stage.mouseEnabled = true;
stage.mouseMoveOutside = true;
// Reference Shape
var rectFijo0 = new createjs.Shape();
rectFijo0.graphics.beginFill("#DCD8D4").rect(140,160,78,35);
stage.addChild(rectFijo0);
// Shape
var rectOpt0 = new createjs.Shape();
rectOpt0.graphics.beginFill("#C51A76").rect(140,160,78,35);
txtOpt0 = new createjs.Text("TEST","bold 20px","#FFF");
txtOpt0.textAlign ="center";
txtOpt0.x = 50;
txtOpt0.y = 50;
// Container
var containerOpt0= new createjs.Container();
containerOpt0.mouseEnabled = true;
//#######
// Probably here is my problem. I don't understand why if I use regX and regY the rectangle moves the lower right corner to the center, instead of just using this point as a registration point. Why? What I am not understanding?
//containerOpt0.regX = 78/2;
//containerOpt0.regY = 35/2;
//#######
containerOpt0.onPress = pressHandler;
containerOpt0.onMouseOver = mouseOverHandler;
containerOpt0.addChild(rectOpt0, txtOpt0);
stage.addChild(containerOpt0);
stage.update();
createjs.Ticker.setFPS(60);
createjs.Ticker.addEventListener("tick", tick);
}
function pressHandler(e){
// onPress Handler to drag
var offset = {x:e.target.x-e.stageX, y:e.target.y-e.stageY};
e.onMouseMove = function(ev) {
e.target.x = ev.stageX+offset.x;
e.target.y = ev.stageY+offset.y;
update = true;
}
}
function mouseOverHandler(e){
e.target.scaleX = .5;
e.target.scaleY = .5;
update = true;
}
function tick() {
if (update) {
update = false;
stage.update();
}
}
window.onload = init();
}());
Here's my JS Fiddle example so you can see exactly what's going on. Just drag the mouse over the rectangle to see what I mean. It must be something easy to achieve but I'm not certain how.
You issue is, that you are drawing your rects not at 0|0, the "standard" way is to draw your shape starting at 0|0 and then position the shape itself somewhere through .x and .y
rectOpt0.graphics.beginFill("#C51A76").rect(140,160,78,35);
=> changed to
rectOpt0.graphics.beginFill("#C51A76").rect(0,0,78,35);
and additionally I then placed the container at 140|160 + the regX/Y offset:
containerOpt0.regX = 78/2; //regX/Y to have is scale to the center point
containerOpt0.regY = 35/2;
containerOpt0.x = 140 + 78/2; //placement + regX offset/correction
containerOpt0.y = 160 + 35/2;
here's the updated fiddle: http://jsfiddle.net/WfMGr/2/

Categories

Resources