Draw a trapezoid in canvas - html

Could somebody advice how to transform image on canvas from rectangle to trapeze?
For example I have a image-rectangle 100x200 and canvas 300x300.
Then I want to transform my image and put corners in the following points:
100,0; 200,0;
0,300; 300,300
And transformation should re-size image to fit new figure.

I get it, you want to do a y-rotation (like the star wars scrolling intro).
Not possible with the current canvas 2d context transform matrix
The 2d transformation matrix looks like this with the last values fixed at 0,0,1:
M11, M21, dx
M12, M22, dy
0, 0, 1
You would need a y-rotation matrix that looks like this:
cosA, 0, sinA
0, 1, 0
-sinA, 0, cosA
But you can't set -sinA, 0, cosA
[Previous answer]
Here's how you change an rectangle-containing-image to a trapezoid-containing-image
You have to draw each leg of the trapeze individually. But you can draw 3 of the sides and then use closePath() to automatically draw the 4th side.
This code animates between the rectangle and the trapezoid and scales the clipped image. This code assumes you want the image presented in a way that keeps the scaling image as large as possible.
Here's code and a Fiddle: http://jsfiddle.net/m1erickson/7T2YQ/
<!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>
<style>
body{ background-color: ivory; padding:20px;}
canvas{border:1px solid red;}
</style>
<script>
$(function(){
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
ctx.lineWidth=5;
window.requestAnimFrame = (function(callback) {
return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame ||
function(callback) {
window.setTimeout(callback, 1000 / 60);
};
})();
var left=1.0;
var right=300;
var sizing=.25;
var img=new Image();
img.onload=function(){
animate();
}
img.src="http://dl.dropbox.com/u/139992952/stackoverflow/KoolAidMan.png";
function animate() {
// update scaling factors
left+=sizing;
right-=sizing;
if(left<0 || left>100){sizing = -sizing;}
console.log(left+"/"+right);
// clear and save the context
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.save();
// draw the clipping trapezoid
defineTrapezoid(left,right);
ctx.clip();
// draw trapezoid border
defineTrapezoid(left,right);
ctx.stroke();
// draw image clipped in trapeze
var imgX=left/2;
var imgY=left;
var w=300-left;
ctx.drawImage(img,0,0,img.width,img.height,imgX,imgY,w,w);
ctx.restore();
// request new frame
requestAnimFrame(function() {
animate();
});
}
animate();
function defineTrapezoid(left,right){
ctx.beginPath();
ctx.moveTo(left,0);
ctx.lineTo(right,0);
ctx.lineTo(300,300);
ctx.lineTo(0,300);
ctx.closePath();
}
}); // end $(function(){});
</script>
</head>
<body>
<canvas id="canvas" width=300 height=300></canvas>
</body>
</html>

Related

HTML Canvas, How do you create a circle at the position of the mouse when clicked and then for the circle to increase in radius?

So, I have tried attempting this myself and have searched heavily online and I can't seem to solve this particular issue. I am attempting to make a very simple effect that looks like a very basic water ripple. I intend for the user to be able to click somewhere on the canvas, and for an empty circle (with a black stroke) to appear where the mouse has clicked (starting at a radius of zero), and continuously expand the radius as an animation.
I currently have this code:
<!DOCTYPE html>
<html>
<head>
<!-- Search Engine Optimisation (SEO) -->
<title> Ripple </title>
<meta description="Codelab assignment 3">
<meta keywords="Uni, assignment, ripple, interactive, discovery">
<!-- End of Metadata -->
<!-- Links -->
<link rel="stylesheet" type="text/css" href="style.css">
</head>
<body>
<canvas id="myCanvas" width="1024" height="768" style="border: 1px solid"></canvas>
</body>
<script type="text/javascript">
var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
var canvasWidth = canvas.width;
var canvasHeight = canvas.height;
var radius = 0;
//Have a rectangle fill the canvas and add a hit region
//Call the ripple function from the rectangle function
//Track mouse position in rectangle
function ripple(e) {
// ctx.clearRect(0, 0, canvasWidth, canvasHeight);
ctx.beginPath();
ctx.arc(e.clientX,e.clientY,radius,0,2*Math.PI);
//ctx.closePath();
ctx.stokeStyle = "black";
ctx.stroke();
radius++;
requestAnimationFrame(ripple);
}
canvas.addEventListener('mousedown', ripple);
</script>
</html>
This is what it currently does:
Screenshot
I really appreciate any help!
You'd have to pass the mouse event when calling the ripple function through requestAnimationFrame.
also, you'll need to set the radius to 0 and clear running animation frame (if any) on mouse click
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var canvasWidth = canvas.width;
var canvasHeight = canvas.height;
var radius = 0;
var rAF;
function ripple(e) {
ctx.clearRect(0, 0, canvasWidth, canvasHeight);
ctx.beginPath();
ctx.arc(e.offsetX, e.offsetY, radius, 0, 2 * Math.PI);
ctx.stokeStyle = "black";
ctx.stroke();
radius++;
rAF = requestAnimationFrame(function() {
ripple(e);
});
}
canvas.addEventListener('mousedown', function(e) {
if (rAF) cancelAnimationFrame(rAF);
radius = 0;
ripple(e);
});
body{margin:10px 0 0 0;overflow:hidden}canvas{border:1px solid #ccc}
<canvas id="canvas" width="635" height="208"></canvas>
note: use e.offsetX and e.offsetY to get proper mouse coordinates relative to canvas.

inclined calendar with html5 and css3 and / or any other idea

I need something like the picture shown in the link below, I have no idea how to do it, the most important think is that the calendar is generated dynamically.... this calendar 'll display in a web page.
Interesting project!
You can use canvas transforms to radiate your calendar around a centerpoint.
A Demo: http://jsfiddle.net/m1erickson/Q7S9L/
The idea is to draw a line of your calendar vertically into a column:
And then rotate that column using canvas transforms.
Transforms include context.translate (which moves) and context.rotate (which rotates)
// save the context state
ctx.save();
// translate to the centerpoint around which we will rotate the column
ctx.translate(cx,cy);
// rotate the canvas (which will rotate the column)
ctx.rotate( desiredRadianAngle );
// now draw the column and it will be rotated to the desired angle
Here's example code:
<!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>
<style>
body{ background-color: ivory; }
canvas{border:1px solid red;}
</style>
<script>
$(function(){
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var year=2014;
var PI2=Math.PI*2;
var cx=375;
var cy=375;
var radialIncrement=15;
var rotationIncrement=-Math.PI/31;
var months=['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'];
var days=[31,28,31,30,31,30,31,31,30,31,30,31];
var dayNames=['Su','M','Tu','W','Th','F','Sa','Su','M','Tu','W','Th','F','Sa','Su','M','Tu','W','Th','F','Sa','Su','M','Tu','W','Th','F','Sa','Su','M','Tu','W','Th','F','Sa','Su','M','Tu','W','Th','F','Sa'];
var monthsFirstWeekday=[]
for(var m=1;m<=12;m++){
monthsFirstWeekday.push(new Date(m+"/01/"+year).getDay());
}
for(var d=0;d<=38;d++){
ctx.save();
ctx.translate(cx,cy);
ctx.rotate(rotationIncrement*(31-d)+Math.PI/2);
var x=-3;
var y=-13*radialIncrement-150;
ctx.font="12px verdana";
ctx.fillStyle="blue";
ctx.fillText(dayNames[d],x,y);
ctx.restore();
}
for(var m=0;m<months.length;m++){
ctx.save();
ctx.translate(cx,cy+25);
ctx.rotate(Math.PI*3/2);
ctx.fillStyle="blue";
ctx.fillText(months[m],0,-(months.length-m)*radialIncrement-150);
ctx.restore();
}
for(var d=0;d<=38;d++){
ctx.save();
ctx.translate(cx,cy);
ctx.rotate(rotationIncrement*(31-d)+Math.PI/2);
for(var m=0;m<months.length;m++){
var x=0;
var y=-(months.length-m)*radialIncrement-150;
var dd=d-monthsFirstWeekday[m]+1;
if(dd>0 && dd<=days[m]){
ctx.fillStyle="black";
ctx.fillText(dd,x,y);
}else{
ctx.beginPath();
ctx.arc(x+3,y,1,0,Math.PI*2);
ctx.closePath();
ctx.fillStyle="red";
ctx.fill();
}
}
ctx.restore();
}
}); // end $(function(){});
</script>
</head>
<body>
<canvas id="canvas" width=775 height=650></canvas>
</body>
</html>

HTML Canvas: Rotate the Image 3D effect

How can i rotate the image (eg. to 45degrees) and squash the image. supposed i have a perfect square image. I can rotate it to any angle i want but i want to make the rotated square squashed, making the height 2/3 smaller than the width. the resulting image would be not a perfect rotated square but a squashed one.
do you know how can I achieve the effect?
Squishing a square is exceedingly easy, simply apply a scale:
ctx.scale(1, 2/3); // squish it to 2/3 vertical size
You'll have to translate it by the (opposite fraction * the height) / 2 to get it centered, though.
So to rotate and then squish a 200x200 square image you'd simply:
// rotation first
ctx.translate(100,100);
ctx.rotate(.3);
ctx.translate(-100,-100);
// than scale
ctx.translate(0,200 * (1/3) / 2) // move by half of the 1/3 space to center it
ctx.scale(1, 2/3); // squish it to 2/3 vertical size
ctx.drawImage(img, 0,0);
Example: http://jsfiddle.net/simonsarris/3Qr3S/
You can use 2D canvas to “fake” 3d by distorting width vs height
Do this by using context.drawImage and varying the width vs the height disproportionally
// draw image increasingly "squashed"
// to fake a 3d effect
ctx.drawImage(img,0,0,img.width,img.height,
left,
10,
(300-(right-left))/1,
300-(right-left)/1.5);
You can play with the distortion ratios to get different effects, but it’s all just “squishing”.
Here’s code and a Fiddle: http://jsfiddle.net/m1erickson/J2WfS/
<!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>
<style>
body{ background-color: ivory; padding:20px;}
canvas{border:1px solid red;}
</style>
<script>
$(function(){
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
window.requestAnimFrame = (function(callback) {
return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame ||
function(callback) {
window.setTimeout(callback, 1000 / 60);
};
})();
var left=1.0;
var right=300;
var sizing=.25;
var img=new Image();
img.onload=function(){
animate();
}
img.src="koolaidman.png";
function animate() {
// update scaling factors
left+=sizing;
right-=sizing;
if(left<0 || left>100){sizing = -sizing;}
console.log(left+"/"+right);
// clear and save the context
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.save();
// draw image increasingly "squashed"
// to fake a 3d effect
ctx.drawImage(img,0,0,img.width,img.height,
left,
10,
(300-(right-left))/1,
300-(right-left)/1.5);
ctx.restore();
// request new frame
requestAnimFrame(function() {
animate();
});
}
animate();
}); // end $(function(){});
</script>
</head>
<body>
<canvas id="canvas" width=300 height=235></canvas>
</body>
</html>

Canvas: Click event on line

Please take a look at this little example. The clickhandler only works if you click in the middle of the line. It seems that the method isPointInPath does not consider the width of the line. Is there a way to solve this problem?
Yes, you are correct.
The new isPointInPath() works only on the centerline of a "fat" line--not the full width of the line.
It's more user friendly on closed shapes that are more than 1 pixel wide ;)
A Workaround for your exact question: Instead of drawing a fat line, draw a 20px wide rectangle.
Here is code and a Fiddle: http://jsfiddle.net/m1erickson/QyWDY/
This code uses basic trigonometry to create a rectangle around a line. In the mousedown event handler, it redraws the rectangle transparently and then tests isPointInPath().
If you need to test a poly-line, you can use these same principles to make rectangle-lines for each segment of your poly-line.
<!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>
<style>
body{ background-color: ivory; }
canvas{border:1px solid red;}
</style>
<script>
$(function(){
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
// get canvas's relative position
var canvasOffset=$("#canvas").offset();
var offsetX=canvasOffset.left;
var offsetY=canvasOffset.top;
// line specifications
var x1=50;
var y1=50;
var x2=300;
var y2=100;
// draw the lineRectangle
var lineRect=defineLineAsRect(x1,y1,x2,y2,20);
drawLineAsRect(lineRect,"black");
// overlay the line (just as visual proof)
drawLine(x1,y1,x2,y2,3,"red");
function drawLine(x1,y1,x2,y2,lineWidth,color){
ctx.fillStyle=color;
ctx.strokeStyle=color;
ctx.lineWidth=lineWidth;
ctx.save();
ctx.beginPath();
ctx.moveTo(x1,y1);
ctx.lineTo(x2,y2);
ctx.stroke();
ctx.restore();
}
function drawLineAsRect(lineAsRect,color){
var r=lineAsRect;
ctx.save();
ctx.beginPath();
ctx.translate(r.translateX,r.translateY);
ctx.rotate(r.rotation);
ctx.rect(r.rectX,r.rectY,r.rectWidth,r.rectHeight);
ctx.translate(-r.translateX,-r.translateY);
ctx.rotate(-r.rotation);
ctx.fillStyle=color;
ctx.strokeStyle=color;
ctx.fill();
ctx.stroke();
ctx.restore();
}
function defineLineAsRect(x1,y1,x2,y2,lineWidth){
var dx=x2-x1; // deltaX used in length and angle calculations
var dy=y2-y1; // deltaY used in length and angle calculations
var lineLength= Math.sqrt(dx*dx+dy*dy);
var lineRadianAngle=Math.atan2(dy,dx);
return({
translateX:x1,
translateY:y1,
rotation:lineRadianAngle,
rectX:0,
rectY:-lineWidth/2,
rectWidth:lineLength,
rectHeight:lineWidth
});
}
function handleMouseDown(e){
mouseX=parseInt(e.clientX-offsetX);
mouseY=parseInt(e.clientY-offsetY);
// draw our lineRect
drawLineAsRect(lineRect,"transparent");
// test if hit in the lineRect
if(ctx.isPointInPath(mouseX,mouseY)){
alert('Yes');
}
}
canvas.addEventListener("mousedown", handleMouseDown, false);
}); // end $(function(){});
</script>
</head>
<body>
<canvas id="canvas" width=310 height=115></canvas>
</body>
</html>

duplicate wheel and move wheels forwards

This code is diplaying a rotating wheel. What I want to achieve is to duplicate the wheel and re position the duplicate and move both wheels forwards. Just like the wheels of a car looks like. I´m very new with canvas. Thanks in advance
<html>
<head>
<script type="text/javascript">
addEventListener("load", windowLoaded, false);
function windowLoaded()
{
canvasApp();
}
function canvasApp()
{
var canvas = document.getElementById("canvas01");
var context = canvas.getContext("2d");
var wiel = new Image();
wiel.src = "wiel.png";
setInterval(draw, 25);
function draw(width)
{
context.clearRect(width, 0, 800, 600)
context.drawImage(wiel, 0, 0);
context.translate(176, 176);
context.rotate(1 * 0.1);
context.translate(-176, -176);
}
}
</script>
</head>
<body>
<canvas id="canvas01" width="800" height="600">
no support
</canvas>
</body>
</html>
Here is how you animate 2 rotating "wheels" across the canvas: http://jsfiddle.net/m1erickson/Yv62X/
The “window.requestAnimFrame” is there for cross-browser compatibility—thanks to Paul Irish for this useful feature.
Notice that RequestAnimFrame() is now preferred over setInterval() for concurrent animations, etc.
The animate() function goes through these steps:
Update: calculates the position & rotation required in this animation frame.
Clear: clears the canvas to make it ready for drawing
Draw: calls the draw() function which does the actual drawing
The draw() function: We draw both wheels using this same function—just changing the attributes. This follows an important programming concept of “DRY”—Don’t Repeat Yourself. Two wheels in a single function makes for easier debugging, more readable and more maintainable code.
<!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>
<style>
body{ background-color: ivory; }
canvas{border:1px solid red;}
</style>
<script>
$(function(){
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
window.requestAnimFrame = (function(callback) {
return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame ||
function(callback) {
window.setTimeout(callback, 1000 / 60);
};
})();
var rotation=0;
var radius=50;
var x=50;
var y=100;
var direction=1;
function animate() {
// update
rotation+=10;
x+=1;
if(x-50>canvas.width){ x=0 }
// clear
ctx.clearRect(0, 0, canvas.width, canvas.height);
// draw stuff
draw(x,y,rotation,"red");
draw(x+150,y,rotation,"green");
// request new frame
requestAnimFrame(function() {
animate();
});
}
animate();
function draw(x,y,degrees,color){
var radians=degrees*(Math.PI/180);
ctx.save();
ctx.beginPath();
ctx.translate(x,y);
ctx.rotate(radians);
ctx.fillStyle="black";
ctx.strokeStyle="gray";
ctx.arc(0, 0, radius, 0 , 2 * Math.PI, false);
ctx.fill();
ctx.stroke();
ctx.beginPath();
ctx.strokeStyle=color;
ctx.lineWidth=5;
ctx.moveTo(-20,0);
ctx.lineTo(+20,0);
ctx.stroke();
ctx.restore();
}
}); // end $(function(){});
</script>
</head>
<body>
<canvas id="canvas" width=400 height=200></canvas>
</body>
</html>