I have a small image editor using KineticJS: http://www.scrapwebshop.nl/apps/index.html
For this webapp I want to 'color' an image using another image. I use globalCompositeOperation = source-in for this. This works great. This coloring I do in a popup (click in the color wheel in my example) in a separate canvas. When the user is finished applying his ink I want to add the data of this scratch-pad-like canvas as a layer to my main KineticJS canvas.
I can't get this to work. I can add the context directly to my main canvas, but then I loose my layer management and the transparency. You'll see when you hit the 'Inkt toepassen' button. For this I use these lines:
// Get context of main canvas:
var context = layer.getCanvas().getContext();
// Get image data from scratch pad:
var imgData = inkContext.getImageData(0, 0, inkCanvas.width, inkCanvas.height);
// Copy image data to main canvas
context.putImageData(imgData, 0, 0);
How can I create a KineticJS layer from the data on my scratch pad?
It looks like you're trying to hijack an internal KineticJS context to accomplish your compositing. Although this works, its results are temporary because the KineticJS will quickly reclaim and overdraw the context--that's why it's an internal context(!).
A workaround is to create an in-memory html canvas element used for your composited drawing (no need to add this canvas to the DOM). Then use this canvas as the image source for a KineticJS Image object. Then any changes to the canvas will be reflected through the Kinetic.Image onto the stage.
Create an in-memory 'scratch' canvas
Draw whatever is needed on the scratch canvas
Create a Kinetic.Image with the scratch canvas as the image source:
When needed, make changes to the scratch canvas and refresh the Kinetic.Image with layer.draw()
. The new changes will display on the stage.
Here's an example that uses compositing on an in-memory canvas element and displays the result through a Kinetic.Image:
var stage = new Kinetic.Stage({
container: 'container',
width: 300,
height: 300
});
var layer = new Kinetic.Layer();
stage.add(layer);
var PI=Math.PI;
var PI2=PI*2;
var cx=50;
var cy=50;
var radius=50;
var angle=0;
var circumference=2*radius*PI;
var cutCount=15;
var cutRadius=circumference/cutCount/2;
var canvas=document.createElement('canvas')
var ctx=canvas.getContext('2d');
canvas.width=2*radius;
canvas.height=2*radius;
ctx.beginPath();
ctx.arc(cx,cy,radius,0,PI2);
ctx.closePath();
ctx.fillStyle='blue';
ctx.fill();
var c=new Kinetic.Image({image:canvas,x:30,y:30,});
layer.add(c);
layer.draw();
$("#test").click(function(){
var x=cx+radius*Math.cos(angle);
var y=cy+radius*Math.sin(angle);
angle+=(PI2/cutCount);
ctx.globalCompositeOperation='destination-out';
ctx.beginPath();
ctx.arc(x,y,cutRadius,0,PI2);
ctx.closePath();
ctx.fill();
ctx.globalCompositeOperation='source-over';
layer.draw();
});
body{padding:20px;}
#container{
border:solid 1px #ccc;
margin-top: 10px;
width:300px;
height:300px;
}
<script src="http://d3lp1msu2r81bx.cloudfront.net/kjs/js/lib/kinetic-v5.1.0.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<button id="test">Test</button><br>
<h4>Using compositing in KineticJS via 'scratch' canvas</h4>
<div id="container"></div>