Here's my example: http://jsbin.com/urofan/7/edit
I would like to draw the video into a custom shape, not in a rectangle shape, is that possible right now? (PS: The shape is draggable) All I found in StackO or in the web are for rectangular drawings...
In the future, the shape will be a circle with adjustable radius and position (draggable and resizable).
Thanks for your help.
Allan.
You can contain an image (video frame grab) into a path using the clip method.
First define the path you want the video frame to be contained in.
Note that you don’t have to do fill/stroke.
context.beginPath();
context.moveTo(200, 50);
context.lineTo(420, 80);
context.lineTo(250, 400);
context.lineTo(40, 80);
context.closePath();
Next, create a clipping path from your defined path.
Everything drawn after this will be clipped inside your clipping path.
context.clip();
Finally, draw a frame grab of the video and drawImage into the clipping path.
The frame grab will only appear inside your clipping path.
context.drawImage(0,0,canvas.width,canvas.height);
Here is code and a Fiddle: http://jsfiddle.net/m1erickson/aMW74/
<!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-v4.5.1.min.js"></script>
<style>
#container{
border:solid 1px #ccc;
margin-top: 10px;
}
</style>
<script>
$(function(){
var stage = new Kinetic.Stage({
container: 'container',
width: 500,
height: 500
});
var layer = new Kinetic.Layer();
stage.add(layer);
var img=document.createElement("img");
img.onload=function(){
drawClippedImage(img);
}
img.src="https://dl.dropboxusercontent.com/u/139992952/stackoverflow/KoolAidMan.png";
function drawPathForClipping(context){
context.beginPath();
context.moveTo(200, 50);
context.lineTo(420, 80);
context.lineTo(250, 400);
context.lineTo(40, 80);
context.closePath();
}
function drawClippedImage(img){
var shape = new Kinetic.Shape({
id: 'shape',
drawFunc: function(canvas) {
var context = canvas.getContext();
// define the path that will be used for clipping
drawPathForClipping(context);
// make the last path a clipping path
context.clip();
// draw a clipped image (frame grab)
context.drawImage(img,0,0,img.width,img.height);
// styling, draw the clip path for real as a border
drawPathForClipping(context);
canvas.stroke(this);
},
stroke: 'black',
strokeWidth: 4,
draggable: true
});
// add the shape shape to the layer
layer.add(shape);
layer.draw();
}
}); // end $(function(){});
</script>
</head>
<body>
<div id="container"></div>
</body>
</html>
Related
I am trying to convert an image to another color using kineticjs, actually my image will be on a layer and also a png one can i change only the image objects color? any help will be very greatful
You can replace non-transparent pixels with a new color using compositing.
In particular source-atop compositing will replace all existing non-transparent pixels with any color you draw.
KineticJS does not currently offer compositing out-of-the-box, but you can easily use an html5 Canvas element to do the compositing and then use that element as an image source for a Kinetic.Image element.
Here's example code and a Demo:
var stage = new Kinetic.Stage({
container: 'container',
width: 350,
height: 350
});
var layer = new Kinetic.Layer();
stage.add(layer);
var canvas=document.createElement('canvas');
var ctx=canvas.getContext('2d');
var kImage;
var img=new Image();
img.onload=start;
img.src="https://dl.dropboxusercontent.com/u/139992952/multple/flower.png";
function start(){
cw=canvas.width=img.width;
ch=canvas.height=img.height;
ctx.drawImage(img,0,0);
kImage=new Kinetic.Image({
image:canvas,
width:img.width,
height:img.height,
draggable:true,
});
layer.add(kImage);
layer.draw();
document.getElementById('makeGreen').onclick=function(){
ctx.globalCompositeOperation='source-atop';
ctx.fillStyle='lightgreen';
ctx.fillRect(0,0,cw,ch);
layer.draw();
};
document.getElementById('makeOriginal').onclick=function(){
ctx.globalCompositeOperation='source-over';
ctx.drawImage(img,0,0);
layer.draw();
};
}
body{padding:20px;}
#container{
border:solid 1px #ccc;
margin-top: 10px;
width:350px;
height:350px;
}
<script src="http://d3lp1msu2r81bx.cloudfront.net/kjs/js/lib/kinetic-v5.1.0.min.js"></script>
<button id=makeGreen>Green</button>
<button id=makeOriginal>Original</button>
<div id="container"></div>
Is it possible to move an image behind a mask without moving the mask itself ? I am looking for an operation which allow to move an image behind a mask and it should be accurate and smooth.
The best answer I am looking is to mask an Kinetic.Image object. Kinetic.Image is draggable and need to worry about it's movement. Please let me know if it's really possible to mask Kinetic.Image Object ?
A Demo: http://jsfiddle.net/m1erickson/u28MS/
Use a Kinetic.Shape to get access to the canvas context and then create a clipping region.
Create a new Kinetic.Shape
Define your non-rectangular path in the shape
Call clip() to restrict drawing to that path.
Draw the image into the clipping region.
Give the image x & y properties so that the image can be draw
Here's what that looks like in code:
// create a Kinetic.Shape which gives you access
// to a context to draw on
clippingShape = new Kinetic.Shape({
sceneFunc: function(context) {
// define your path here
// context.beginPath(); ...
// make your path a clipping region
context.clip();
// draw the image inside the clipping region
// img.x & img.y are offsets which can be used
// to "drag" the image around the clipping region
context.drawImage(img,img.x,img.y);
// KineticJS specific context method
context.fillStrokeShape(this);
},
stroke: 'black',
strokeWidth: 4,
listening:false
});
Listen for mouse events on the stage to cause the image to reposition when drawn in the Shape.
In mousedown: Save the mouse position and set a flag indicating the drag has begun.
In mousemove: Calc how much the mouse has moved and offset the image's x/y by that distance.
In mouseup: clear the dragging flag since the drag is over.
The mouse event handlers look like this:
var isdown=false;
stage.getContent().onmousedown=function(e){
var pos=stage.getPointerPosition();
img.lastX=parseInt(pos.x);
img.lastY=parseInt(pos.y);
isdown=true;
};
stage.getContent().onmouseup=function(e){
isdown=false;
};
stage.getContent().onmousemove=function(e){
if(!isdown){return;}
var pos=stage.getPointerPosition();
var mouseX=parseInt(pos.x);
var mouseY=parseInt(pos.y);
var dx=mouseX-img.lastX;
var dy=mouseY-img.lastY;
img.lastX=mouseX;
img.lastY=mouseY;
img.x+=dx;
img.y+=dy;
layer.draw();
};
[ Previous version of answer -- replaced with new answer above after questioners commments ]
This kind of clipping is traditionally done with a foreground image that contains a transparent "viewport" which lets the user see a portion of the background image beneath.
A Demo: http://jsfiddle.net/m1erickson/2f9yu/
Create a draggable background image on a bottom layer:
// create a background layer
var bottomLayer=new Kinetic.Layer();
stage.add(bottomLayer);
// put a draggable image on the background layer
var city=new Kinetic.Image({ image:bk,x:0,y:0,draggable:true,width:700,height:440, });
bottomLayer.add(city);
bottomLayer.draw();
Create a non-draggable foreground image on a top layer.
The top image has a transparent "viewport".
Important: the top layer does not listen for events, so dragging moves the bottom image, not the top image.
// create a top layer that does not respond to mouse events
// any mouse events will filter down to the background image
// this enables the background to be dragged even while behind the top image
var topLayer=new Kinetic.Layer({listening:false,});
stage.add(topLayer);
// create a top image with transparent pixels
// used as a viewport to see a portion of the bottom image
var mirror=new Kinetic.Image({ image:viewport,x:0,y:0 });
topLayer.add(mirror);
topLayer.draw();
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:300px;
}
</style>
<script>
$(function(){
var stage = new Kinetic.Stage({
container: 'container',
width: 350,
height: 300
});
var layer = new Kinetic.Layer();
stage.add(layer);
var bottomLayer=new Kinetic.Layer();
stage.add(bottomLayer);
var topLayer=new Kinetic.Layer({listening:false,});
stage.add(topLayer);
var loadedCount=0;
//
var bk=new Image();
bk.onload=start;
bk.src="https://dl.dropboxusercontent.com/u/139992952/stackoverflow/desert1.jpg";
//
var viewport=new Image();
viewport.onload=start;
viewport.src="https://dl.dropboxusercontent.com/u/139992952/multple/car4.png";
function start(){
if(++loadedCount<2){return;}
var city=new Kinetic.Image({ image:bk,x:0,y:0,draggable:true,width:700,height:440, });
bottomLayer.add(city);
bottomLayer.draw();
var mirror=new Kinetic.Image({ image:viewport,x:0,y:0 });
topLayer.add(mirror);
topLayer.draw();
}
}); // end $(function(){});
</script>
</head>
<body>
<h4>Drag to move the background image in the mirror</h4>
<div id="container"></div>
</body>
</html>
I have made a drag and drop application in HTML5 canvas with kinetic js. Can we also add the paint brush functionality to the same canvas using kinetic js? If yes, please share the link for one such application, and also the code, if possible.
You can use mouse events to let the user create a sketch on the canvas.
Here's how to let the user create a Kinetic polyline.
On mousedown:
Set a mousedown flag to true (indicating that the user is sketching)
Create a new Kinetic Line object
On mousemove:
Add the current mouse position to the points in the line object
Redraw the line that now includes the latest mouse position
On mouseup:
Clear the mousedown flag.
Repeat every time the user sketches a new polyline.
To let the user draw other Kinetic shapes (rect,circle,etc.) you have many options:
Have the user select which shape they want to create. Use mousedown + mouseup to get the bounds of the shape they want. Then add that kinetic shape with those bounds to the stage.
OR
Have the user select which shape they want to create. Create a generic version of that shape and put it on the stage. Let the user drag the generic shape to their desired position. Let the user customize that generic shape by dragging the bounds anchors.
OR
Have the user select which shape they want to create and have them text input the bounds. Create a generic version of that shape and put it on the stage. Let the user drag the generic shape to their desired position.
Really, there are so many options that the design is up to you.
Here is code and a Fiddle: http://jsfiddle.net/m1erickson/WW3sK/
<!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://www.html5canvastutorials.com/libraries/kinetic-v4.3.3-beta.js"></script>
<style>
#container{
border:solid 1px #ccc;
margin-top: 10px;
}
</style>
<script>
$(function(){
// create a stage and a layer
var stage = new Kinetic.Stage({
container: 'container',
width: 400,
height: 400
});
var layer = new Kinetic.Layer();
stage.add(layer);
// an empty stage does not emit mouse-events
// so fill the stage with a background rectangle
// that can emit mouse-events
var background = new Kinetic.Rect({
x: 0,
y: 0,
width: stage.getWidth(),
height: stage.getHeight(),
fill: 'white',
stroke: 'black',
strokeWidth: 1,
})
layer.add(background);
layer.draw();
// a flag we use to see if we're dragging the mouse
var isMouseDown=false;
// a reference to the line we are currently drawing
var newline;
// a reference to the array of points making newline
var points=[];
// on the background
// listen for mousedown, mouseup and mousemove events
background.on('mousedown', function(){onMousedown();});
background.on('mouseup', function(){onMouseup();});
background.on('mousemove', function(){onMousemove();});
// On mousedown
// Set the isMouseDown flag to true
// Create a new line,
// Clear the points array for new points
// set newline reference to the newly created line
function onMousedown(event) {
isMouseDown = true;
points=[];
points.push(stage.getMousePosition());
var line = new Kinetic.Line({
points: points,
stroke: "green",
strokeWidth: 5,
lineCap: 'round',
lineJoin: 'round'
});
layer.add(line);
newline=line;
}
// on mouseup end the line by clearing the isMouseDown flag
function onMouseup(event) {
isMouseDown=false;
}
// on mousemove
// Add the current mouse position to the points[] array
// Update newline to include all points in points[]
// and redraw the layer
function onMousemove(event) {
if(!isMouseDown){return;};
points.push(stage.getMousePosition());
newline.setPoints(points);
layer.drawScene();
}
}); // end $(function(){});
</script>
</head>
<body>
<div id="container"></div>
</body>
</html>
I have done something some weeks before. I don't know if it can help you.
http://jsfiddle.net/F3zwW/10/
var x;
var y;
var entry;
var isFinished = false;
circle.on('dragstart', function(evt) {
entry = new Kinetic.Circle({
x: evt.x,
y: evt.y,
radius: 10,
fill: 'red',
stroke: 'black',
strokeWidth: 2
});
group.add(entry);
layer.add(group);
entry.moveToTop();
});
circle.on('dragmove', function(evt) {
if (isFinished) return;
if (x != undefined && y != undefined) {
var line = new Kinetic.Line({
points: [x, y, evt.x, evt.y],
stroke: 'red',
strokeWidth: 20,
lineCap: 'round',
lineJoin: 'round'
});
length += Math.sqrt(Math.pow(evt.x - x, 2) + Math.pow(evt.y - y, 2));
group.add(line);
}
x = evt.x;
y = evt.y;
layer.add(group);
circle.moveToTop();
entry.moveToTop();
layer.draw();
if (length > 120) circle.fire('dragend');
});
circle.on('dragend', function(evt) {
if (isFinished) return;
var exit = new Kinetic.Circle({
x: x,
y: y,
radius: 10,
fill: 'red',
stroke: 'black',
strokeWidth: 2
});
group.add(exit);
layer.add(group);
circle.hide();
layer.draw();
isFinished = true;
});
Is that the behavior you are looking for ?
Here I wanted for some reasons to limit the length but you can easily remove this restriction.
I'm trying to perform a crop of a background image with different shapes.
The objective is to move/rotate around the polygons, crop the background with the shape of the polygon, somehow plot the cropped image over the polygon and save the cropped polygon as a new image.
So far I can drag and rotate(arrow keys) the polygons over the canvas.
First, I'm having problems rotating the polygons: I want them to rotate on its center.
And second, cropping the background with the polygon shape.
Here's a link to a jsbin: http://jsbin.com/efoqav/1/edit
Any ideas?
Thanks.
Here’s how to use your Kinetic polygon to clip a background image
First, use the background image as a fillPattern in your Kinetic polygon. Make the fill non-repeating and offset the pattern by the x/y position of the polygon:
var hexagon = new Kinetic.RegularPolygon({
x: 50,
y: 50,
sides: 6,
radius: 50,
fillPatternImage: img,
fillPatternRepeat: "no-repeat",
fillPatternOffset: [-50,-50],
stroke: 'black',
strokeWidth: 3,
draggable: true
});
Then when th user drags the polygon (or you move it with keystrokes), reposition the fillPatternOffset by the current position of the polygon. Essentially, the fill inside the polygon will “follow” the dragging polygon.
hexagon.on('dragmove', function() {
var position=this.getAbsolutePosition();
var x=position.x;
var y=position.y
this.setFillPatternOffset(x,y);
layer.draw();
});
To rotate your polygon around its center (centerX,centerY), do this trigonometry to each of your Kinetic Polygon Points and then reset the shape with yourKineticPolygon.setPoints.
// if the rotation angle is degrees, you must first convert it to radians:
var radianAngle = degreeAngle * Math.PI/180;
// modify each of your polygon points like this
var dx = centerX – pointX;
var dy = centerY – pointY;
var radius = Math.sqrt( dx*dx + dy*dy);
var rotatedX = centerX + radius * Math.cos(radianAngle);
var rotatedY = centerY + radius * Math.cos(radianAngle);
And to save the stage to an image, you can use stage.toDataURL like this:
// hide the background since you're just interested in the clip
background.hide();
// this saves the stage (your clipped polygon) to an image url
stage.toDataURL({
// just like an image object, you need an onload-ish callback
callback: function(dataUrl){
// testing -- put the image in an html img
var imgElement=document.getElementById("saved");
imgElement.src=dataUrl;
// reshow the background
background.show();
}
});
Here’s code and a Fiddle: http://jsfiddle.net/m1erickson/eQYB8/
<!doctype html>
<html>
<head>
<link rel="stylesheet" type="text/css" media="all" href="css/reset.css" /> <!-- reset css -->
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
<script src="http://d3lp1msu2r81bx.cloudfront.net/kjs/js/lib/kinetic-v4.5.1.min.js"></script>
<style>
body{ background-color: ivory; padding:20px;}
img{border:1px solid red;}
</style>
<script>
$(function(){
// this just generates a sample image
var canvas=document.createElement("canvas");
var ctx=canvas.getContext("2d");
var count=0;
canvas.width=300;
canvas.height=300;
for(var x=0;x<10;x++){
for(var y=0;y<10;y++){
ctx.beginPath();
ctx.arc(x*30+15,y*30+15,15,0,Math.PI*2,false);
ctx.fillText(count++,x*30+11,y*30+18);
ctx.stroke();
}
}
var img=new Image();
img.onload=function(){
draw();
}
img.src=canvas.toDataURL();
function draw(){
var stage = new Kinetic.Stage({
container: 'container',
width: 300,
height: 300
});
var layer = new Kinetic.Layer();
stage.add(layer);
var background = new Kinetic.Image({
x: 0,
y: 0,
image: img,
width: 300,
height: 300,
opacity:.25
});
layer.add(background);
var hexagon = new Kinetic.RegularPolygon({
x: 50,
y: 50,
sides: 6,
radius: 50,
fillPatternImage: img,
fillPatternRepeat: "no-repeat",
fillPatternOffset: [-50,-50],
stroke: 'black',
strokeWidth: 3,
draggable: true
});
layer.add(hexagon);
layer.draw();
hexagon.on('dragmove', function() {
var position=this.getAbsolutePosition();
var x=position.x;
var y=position.y
this.setFillPatternOffset(x,y);
layer.draw();
});
$("#save").click(function(){
background.hide();
stage.toDataURL({
callback: function(dataUrl){
var imgElement=document.getElementById("saved");
imgElement.src=dataUrl;
background.show();
}
});
});
}
}); // end $(function(){});
</script>
</head>
<body>
<button id="save">Save</button><br><br>
<p>Drag the Polygon to your desired clip</p><br>
<div id="container"></div><br>
<p>Saved results without background</p>
<img id="saved" width=300 height=300/>
</body>
</html>
I want to get a .jpg on a canvas, add a rectangle and a String, which is working very good. After that I want to create a jpg out of the canvas, which works fine but the jpg of the canvas does only show the rectangle and the String. Quick Code-example - i know its a ugly canvas - just testing ;)
<!DOCTYPE html>
<html>
<body>
<canvas id="meinCanvas" width="600" height="600" style="border:1px solid #c3c3c3;">
Your browser does not support the canvas element.
</canvas>
</body>
<script type="text/javascript">
var canv = document.getElementById("meinCanvas");
var context = canv.getContext("2d");
context.fillStyle = "#000000";
context.fillRect(10,10, 200, 100);
var img = new Image();
img.onload = function() {
context.drawImage(img, 300, 300);
};
img.src="one.jpg";
context.font = "bold 12px sans-serif";
context.fillText("test", 500, 500);
imgsr = canv.toDataURL("image/jpeg");
document.write('<img src="' +imgsr +'"/>');
</script>
</html>
}
In the upper part (the canvas) the img is shown properly, but in the .jpeg beneth it the img is not shown. Help would be great. thanks.
Image is not loaded yet when you save it.
Put the toDataUrl in img.onload or link it to an event or timer