This may be off topic but I'm not sure where else to go with this question. I'm just getting started with HTML5 canvas element and all of the incredibly powerful things it can do. I was hoping someone could offer some advise. When working with custom paths and bezier curves, what is the easiest/best way to visualize where the points belong on the canvas to achieve a desired effect. Right now it feels like I'm just guessing plotting points in any place hoping to end up with the right angle/shape that I want.
To be more specific I want to create a shape that will act as an image mask, and will later need to animate this shape. Much like this fiddle http://jsfiddle.net/jimrhoskins/dDUC3/1/ (someone else's work) but since I can't see where the picture is on the canvas or where any of the points are, I'm really just guessing at the approximate shape I need to make. I'm just wondering if there's a better way, or some function in javascript that can map the location of an image and give me at least a better place to start.
Here is what I know/have tried already
// Grab the Canvas and Drawing Context
var canvas = document.getElementById('c');
var context = canvas.getContext('2d');
// Create an image element
var img = document.createElement('IMG');
// When the image is loaded, draw it
img.onload = function () {
// Save the state, so we can undo the clipping
context.save();
// Create a shape, of some sort
context.beginPath();
context.moveTo(somex, somey);
context.bezierCurveTo(somexstart, someystart, somexcontrol, someycontro, somexend, someyend);
context.arcTo(somecoordinates);
context.closePath();
// Clip to the current path
context.clip();
context.drawImage(img, 0, 0);
// Undo the clipping
context.restore();
}
// Specify the src to load the image
img.src = "url";
How about opening the image in an SVG editor. Drawing a path on a layer above the image. Then open the SVG and copy the coordinates?
Try an SVG Editor. You can get the points there. You can add images too. SVG animation is used nowadays as well. If you have Adobe Illustrator, it will be easier to draw there and just save it as SVG.
Related
I am trying to verify that this happens no matter what, and there's no way to bypass it. It seems pretty silly to me that createjs uses this architecture. But I noticed that creating a stage from an existing canvas element removes all shapes, writings, etc from the canvas? Code is below:
html:
<canvas id="canvas" width="800" height="400"></canvas>
js:
var canv = document.getElementById("canvas");
var stage = new createjs.Stage(canv);
var ctx = canv.getContext('2d');
ctx.beginPath();
ctx.arc(50,50,10,0,2*Math.PI);
ctx.stroke();
createjs.Ticker.addEventListener("tick", tick);//circle created is overwritten here!!!?! Why createjs!?
//stage.update();
createjs.MotionGuidePlugin.install();
var shape1 = new createjs.Shape();
shape1.graphics.f("#000000").dc(0,0,10);
var path1 = new createjs.Shape();
path1.graphics.beginStroke("#ff0000").mt(0,0).qt(50,100,100,0);
stage.addChild(path1, shape1);
createjs.Tween.get(shape1).to({guide:{ path:[0,0, 50,100, 100,0] }},2000, createjs.Ease.cubicInOut);
function tick(event) {
stage.update();
}
Is this something that cannot be bypassed? It seems silly to me that createjs wouldn't just actually use the existing element unerased. If not, what is the point in passing in an element in the first place, why doesn't it just create a canvas element, and give you the ID? Anyways, if this is how it's going to be, unfortunately, I am going to have to go somewhere else. Sad, because createjs seemed pretty useful.
CreateJS uses a retained graphics mode, that is, it stores the state and redraws it each time. This is because the canvas is basically a big Bitmap with drawing commands – clearing the stage is the only way to remove the previous state.
But good news! There are lots of ways to get around these limitations if you want to blend CreateJS content with other content, or even make additive drawing effects.
The first is easy, which is setting autoClear. This will prevent the clear, and just draw the new contents over the old one.
stage.autoClear = false;
The second is a bit tougher, but great for instances where you want to mix CreateJS content with other libraries or effects. You can basically use the other canvas as the source to a Bitmap you include in CreateJS:
// Create a child for CreateJS referencing the other canvas
var bmp = new createjs.Bitmap(otherCanvas);
// Add it at the bottom (or top or wherever) in your new CreateJS canvas
stage.addChildAt(bmp, 0);
This is a great approach because it lets you put your content wherever you want, edit it separately, etc.
If you have a different case this doesn't cover, let me know and I can try to make a recommendation!
Cheers.
I'm writing an application that needs static clipping for images on the canvas (as you move the images on the canvas the clipping area stays in one place). I have three cases: polygon, ellipse, any shape specified with an image. I was able to cope with polygon and ellipse, because I can do them with paths and arcs, but when it comes to a mask specified via an image I'm not sure what to do.
Example shape to clip to:
Let's say I am not able to draw it using paths
So I have it specified with an image, I know how to obtain image data from it. What I'm trying to achieve is to clip everything that is out of that figure.
I was trying like this:
canvas.clipTo = function (ctx) {
ctx.drawImage(shape.src, left, top);
};
And like this:
canvas.clipTo = function (ctx) {
ctx.putImageData(imgData, left, top);
};
Of course none of them work as I expect, it just draws that black shape instead of clipping to that region.
Any ideas how to do it?
I do it by creating a new canvas the same size as the mask image. Then draw the image on that canvas, then set the ctx.globalCompositeOperation to "destination-in" draw the mask over the image (masking it) , then draw the that canvas to the on-screen canvas with ctx.drawImage
As this is most definitely a duplicated question I will not give the answer as code, it's been done to death here on stackoverflow.
Oh and I forgot. Using imageData to clip is a very inefficient way to do it.
I need to implement a way to apply different texture to quite complicated nested canvas. Consider for example this image:
Car
I want to let the user to choose a fabric for the door and another for the rest of the body with different features such as scale, rotation angle and transparency.
Is there a js library that can help or pure javascript (maybe with HTML5) is enough?
Thanks a lot.
Yes, you can texturize your car using only native html5 canvas.
No libraries are necessary because your tasks are simple and canvas has built-in methods for all the things you're wanting to do.
Start by creating an image for each part of your car. Each part-image will be opaque where you want the texture applied and transparent where you don't want the texture applied.
To apply a texture to any part, first draw the part on a second in-memory canvas. Then draw your texture on top of the second canvas. You can constrain your texture to only fill within the desired part using the source-atop compositing mode.
You can scale & rotate the texture using context.scale & context.rotate.
You can control the transparency of the texture using context.globalAlpha.
When you have your part textured as desired, just draw the in-memory (part) canvas to the main canvas.
Here is example code and a Demo:
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var c=document.createElement('canvas');
var cctx=c.getContext('2d');
var cw,ch;
var car=new Image();
car.onload=start;
car.src='https://dl.dropboxusercontent.com/u/139992952/carForTexturing.png';
var door=new Image();
door.onload=start;
door.src='https://dl.dropboxusercontent.com/u/139992952/doorForTexturing.png';
var texture1=new Image();
texture1.onload=start;
texture1.src='https://dl.dropboxusercontent.com/u/139992952/texture1.png';
var imgCount=3;
function start(){
if(--imgCount>0){return;}
cw=canvas.width=c.width=car.width;
ch=canvas.height=c.height=car.height;
ctx.drawImage(car,0,0);
texturize(door, texture1, 0.50, Math.PI/4, 0.30);
ctx.drawImage(c,0,0);
}
function texturize(carpartImage,texture,scale,rotation,opacity){
cctx.clearRect(0,0,cw,ch);
cctx.drawImage(carpartImage,0,0);
cctx.save();
cctx.translate(cw/2,ch/2);
cctx.rotate(rotation);
cctx.globalAlpha=opacity;
cctx.globalCompositeOperation='source-atop';
cctx.drawImage(texture,-texture.width/2,-texture.height/2)
cctx.restore();
}
<canvas id="canvas" width=842 height=596></canvas>
I need to clear a rectangle Drawn on Image in Canvas with out damage existing image. I can draw small rectangle points and clear that out. But the problem is when I clear rectangle it remains as white small patch on image.
Can someone tell me how to clear a rectangle on image without damage the existing image.
I have used following methods to clear rectangles but didn't work.
1) context.fillStyle ="white";
2) context.clearRect(xCoordinate, yCoordinate, 10, 08);
Thanks in advance!
Canvas doesn't work that way. It's a single layer, its also transparent by default. So with that in mind, you might be able to achieve what you want by simply giving the canvas element a CSS background. That way anything you draw on top of that background can easily be removed and the background will show through.
#backed-canvas{
background-image: url(http://www.placebear.com/300/200);
}
JSFiddle example: https://jsfiddle.net/yLf5erut/
There is one thing you can do.
When create a rectangle on the canvas just get the image data like:
var imgData = context.getImageData(xCoordinate, yCoordinate, 10, 8);
and draw the rectangle.
When clearing out the rectangle just place then image data back like this:
context.putImageData(imgData, xCoordinate, yCoordinate);
I suggest using 2 canvas elements one over another.
So you can have the original image drawn on the bottom canvas with low zIndex, and the top one with highter zIndex can be used to draw / clear whatever needed. This is a common practice, and for more complecated animations you will end up with better performance.
I have a canvas element that I'm setting the background on dynamically via code. Then I'm using the Sketch library (http://intridea.github.io/sketch.js/) to draw on the canvas. - This all works.
However, whenever I try to convert the canvas using canvas.toDataURL("image/png") it's able to save the canvas drawing, however isn't saving the background. - I understand this is working as designed.
Is there a way to merge the two? I was toying around with the idea that I could set the image src to the background src after I'm done drawing and try to export that, however I'm not certain. Does anyone have any experience with this?
As you've discovered, the canvas and its background are maintained separately and toDataURL will not also capture the background.
You can combine the background with the sketch using canvas compositing.
The 'destination-over' compositing mode will let you drawImage your background behind the sketches
context.globalCompositeOperation="destination-over";
context.drawImage(backgroundImage,0,0);
Now the background pixels have been drawn behind you sketch and both will be captured with toDataURL.
Yes, You are correct. I fetch the background image along with canvas image and download.
ctx.width = 2503;
ctx.height = 250;
ctx.globalCompositeOperation="destination-over";
var background = new Image();
background.src = "http://localhost/xxxxx/xxxxx/xxxxx/xxxxx/ecg_back.png";
ctx.drawImage(background, 0, 0);
// create pattern
var ptrn = ctx.createPattern(background, 'repeat'); // Create a pattern with this image, and set it to "repeat".
ctx.fillStyle = ptrn;
ctx.fillRect(0, 0, ctx.width, ctx.height);
How are you adding the background to the canvas? Are you setting it in css as a background image? Or are you adding the image directly to the canvas? I think you'll need to do the latter, as per the example here.