my script isn't working. It was supposed to create random circles all touching the bottom of the canvas, with their radius shrinking each circle by the number of circles.
Here is the code:
for (var i = 0; i < NUM_CIRCLES; i++){
var circle = new Circle(radius);
circle.setPosition(CENTER_X,CENTER_Y);
circle.setColor(color);
add(circle);
radius /= i;
CENTER_Y = getHeight() - radius;
color = Randomizer.nextColor();
}
Ok so here is the full code:
var NUM_CIRCLES = 30;
var BIG_RADIUS = 180;
var color = Randomizer.nextColor();
var radius = BIG_RADIUS;
var CENTER_X = getWidth() / 2;
var CENTER_Y = getHeight() - radius;
function start(){
for (var i = 0; i < NUM_CIRCLES; i++){
var circle = new Circle(radius);
circle.setPosition(CENTER_X,CENTER_Y);
circle.setColor(color);
add(circle);
radius /= i;
CENTER_Y = getHeight() - radius;
color = Randomizer.nextColor();
}
}
as far as i understand you are trying to produce circles from bigger to smaller reducing radius of them by number of circles
to achive that do eachReduce = radius / numberofcircles and use it as eachReduce constant to reduce each circle by that number to achieve bigger to smaller size till zero
take a look at below example
let numofcir = 10,
radius = 80,
reduceEachBy = radius / numofcir,
offset = radius / 2
function setup() {
createCanvas(640, 360);
noLoop()
}
function draw() {
background(0)
stroke(255)
noFill()
for(let i=0;i < numofcir;i++){
// in p5 ellipse creates circle by x and y radius
ellipse(offset + (i * offset),150,radius,radius)
radius -= reduceEachBy
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.0/p5.min.js" integrity="sha512-N4kV7GkNv7QR7RX9YF/olywyIgIwNvfEe2nZtfyj73HdjCUkAfOBDbcuJ/cTaN04JKRnw1YG1wnUyNKMsNgg3g==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
How can i rotate a image 45 degrees contained in an ImageData object?
https://developer.mozilla.org/en/docs/Web/API/ImageData
I do not want to do that with canvas i just want for ImageData.
Scan line rendering.
Why in imageData?? it is very slow
You can use a scan line renderer. This scans across the new (destination) row by row, calculating the x,y coordinate of the pixel at that point and then setting the color to match.
The example rotates the image via the image data array. the Rotation amount and the rotation center are set and a very simple matrix (ax,ay,ox,oy) is created to rotate a scan pixel (x,y) into a lookup pixel (rx,ry). The solution is a nearest neighbour lookup, but you can create a bilinear, or tri etc by interpreting the pixel colors via the fractional remainder of the rx,ry pixel locations.
const ctx = canvas.getContext("2d");
const randI = (min, max = min + (min = 0)) => (Math.random() * (max - min) + min) | 0;
const doFor = (count, cb) => { var i = 0; while (i < count && cb(i++) !== true); };
doFor(150,i=>{
ctx.fillStyle = "hsl("+randI(360)+",100%,50%)";
ctx.fillRect(randI(canvas.width),randI(canvas.height),randI(10,20),randI(10,20));
});
ctx.font = "28px Arial black";
ctx.textAlign = "center";
ctx.fillStyle = "black";
ctx.strokeStyle = "white";
ctx.lineWidth = "5";
ctx.lineJoin = "round";
ctx.strokeText("Rotate me!",128,128);
ctx.fillText("Rotate me!",128,128);
// the rotation origin
const ox = 128;
const oy = 128;
// the rotation amount
const rot = Math.PI / 4; // 45 deg
// the rotated x axis
const ax = Math.cos(rot); // 45 deg
const ay = Math.sin(rot); // 45 deg
// get the source pixel data
const imageData = ctx.getImageData(0,0,256,256);
const d32 = new Uint32Array(imageData.data.buffer);
// create a destination pixel array
const rotImageData = new Uint32Array(imageData.data.length/4);
// scan each pixel and row adding pixels to rotImageData from the transformed
// x,y coordinate.
for(y = 0; y < 256; y += 1){
for(x = 0; x < 256; x += 1){
const ind = (x + y * 256);
// transform the current pixel to the rotated pixel
const rx = (x - ox) * ax - (y-oy) * ay + ox;
const ry = (x - ox) * ay + (y-oy) * ax + oy;
// use nearest pixel lookup and get index of original image
const ind1 = ((rx | 0) + (ry | 0) * 256);
rotImageData[ind] = d32[ind1];
}
}
// create a second canvas
var c1 = document.createElement("canvas");
c1.width = 256;
c1.height = 256;
var ctx1 = c1.getContext("2d");
// put the new image data into the imageData array
d32.set(rotImageData);
// and put that on the new canvas
ctx1.putImageData(imageData,0,0);
// add the canvas to the page
document.body.appendChild(c1);
canvas {border : 2px solid black;}
<canvas id="canvas" width=256 height=256></canvas>
I'm making an HTML5 canvas hexagon grid based system and I need to be able to detect what hexagonal tile in a grid has been clicked when the canvas is clicked.
Several hours of searching and trying my own methods led to nothing, and porting implementations from other languages has simply confused me to a point where my brain is sluggish.
The grid consists of flat topped regular hexagons like in this diagram:
Essentially, given a point and the variables specified in this image as the sizing for every hexagon in the grid (R, W, S, H):
I need to be able to determine whether a point is inside a hexagon given.
An example function call would be pointInHexagon(hexX, hexY, R, W, S, H, pointX, pointY) where hexX and hexY are the coordinates for the top left corner of the bounding box of a hexagonal tile (like the top left corner in the image above).
Is there anyone who has any idea how to do this? Speed isn't much of a concern for the moment.
Simple & fast diagonal rectangle slice.
Looking at the other answers I see that they have all a little over complicated the problem. The following is an order of magnitude quicker than the accepted answer and does not require any complicated data structures, iterators, or generate dead memory and unneeded GC hits. It returns the hex cell row and column for any related set of R, H, S or W. The example uses R = 50.
Part of the problem is finding which side of a rectangle a point is if the rectangle is split diagonally. This is a very simple calculation and is done by normalising the position of the point to test.
Slice any rectangle diagonally
Example a rectangle of width w, and height h split from top left to bottom right. To find if a point is left or right. Assume top left of rectangle is at rx,ry
var x = ?;
var y = ?;
x = ((x - rx) % w) / w;
y = ((y - ry) % h) / h;
if (x > y) {
// point is in the upper right triangle
} else if (x < y) {
// point is in lower left triangle
} else {
// point is on the diagonal
}
If you want to change the direction of the diagonal then just invert one of the normals
x = 1 - x; // invert x or y to change the direction the rectangle is split
if (x > y) {
// point is in the upper left triangle
} else if (x < y) {
// point is in lower right triangle
} else {
// point is on the diagonal
}
Split into sub cells and use %
The rest of the problem is just a matter of splitting the grid into (R / 2) by (H / 2) cells width each hex covering 4 columns and 2 rows. Every 1st column out of 3 will have diagonals. with every second of these column having the diagonal flipped. For every 4th, 5th, and 6th column out of 6 have the row shifted down one cell. By using % you can very quickly determine which hex cell you are on. Using the diagonal split method above make the math easy and quick.
And one extra bit. The return argument retPos is optional. if you call the function as follows
var retPos;
mainLoop(){
retPos = getHex(mouse.x, mouse.y, retPos);
}
the code will not incur a GC hit, further improving the speed.
Pixel to Hex coordinates
From Question diagram returns hex cell x,y pos. Please note that this function only works in the range 0 <= x, 0 <= y if you need negative coordinates subtract the min negative pixel x,y coordinate from the input
// the values as set out in the question image
var r = 50;
var w = r * 2;
var h = Math.sqrt(3) * r;
// returns the hex grid x,y position in the object retPos.
// retPos is created if not supplied;
// argument x,y is pixel coordinate (for mouse or what ever you are looking to find)
function getHex (x, y, retPos){
if(retPos === undefined){
retPos = {};
}
var xa, ya, xpos, xx, yy, r2, h2;
r2 = r / 2;
h2 = h / 2;
xx = Math.floor(x / r2);
yy = Math.floor(y / h2);
xpos = Math.floor(xx / 3);
xx %= 6;
if (xx % 3 === 0) { // column with diagonals
xa = (x % r2) / r2; // to find the diagonals
ya = (y % h2) / h2;
if (yy % 2===0) {
ya = 1 - ya;
}
if (xx === 3) {
xa = 1 - xa;
}
if (xa > ya) {
retPos.x = xpos + (xx === 3 ? -1 : 0);
retPos.y = Math.floor(yy / 2);
return retPos;
}
retPos.x = xpos + (xx === 0 ? -1 : 0);
retPos.y = Math.floor((yy + 1) / 2);
return retPos;
}
if (xx < 3) {
retPos.x = xpos + (xx === 3 ? -1 : 0);
retPos.y = Math.floor(yy / 2);
return retPos;
}
retPos.x = xpos + (xx === 0 ? -1 : 0);
retPos.y = Math.floor((yy + 1) / 2);
return retPos;
}
Hex to pixel
And a helper function that draws a cell given the cell coordinates.
// Helper function draws a cell at hex coordinates cellx,celly
// fStyle is fill style
// sStyle is strock style;
// fStyle and sStyle are optional. Fill or stroke will only be made if style given
function drawCell1(cellPos, fStyle, sStyle){
var cell = [1,0, 3,0, 4,1, 3,2, 1,2, 0,1];
var r2 = r / 2;
var h2 = h / 2;
function drawCell(x, y){
var i = 0;
ctx.beginPath();
ctx.moveTo((x + cell[i++]) * r2, (y + cell[i++]) * h2)
while (i < cell.length) {
ctx.lineTo((x + cell[i++]) * r2, (y + cell[i++]) * h2)
}
ctx.closePath();
}
ctx.lineWidth = 2;
var cx = Math.floor(cellPos.x * 3);
var cy = Math.floor(cellPos.y * 2);
if(cellPos.x % 2 === 1){
cy -= 1;
}
drawCell(cx, cy);
if (fStyle !== undefined && fStyle !== null){ // fill hex is fStyle given
ctx.fillStyle = fStyle
ctx.fill();
}
if (sStyle !== undefined ){ // stroke hex is fStyle given
ctx.strokeStyle = sStyle
ctx.stroke();
}
}
I think you need something like this~
EDITED
I did some maths and here you have it. This is not a perfect version but probably will help you...
Ah, you only need a R parameter because based on it you can calculate H, W and S. That is what I understand from your description.
// setup canvas for demo
var canvas = document.getElementById('canvas');
canvas.width = 300;
canvas.height = 275;
var context = canvas.getContext('2d');
var hexPath;
var hex = {
x: 50,
y: 50,
R: 100
}
// Place holders for mouse x,y position
var mouseX = 0;
var mouseY = 0;
// Test for collision between an object and a point
function pointInHexagon(target, pointX, pointY) {
var side = Math.sqrt(target.R*target.R*3/4);
var startX = target.x
var baseX = startX + target.R / 2;
var endX = target.x + 2 * target.R;
var startY = target.y;
var baseY = startY + side;
var endY = startY + 2 * side;
var square = {
x: startX,
y: startY,
side: 2*side
}
hexPath = new Path2D();
hexPath.lineTo(baseX, startY);
hexPath.lineTo(baseX + target.R, startY);
hexPath.lineTo(endX, baseY);
hexPath.lineTo(baseX + target.R, endY);
hexPath.lineTo(baseX, endY);
hexPath.lineTo(startX, baseY);
if (pointX >= square.x && pointX <= (square.x + square.side) && pointY >= square.y && pointY <= (square.y + square.side)) {
var auxX = (pointX < target.R / 2) ? pointX : (pointX > target.R * 3 / 2) ? pointX - target.R * 3 / 2 : target.R / 2;
var auxY = (pointY <= square.side / 2) ? pointY : pointY - square.side / 2;
var dPointX = auxX * auxX;
var dPointY = auxY * auxY;
var hypo = Math.sqrt(dPointX + dPointY);
var cos = pointX / hypo;
if (pointX < (target.x + target.R / 2)) {
if (pointY <= (target.y + square.side / 2)) {
if (pointX < (target.x + (target.R / 2 * cos))) return false;
}
if (pointY > (target.y + square.side / 2)) {
if (pointX < (target.x + (target.R / 2 * cos))) return false;
}
}
if (pointX > (target.x + target.R * 3 / 2)) {
if (pointY <= (target.y + square.side / 2)) {
if (pointX < (target.x + square.side - (target.R / 2 * cos))) return false;
}
if (pointY > (target.y + square.side / 2)) {
if (pointX < (target.x + square.side - (target.R / 2 * cos))) return false;
}
}
return true;
}
return false;
}
// Loop
setInterval(onTimerTick, 33);
// Render Loop
function onTimerTick() {
// Clear the canvas
canvas.width = canvas.width;
// see if a collision happened
var collision = pointInHexagon(hex, mouseX, mouseY);
// render out text
context.fillStyle = "Blue";
context.font = "18px sans-serif";
context.fillText("Collision: " + collision + " | Mouse (" + mouseX + ", " + mouseY + ")", 10, 20);
// render out square
context.fillStyle = collision ? "red" : "green";
context.fill(hexPath);
}
// Update mouse position
canvas.onmousemove = function(e) {
mouseX = e.offsetX;
mouseY = e.offsetY;
}
#canvas {
border: 1px solid black;
}
<canvas id="canvas"></canvas>
Just replace your pointInHexagon(hexX, hexY, R, W, S, H, pointX, pointY) by the var hover = ctx.isPointInPath(hexPath, x, y).
This is for Creating and copying paths
This is about the Collision Detection
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var hexPath = new Path2D();
hexPath.lineTo(25, 0);
hexPath.lineTo(75, 0);
hexPath.lineTo(100, 43);
hexPath.lineTo(75, 86);
hexPath.lineTo(25, 86);
hexPath.lineTo(0, 43);
function draw(hover) {
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = hover ? 'blue' : 'red';
ctx.fill(hexPath);
}
canvas.onmousemove = function(e) {
var x = e.clientX - canvas.offsetLeft, y = e.clientY - canvas.offsetTop;
var hover = ctx.isPointInPath(hexPath, x, y)
draw(hover)
};
draw();
<canvas id="canvas"></canvas>
I've made a solution for you that demonstrates the point in triangle approach to this problem.
http://codepen.io/spinvector/pen/gLROEp
maths below:
isPointInside(point)
{
// Point in triangle algorithm from http://totologic.blogspot.com.au/2014/01/accurate-point-in-triangle-test.html
function pointInTriangle(x1, y1, x2, y2, x3, y3, x, y)
{
var denominator = ((y2 - y3)*(x1 - x3) + (x3 - x2)*(y1 - y3));
var a = ((y2 - y3)*(x - x3) + (x3 - x2)*(y - y3)) / denominator;
var b = ((y3 - y1)*(x - x3) + (x1 - x3)*(y - y3)) / denominator;
var c = 1 - a - b;
return 0 <= a && a <= 1 && 0 <= b && b <= 1 && 0 <= c && c <= 1;
}
// A Hex is composite of 6 trianges, lets do a point in triangle test for each one.
// Step through our triangles
for (var i = 0; i < 6; i++) {
// check for point inside, if so, return true for this function;
if(pointInTriangle( this.origin.x, this.origin.y,
this.points[i].x, this.points[i].y,
this.points[(i+1)%6].x, this.points[(i+1)%6].y,
point.x, point.y))
return true;
}
// Point must be outside.
return false;
}
Here is a fully mathematical and functional representation of your problem. You will notice that there are no ifs and thens in this code other than the ternary to change the color of the text depending on the mouse position. This whole job is in fact nothing more than pure simple math of just one line;
(r+m)/2 + Math.cos(a*s)*(r-m)/2;
and this code is reusable for all polygons from triangle to circle. So if interested please read on. It's very simple.
In order to display the functionality I had to develop a mimicking model of the problem. I draw a polygon on a canvas by utilizing a simple utility function. So that the overall solution should work for any polygon. The following snippet will take the canvas context c, radius r, number of sides s, and the local center coordinates in the canvas cx and cy as arguments and draw a polygon on the given canvas context at the right position.
function drawPolgon(c, r, s, cx, cy){ //context, radius, sides, center x, center y
c.beginPath();
c.moveTo(cx + r,cy);
for(var p = 1; p < s; p++) c.lineTo(cx + r*Math.cos(p*2*Math.PI/s), cy + r*Math.sin(p*2*Math.PI/s));
c.closePath();
c.stroke();
}
We have some other utility functions which one can easily understand what exactly they are doing. However the most important part is to check whether the mouse is floating over our polygon or not. It's done by the utility function isMouseIn. It's basically calculating the distance and the angle of the mouse position to the center of the polygon. Then, comparing it with the boundaries of the polygon. The boundaries of the polygon can be expressed by simple trigonometry, just like we have calculated the vertices in the drawPolygon function.
We can think of our polygon as a circle with an oscillating radius at the frequency of number of sides. The oscillation's peak is at the given radius value r (which happens to be at the vertices at angle 2π/s where s is the number of sides) and the minimum m is r*Math.cos(Math.PI/s) (each shows at at angle 2π/s + 2π/2s = 3π/s). I am pretty sure the ideal way to express a polygon could be done by the Fourier transformation but we don't need that here. All we need is a constant radius component which is the average of minimum and maximum, (r+m)/2 and the oscillating component with the frequency of number of sides, s and the amplitude value maximum - minimum)/2 on top of it, Math.cos(a*s)*(r-m)/2. Well of course as per Fourier states we might carry on with smaller oscillating components but with a hexagon you don't really need further iteration while with a triangle you possibly would. So here is our polygon representation in math.
(r+m)/2 + Math.cos(a*s)*(r-m)/2;
Now all we need is to calculate the angle and distance of our mouse position relative to the center of the polygon and compare it with the above mathematical expression which represents our polygon. So all together our magic function is orchestrated as follows;
function isMouseIn(r,s,cx,cy,mx,my){
var m = r*Math.cos(Math.PI/s), // the min dist from an edge to the center
d = Math.hypot(mx-cx,my-cy), // the mouse's distance to the center of the polygon
a = Math.atan2(cy-my,mx-cx); // angle of the mouse pointer
return d <= (r+m)/2 + Math.cos(a*s)*(r-m)/2;
}
So the following code demonstrates how you might approach to solve your problem.
// Generic function to draw a polygon on the canvas
function drawPolgon(c, r, s, cx, cy){ //context, radius, sides, center x, center y
c.beginPath();
c.moveTo(cx + r,cy);
for(var p = 1; p < s; p++) c.lineTo(cx + r*Math.cos(p*2*Math.PI/s), cy + r*Math.sin(p*2*Math.PI/s));
c.closePath();
c.stroke();
}
// To write the mouse position in canvas local coordinates
function writeText(c,x,y,msg,col){
c.clearRect(0, 0, 300, 30);
c.font = "10pt Monospace";
c.fillStyle = col;
c.fillText(msg, x, y);
}
// Getting the mouse position and coverting into canvas local coordinates
function getMousePos(c, e) {
var rect = c.getBoundingClientRect();
return { x: e.clientX - rect.left,
y: e.clientY - rect.top
};
}
// To check if mouse is inside the polygone
function isMouseIn(r,s,cx,cy,mx,my){
var m = r*Math.cos(Math.PI/s),
d = Math.hypot(mx-cx,my-cy),
a = Math.atan2(cy-my,mx-cx);
return d <= (r+m)/2 + Math.cos(a*s)*(r-m)/2;
}
// the event listener callback
function mouseMoveCB(e){
var mp = getMousePos(cnv, e),
msg = 'Mouse at: ' + mp.x + ',' + mp.y,
col = "black",
inside = isMouseIn(radius,sides,center[0],center[1],mp.x,mp.y);
writeText(ctx, 10, 25, msg, inside ? "turquoise" : "red");
}
// body of the JS code
var cnv = document.getElementById("myCanvas"),
ctx = cnv.getContext("2d"),
sides = 6,
radius = 100,
center = [150,150];
cnv.addEventListener('mousemove', mouseMoveCB, false);
drawPolgon(ctx, radius, sides, center[0], center[1]);
#myCanvas { background: #eee;
width: 300px;
height: 300px;
border: 1px #ccc solid
}
<canvas id="myCanvas" width="300" height="300"></canvas>
At the redblog there is a full explanation with math and working examples.
The main idea is that hexagons are horizontally spaced by $3/4$ of hexagons size, vertically it is simply $H$ but the column needs to be taken to take vertical offset into account. The case colored red is determined by comparing x to y at 1/4 W slice.
I have a square image like this:
I am trying to stretch this image into a polygon like this:
So far I have been able to create a polygon on the canvas as the above image using the following javascript:
function drawCanvas() {
var c2 = document.getElementById('myCanvas6').getContext('2d');
var img = document.getElementById("scream");
c2.fillStyle = '#000';
c2.beginPath();
c2.moveTo(20, 20);
c2.lineTo(320, 50);
c2.lineTo(320, 170);
c2.lineTo(20, 200);
//c2.drawImage(img, 150, 10, img.width, img.height);
c2.closePath();
c2.fill();
}
I tried using drawImage() method, but it does not stretch the points A, B, C, D to the new positions. Is there anyway this can be achieved?
The 2D canvas is called 2D for a very good reason. You can not transform a square such that any of its side converge (are not parallel) hence 2D
But where there is a need there is always a way..
You can do it by cutting the image into slices and then draw each slice slightly smaller than the last.
We humans don't like to see an image distort when it converges, so you need to add the distortion we expect, perspective. The further away the object the smaller the distance between points appears to the eye.
So the function below draws an image with the top and bottom edges converging..
It is not true 3D but it does make the image appear as distorted as jus converging the top and bottom without decreasing the y step. The animation introduced a bit of an optical illusion. the second render shortens the image to make it appear a little less fake.
See the code on how to use the function.
/** CreateImage.js begin **/
// creates a blank image with 2d context
var createImage=function(w,h){var i=document.createElement("canvas");i.width=w;i.height=h;i.ctx=i.getContext("2d");return i;}
/** CreateImage.js end **/
var can = createImage(512,512);
document.body.appendChild(can);
var ctx = can.ctx;
const textToDisplay = "Perspective"
const textSize = 80;
ctx.font = textSize+"px arial";
var w = ctx.measureText(textToDisplay).width + 8;
var text = createImage(w + 64,textSize + 32);
text.ctx.fillStyle = "#08F";
text.ctx.strokeStyle = "black";
text.ctx.lineWidth = 16;
text.ctx.fillRect(0,0,text.width,text.height);
text.ctx.strokeRect(0,0,text.width,text.height);
text.ctx.font = textSize+"px arial";
text.ctx.fillStyle = "#F80";
text.ctx.strokeStyle = "Black";
text.ctx.lineWidth = 4;
text.ctx.strokeText(textToDisplay,38,textSize + 8);
text.ctx.fillText(textToDisplay,38,textSize + 8);
// Not quite 3D
// ctx is the context to draw to
// image is the image to draw
// x1,x2 left and right edges of the image
// zz1,zz2 top offset for left and right
// image top edge has a slops from zz1 to zz2
// yy if the position to draw top. This is where the top would be if z = 0
function drawPerspective(ctx, image, x1, zz1, x2, zz2, yy){
var x, w, h, h2,slop, topLeft, botLeft, zDistR, zDistL, lines, ty;
w = image.width; // image size
h = image.height;
h2 = h /2; // half height
slop = (zz2 - zz1) / (x2 - x1); // Slope of top edge
z1 = h2 - zz1; // Distance (z) to first line
z2 = (z1 / (h2 - zz2)) * z1 - z1; // distance (z) between first and last line
if(z2 === 0){ // if no differance in z then is square to camera
topLeft = - x1 * slop + zz1; // get scan line top left edge
ctx.drawImage(image,0, 0, w, h,x1, topLeft + yy ,x2-x1, h - topLeft * 2) // render to desination
return;
}
// render each display line getting all pixels that will be on that line
for (x = x1; x < x2; x++) { // for each line horizontal line
topLeft = (x - x1) * slop + zz1; // get scan line top left edge
botLeft = ((x + 1) - x1) * slop + zz1; // get scan line bottom left edge
zDistL = (z1 / (h2 - topLeft)) * z1; // get Z distance to Left of this line
zDistR = (z1 / (h2 - botLeft)) * z1; // get Z distance to right of this line
ty = ((zDistL - z1) / z2) * w; // get y bitmap coord
lines = ((zDistR - z1) / z2) * w - ty;// get number of lines to copy
ctx.drawImage(image,
ty % w, 0, lines, h, // get the source location of pixel
x, topLeft + yy,1 , h - topLeft * 2 // render to desination
);
}
}
var animTick = 0;
var animRate = 0.01;
var pos = 0;
var short = 0;
function update1(){
animTick += animRate;
pos = Math.sin(animTick) * 20 + 20;
short = Math.cos((pos / 40) * Math.PI) * text.width * 0.12 - text.width * 0.12;
ctx.clearRect(0,0,can.width,can.height)
drawPerspective(ctx,text,0,0,text.width,pos,20)
drawPerspective(ctx,text,0,0,text.width+short,pos,textSize + 32 + 30)
requestAnimationFrame(update1);
}
update1();
I think this is a good solution for you: http://jsfiddle.net/fQk4h/
Here is the magic:
for (i = 0; i < w; i++) {
dy = (leftTop * (w - i)) / w;
dh = (leftBot * (w - i) + h * i) / w;
ctx.drawImage(tmpCtx.canvas,
i, 0, 1, h,
i, dy, 1, dh);
}
ctx.restore();