So I have a canvas which I want to draw multiple images onto and then layer them, so; first image would have opacity: 0.5; image two would have opacity: 0.7 and then third being opacity: 0.3;. My question.
Should I have multiple canvas elements on one page and then position: absolute; them on top of each other or try something else?
Just wondering A. Performance and B. is this semantically correct? Thanks.
You can draw the images in the same canvas.
Just change the .globalAlpha property before drawing the image.
ctx.save();
ctx.globalAlpha = 0.8;
ctx.drawImage(image1, 0, 0);
ctx.restore();
ctx.save();
ctx.globalAlpha = 0.3;
ctx.drawImage(image2, 0, 0);
ctx.restore();
ctx.save();
ctx.globalAlpha = 0.5;
ctx.drawImage(image3, 0, 0);
ctx.restore();
//...
fiddle
Yes, multiple canvas elements on top of each other is a good way to achieve layering. Though, of course, I'd stick with only two or three, for performance reasons, unless you know that your site will only be viewing by performant browsers/processors. If you don't mind losing the layering in the output, you could just use one hidden canvas as a cache to prepare drawing on, and then copy each layer over from that to another canvas which you display.
If you use multiple elements, you might want to place them within a div wrapper, or something similar, for better organisation. And note that canvases are transparent by default: in other words, you can see what's underneath them so long as you don't draw over what you want to see or set a background colour.
Rather than setting the CSS opacity on your canvas elements, use instead the globalAlpha javascript property on your canvas context when you are drawing; or set the alpha as a fillStyle before any of your individual drawing function calls, like so:
var red = 255, // 100%
green = 128, // 50%
blue = 0, // 0%
alpha = 0.5; // 50%
canvasContext.fillStyle = "rgba(" + red + "," + green + "," + blue + "," + alpha + ")";
// orange at half opacity
With CSS you can set the position and opacity of an img, so why would you want to use the canvas tag? A: Having multiple canvases don't seem to have an effect however we are only displaying 1 image on each canvas, B Well if it provides the output you want yes, however I would just stick with one canvas.
Exmaple 1 using one canvas : https://jsfiddle.net/CanvasCode/jae7snxh/
var canvas = document.getElementById('canvas');
var context = canvas.getContext('2d');
var image1 = new Image();
image1.src = "https://encrypted-tbn2.gstatic.com/images?q=tbn:ANd9GcQRsJ_wNvd0PfISyPZ5a_QI3Dpeo0g4T5Tuk-R26JXPxfhyFxBTVQ";
var image2 = new Image();
image2.src = "https://encrypted-tbn3.gstatic.com/images?q=tbn:ANd9GcQQqnYE7Xtre5W0seeFETl00OPSGoujI6xUOHr18GzB4hJE5bCIaQ";
var image3 = new Image();
image3.src = "https://encrypted-tbn2.gstatic.com/images?q=tbn:ANd9GcRkg3mvI5DwGqG9AUmOEVU6bDDQgM6fT7nQKr8D7XwbQ59lxDiVlA";
context.fillStyle = "#FF0000";
context.fillRect(0,0,500,400);
// Save original state of the context settings
context.save();
context.globalAlpha = 0.8;
context.drawImage(image1, 0, 0);
context.globalAlpha = 0.3;
context.drawImage(image2, 0, 0);
context.globalAlpha = 0.5;
context.drawImage(image3, 0, 0);
context.restore();
// Restore original state of the context settings
Chrome network shows it takes 334MS
Multiple canvas example : https://jsfiddle.net/CanvasCode/jae7snxh/3/
var canvas1 = document.getElementById('canvas1');
var context1 = canvas1.getContext('2d');
var canvas2 = document.getElementById('canvas2');
var context2 = canvas2.getContext('2d');
var canvas3 = document.getElementById('canvas3');
var context3 = canvas3.getContext('2d');
var image1 = new Image();
image1.src = "https://encrypted-tbn2.gstatic.com/images?q=tbn:ANd9GcQRsJ_wNvd0PfISyPZ5a_QI3Dpeo0g4T5Tuk-R26JXPxfhyFxBTVQ";
var image2 = new Image();
image2.src = "https://encrypted-tbn3.gstatic.com/images?q=tbn:ANd9GcQQqnYE7Xtre5W0seeFETl00OPSGoujI6xUOHr18GzB4hJE5bCIaQ";
var image3 = new Image();
image3.src = "https://encrypted-tbn2.gstatic.com/images?q=tbn:ANd9GcRkg3mvI5DwGqG9AUmOEVU6bDDQgM6fT7nQKr8D7XwbQ59lxDiVlA";
context1.globalAlpha = 0.8;
context1.drawImage(image1, 0, 0);
context2.globalAlpha = 0.3;
context2.drawImage(image2, 0, 0);
context3.globalAlpha = 0.5;
context3.drawImage(image3, 0, 0);
Chrome network shows it takes 334MS
Related
i have a function that has a loop. in the loop it creates a canvas and sets the opacity.
Then it sets the background color and converts the canvas to an image.
Somehow the Opacity is being set on the canvas but the background color doesn't get set.
if (remain <= 0) {
var canvas = document.createElement('canvas');
context = canvas.getContext('2d');
for (var i = 0; i < img.length; ++i) {
if (img[i]) {
var opacity = item.opa;
context.globalAlpha = opacity;
context.drawImage(img[i],0,0);
}
}
var background = mp.colbk; //returns rgb(255,0,0)
context.fillStyle = background;
var im = new Image();
im.src = canvas.toDataURL();
}
Im not sure why my background is not being set. any suggestions?
Thank you in advance.
With context.fillStyle = background, you are NOT setting the background color of the canvas. Instead, it sets the fill color of the drawing tool for the canvas.
In other words, context.fillStyle only applies to lines or shapes drawn on the canvas afterwards.
To fill the canvas with a color, use the fillRect() function:
context.fillStyle = background;
context.fillRect(0, 0, canvas.width, canvas.height);
This canvas cheat sheet proved to be helpful
I want to change color a Image in canvas
this is the Image
You can see there is a Image transparent I was try using PutImgData but my transparent is changing color
Is there anyway to change color the car and money only ?
I was using this code :
var canvas = document.getElementById("canvas"),
ctx = canvas.getContext("2d"),
image = document.getElementById("testImage");
canvas.height = canvas.width = 100;
ctx.fillStyle = 'red';
ctx.fillRect(10,10,20,10);
ctx.drawImage(image,0,0);
var imgd = ctx.getImageData(0, 0, 45, 45),
pix = imgd.data;
for (var i = 0, n = pix.length; i <n; i += 4) {
if(pix[i+3]==0)
{continue;}
pix.length[i]=r|pix.length[i];
pix.length[i+1]=g|pix.length[i+1];
pix.length[i+2]=b|pix.length[i+2];
pix[i + 3] = 255;
}
ctx.putImageData(imgd, 0, 0);
To mix manually you would have to apply a different formula to mix foreground (new color) and background (image) to preserve anti-aliased pixels (and just in case: the image included in the question is not actually transparent, but I guess you just tried to illustrate transparency using the solid checkerboard background?).
I would suggest a different approach which is CORS safe and much faster (and simpler) -
There are a couple of ways to do this: one is to draw in the color you want, then set composite mode to destination-in and then draw the image, or draw the image, set composite mode to source-in and then draw the color.
Example using the first approach coloring the following image blue:
var img = new Image; img.onload = draw; img.src = "//i.stack.imgur.com/cZ0gC.png";
var ctx = c.getContext("2d");
function draw() {
// draw color
ctx.fillStyle = "#09f";
ctx.fillRect(0, 0, c.width, c.height);
// set composite mode
ctx.globalCompositeOperation = "destination-in";
// draw image
ctx.drawImage(this, 0, 0);
}
<canvas id=c></canvas>
Example using second approach:
var img = new Image; img.onload = draw; img.src = "//i.stack.imgur.com/cZ0gC.png";
var ctx = c.getContext("2d");
function draw() {
// draw image
ctx.drawImage(this, 0, 0);
// set composite mode
ctx.globalCompositeOperation = "source-in";
// draw color
ctx.fillStyle = "#09f";
ctx.fillRect(0, 0, c.width, c.height);
}
<canvas id=c></canvas>
To reset comp. mode back to normal use:
// reset comp. mode
ctx.globalCompositeOperation = "source-over";
As with getImageData(), the drawback with this technique is that your canvas must only hold the content of this image while doing this process. A workaround if the image needs to be colored and mixed with other content is to use an off-screen canvas to do the processing, then draw that canvas back onto the main canvas.
I created a small plug-in for my map application. This plug-in adds text labels to geometric features. It looks like so:
On the screen above you can see a map, a horizontal linestring and a text label. I created this label by using canvas, canvas.getContext("2d") and a bunch of standard functions like ctx.strokeText, ctx.fillText etc. The problem I face now is that the linestring on the screen is interactive or moveable and I want my label to move as well. I'm not asking about the exact solution to my problem. What I'm interested in is just how to get backround pixels (right below my text label), so that I could restore them before I "move" or redraw the label at a new place. If you can provide a teeny-weeny example where you have some background and then draw some object and then "remove" it, it will be great.
You probably want to use context.getImageData and context.putImageData
Assuming your canvas has the id "myCanvas", calling doDraw() will cause a black rectangle to blink on a complex background.
First, the background is drawn in doDraw(). Then, the background that is to be covered by the rectangle is captured in drawRectangle() and saved in the variable "imageData". Then the rectangle is drawn over the background. Then, 1 second later, eraseRectangle() is called, and the background is replaced by a call to putImageData().
In this fiddle:
https://jsfiddle.net/f3Luxcoc/
Here's the javascript:
//coordinates of rectangle
var xp = 20;
var yp = 20;
var wp = 80;
var hp = 80;
//saved background image
var imageData = null;
function doDraw() {
var can = document.getElementById("myCanvas");
can.width = 500;
can.height = 500;
var context = can.getContext("2d");
//draw background contents
var image = getImage();
context.drawImage(image, 0, 0);
context.drawImage(image, 100, 0);
context.drawImage(image, 0, 100);
context.drawImage(image, 100, 100);
drawRectangle();
}
function drawRectangle() {
var can = document.getElementById("myCanvas");
var context = can.getContext("2d");
//capture background
imageData = context.getImageData(xp, yp, wp, hp);
//draw Rectangle
context.rect(xp, yp, wp, hp);
context.fill();
setTimeout(function() {
eraseRectangle();
}, 1000);
}
function eraseRectangle() {
var can = document.getElementById("myCanvas");
var context = can.getContext("2d");
context.putImageData(imageData, xp, yp);
setTimeout(function() {
drawRectangle();
}, 1000);
}
doDraw();
function getImage() {
var image1 = new Image(237, 110);
image1.src = "data:image/png;base64,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"
return image1;
}
Before exporting an image from my canvas, I create a new canvas where I do some manipulations (cropping, etc). In this new canvas I fill in the background to blue so that when I export the image the background is blue. However when I put the drawing from the first canvas in, it makes parts of the background transparent. How do I fix this?
Here's the drawing from the first canvas:
Here's what I want:
But I get the following:
Here's my part of my code:
//Create Copy of Canvas
var copyOfContext = document.createElement('canvas').getContext('2d');
copyOfContext.canvas.width = c.width;
copyOfContext.canvas.height = c.height;
copyOfContext.fillStyle = "yellow";
copyOfContext.fillRect(0, 0, c.width, c.height);
copyOfContext.putImageData(trimmedRect, 0, 0);
croppedImageURL = copyOfContext.canvas.toDataURL("image/png");
Edit: The reason I'm not doing it in my first canvas is bc I have a specific look for that to fit the webpage, so I'm using a second canvas to get the result and color I want. :)
To copy from canvas to canvas just use drawImage.
The demo shows how it is done.
var can1 = document.createElement("canvas");
var can2 = document.createElement("canvas");
can1.width = can2.width = 200;
can1.height = can2.height = 200;
can1.ctx = can1.getContext("2d");
can2.ctx = can2.getContext("2d");
can1.ctx.fillStyle = "yellow";
can1.ctx.fillRect(0,0,200,200);
can2.ctx.strokeStyle = "black";
can2.ctx.lineWidth = 5;
can2.ctx.strokeRect(40,40,120,120);
document.body.appendChild(can1);
document.body.appendChild(can2);
can1.ctx.drawImage(can2,30,30,140,140,30,30,140,140);
I'm playing with canvas in HTML5 and Javascript and I have a problem:
I'd like to apply transformations used on the current image to multiple images.
What I did:
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
var img = new Image();
img.onload = function() {
//transformation stuff like:
canvas.height = img.height;
canvas.width = img.width;
ctx.drawImage(img, -img.width / 2, -img.height / 2, img.width, img.height);
ctx.beginPath();
ctx.lineTo(42, 42);
ctx.stroke();
ctx.lineTo(42, 24);
ctx.stroke();
...
ctx.rotate(Math.PI / 2);
...
};
img.src = //base64Img;
So I will apply a lot of transformations like draw some lines, crop, zoomIn etc...
How can I apply this to multiple files (more than 200) once (when these transformations are done) ?
Obviously, it will be done in multiples functions like a function to rotate, to draw a line etc.
Thank you for your help.
Put your transformations, path drawings & image drawing into a function with arguments that tell the function how each image will be treated:
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var img=new Image();
img.onload=start;
img.src="https://dl.dropboxusercontent.com/u/139992952/stackoverflow/house32x32transparent.png";
function start(){
// Note: img coordinates are [centerX,centerY] rather than the usual [left,top]
drawTransformedImage(img,25,50,0,.75);
drawTransformedImage(img,75,50,Math.PI*1/6,1);
drawTransformedImage(img,150,50,Math.PI*2/6,2);
drawTransformedImage(img,225,50,Math.PI*3/6,1);
drawTransformedImage(img,275,50,Math.PI*4/6,.5);
}
function drawTransformedImage(img,cx,cy,radAngle,scale){
// save incoming styling
var lw=ctx.lineWidth;
var ss=ctx.strokeStyle;
// cache often used half-sizes
var iwHalf=img.width/2;
var ihHalf=img.height/2;
ctx.lineWidth=2;
// do the specified transformations
ctx.translate(cx,cy);
ctx.rotate(radAngle);
ctx.scale(scale,scale);
// draw the image
ctx.drawImage(img,-iwHalf,-ihHalf);
// stroke some paths
ctx.beginPath();
ctx.moveTo(-iwHalf,ihHalf);
ctx.lineTo(-iwHalf,-ihHalf);
ctx.strokeStyle='orange';
ctx.stroke();
ctx.beginPath();
ctx.moveTo(-iwHalf,-ihHalf);
ctx.lineTo(+iwHalf,-ihHalf);
ctx.strokeStyle='blue';
ctx.stroke();
// clean up: reset transformations and stylings
ctx.setTransform(1,0,0,1,0,0);
ctx.lineWidth=lw;
ctx.strokeStyle=ss;
}
body{ background-color: white; }
#canvas{border:1px solid red;}
<canvas id="canvas" width=300 height=150></canvas>
Transforming an Image
Your example does not show a image being transformed, making your question unclear.
The transform is independent of the image, it is used to transform pixel coordinates drawn onto the canvas. It does not affect the image. You can set the transform and then draw the 200 images and they will all have the same transformation applied when their content is rendered to the canvas.
Code example
To transform the image you must create a canvas, set the transform, then render the image onto that canvas. The canvas is now the transformed image.
An example of transforming an image.
var mirrorImage = function (image, vertical, horizontal) {
var imageResult, ctx, vF, hF, posX, posY;
// create new canvas
imageResult = document.createElement("canvas");
// set the pixels size to match the image
imageResult.width = image.width;
imageResult.height = image.height;
// create a drawable surface
ctx = imageResult.getContext("2d");
// create the mirror transformation
hF = horizontal ? -1, 0;
vF = vertical ? -1 : 0;
posX = horizontal ? image.width, 0;
posY = vertical ? image.height : 0;
// Apply the transform to the new image
ctx.setTransform(hF, 0, 0, vF, posX, posY);
// transform the original image by drawing it onto the new
ctx.drawImage(image, 0, 0);
// return the new image.
return imageResult;
}
// create image
var img = new Image();
img.src = "ship.png";
// when loaded transform the image
img.onload = function () {
img = mirrorImage(img, true, true);
// the image has been transformed.
}
To do that to 200 images you have to call mirrorImage (or what ever you are doing) for each image.