I am new to the "canvas" term in HTML. I sliced a picture in 2 halves, leaving a small gap between them. I want to rotate each half separately to create a half folding effect.
window.onload = function () {
var myCanv = document.getElementById("myCanvas");
var context = myCanv.getContext('2d');
var myImage = document.getElementById("myImage");
context.drawImage(myImage, 0, 0, myImage.width / 2, myImage.height, 0, 0, myCanv.width / 2, myCanv.height);
context.drawImage(myImage, (myImage.width / 2) + 1, 0, myImage.width / 2, myImage.height, (myCanv.width / 2) + 0.5, 0, myCanv.width / 2, myCanv.height);
};
Is there any way that I can do this using canvas? I appreciate any help. :)
Here is a fiddle. I know it's not much but any hint is useful.
You probably want to skew the 2 halves of the image rather than rotate them.
To skew you can use context.transform or context.setTransform.
Example code and a Demo:
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var cw=canvas.width;
var ch=canvas.height;
var skewLeft=.1;
var skewRight=-.1;
var cx=100;
var y=30;
var iw,ih;
var img=new Image();
img.onload=start;
img.src="https://dl.dropboxusercontent.com/u/139992952/multple/cars.jpg";
function start(){
iw=img.width;
ih=img.height;
draw();
}
function draw(){
// fill the canvas background with gray
ctx.fillStyle='gray';
ctx.fillRect(0,0,cw,ch);
ctx.fillStyle='black'
// draw the left skewed page with a stroked border
ctx.setTransform(1,skewLeft,0,1,cx,0);
ctx.drawImage(img,0,0,iw/2,ih,-iw/2,y,iw/2,ih);
ctx.strokeRect(-iw/2,y,iw/2,ih);
ctx.setTransform(1,0,0,1,0,0);
// draw the right skewed page with a stroked border
ctx.setTransform(1,skewRight,0,1,cx,0);
ctx.drawImage(img,iw/2,0,iw/2,ih,0,y,iw/2,ih);
ctx.strokeRect(0,y,iw/2,ih);
ctx.setTransform(1,0,0,1,0,0);
}
body{ background-color:white; }
img,#canvas{border:1px solid red;}
<h4>Original Image (left) and<br>Image halved, skewed & bordered to look like a fold</h4>
<img src='https://dl.dropboxusercontent.com/u/139992952/multple/cars.jpg'>
<canvas id="canvas" width=225 height=150></canvas>
Related
I want to swap two circular cuts from an image and swap their locations and draw them to the canvas. I am having issues, however, drawing the second circular image. Interestingly in second if you uncomment the first line it draws that image, otherwise if you throw it at the end of the function, it doesn't draw (at least on top). If I comment out the first function, I get the image to draw on the canvas. The first function always executes before the second.
function first() {
ctx.drawImage(imgBig, 0, 0);
ctx.beginPath();
ctx.arc(imgObj1.x + imgObj1.width / 2, imgObj1.y + imgObj1.width / 2, imgObj1.width / 2, 0, 6.28, false);
ctx.clip();
ctx.stroke(); // the outline of circle
ctx.closePath();
ctx.drawImage(imgBig, imgObj2.x, imgObj2.y, imgObj2.width, imgObj2.height, imgObj1.x, imgObj1.y, imgObj1.width, imgObj1.height);
function second() {
// ctx.drawImage(imgCuttingBoard, 0, 0); // this will draw over canvas
ctx.beginPath();
ctx.arc(imgObj2.x + imgObj2.width / 2, imgObj2.y + imgObj2.width / 2, imgObj2.width / 2, 0, 6.28, false);
ctx.clip();
ctx.closePath();
ctx.drawImage(imgCuttingBoard, imgObj1.x, imgObj1.y, imgObj1.width, imgObj1.height, imgObj2.x, imgObj2.y,
imgObj2.width, imgObj2.height); // this doesn't draw on top of the image (might be drawing underneath?)
// ctx.drawImage(imgCuttingBoard, 0, 0); // this will not draw over canvas here
}
Assuming you have given the image time to fully load before trying to drawImage it. You did use image.onload and wait for image to load?
Then your problem is likely clipping ...
context.clip is cumulative. If one clip (clip#1) is applied to the canvas followed by another clip (clip#2), then the resulting clipping area is the intersection of clip#1 and clip#2. The resulting clip is not clip#2.
So if you want to undo clip#1 so you can use the full clip#2, you must wrap the first clip in context.save and context.restore.
Here's a slightly different way of doing it using a temporary canvas
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var cw=canvas.width;
var ch=canvas.height;
var img=new Image();
img.onload=start;
img.src="https://dl.dropboxusercontent.com/u/139992952/multple/faces%20no%20background.png";
function start(){
cw=canvas.width=img.width;
ch=canvas.height=img.height;
ctx.drawImage(img,0,0);
// do the swap
clipCircle(img,63.5,56,54,203,177);
clipCircle(img,203,177,54,63.5,56);
}
function clipCircle(img,sourceCX,sourceCY,r,newCX,newCY){
var c=document.createElement('canvas');
var cctx=c.getContext('2d');
c.width=2*r;
c.height=2*r;
// define an clipping circle
cctx.beginPath();
cctx.arc(r,r,r,0,Math.PI*2);
// draw the source into the temp canvas
cctx.drawImage(img,-sourceCX+r,-sourceCY+r);
// draw the temp canvas onto the main canvas
ctx.drawImage(c,newCX-r,newCY-r);
}
body{ background-color: ivory; }
canvas{border:1px solid red; margin:0 auto; }
<h4>Swapped clipping on canvas<br>(top-left swapped with bottom-center)</h4>
<canvas id="canvas" width=300 height=300></canvas>
<h4>Original Image</h4>
<img src='https://dl.dropboxusercontent.com/u/139992952/multple/faces%20no%20background.png'>
image = new Image();
image.src = 'assets/img/image.png';
for (var i = 0; i < this.bombs.length; i++) {
var bomb = this.bombs[i];
ctx.drawImage(image, bomb.x - 2, bomb.y - 2, 15, 8);
}
This is an image in my canvas game and falling down from top. But I want, get images rotate random each state.
I tried this:
function drawRotated(degrees){
ctx.clearRect(0,0,canvas.width,canvas.height);
ctx.save();
ctx.translate(canvas.width/2,canvas.height/2);
ctx.rotate(degrees*Math.PI/180);
ctx.drawImage(image,-image.width/2,-image.width/2);
ctx.restore();
}
Added this function in my image but its not working. How can I do it?
You're on the right track!
To rotate one (or more) images:
Translate to the center point where you want the image centered.
Rotate by the desired angle
Draw the image
Undo the transformations (undo translate & rotate).
A couple of changes:
You always translate to the middle of the canvas. If you want the bomb to drop you must increasingly translate down the canvas.
A typo: In drawImage you have used width for both the width & height argument.
An efficiency: context.save and context.restore are more expensive operations because they save & restore all of the canvas styles. Instead, it's more efficient to reset only your transformations (translate,rotate) with context.setTransform(1,0,0,1,0,0)
Here's your code refactored for these changes:
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var cw=canvas.width;
var ch=canvas.height;
var bomb;
var img=new Image();
img.onload=start;
img.src="https://dl.dropboxusercontent.com/u/139992952/multple/danger.png";
function start(){
var aa=img.width*img.width;
var bb=img.height*img.height;
var cc=Math.sqrt(aa+bb);
bomb={
x:150,y:-img.height/2,
degrees:0,image:img,
maxRotatedHalfHeight:cc/2
};
requestAnimationFrame(animate);
}
function drawRotated(b){
ctx.clearRect(0,0,canvas.width,canvas.height);
ctx.save();
ctx.translate(b.x,b.y);
ctx.rotate(b.degrees*Math.PI/180);
ctx.drawImage(b.image,-b.image.width/2,-b.image.height/2);
ctx.restore();
}
function animate(time){
drawRotated(bomb);
bomb.y+=1;
bomb.degrees+=1;
if(bomb.y<=canvas.height+bomb.maxRotatedHalfHeight){
requestAnimationFrame(animate);
}else{
alert('Animation is complete.');
}
}
body{ background-color: ivory; }
#canvas{border:1px solid red; margin:0 auto; }
<canvas id="canvas" width=300 height=175></canvas>
I'm trying to resize a <canvas> with an image already drawn, but I'm misunderstanding how to use the canvas.scale() method because it doesn't shrink...
Code:
ImageRender.prototype.resizeTo = function () {
var canvas = $('#myCanvas')[0];
var ctx = canvas.getContext("2d");
//current image
var currImg = ctx.getImageData(0, 0, canvas.width, canvas.height);
//
var tempCanvas = $('canvas')[0];
var tempCtx = tempCanvas.getContext("2d");
tempCtx.putImageData(currImg, 0, 0)
//
ctx.scale(0.5, 0.5);
//redraw
ctx.drawImage(tempCanvas, 0, 0);
};
What am I overlooking?
Thanks!
You can scale your canvas with content by "bouncing" the content off a temporary canvas while you resize the original canvas. This save+redraw process is necessary because canvas content is automatically cleared when you resize the canvas width or height.
Example code:
var myCanvas=document.getElementById("canvas");
var ctx=myCanvas.getContext("2d");
var cw=canvas.width;
var ch=canvas.height;
var tempCanvas=document.createElement("canvas");
var tctx=tempCanvas.getContext("2d");
var img=new Image();
img.crossOrigin='anonymous';
img.onload=start;
img.src="https://dl.dropboxusercontent.com/u/139992952/multple/Dog-With-Cute-Cat.jpg";
function start(){
myCanvas.width=img.width;
myCanvas.height=img.height;
ctx.drawImage(img,0,0);
resizeTo(myCanvas,0.50);
}
function resizeTo(canvas,pct){
var cw=canvas.width;
var ch=canvas.height;
tempCanvas.width=cw;
tempCanvas.height=ch;
tctx.drawImage(canvas,0,0);
canvas.width*=pct;
canvas.height*=pct;
var ctx=canvas.getContext('2d');
ctx.drawImage(tempCanvas,0,0,cw,ch,0,0,cw*pct,ch*pct);
}
body{ background-color: ivory; }
#canvas{border:1px solid red; margin:0 auto; }
<h4>Canvas resized to 50%</h4>
<canvas id="canvas" width=300 height=300></canvas>
<h4>Img with original image</h4>
<img src='https://dl.dropboxusercontent.com/u/139992952/multple/Dog-With-Cute-Cat.jpg'>
Simpler way would be using the extra parameters of drawImage(). 4th and 5th parameters let you set the final width and height.
Also, you can paint an image (or a canvas) directly, without the need of getting the ImageData.
Also(2), I think you may want to resize the canvas too (just use its width and height properties)
https://jsfiddle.net/mezeL06o/
I tried to create an HTML canvas, place a rectangle... then INSIDE THAT rectangle, draw various shapes and an RGBa PNG... all of them clipped inside the dimensions of the rectangle. Then I tried to change the color of the PNG when you press an HTML button input. (Further comments in code.)
Heres the problems... A. You have to draw to a temporary canvas and apply "GlobalCompositeOperation source-atop" just AFTER the clipping rectangle. Everything drawn after that is successfully clipped into the rect shape. Then the whole thing is copied (drawn) to a MAIN canvas. I was told to do it this way in order for the programming to recognize MULTIPLE elements after a "composite" operation. I have to say this works BEAUTIFULLY!! but here's problem B...
To to a "getData" on an image (to change color), I think you have to place the image on a canvas, and doing all the image pixel manipulation screws up the "composite" operation, so I tried to draw the PNG to a THIRD canvas, do the pixel changes, and then draw it to the temporary canvas... adding it to the rest of the elements....THEEENNN draw it all to the main canvas. Does not work. See code. Please help, Im mad enough to chew neutronium.
<!DOCTYPE HTML>
<html>
<head>
</head>
<body>
<canvas id="theCanvas" width="200" height="200" style="border:2px solid #000000;"></canvas>
<canvas id="tempCanvas" width="200" height="200" style="display:none;"></canvas>
<canvas id="anotherCanvas" width="200" height="200" style="display:none;"></canvas>
<form>
<input type="button" id="changeColor" value="Click to Change Color of Graphic">
</form>
<script type="text/javascript" src="hereWeGoAgain_GHELP.js"></script>
</body>
</html>
//------------------------------------- JS
window.addEventListener("load", eventWindowLoaded, false);
function eventWindowLoaded () {
canvasApp();
}
function canvasApp() {
var canvas = document.getElementById('theCanvas');// the main canvas, where it all goes in the end
var context = canvas.getContext('2d');
var tempCanvas = document.getElementById('tempCanvas');// the canvas to do my "source-atop" stuff...
var tempContext = tempCanvas.getContext('2d');
var anotherCanvas = document.getElementById('anotherCanvas');
var anotherContext = anotherCanvas.getContext('2d');
// ...and Im thinking I should draw the RGBA PNG here, before placing it in the temp canvas, with the other elements
var cc = document.getElementById('changeColor');
cc.addEventListener('click', function(){changeColorFunction('ff0000');}, false);
// the HTML form button to change the PNG color
var colorOfThePlacedPNG = "#000000";
var imagesToLoad = 0;
var imagesLoaded = 0;
function drawScreen() {
tempContext.fillStyle="#999999";
tempContext.fillRect(0,0,200,200); //color the whole temp canvas area grey....
tempContext.fillStyle="#2baae1";
tempContext.fillRect(30,30,140,140);//now draw a light blue rect inside....
tempContext.globalCompositeOperation="source-atop"; // now make everything drawn AFTERWARDS be clipped (masked) inside the blue rect
// when I comment out the above "global Comp Op"... everything draws to the main canvas normally...just not clipped(masked) however
tempContext.fillStyle="#f47e1f";
tempContext.fillRect(150,100,150,150);//SO heres an orange box intentionally clipped off the bottom right in the blue rect
tempContext.fillStyle="#d89bc5";
tempContext.fillRect(40,50,80,200);//AND heres a light purple rect intentionally clipped at the bottom of the blue rect
getTheImageData(); //draw PNG to another canvas, convert image data, put in tempContext
//tempContext.restore();//dont know if I need this
context.drawImage(tempCanvas, 0, 0);// and then FINALLY draw all to the main canvas
}
var loaded = function(){
imagesLoaded += 1;
if(imagesLoaded === imagesToLoad){
drawScreen();
}
}
var loadImage = function(url){
var image = new Image();
image.addEventListener("load",loaded);
imagesToLoad += 1;
image.src = url;
return image;
}
function changeColorFunction(e) {
colorOfThePlacedPNG = e;
drawScreen();
}
function getTheImageData(){
anotherContext.drawImage(testPNGimage, 0, 0);// draw to the third canvas(another canvas)
var imgData = anotherContext.getImageData(0, 0, 200, 200);
// how do i color it red? ....like #ff0000 ???
var i;
for (i = 0; i < imgData.data.length; i += 4) {
imgData.data[i] = 255 - imgData.data[i];
imgData.data[i+1] = 255 - imgData.data[i+1];
imgData.data[i+2] = 255 - imgData.data[i+2];
imgData.data[i+3] = 255;
}
tempContext.putImageData(imgData, 0, 0);
}
var testPNGimage = loadImage("test.png");// the PNG is just a 75X75px black squiggle drawn in pshop
}
You're overcomplicating things!
There is a clipping method built into canvas.
Use clipping instead of compositing and multiple canvases.
Do this and all new drawings will be clipped inside your 140x140 rect:
context.beginPath();
context.rect(30,30,140,140);
context.clip();
Here's a simplified redesign of your code:
Draw a grey rect filling the canvas.
Draw a blue 140x140 rect at [30,30].
Clip all new drawings into the blue rect with context.clip()
Draw a clipped orange rect.
Draw a clipped purple rect.
Unclip so new drawings will be visible anywhere on the canvas.
Draw the squiggle image (it's not clipped).
Use .getImageData to invert every pixel's color.
And a Demo:
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var cw=canvas.width;
var ch=canvas.height;
var img=new Image();
img.crossOrigin='anonymous';
img.onload=start;
img.src="https://dl.dropboxusercontent.com/u/139992952/multple/squiggle.png";
function start(){
//color the whole canvas area grey....
ctx.fillStyle="#999999";
ctx.fillRect(0,0,200,200);
//now draw a light blue rect inside....
ctx.fillStyle="#2baae1";
ctx.beginPath();
ctx.rect(30,30,140,140);
ctx.fill();
// save the unclipped context state
ctx.save();
// cause all new drawings to be clipped inside
// the blue 140x140 rect at [30,30]
ctx.clip();
//SO heres an orange box intentionally clipped off the bottom right in the blue rect
ctx.fillStyle="#f47e1f";
ctx.fillRect(150,100,150,150);
//AND heres a light purple rect intentionally clipped at the bottom of the blue rect
ctx.fillStyle="#d89bc5";
ctx.fillRect(40,50,80,200);
// restore the context state (releases clipping for new drawings)
ctx.restore();
// draw the squiggley line image -- it's not clipped in the blue rect
ctx.drawImage(img,0,0);
// invert the colors using getImageData
var imgData = ctx.getImageData(0, 0, 200, 200);
var i;
for (i = 0; i < imgData.data.length; i += 4) {
imgData.data[i] = 255 - imgData.data[i];
imgData.data[i+1] = 255 - imgData.data[i+1];
imgData.data[i+2] = 255 - imgData.data[i+2];
imgData.data[i+3] = 255;
}
ctx.putImageData(imgData, 0, 0);
}
body{ background-color: ivory; }
#canvas{border:1px solid red; margin:0 auto; }
<canvas id="canvas" width=200 height=200></canvas>
As starting point I have a image on my canvas:
var canvas = $('canvas')[0];
var ctx=canvas.getContext("2d");
var img=document.getElementById("scream");
ctx.drawImage(img,0,0,240,297);
Now I would like to add a frame to this Image on the same canvas. For this:
I first replace the image with the Frame.
Next I try to copy the old canvas content inside of this frame
I try to do this like that:
var frame = document.getElementById("frame");
var ctx = $('canvas')[0].getContext("2d");
var dst = ctx.canvas;
ctx.drawImage(frame,0,0, 240, 297);
ctx.drawImage(dst, 40, 40);
But the code is not working because it copies the frame again to the canvas instead of the image: Here you can see a demo: https://jsfiddle.net/35mxfsv0/
What do I wrong? What do I have to change? Thanks
As you just assign the original canvas to dst, when you draw anything on that canvas, the dst will also changed (because they're pointing to same canvas).
So you have to assign a new canvas to dst, and draw the image from origin to dst, then draw the frame on origin, and last, draw dst's image to origin.
window.onload = function() { // Make it safe that window.onload ensures all images loaded.
var canvas = $('canvas')[0];
var ctx=canvas.getContext("2d");
var img=document.getElementById("scream");
ctx.drawImage(img,0,0,240,297);
//START OF MY CODE
var frame = document.getElementById("frame");
// Comment out as we demo in same scope, ctx is already have what we want.
//var ctx = $('canvas')[0].getContext("2d");
// Create a new canvas, and draw the image on the origin canvas to it.
var dst = document.createElement('canvas');
dst.width = canvas.width;
dst.height = canvas.height;
var dstCtx = dst.getContext('2d');
dstCtx.drawImage(canvas, 0, 0);
// Above is what you suppose the canvas should do.
//var dst = ctx.canvas;
// Draw frame
ctx.drawImage(frame,0,0, 240, 297);
// As your frame is not an opacity one, you have to copy to specific position.
ctx.drawImage(dst, 0, 0, dst.width, dst.height, 10, 10, 220, 277);
}
img{display:none}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<canvas id="myCanvas" width="240" height="297" style="border:1px solid #d3d3d3;">
</canvas>
<img src="http://www.w3schools.com/tags/img_the_scream.jpg" id="scream"/>
<img src="http://www.wpclipart.com/page_frames/picture_frames/wood_picture_frame.jpg" id="frame"/>
However, if you still have the access to that scream image, you can just draw frame first, then draw image on it:
var canvas = $('canvas')[0];
var ctx=canvas.getContext("2d");
var img=document.getElementById("scream");
var frame = document.getElementById("frame");
ctx.drawImage(frame,0,0, 240, 297);
// 10, 10 seems to fit the frame.
ctx.drawImage(img, 10, 10);
Please change id of your html and js file.