Using same data array every time canvas moving but not continuously?
How to move canvas line left to right with that data array ?
if data array is completed use same data to continuously
here is my code:
<!DOCTYPE html>
<html>
<head>
<title></title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
</head>
<body>
<canvas id="canvas" width="160" height="160" style="background-color: black;"></canvas>
<script type='text/javascript'>
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
ctx.fillStyle ="#dbbd7a";
ctx.fill();
var fps = 1000;
var n = 0;
drawWave();
var data = [
148,149,149,150,150,150,143,82,82,82,82,82,82,82,
148,149,149,150,150,150,143,82,82,82,82,82,82,82,
148,149,149,150,150,150,143,82,82,82,82,82,82,82,
148,149,149,150,150,150,143,82,82,82,82,82,82,82,
148,149,149,150,150,150,143,82,82,82,82,82,82,82,
148,149,149,150,150,150,143,82,82,82,82,82,82,82,
148,149,149,150,150,150,143,82,82,82,82,82,82,82,
148,149,149,150,150,150,143,82,82,82,82,82,82,82,
148,149,149,150,150,150,143,82,82,82,82,82,82,82,
148,149,149,150,150,150,143,82,82,82,82,82,82,82,
];
function drawWave() {
setTimeout(function () {
requestAnimationFrame(drawWave);
ctx.lineWidth="2";
ctx.strokeStyle='green';
ctx.clearRect(0, 0, canvas.width, canvas.height);
// Drawing code goes here
n += 1.5;
if (n > 200) {
n = 0;
}
ctx.beginPath();
for (var x = 0; x < n; x++) {
ctx.lineTo(x, data[x]);
}
ctx.stroke();
}, 1000/fps);
}
</script>
</body>
</html>
There are some problems with your code:
The reason for your non-continuous delay at the end of your animation loop...
Your array has 140 elements but your code is trying to plot 200 elements. The delay is your code trying to plot (200-140) non-existent array elements.
If(n>=data.length) // not n>200 (there are only 140 data elements to process!)
Using setTimeout with a fps interval of 1000 is not achievable (60fps is a practical maximum).
Var fps=60; // not fps=1000 is too fast to be achieved
You are incrementing n by 1.5 each time. This will skip some of your data elements. If this is not your intention you should instead increment n by 1.
n+=1; // not n+=1.5 which will skip some of your data[] elements
You are clearing the canvas and completely redrawing the wave in each animation loop. This works, but instead, keep your previous canvas and add the additional line to plot your next [x,y]. Only clear after you have drawn all your data points.
ctx.beginPath();
ctx.moveTo(n-1,data[n-1]);
ctx.lineTo(n,data[n]);
ctx.stroke();
Here is a Fiddle: http://jsfiddle.net/m1erickson/vPXkm/
[Addition based on OP's new information]
After your further clarification, I might understand what you desire
I think you want to have a wave pattern originate new plots from the left part of the canvas and push the existing data to the right using animation. After all x,y are plotted from your data[] source, you want the plots to repeat at the beginning of data[].
So here is how you do that:
Resize the canvas to twice the width of your data[].
Plot your data across the canvas twice. (data[0-140] and then data[0-140] again).
Convert the canvas to an image.
Resize the canvas to the width of your data[].
Animate the image across the canvas with an increasing offsetX to give the illusion of movement.
When you run out of image, reset the offset.
This reset appears seamless since the image is repeated twice.
Here is new code and another Fiddle: http://jsfiddle.net/m1erickson/qpWrj/
<!DOCTYPE html>
<html>
<head>
<title></title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
</head>
<body>
<canvas id="canvas" width="560" height="160" style="background-color: black;"></canvas>
<script type='text/javascript'>
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var data = [
148,149,149,150,150,150,143,82,82,82,82,82,82,82,
148,149,149,150,150,150,143,82,82,82,82,82,82,82,
148,149,149,150,150,150,143,82,82,82,82,82,82,82,
148,149,149,150,150,150,143,82,82,82,82,82,82,82,
148,149,149,150,150,150,143,82,82,82,82,82,82,82,
148,149,149,150,150,150,143,82,82,82,82,82,82,82,
148,149,149,150,150,150,143,82,82,82,82,82,82,82,
148,149,149,150,150,150,143,82,82,82,82,82,82,82,
148,149,149,150,150,150,143,82,82,82,82,82,82,82,
148,149,149,150,150,150,143,82,82,82,82,82,82,82,148
];
var fps = 30;
var offsetX=-data.length*2;
var waveImage;
createWaveImage();
function createWaveImage(){
// make the canvas double data.length
// and fill it with a background color
canvas.width=data.length*2;
ctx.fillStyle ="#dbbd7a";
ctx.strokeStyle="green";
ctx.lineWidth=2;
ctx.fillRect(0,0,canvas.width,canvas.height);
// plot data[] twice
ctx.beginPath();
ctx.moveTo(0,data[0]);
for(var x=1; x<data.length*2; x++){
var n=(x<data.length)?x:x-data.length;
ctx.lineTo(x,data[n]);
}
ctx.stroke();
// convert the canvas to an image
waveImage=new Image();
waveImage.onload=function(){
// resize the canvas to data.length
canvas.width=data.length;
// refill the canvas background color
ctx.fillStyle ="#dbbd7a";
ctx.fillRect(0,0,canvas.width,canvas.height);
// animate this wave image across the canvas
drawWave();
}
waveImage.src=canvas.toDataURL();
}
// animate the wave image in an endless loop
function drawWave() {
setTimeout(function () {
requestAnimationFrame(drawWave);
// Draw the wave image with an increasing offset
// so it appears to be moving
ctx.drawImage(waveImage,offsetX++,0);
// if we've run out of image, reset the offsetX
if((offsetX)>0){
offsetX=-data.length;
}
}, 1000/fps);
}
</script>
</body>
</html>
Related
I am trying to copy a feature from autocad like this which is the line function.
Things I did:
Ask for the first coordinate
Ask for the second coordinate
Display the final line
Things I want to know how to do:
After the first click (for the first coordinates), I want to display a line each 50ms where the user is putting his cursor even if he isn't clicking
Delete that line every time he changes the cursor position until the user clicks
This is have i have now:
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
function drawLine(first, last) {
ctx.beginPath();
ctx.moveTo(first.x, first.y);
ctx.lineTo(last.x, last.y);
ctx.fill();
ctx.stroke();
}
function getCursorPosition(canvas, event) {
const rect = canvas.getBoundingClientRect();
const x = event.clientX - rect.left;
const y = event.clientY - rect.top;
console.log("x: " + x + " y: " + y);
return {x, y};
}
function lFunction(e) {
const clicked = getCursorPosition(canvas, e);
itteration++;
if (itteration % 2 != 0) {
firstClick = clicked;
} else if (itteration % 2 == 0) {
drawLine(firstClick, clicked);
}
}
lFunction();
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Canvas</title>
</head>
<body>
<canvas id="canvas" height="400" width="400" style="border: 1px solid black"></canvas>
<script src="script.js"></script>
</body>
</html>
If it doesn't work it is because i took it from a bigger file, which I prefer not to share.
Thank you for any help in advance.
I am still a beginner, so please do not be harsh.
P.S: If someone could help me with the degree thing and the auto refreshing length.
One way to achieve this is to 'remember' your line drawing action, update it as the mouse moves, and every 50ms clear the canvas and redraw the most recent line.
var currentLine = {
start: null,
finish: null
}
var currentlyDrawing = false;
var mouseTracker = function(e){
currentLine.finish = getCursorPosition(canvas, e);
}
canvas.addEventListener('click', e => {
if(!currentlyDrawing) {
let position = getCursorPosition(canvas, e);
currentLine.start = position;
currentLine.finish = position;
canvas.addEventListener('mousemove', mouseTracker);
currentlyDrawing = true;
} else {
currentlyDrawing = false;
canvas.removeEventListener('mousemove', mouseTracker);
}
})
setInterval(() => {
ctx.clearRect(0, 0, canvas.width, canvas.height);
drawLine(currentLine.start, currentLine.finish);
}, 50);
Now, obviously this only works for a single line.
The next step is replace currentLine with an array of line. Then your click event handler will create a new line (if it is not currentlyDrawing) and append it to the list of line, and mouseTracker will set the finish property on the last line in the array. Then your timer function will clear the screen, then iterate through the line array and call drawLine on each of them.
Is it possible to make an animation effect on the canvas while moving?
I just need to make an animation movement between canvas' positions,
Like in css3: -webkit-transition-duration: 1s;
Any help is appreciated.
<html>
<head>
<style>
#myCanvas {
-webkit-transition-duration: 1s;
}
</style>
<title>JS Bin</title>
</head>
<body>
<canvas id="myCanvas" width="1280" height="600" style="border:1px solid #d3d3d3;color:red;"></canvas>
<script>
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
var w = document.getElementById("myCanvas");
timer = setInterval(function() {
var f = Math.floor(1+Math.random()*680);
var f2 = Math.floor(1+Math.random()*400);
console.log (f, f2);
ctx.fillStyle="#FF0000";
ctx.clearRect(0, 0, c.width, c.height);
ctx.fillRect(f, f2, 100, 50);
w.onclick = function() {
clearInterval(timer);
falling();
}
}, 300 //the seconds of interval movement)
function falling(){
ctx.clearRect(0,0,c.width,c.height);
ctx.fillRect(500,500,100,50)
}
</script>
</body>
</html>
Sure. If you just want to calculate interim positions along a line from a starting point to an ending point then you can do it like this:
// percentComplete is a number between 0.00 and 1.00
// representing the current progress of the animation from start to end
var x = startingX+(endingX-startingX)*percentComplete;
var y = startingY+(endingY-startingY)*percentComplete;
If you want to animate with flair, then you can use Robert Penner's easing functions to animate in a non-linear way.
To include a fixed duration for your animation you can calculate percentComplete based as:
var percentComplete = elapsedTime / animationDuration;
Hey guys I've been trying to wrap my head around the HTML5 Canvas animation but failed miserably I wanted to achieve the below figure by animating this custom shape in an interval of 10 seconds.
I've pretty much screwed the math of it so I ended up just writing every lineTo statement manually, tried Paul Irish's requestAnimationFrame at the end to animate the line but no luck.
Any help would be highly appreciated, here is
thelive demo
Thanks guys
It's not moving cause you are basically not moving anything - the same shape is drawn to the same position each iteration.
Here is a modified version which animates the pulse to the left (adjust dlt to change speed):
Modified fiddle here
var segX = canvas.width / 6;
var segY = canvas.height / 2;
function draw() {
ctx.clearRect(0,0,canvas.width, canvas.height);
ctx.beginPath();
ctx.moveTo(0, segY);
for(var i = dlt, h = true; i < canvas.width + segX; i += segX) {
if (h) {
ctx.lineTo(i, segY);
ctx.lineTo(i, segY + segX);
} else {
ctx.lineTo(i, segY + segX);
ctx.lineTo(i, segY);
}
h = !h;
}
ctx.stroke();
dlt--;
if (dlt < -segX * 2) dlt = 0;
requestAnimFrame(draw);
}
You're basically needing a function that returns only 2 values--high and low.
Here's a function that returns only low/high values based on a period and oscillation values:
// squared wave
// p = period (how long it takes the wave to fully complete and begin a new cycle)
// o = oscillation (change in wave height)
function squareY(x) {
return( (x%p)<o?o:0 );
}
Demo: http://jsfiddle.net/m1erickson/A69ZV/
Example code:
<!doctype html>
<html>
<head>
<link rel="stylesheet" type="text/css" media="all" href="css/reset.css" />
<script 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");
ctx.lineWidth=3;
var p=30; // period
var o=15; // oscillation
var fps = 60;
var n=0;
animate();
function animate() {
setTimeout(function() {
requestAnimationFrame(animate);
// Drawing code goes here
n+=1.5;
if(n>300){
n=0;
}
ctx.clearRect(0,0,canvas.width,canvas.height);
ctx.beginPath();
for(var x=0;x<n;x++){
var y=squareY(x);
ctx.lineTo(x,y+50);
}
ctx.stroke();
}, 1000 / fps);
}
// squared sine
function squareY(x) {
return( (x%p)<o?o:0 );
}
}); // end $(function(){});
</script>
</head>
<body>
<canvas id="canvas" width=350 height=350></canvas>
</body>
</html>
In HTML5 Canvas, what's the simplest way to draw and move a line over an Image (already on the canvas), preserving the image underneath? (e.g. have a vertical line track the mouse X position)
My current canvas:
$(document).ready(function() {
canvas = document.getElementById("myCanvas");
context = canvas.getContext("2d");
imageObj = new Image();
imageObj.onload = function() {
context.drawImage(imageObj, 0,0);
}
imageObj.src = "http://example.com/some_image.png";
$('#myCanvas').click(doSomething);
});
You will have to do most of the ground-work with canvas which in this case you will have to implement the functionality to move the line and then redraw everything.
The steps can be:
Keep the line as an object which can self-render (method on the object)
Listen to mousemove (in this case) in order to move the line
For each move, redraw background (image) then render the line at its new position
You can redraw the background as a whole or you can optimize it to just draw over the last line.
Here is some example code of this and a live demo here:
var canvas = document.getElementById('demo'), /// canvas element
ctx = canvas.getContext('2d'), /// context
line = new Line(ctx), /// our custom line object
img = new Image; /// the image for bg
ctx.strokeStyle = '#fff'; /// white line for demo
/// start image loading, when done draw and setup
img.onload = start;
img.src = 'http://i.imgur.com/O712qpO.jpg';
function start() {
/// initial draw of image
ctx.drawImage(img, 0, 0, demo.width, demo.height);
/// listen to mouse move (or use jQuery on('mousemove') instead)
canvas.onmousemove = updateLine;
}
Now all we need to do is to have a mechnism to update the background and the line for each move:
/// updates the line on each mouse move
function updateLine(e) {
/// correct mouse position so it's relative to canvas
var r = canvas.getBoundingClientRect(),
x = e.clientX - r.left,
y = e.clientY - r.top;
/// draw background image to clear previous line
ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
/// update line object and draw it
line.x1 = x;
line.y1 = 0;
line.x2 = x;
line.y2 = canvas.height;
line.draw();
}
The custom line object is in this demo very simple:
/// This lets us define a custom line object which self-draws
function Line(ctx) {
var me = this;
this.x1 = 0;
this.x2 = 0;
this.y1 = 0;
this.y2 = 0;
/// call this method to update line
this.draw = function() {
ctx.beginPath();
ctx.moveTo(me.x1, me.y1);
ctx.lineTo(me.x2, me.y2);
ctx.stroke();
}
}
If you are not gonna do anything specific with the image itself you can also set it as a background-image using CSS. You will still need to clear the canvas before redrawing the line though.
May this is not an actual answer, just in case you need it (in the future). Working with canvas would be better (and easier) with some library. I have tried EaselJS of CreateJS and find myself loving it.
You can have a look at it EaselJS
(I have done an example allow drawing and dragging image using EaselJS long time before)
You can get your "crosshairs" by listening to mousemove events and then:
clear the canvas
draw the image
draw your line at the mouse position
Here is code and a Fiddle: http://jsfiddle.net/m1erickson/jEc7N/
<!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=2;
var canvasOffset=$("#canvas").offset();
var offsetX=canvasOffset.left;
var offsetY=canvasOffset.top;
var img=new Image();
img.onload=function(){
canvas.width=img.width;
canvas.height=img.height;
ctx.drawImage(img,0,0);
}
img.src="https://dl.dropboxusercontent.com/u/139992952/stackoverflow/KoolAidMan.png";
function handleMouseMove(e){
mouseX=parseInt(e.clientX-offsetX);
mouseY=parseInt(e.clientY-offsetY);
ctx.clearRect(0,0,canvas.width,canvas.height);
ctx.drawImage(img,0,0);
ctx.beginPath();
ctx.moveTo(mouseX,0);
ctx.lineTo(mouseX,canvas.height);
ctx.moveTo(0,mouseY);
ctx.lineTo(canvas.width,mouseY);
ctx.stroke();
}
$("#canvas").mousemove(function(e){handleMouseMove(e);});
}); // end $(function(){});
</script>
</head>
<body>
<canvas id="canvas" width=300 height=300></canvas>
</body>
</html>
or just use 2 layers:
background layer has image and do not change,
top layer has line, what you can clear and redraw it lots of time without affecting background layer.
I have one image like this and I want to fill with pattern like this to make result like this .
I can fill the pattern using following code but I don't know how to curve pattern properly along the collar shape because it should look like real but my result become like this. .
Here is my sample script
$(function(){
drawCanvas("body","collar","images/collar.png", 180);
function drawCanvas(overlayType, canvasID, imageSource, degreeRotate){
var canvas=document.getElementById(canvasID);
var ctx=canvas.getContext("2d");
var imgBody=new Image();
var imgPattern=new Image();
imgPattern.onload=function(){
imgBody.onload=function(){
start();
}
imgBody.src=imageSource;
}
imgPattern.src="images/pattern.png";
function start(){
ctx.drawImage(imgBody,0,0);
if(overlayType=="body"){
ctx.globalCompositeOperation="source-atop";
ctx.globalAlpha=.85;
var pattern = ctx.createPattern(imgPattern, 'repeat');
ctx.fillStyle = pattern;
ctx.rect(0, 0, canvas.width, canvas.height);
ctx.rotate(degreeRotate * Math.PI/180);
ctx.fill();
ctx.translate(150,0);
ctx.globalAlpha=.1;
ctx.drawImage(imgBody,150,0);
}
}
}});
Can someone guide me to how to manage pattern to curve along side collar shape to look like real?
You can get this close by simply slicing and offsetting your pattern vertically
Original "collar" image:
Collar filled with curved checkered texture
**The Method:*
Create an image tiled with your checkered texture.
Draw that texture image onto a temporary canvas.
Get the image data for the temporary canvas.
For each column of pixels, offset that entire column by the curve of your collar.
A quadratic curve fits the curve of your collar well, so I used that in the example to determin the Y offset.
Put the image data back on the temporary canvas.
(You now have a curved checkered pattern to apply to your collar image).
Draw the collar image on your main canvas.
Set context.globalCompositeOperation=”source-atop”
Draw the texture from the temporary canvas onto the main canvas.
(The compositing mode will paint the texture only on the collar—not the background)
Here is code and a Fiddle: http://jsfiddle.net/m1erickson/hdXyk/
<!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(){
// get canvas references (canvas=collar, canvas1=texture)
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var canvas1=document.getElementById("canvas1");
var ctx1=canvas1.getContext("2d");
// preload the texture and collar images before starting
var textureImg,collarImg;
var imageURLs=[];
var imagesOK=0;
var imgs=[];
imageURLs.push("https://dl.dropboxusercontent.com/u/139992952/stackoverflow/checkered.png");
imageURLs.push("https://dl.dropboxusercontent.com/u/139992952/stackoverflow/collar.png");
loadAllImages();
function loadAllImages(callback){
for (var i = 0; i < imageURLs.length; i++) {
var img = new Image();
img.crossOrigin="anonymous";
imgs.push(img);
img.onload = function(){
imagesOK++;
if (imagesOK==imageURLs.length ) {
textureImg=imgs[0];
collarImg=imgs[1];
start();
}
};
img.src = imageURLs[i];
}
}
function start(){
// set both canvas dimensions
canvas.width=collarImg.width;
canvas.height=collarImg.height+5;
canvas1.width=textureImg.width;
canvas1.height=textureImg.height;
// draw the textureImg on canvas1
ctx1.drawImage(textureImg,0,0,canvas1.width,canvas1.height);
// curve the texture into a collar shaped curved
curveTexture(collarImg.width,collarImg.height);
// draw the collarImg on canvas
ctx.drawImage(collarImg,0,0);
// set compositing to source-atop
// any new drawing will ONLY fill existing non-transparent pixels
ctx.globalCompositeOperation="source-atop";
// draw the curved texture from canvas1 onto the collar of canvas
// (the existing pixels are the collar, so only the collar is filled)
ctx.drawImage(canvas1,0,0);
}
function curveTexture(w,h){
// define a quadratic curve that fits the collar bottom
// These values change if the collar image changes (+5,-32)
var x0=0;
var y0=h+5;
var cx=w/2;
var cy=h-32;
var x1=w;
var y1=h+5;
// get a,b,c for quadratic equation
// equation is used to offset columns of texture pixels
// in the same shape as the collar
var Q=getQuadraticEquation(x0,y0,cx,cy,x1,y1);
// get the texture canvas pixel data
// 2 copies to avoid self-referencing
var imageData0 = ctx1.getImageData(0,0,w,h);
var data0 = imageData0.data;
var imageData1 = ctx1.getImageData(0,0,w,h);
var data1 = imageData1.data;
// loop thru each vertical column of pixels
// Offset the pixel column into the shape of the quad-curve
for(var y=0; y<h; y++) {
for(var x=0; x<w; x++) {
// the pixel to write
var n=((w*y)+x)*4;
// the vertical offset amount
var yy=parseInt(y+h-(Q.a * x*x + Q.b*x + Q.c));
// the offset pixel to read
var nn=((w*yy)+x)*4;
// offset this pixel by the quadCurve Y value (yy)
data0[n+0]=data1[nn+0];
data0[n+1]=data1[nn+1];
data0[n+2]=data1[nn+2];
data0[n+3]=data1[nn+3];
}
}
ctx1.putImageData(imageData0,0,0);
}
// Quadratic Curve: given x coordinate, find y coordinate
function getQuadraticY(x,Q){
return(Q.a * x*x + Q.b*x + Q.c);
}
// Quadratic Curve:
// Given: start,control,end points
// Find: a,b,c in quadratic equation ( y=a*x*x+b*x+c )
function getQuadraticEquation(x0,y0,cx,cy,x2,y2){
// need 1 more point on q-curve, so calc its midpoint XY
// Note: since T=0.5 therefore TT=(1-T)=0.5 also [so could simplify]
var T=0.50;
var TT=1-T;
var x1=TT*TT*x0+2*TT*T*cx+T*T*x2;
var y1=TT*TT*y0+2*TT*T*cy+T*T*y2;
var A = ((y1-y0)*(x0-x2)
+ (y2-y0)*(x1-x0))/((x0-x2)*(x1*x1-x0*x0)
+ (x1-x0)*(x2*x2-x0*x0));
var B = ((y1-y0)-A*(x1*x1-x0*x0))/(x1-x0);
var C = y0-A*x0*x0-B*x0;
return({a:A,b:B,c:C});
}
}); // end $(function(){});
</script>
</head>
<body>
<p>"Curve" a texture by offsetting Y pixels based on Q-curve</p>
<canvas id="canvas" width=300 height=300></canvas>
<p>The temporary texture canvas</p>
<canvas id="canvas1" width=300 height=300></canvas>
</body>
</html>
You can triangulate the polygon and then bend the mesh. Then you can fill the mesh with the pattern. Here is an example of a triangulation in Java: How does this code for delaunay triangulation work?. Here is an example of a triangulation and a bit of work to remove long edges. It's a concave hull of a 2d point set.