Reputation: 48
I want to make an eraser with kineticjs, but i have some problem.
The eraser need to be efficient on multiple layer (layerA, layerB in my code) and with a simple button or some check box I can choose if the eraser will work on the first or second layer, and why not on all of them. I also need to keep them draggable.
her is a jsfiddle that show what I've explained:
http://jsfiddle.net/junkees/jA2V8/2/
var stage = new Kinetic.Stage({
container: 'container',
width: 400,
height: 500
});
var layerA = new Kinetic.Layer();
var imageObj = new Image();
imageObj.onload = function() {
var x = new Kinetic.Image({
x: 0,
y: 0,
image: imageObj,
draggable:false
});
// add the shape to the layer
layerA.setListening(false);
layerA.add(x);
// add the layer to the stage
stage.add(layerA);
layerA.setZIndex(10);
//layerA.draw();
};
imageObj.src="https://imagizer.imageshack.us/v2/595x397q90/707/u8q3.jpg"
var layerB = new Kinetic.Layer();
var imagj = new Image();
imagj.onload = function() {
var x = new Kinetic.Image({
x: 0,
y: 0,
image: imagj,
});
// add the shape to the layer
layerB.setDraggable(true);
layerB.setListening(true);
layerB.add(x);
// add the layer to the stage
stage.add(layerB);
layerB.setZIndex(100);
layerB.draw();
};
imagj.src = 'http://jsfiddle.net/img/initializing.png';
i whant to be able to erase the frog (or something other of her layer) and to erase a part of the cup of coffee(second layer) with my mouse, with a circle (the radius doesn't matter, i'll make a jquery slider to define it's size ;) )
I'm using the latest version of kineticjs, the 5.1.0
sorry for all the previous post about this question, I've read them but them didn't work for me because of the version. I've already search everywhere google let me search and didn't found something that can help me so I ask her my question
Here I've found something that partially works:
http://jsfiddle.net/junkees/jA2V8/3/
In this one I've created a new shape and attach it to the layer, because the shape and the image are both in the same layer and the layer is draggable so it'll drag both of them like you can see but it's just a micro part of what I want :/
I've edited my code and her I can say little by little i'll success to do it! her the new jsfiddle: http://jsfiddle.net/junkees/jA2V8/5/ and her some problem:
Am I in the right way to finish this?
Upvotes: 0
Views: 526
Reputation: 105035
globalCompositeOperation
is used to "erase" existing canvas pixels using new drawings (like your circle-dragged-with-mouse).
KineticJS is not yet well suited to creating an "eraser" tool. That's because it doesn't yet support globalCompositeOperation
.
A workaround is to create a Kinetic.Shape object which lets you draw with native canvas commands.
Then you get a reference to a native canvas context while using a Kinetic.Shape like this:
var ctx=yourLayer.getContext()._context;
With this native canvas context you can use globalCompositeOperation
to turn the custom shape into an eraser.
ctx.globalCompositeOperation='destination-out';
// now any new drawings will erase existing pixels
You will need to have a Kinetic.Shape "eraser" on every layer that you want to penetrate with the erasings.
Here is a Demo: http://jsfiddle.net/m1erickson/tf7m3/
The circles show the Kinetic.Shape erasers on both the middle and top layers in action. They use 'destination-out' compositing to erase the red and blue rectangles on the middle & top layers. The result is that the bottom layer shows through the "erased" circles.
Example code:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Prototype</title>
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
<script src="http://d3lp1msu2r81bx.cloudfront.net/kjs/js/lib/kinetic-v5.0.1.min.js"></script>
<style>
body{padding:20px;}
#container{
border:solid 1px #ccc;
margin-top: 10px;
width:350px;
height:219px;
}
</style>
<script>
$(function(){
var stage = new Kinetic.Stage({
container: 'container',
width: 350,
height: 219
});
var bottomlayer = new Kinetic.Layer();
stage.add(bottomlayer);
var middlelayer = new Kinetic.Layer();
stage.add(middlelayer);
var toplayer = new Kinetic.Layer();
stage.add(toplayer);
var sw=stage.width();
var sh=stage.height();
var cutouts=[];
var PI2=Math.PI*2;
var img=new Image();
img.onload=start;
img.src="https://dl.dropboxusercontent.com/u/139992952/stack1/landscape1.jpg";
function start(){
var kImage=new Kinetic.Image({
image:img,
});
bottomlayer.add(kImage);
bottomlayer.draw();
middlelayer.draw();
toplayer.draw();
};
var midRed=new Kinetic.Rect({
x:sw/4,y:0,width:stage.width()/2,height:stage.height(),
fill:"red",
opacity:0.50
});
middlelayer.add(midRed);
var middleEraser=new Kinetic.Shape({
x:0,y:0,
fill:"blue",
drawFunc: function(context) {
var ctx=middlelayer.getContext()._context;
ctx.save();
ctx.globalCompositeOperation="destination-out";
ctx.beginPath();
for(var i=0;i<cutouts.length;i++){
var cut=cutouts[i];
ctx.arc(cut.x,cut.y,15,0,PI2);
ctx.closePath();
}
ctx.fill();
ctx.restore();
}
});
middlelayer.add(middleEraser);
var topBlue=new Kinetic.Rect({
x:stage.width()/2,y:0,width:stage.width()/2,height:stage.height(),
fill:"blue",
opacity:0.50
});
toplayer.add(topBlue);
toplayer.draw();
var topEraser=new Kinetic.Shape({
x:0,y:0,
fill:"blue",
drawFunc: function(context) {
var ctx=toplayer.getContext()._context;
ctx.save();
ctx.globalCompositeOperation="destination-out";
ctx.beginPath();
for(var i=0;i<cutouts.length;i++){
var cut=cutouts[i];
ctx.arc(cut.x,cut.y,15,0,PI2);
ctx.closePath();
}
ctx.fill();
ctx.restore();
}
});
toplayer.add(topEraser);
stage.on('contentClick',function(){
var pos=stage.getPointerPosition();
var mouseX=parseInt(pos.x);
var mouseY=parseInt(pos.y);
cutouts.push({x:mouseX,y:mouseY});
middlelayer.draw();
toplayer.draw();
});
}); // end $(function(){});
</script>
</head>
<body>
<h4>Click to "erase" top 2 layers & reveal bottom image</h4>
<div id="container"></div>
</body>
</html>
Upvotes: 1