Clear canvas JavaScript - javascript

I'm trying to clear the canvas. I tried closing the path, but it didn't change anything. also, I am not too sure if the ctxBg.close(); is on the right place.
Thank you.
function drawGrid () {
drawGrid();
ctxBg.clearRect(0, 0, canvas.width, canvas.height);
function drawGrid () {
for (var i = 75; i <= canvasWidth-25; i+= 25) {
ctxBg.beginPath();
ctxBg.moveTo(-25 + i,55);
ctxBg.lineTo(-25 + i, canvasHeight - 55);
ctxBg.stroke();
}
for (var i = 25; i <= canvasHeight -75; i+= 25) {
ctxBg.beginPath();
ctxBg.moveTo(55,25 + i);
ctxBg.lineTo(canvasWidth-55, 25 + i);
ctxBg.stroke();
}ctxBg.close();
}

You have two definitions of the drawGrid() function:
function drawGrid () {
...
function drawGrid () {
You can only have one. Next, there is no close() method on a context, only closePath(). However, this is not useful here. closePath does not "end" a path, but connects the first and last point in the path so the path shape is closed.
This is not useful with lines of course, and in any case, it has to be called before stroke().
Third, you are (attempting to) rendering the grid then clear it right away. This won't show anything on canvas. You need to either separate those operations.
Here's a suggested solution. Two functions, one to draw the grid, one to clear it:
var canvas = document.querySelector("canvas"),
canvasWidth = canvas.width, canvasHeight = canvas.height,
ctxBg = canvas.getContext("2d");
ctxBg.translate(0.5, 0.5); // just to make the lines sharper
function drawGrid() {
ctxBg.beginPath(); // this can be placed here
for (var i = 75; i <= canvasWidth - 25; i += 25) {
ctxBg.moveTo(-25 + i, 55);
ctxBg.lineTo(-25 + i, canvasHeight - 55);
}
for (var i = 25; i <= canvasHeight - 75; i += 25) {
ctxBg.moveTo(55, 25 + i);
ctxBg.lineTo(canvasWidth - 55, 25 + i);
}
ctxBg.stroke(); // stroke all at once
// remove button code (ref. comments)
var button = document.querySelector("button");
button.parentNode.removeChild(button);
}
function clearGrid() {
ctxBg.clearRect(0, 0, canvas.width, canvas.height);
}
<button onclick="drawGrid()">Grid</button>
<button onclick="clearGrid()">Clear</button><br>
<canvas></canvas>
Update: if the button that needs to be removed is a HTML button as in the example above, then remove it by either using style:
// assumes the button element is stored in variable button:
button.style.display = "none";
or completely, using its parentNode and removeChild():
button.parentNode.removeChild(button);

ctxBg.clearRect(0,0,canvas.width,canvas.height);
This clears your canvas.

Related

How do I create a random number that remains constant and doesn't change in Javascript?

I'm trying to have a few circles drawn on the screen that do not move after initialization. Right now it is constantly drawing them to the screen instead of keeping them there. Here's the code:
for (let i = 0; i < 1; i++) {
//location
const r = random(100, 900);
const r2 = random(900, 100);
//size
const rS = random(50, 250);
const rS2 = random(250, 50);
//draw the ellipse with parameters
ellipse(r, r2, rS, rS2);
}
(This is with the p5.js library)
It sounds like your code is in the draw() function, which is called multiple times a second. Since you call random() every single time, it creates new parameters every single time. Instead, you should assign parameters to a variable somewhere else (like in the setup function) and then use those in the draw function. Something like:
var ellipses = [];
function setup() {
createCanvas(640, 480);
for (let i = 0; i < 1; i++) {
ellipses.push({
r: random(100, 300),
r2: random(300, 100),
rS: random(50, 250),
rS2: random(250, 50)
});
}
}
function draw() {
clear();
//location
//draw the ellipse with parameters
ellipses.forEach(function (e) {
ellipse(e.r, e.r2, e.rS, e.rS2);
})
}
<script src="https://unpkg.com/p5#1.1.9/lib/p5.min.js"></script>

Create shapes by for loop in canvas

EDIT:i will post all my code the html and js,and excuse me for too many comments
I am trying to create rectangles in canvas by for loop (there is input user)
and I want to access them in another function to do some stuff,
the main problem is how to access the shapes's name after loop I have tried this but when i call them in another function it gives me,
undefined "object name"
var canvas = document.querySelector('canvas');
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
var c = document.getElementById("myCanvas");
//drawing the base off the towers
var base_twr1 = c.getContext("2d");
base_twr1.beginPath();
base_twr1.moveTo(550, 500);
base_twr1.lineTo(300, 500);
base_twr1.lineWidth = 10;
base_twr1.strokeStyle = '#ff0000';
base_twr1.closePath();
base_twr1.stroke();
var base_twr2 = c.getContext("2d");
base_twr2.beginPath();
base_twr2.moveTo(900, 500);
base_twr2.lineTo(650, 500);
base_twr2.closePath();
base_twr2.stroke();
var base_twr3 = c.getContext("2d");
base_twr3.beginPath();
base_twr3.moveTo(1250, 500);
base_twr3.lineTo(1000, 500);
base_twr3.closePath();
base_twr3.stroke();
//drawing the towers
var twr1 = c.getContext("2d");
twr1.beginPath();
twr1.moveTo(430, 300);
twr1.lineTo(430, 500);
twr1.closePath();
twr1.stroke();
var twr2 = c.getContext("2d");
twr2.beginPath();
twr2.moveTo(780, 300);
twr2.lineTo(780, 500);
twr2.closePath();
twr2.stroke();
var twr3 = c.getContext("2d");
twr3.beginPath();
twr3.moveTo(1130, 300);
twr3.lineTo(1130, 500);
twr3.closePath();
twr3.stroke();
//array to know each tower what contains
//to avoid collisions
var disks_in_twrs = [];
var twr1_holder = [];
var twr2_holder = [];
var twr3_holder = [];
//start function check the user input
//and call another function if everthing
//is fine
function btn_start() {
disks_number = document.getElementById("disk_input").value;
disks_number = parseInt(disks_number);
if (disks_number > 0) {
if (disks_number < 8)
put_disks(disks_number);
} else
alert('write number');
}
var width_disks_start = 305;
var height_disks_start = 490;
var disk_width = 220;
function put_disks(disks) {
for (i = 0; i < disks; i++) {
// var r = Math.floor((Math.random() * 256));
// var g = Math.floor((Math.random() * 256));
// var b = Math.floor((Math.random() * 256));
str1 = "disk";
width_disks_start = width_disks_start + 10;
height_disks_start = height_disks_start - 20;
disk_width = disk_width - 30;
// eval("disks_in_twrs.push(str1 + i)" );
// disks_in_twrs[i]=c.getContext("2d");
// disks_in_twrs[i].rect((Math.random)*100,(Math.random)*100,150,100);
// disks_in_twrs[i].stroke();
// alert(disks_in_twrs);
twr1_holder.push(str1 + i);
// ctx.fillStyle = 'rgb(' + r + ',' + g + ', ' + b + ')';
// alert(str1 + i);
//twr1_holder[i] = c.getContext("2d");
eval("var disk"+i+"= c.getContext('2d');");
// twr1_holder[i].rect(width_disks_start, height_disks_start, disk_width, 20);
eval("disk"+i+".rect(width_disks_start, height_disks_start, disk_width, 20);");
// twr1_holder[i].strokeStyle = "black";
eval("disk"+i+".strokeStyle = 'black';");
// twr1_holder[i].stroke();
eval("disk"+i+".stroke();");
// alert(disk1.toSource());
}
}
function hide_me(){
alert("byeeeeeeeeeeeeeeeee");
twr1.fillRect(430, 500, 250, 250);
// disk2.rect(515, 51, 6, 20);
// disk2.strokeStyle = 'red';
}
<!DOCTYPE html>
<html>
<head>
<title>tower of Hanoi</title>
<style type="text/css">
canvas{
border : 1px solid black;
}
</style>
</head>
<body>
<label>how many disk do you want ?</label>
<input type="text" id="disk_input">
<button id="start" onclick="btn_start()">start</button>
<label>note that maximum disk is 8 :P</label>
<button id="make_hidden" onclick="hide_me()" >make me hide</button>
<canvas id="myCanvas" >
</canvas>
<script src="tower.js">
</script>
</body>
</html>
There's a lot going on here! I recommend attacking each issue in your code separately and building up understanding gradually, because this is an application that requires a lot of different components (DOM manipulation/event handlers, JS canvas, objects/arrays/loops, design, etc). If you're uncomfortable with any of these concepts, pick one area (such as DOM manipulation) and spend time working on simple, understandable examples, then apply what you learned to the main application.
Firstly, almost always avoid eval entirely. Mozilla says never to use it! If you're using it, it probably means your design has gone haywire somewhere along the line, which I would contend is the case here.
As for event handlers and document manipulation, I recommend avoiding onclick. Adding event listeners in your script can take care of the job; you'll likely be listening for clicks on the canvas to enable interaction later on.
Next: using canvas. You generally only need to retrieve the context once per application, not before each drawing. Your drawing code looks good other than this, except that it's not very DRY, which is usually a signal to redesign.
The hardest part is designing your code to meet your goals, which I'm not entirely clear on. Are you making an interactive Towers of Hanoi app, or one that simply animates a solver algorithm and requires no user input? Either way, I opted to use object constructors to represent Towers and Disks. Using arrays to hold these objects means you identify towers and disks by their position in an array rather than evaling a string name. Whenever you want to perform an action on your towers, such as drawing them, all you need to do is loop through the towers and call draw on each one. Later, when it comes to handling user input or writing a solver algorithm, it should be fairly easy to manipulate these arrays to suit your needs (e.g., figuring out which disk was clicked on, moving disks between towers, etc).
Keep in mind the below example is just a quick sketch to get you going and may not follow best design principles or ones that meet your needs. For example, I've hard-coded most drawing coordinate values, so it's non-responsive, so many exercises are left for the reader to improve on.
const Disk = function(width, color) {
this.width = width;
this.color = color;
};
const Tower = function(x, disks) {
this.x = x;
this.disks = [];
this.width = 20;
};
Tower.prototype.draw = function(c, ctx) {
ctx.lineWidth = this.width;
ctx.strokeStyle = "#000";
ctx.beginPath();
ctx.moveTo(this.x, 0);
ctx.lineTo(this.x, c.height);
ctx.stroke();
this.disks.forEach((e, i) => {
ctx.fillStyle = e.color;
ctx.fillRect(
this.x - e.width / 2,
c.height - (i + 1) * this.width,
e.width, this.width
);
});
};
const draw = (c, ctx, towers) => {
ctx.clearRect(0, 0, c.width, c.height);
towers.forEach(t => t.draw(c, ctx));
};
const initialize = disks => {
const towers = [
new Tower(c.width / 5),
new Tower(c.width / 2),
new Tower(c.width - c.width / 5)
];
for (let i = disks; i > 0; i--) {
towers[0].disks.push(
new Disk(i * 30, `hsl(${Math.random() * 360}, 50%, 50%`)
);
}
return towers;
};
document.getElementById("initialize-form")
.addEventListener("submit", e => {
e.preventDefault();
towers = initialize(parseInt(e.target.elements[0].value), towers);
draw(c, ctx, towers);
});
document.getElementById("btn-hide").addEventListener("click",
e => document.getElementById("menu").style.display = "none"
);
const c = document.getElementById("hanoi");
c.width = 600;
c.height = 200;
const ctx = c.getContext("2d");
let towers;
body {
margin: 0;
}
#hanoi {
padding: 0.5em;
}
#initialize-form {
display: inline-block;
}
#menu {
padding: 0.5em;
display: inline-block;
}
<div id="menu">
<form id="initialize-form">
<label>Enter disks:</label>
<input type="number" min="1" max="8" value="6">
<button type="submit">start</button>
</form>
<button id="btn-hide">hide</button>
</div>
<canvas id="hanoi"></canvas>
For what you are trying to do you should consider using a canvas library, maybe Konva:
https://konvajs.github.io/
Here is an example:
<script src="https://cdn.rawgit.com/konvajs/konva/2.1.7/konva.min.js"></script>
<div id="container"></div>
<script>
function KonvaRect(x, y, fill, draggable) {
return new Konva.Rect({
x: x, y: y, width: 50, height: 50,
fill: fill, stroke: 'black',
strokeWidth: 4, draggable: draggable
});
}
var boxes = [];
boxes.push(KonvaRect(50, 10, '#00D2FF', true));
boxes.push(KonvaRect(200, 10, '#0000FF', true));
boxes.push(KonvaRect(125, 10, '#FF0000', false));
var layer = new Konva.Layer();
boxes.forEach(function(b) { layer.add(b) });
var stage = new Konva.Stage({
container: 'container', width: 600, height: 170
});
stage.add(layer);
function moveCenter() {
boxes.forEach(function(b) { b.move({ x:0, y: Math.random() * 10 }) });
layer.batchDraw();
}
boxes[0].on('mouseover', function() {
moveCenter();
});
</script>
On this example I put 3 boxes in an array and when we detect the mouse over the light blue box all boxes move randomly down, also both blue boxes you can click and drag around the canvas.
And for the record there are many many other libraries out there...

How to move image on canvas using arrow keys in javascript

I've tried a few different ways that I have seen on here, but I can't quite get my image to move. Whenever I try adapting code for arrow key presses, it just seems to make my canvas shrink and my player model (spaceperson) disappear.
here is the "drawing board" I keep returning to, and what I have so far.
// Get the canvas and context
var canvas = document.getElementById("space");
var ctx = canvas.getContext("2d");
canvas.width = 1920;
canvas.height = 700;
// Create the image object
var spaceperson = new Image();
// Add onload event handler
spaceperson.onload = function () {
// Done loading, now we can use the image
ctx.drawImage(spaceperson, 280, 300);
};
// artwork by Harrison Marley (using make8bitart.com)
spaceperson.src = "http://i.imgur.com/Eh9Dpq2.png";`
I am quite new to javascript, and I am just trying to work out how I can move the specperson image using arrow keys. I was trying to make a class for space person to access their x,y values, but I can't seem to draw the image without using .onload
here a more complete example:
//just a utility
function image(url, callback){
var img = new Image();
if(typeof callback === "function"){
img.onload = function(){
//just to ensure that the callback is executed async
setTimeout(function(){ callback(img, url) }, 0)
}
}
img.src = url;
return img;
}
//a utility to keep a value constrained between a min and a max
function clamp(v, min, max){
return v > min? v < max? v: max: min;
}
//returns a function that can be called with a keyCode or one of the known aliases
//and returns true||false wether the button is down
var isKeyDown = (function(aliases){
for(var i=256, keyDown=Array(i); i--; )keyDown[i]=false;
var handler = function(e){
keyDown[e.keyCode] = e.type === "keydown";
e.preventDefault(); //scrolling; if you have to suppress it
};
addEventListener("keydown", handler, false);
addEventListener("keyup", handler, false);
return function(key){
return(true === keyDown[ key in aliases? aliases[ key ]: key ])
}
})({
//some aliases, to be extended
up: 38,
down: 40,
left: 37,
right: 39
});
// Get the canvas and context
var canvas = document.getElementById("space");
canvas.width = 1920;
canvas.height = 700;
var ctx = canvas.getContext("2d");
//the acutal image is just a little-part of what defines your figue
var spaceperson = {
image: image("//i.imgur.com/Eh9Dpq2.png", function(img){
spaceperson.width = img.naturalWidth;
spaceperson.height = img.naturalHeight;
//start the rendering by calling update
update();
}),
//position
x: 60, y: 310,
width: 0, height: 0,
speed: 200 // 200px/s
};
var lastCall = 0; //to calculate the (real) time between two update-calls
//the render-fucntion
function update(){
//taking account for (sometimes changing) framerates
var now = Date.now(), time = lastCall|0 && (now-lastCall)/1000;
lastCall = now;
requestAnimationFrame(update);
var sp = spaceperson,
speed = sp.speed;
//checking the pressed buttons and calculates the direction
//two opposite buttons cancel out each other, like left and right
var dx = (isKeyDown('right') - isKeyDown('left')) * time,
dy = (isKeyDown('down') - isKeyDown('up')) * time;
//fix the speed for diagonals
if(dx && dy) speed *= 0.7071067811865475; // * 1 / Math.sqrt(2)
if(dx) { //there is some movement on the x-axes
sp.x = clamp(
//calculate the new x-Position
//currentPos + direction * speed
sp.x + dx * sp.speed,
//restraining the result to the bounds of the map
0, canvas.width - sp.width
);
}
//same for y
if(dy) sp.y = clamp(sp.y + dy * sp.speed, 0, canvas.height - sp.height);
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.drawImage(sp.image, sp.x, sp.y);
}
Edit:
A quick question (I hope); if I was to later add other objects, would I check for collisions in update()?
This is still just a very basic example. The main purpose of the update()-function should be to work as the main event-loop.
To trigger all Events that have to happen each frame in the order they have to happen.
var lastCall = 0;
function update(){
//I always want a next frame
requestAnimationFrame(update);
//handle timing
var now = Date.now(),
//time since the last call in seconds
//cause usually it's easier for us to think in
//tems like 50px/s than 0.05px/ms or 0.8333px/frame
time = lastCall|0 && (now-lastCall) / 1000;
lastCall = now;
movePlayer(time);
moveEnemies(time);
moveBullets(time);
collisionDetection();
render();
}
function render(){
ctx.clear(0, 0, canvas.width, canvas.height);
drawBackground(ctx);
for(var i=0; i<enemies.length; ++i)
enemies[i].render(ctx);
player.render(ctx);
}
Not saying that you have to implement all these functions now, but to give you an idea of a possible structure.
Don't be scared to break big tasks (functions) up into subtasks.
And it might make sense to give each enemy a move()-function so you can implement different movement-patterns per enemy,
or you say that the pattern is (and will be) all the same for each enemy, parameterized at the best, then you can handle that in a loop.
Same thing for rendering, as I'm showing in the last part of code.
Here's some slightly modified code from a game I was noodling around with a while back. If you want to see more code, check out the complete JS on GitHub. The game is incomplete but you should gather some helpful clues as to how to move an image around the canvas.
var spaceperson = {
speed: 256,
other_stuff: ''
},
keysDown = [],
update,
main;
addEventListener("keydown", function (e) {
keysDown[e.keyCode] = true;
}, false);
update = function (modifier) {
if (38 in keysDown && spaceperson.y > 0) { // UP
spaceperson.y -= spaceperson.speed * modifier;
}
if (40 in keysDown && spaceperson.y < CANVAS_HEIGHT - SPACEPERSON_HEIGHT) { // DOWN
spaceperson.y += spaceperson.speed * modifier;
}
if (37 in keysDown && spaceperson.x > 0) { // LEFT
spaceperson.x -= spaceperson.speed * modifier;
}
if (39 in keysDown && spaceperson.x < CANVAS_WIDTH - SPACEPERSON_WIDTH) { // RIGHT
spaceperson.x += spaceperson.speed * modifier;
}
}
I'm not sure but i think this can help.
// Get the canvas and context
var canvas = document.getElementById("space");
var ctx = canvas.getContext("2d");
canvas.width = 1920;
canvas.height = 700;
var x = 280;
var y = 300;
// Create the image object
var spaceperson = new Image();
spaceperson.addEventListener("keypress", press);
// Add onload event handler
spaceperson.onload = function () {
// Done loading, now we can use the image
ctx.drawImage(spaceperson, x, y);
};
function press(event) {
if(event.keyCode == 37) {//LEFT
x = x - 1;
} else if(event.keyCode == 38) {//UP
y = y - 1;
} else if(event.keyCode ==39) {//RIGHT
x = x + 1;
} else if(event.keyCode == 40) {//DOWN
y = y + 1;
}
draw();
}
function draw(){
ctx.drawImage(spaceperson,x,y);
}
// artwork by Harrison Marley (using make8bitart.com)
spaceperson.src = "http://i.imgur.com/Eh9Dpq2.png";
I found a solution!
// Get the canvas and context
var canvas = document.getElementById("space");
var ctx = canvas.getContext("2d");
canvas.width = 1920;
canvas.height = 700;
var xPos = 60;
var yPos = 310;
// Create the image object
var spaceperson = new Image();
// Add onload event handler
spaceperson.onload = function () {
// Done loading, now we can use the image
ctx.drawImage(spaceperson, xPos, yPos);
};
function move(e){
if(e.keyCode==39){
xPos+=10;
}
if(e.keyCode==37){
xPos-=10;
}
if(e.keyCode==38){
yPos-=10;
}
if(e.keyCode==40){
yPos+=10;
}
canvas.width=canvas.width;
ctx.drawImage(spaceperson, xPos, yPos);
}
document.onkeydown = move;
// artwork by Harrison Marley
spaceperson.src = "http://i.imgur.com/Eh9Dpq2.png";

How to make javascript canvas draw faster?

I have the following code to display an ECG. I use the canvas to draw the graph background (each grid of 2.5 mm dimension). Later I'm taking the y coordinates from an array array_1 (x coordinates are calculated within the program). The problem with this approach is it will take around 40 seconds to plot the entire graph since there are 1250 values within array array_1. What I could do is I could do the plotting part within a loop in which case, the entire graph is plotted as soon as the page is loaded. But, I need the plotting to happen over the course of 5 seconds. Not more. Not less. How would I alter the code to do this? Please help.
<!DOCTYPE html>
<html>
<head>
<title></title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
</head>
<body>
<canvas id="canvas" width="1350" height="1300" style="background-color: white;"></canvas>
<script type='text/javascript'>
var canvas = document.getElementById("canvas");
var ctxt = canvas.getContext("2d");
var n1 = 1;
var n1_x=49; //Graph x coordinate starting pixel.
var n1_y=72;//Graph y coordinate starting pixel.
var array_1 = []// array from which y coordinates are taken. Has 1250 elements
var ctx = canvas.getContext("2d");
var x=0;
var y=0;
var Line_position=-1;
while(x<=1350)//graph width
{
ctxt.lineWidth = "0.5";
Line_position=Line_position+1;
if(Line_position%5==0)
{
ctxt.lineWidth = "1.5";
}
ctxt.strokeStyle = "black";
ctxt.beginPath();
ctxt.moveTo(x, 0);
ctxt.lineTo(x, 1300);
ctxt.stroke();
x=x+9.43;
}
Line_position=-1;
while(y<=1300)//graph height
{
ctxt.lineWidth = "0.5";
Line_position=Line_position+1;
if(Line_position%5==0)
{
ctxt.lineWidth = "1.5";
}
ctxt.strokeStyle = "black";
ctxt.beginPath();
ctxt.moveTo(0, y);
ctxt.lineTo(1350,y);
ctxt.stroke();
y=y+9.43;
}
drawWave();
function drawWave()
{
requestAnimationFrame(drawWave);
ctx.lineWidth = "1";
ctx.strokeStyle = 'blue';
ctx.beginPath();
ctx.moveTo(n1_x- 1, n1_y+array_1[n1-1]);//move to the pixel position
ctx.lineTo(n1_x, n1_y+array_1[n1]);//Draw to the pixel position
ctx.stroke();
n1_x=n1_x+0.374;//Incrementing pixel so as to traverse x axis.
n1++;
}
</script>
</body>
</html>
Here is the array:
array_1 = [69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,72,72,72,72,72,72,72,73,73,74,74,74,74,74,74,74,73,73,73,73,74,74,74,74,73,73,73,73,73,73,73,73,73,73,73,73,73,74,74,74,73,73,73,72,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,72,72,72,71,72,72,72,73,73,73,72,72,72,73,73,73,74,73,73,72,72,72,72,72,73,73,73,73,73,72,72,72,72,73,73,73,72,72,72,71,101,71,70,70,70,69,68,68,67,67,66,66,67,67,69,70,72,72,72,73,73,74,73,73,73,73,73,73,73,73,73,74,76,77,76,70,57,40,22,11,11,22,40,57,69,73,73,71,71,71,72,72,73,73,74,74,74,73,72,72,72,72,72,72,72,72,72,72,72,72,71,71,70,70,71,71,71,71,70,70,69,69,69,69,69,69,69,68,68,68,67,67,66,66,65,65,64,63,63,62,62,62,62,62,62,62,62,63,63,64,65,66,67,68,68,69,70,71,72,72,72,73,73,73,73,72,72,72,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,72,72,72,73,73,73,73,72,73,73,73,73,73,73,73,73,73,73,72,72,72,72,72,72,73,73,74,74,74,74,74,74,73,73,72,73,73,73,74,73,73,72,72,72,73,73,73,72,72,73,73,74,74,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,72,72,71,70,70,70,70,70,69,69,68,67,67,67,67,68,69,71,72,72,73,73,73,73,74,74,74,74,74,73,73,73,73,75,77,78,76,67,53,35,18,8,10,23,41,58,69,73,72,71,70,71,72,73,73,73,73,73,73,73,73,72,72,73,73,73,73,72,71,71,70,70,71,71,71,71,71,71,71,71,70,70,69,69,69,69,68,68,67,67,67,67,67,66,65,65,65,64,63,62,61,61,61,60,60,60,59,60,60,60,61,62,63,65,66,66,67,68,69,70,71,72,72,72,72,73,73,73,72,72,72,72,72,72,72,73,73,73,73,73,73,72,72,73,73,73,73,73,73,73,73,73,73,73,73,73,72,72,71,71,72,72,73,73,73,72,72,72,72,72,72,73,73,73,73,73,73,73,73,73,72,73,73,73,73,73,73,72,73,73,73,73,73,73,73,72,72,72,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,72,71,71,70,70,69,69,69,68,67,67,66,65,66,66,68,69,70,71,72,72,73,73,73,73,73,73,74,74,74,74,74,74,76,78,78,74,64,48,29,13,5,10,26,45,62,71,73,72,71,71,72,73,73,73,73,73,74,74,74,73,72,72,72,73,73,73,73,73,73,73,72,72,72,72,71,71,71,71,71,71,71,71,71,70,70,69,69,69,69,68,67,66,66,66,66,65,65,64,63,62,62,61,61,60,60,60,60,61,62,62,63,64,65,66,67,68,70,71,72,72,72,72,72,72,73,73,73,73,73,73,73,74,74,75,75,74,74,74,73,73,73,74,73,73,73,73,73,74,74,74,74,74,73,73,73,73,73,73,73,73,73,73,73,73,73,73,72,72,73,73,74,74,74,73,73,73,73,73,73,73,73,73,73,72,72,72,72,73,73,72,72,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,72,72,73,73,72,72,71,70,70,70,69,69,68,68,67,67,66,67,67,68,69,70,71,72,73,73,74,74,73,73,73,74,75,75,74,73,73,74,76,78,75,67,52,32,15,5,8,22,41,59,69,73,72,71,70,71,72,72,73,73,73,73,73,73,73,73,73,72,72,72,72,72,72,72,72,72,72,71,71,71,70,70,70,70,70,70,70,69,69,69,69,68,68,68,68,67,67,66,65,65,64,64,64,63,62,61,60,60,60,60,60,61,61,62,62,63,64,65,65,66,67,68,69,70,71,71,71,71,71,71,72,72,73,73,73,72,72,73,73,73,73,73,73,73,73,73,73,73,73,73,72,72,72,72,72,72,72,71,71,71,71,71,71,71,72,72,72,72,72,72,72,72,72,71,71,71,72,72,73,73,72,72,72,72,72,73,73,73,73,73,72,72,72,72,72,73,73,73,73,73,72,72,72,73,73,74,73,73,73,73,73,73,73,73,73,73,73,73,72,72,72,72,71,71,71,70,70,70,70,69,69,68,67,67,68,69,71,72,73,73,73,73,73,73,73,73,74,75,75,75,74,74,74,75,77,77,75,67,52,34,18,10,12,26,45,62,71,74,73,72,72,72,73,74,74,74,75,75,74,74,74,74,74,74,74,74,74,73,73,73,73,74,74,73,73,73,73,73,73,73,72,72,71,71,71,71,71,70,70,70,69,69,69,68,68,68,68,67,66,65,64,63,63,62,62,62,63,63,63,63,64,65,66,67,69,69,70,71,72,72,73,73,74,74,74,74,75,75,76,76,74,72,70,70,69,69 ];
I'd probably go about the task something like this. As mentioned in a comment, we need to draw a number of the data-points per-frame. How many we draw depends on the speed that the browser is able to supply an animation frame.
I've hard-coded the value to 4, since that seems to work on my machine, but with not much more work you can probably make the code time itself and adjust this value on the fly so that your animation runs for as close as possible to the target time. I had a quick go, but the results were awful, I'll leave that as an exercise in research or thought for the reader.
By keeping track of how many frames we've already drawn for the current 'refresh-cycle', we know how far to index into the array for the first point to be drawn for each frame.
I've tried to parameterize the code as much as possible, but it's late and I'm tired, I may have overlooked something somewhere.
<!doctype html>
<html>
<head>
<script>
function byId(id,parent){return (parent == undefined ? document : parent).getElementById(id);}
window.addEventListener('load', onDocLoaded, false);
function onDocLoaded(evt)
{
drawBkg(byId('canvas'), 9.43, 5, "0.5", "1.5", "black");
drawCurFrame();
}
var dataSamples = [69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,72,72,72,72,72,72,72,73,73,74,74,74,74,74,74,74,73,73,73,73,74,74,74,74,73,73,73,73,73,73,73,73,73,73,73,73,73,74,74,74,73,73,73,72,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,72,72,72,71,72,72,72,73,73,73,72,72,72,73,73,73,74,73,73,72,72,72,72,72,73,73,73,73,73,72,72,72,72,73,73,73,72,72,72,71,101,71,70,70,70,69,68,68,67,67,66,66,67,67,69,70,72,72,72,73,73,74,73,73,73,73,73,73,73,73,73,74,76,77,76,70,57,40,22,11,11,22,40,57,69,73,73,71,71,71,72,72,73,73,74,74,74,73,72,72,72,72,72,72,72,72,72,72,72,72,71,71,70,70,71,71,71,71,70,70,69,69,69,69,69,69,69,68,68,68,67,67,66,66,65,65,64,63,63,62,62,62,62,62,62,62,62,63,63,64,65,66,67,68,68,69,70,71,72,72,72,73,73,73,73,72,72,72,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,72,72,72,73,73,73,73,72,73,73,73,73,73,73,73,73,73,73,72,72,72,72,72,72,73,73,74,74,74,74,74,74,73,73,72,73,73,73,74,73,73,72,72,72,73,73,73,72,72,73,73,74,74,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,72,72,71,70,70,70,70,70,69,69,68,67,67,67,67,68,69,71,72,72,73,73,73,73,74,74,74,74,74,73,73,73,73,75,77,78,76,67,53,35,18,8,10,23,41,58,69,73,72,71,70,71,72,73,73,73,73,73,73,73,73,72,72,73,73,73,73,72,71,71,70,70,71,71,71,71,71,71,71,71,70,70,69,69,69,69,68,68,67,67,67,67,67,66,65,65,65,64,63,62,61,61,61,60,60,60,59,60,60,60,61,62,63,65,66,66,67,68,69,70,71,72,72,72,72,73,73,73,72,72,72,72,72,72,72,73,73,73,73,73,73,72,72,73,73,73,73,73,73,73,73,73,73,73,73,73,72,72,71,71,72,72,73,73,73,72,72,72,72,72,72,73,73,73,73,73,73,73,73,73,72,73,73,73,73,73,73,72,73,73,73,73,73,73,73,72,72,72,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,72,71,71,70,70,69,69,69,68,67,67,66,65,66,66,68,69,70,71,72,72,73,73,73,73,73,73,74,74,74,74,74,74,76,78,78,74,64,48,29,13,5,10,26,45,62,71,73,72,71,71,72,73,73,73,73,73,74,74,74,73,72,72,72,73,73,73,73,73,73,73,72,72,72,72,71,71,71,71,71,71,71,71,71,70,70,69,69,69,69,68,67,66,66,66,66,65,65,64,63,62,62,61,61,60,60,60,60,61,62,62,63,64,65,66,67,68,70,71,72,72,72,72,72,72,73,73,73,73,73,73,73,74,74,75,75,74,74,74,73,73,73,74,73,73,73,73,73,74,74,74,74,74,73,73,73,73,73,73,73,73,73,73,73,73,73,73,72,72,73,73,74,74,74,73,73,73,73,73,73,73,73,73,73,72,72,72,72,73,73,72,72,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,72,72,73,73,72,72,71,70,70,70,69,69,68,68,67,67,66,67,67,68,69,70,71,72,73,73,74,74,73,73,73,74,75,75,74,73,73,74,76,78,75,67,52,32,15,5,8,22,41,59,69,73,72,71,70,71,72,72,73,73,73,73,73,73,73,73,73,72,72,72,72,72,72,72,72,72,72,71,71,71,70,70,70,70,70,70,70,69,69,69,69,68,68,68,68,67,67,66,65,65,64,64,64,63,62,61,60,60,60,60,60,61,61,62,62,63,64,65,65,66,67,68,69,70,71,71,71,71,71,71,72,72,73,73,73,72,72,73,73,73,73,73,73,73,73,73,73,73,73,73,72,72,72,72,72,72,72,71,71,71,71,71,71,71,72,72,72,72,72,72,72,72,72,71,71,71,72,72,73,73,72,72,72,72,72,73,73,73,73,73,72,72,72,72,72,73,73,73,73,73,72,72,72,73,73,74,73,73,73,73,73,73,73,73,73,73,73,73,72,72,72,72,71,71,71,70,70,70,70,69,69,68,67,67,68,69,71,72,73,73,73,73,73,73,73,73,74,75,75,75,74,74,74,75,77,77,75,67,52,34,18,10,12,26,45,62,71,74,73,72,72,72,73,74,74,74,75,75,74,74,74,74,74,74,74,74,74,73,73,73,73,74,74,73,73,73,73,73,73,73,72,72,71,71,71,71,71,70,70,70,69,69,69,68,68,68,68,67,66,65,64,63,63,62,62,62,63,63,63,63,64,65,66,67,69,69,70,71,72,72,73,73,74,74,74,74,75,75,76,76,74,72,70,70,69,69 ];
function drawBkg(canvasElem, squareSize, numSquaresPerBlock, minorLineWidthStr, majorLineWidthStr, lineColStr)
{
var nLinesDone = 0;
var i, curX, curY;
var ctx = canvasElem.getContext('2d');
ctx.clearRect(0,0,canvasElem.width,canvasElem.height);
// draw the vertical lines
curX=0;
ctx.strokeStyle = lineColStr;
while (curX < canvasElem.width)
{
if (nLinesDone % numSquaresPerBlock == 0)
ctx.lineWidth = majorLineWidthStr;
else
ctx.lineWidth = minorLineWidthStr;
ctx.beginPath();
ctx.moveTo(curX, 0);
ctx.lineTo(curX, canvasElem.height);
ctx.stroke();
curX += squareSize;
nLinesDone++;
}
// draw the horizontal lines
curY=0;
nLinesDone = 0;
while (curY < canvasElem.height)
{
if (nLinesDone % numSquaresPerBlock == 0)
ctx.lineWidth = majorLineWidthStr;
else
ctx.lineWidth = minorLineWidthStr;
ctx.beginPath();
ctx.moveTo(0, curY);
ctx.lineTo(canvasElem.width, curY);
ctx.stroke();
curY += squareSize;
nLinesDone++;
}
}
// position that will be treated as 0,0 when drawing our points.
var originX=49;
var originY=72;
function drawSamples(nSamplesToDraw, firstSample, lineWidthStr, lineColourStr)
{
var can = byId('canvas');
var ctx = can.getContext('2d');
ctx.strokeStyle = lineColourStr;
ctx.lineWidth = lineWidthStr;
console.log(firstSample);
ctx.beginPath();
ctx.moveTo( originX+firstSample-1, dataSamples[firstSample-1]+originY );
for (var i=0; i<nSamplesToDraw; i++)
{
var curSample = dataSamples[i + firstSample];
ctx.lineTo( originX+firstSample+i, curSample+originY );
}
ctx.stroke();
}
var curFrame=0;
var nPointsPerFrame = 4;
function drawCurFrame()
{
if ((dataSamples.length - (nPointsPerFrame * curFrame)) < nPointsPerFrame) // will we over-run the end of the array of datapoints?
{
curFrame = 0; // if so, reset
drawBkg(byId('canvas'), 9.43, 5, "0.5", "1.5", "black");
}
drawSamples(nPointsPerFrame, nPointsPerFrame*curFrame, "1", "blue");
curFrame++;
requestAnimationFrame( drawCurFrame );
}
</script>
<style>
#canvas
{
border: solid 1px black;
background-color: #FFFFFF;
}
</style>
</head>
<body>
<div id='txt'></div>
<canvas id="canvas" width="1350" height="1300"></canvas>
</body>
</html>
Update
Now that I see you have provided some more info I get what you want.
The problem is you need to draw a fixed number of line segments within time t.
As you do not know how long each frame could take you can not rely on a fixed frame rate. The alternative it to just use the current time and save the end time.
Get the start time and then each frame draw all the should be drawn until the current time. As the line segments being drawn will not be displayed until the next screen refresh the time you get will be approx 16ms behind so will need to adjust for that.
What I have done is keep track of the average frame time and used half that time to estimate when the new canvas update will be displayed.
Its a bit pedantic but might as well show how to get a required time as close as possible. If you dont care its a few ms out then just remove the average frame time stuff. You will be at most 30ms off on a slow machine.
var canvas; // canvas
var ctx;
function getCanvas () {
// to do
// get canvas and context
}
function drawGrid () {
// to do
// draw the grid
}
function drawTimedLine(){
if(canvas === undefined){ // if the canvas not available get it
getCanvas();
}
// clear the canvas is repeating animation
ctx.clearRect(0, 0, canvas.width, canvas.height);
drawGrid();
var array_1 = ; // your data
// All stuff needed for timed animation.
// The frame you render will not be displayed untill the next
// vertical refresh which is unknown, Assume it is one frame.
var startDelay = 1000; // if Needed time in milliseconds to delay start
var endTime; // hold the time that the animation has to end
var lastDataPoint; // holds the last point drawn to
var timeToDraw = 5 * 1000; // how long the animation should last
var repeatAfter = 1 *1000; // if you want to repeat the animatoin
var frameCount = 0; // count the frames to get average frame time
var startTime; //the start time;
var numberPoints = array_1.length; // number of points;
var startX = 49; // line starts at
var yOffset = 72; // line Y offset
var endX = 512; // line ends at.
var width = endX - startX; // width
var xStep = width / numberPoints; // X step per point
var pointsPerMS = numberPoints / timeToDraw; // get how many points per ms should be drawn
// function to draw
function drawWave() {
// variable needed
var averageframeTime, timeLeft, i, currentTime;
currentTime = new Date().valueOf(); // gets the time in millisecond;
if (startTime === undefined) { // Is this the first frame
startTime = currentTime; // save the start time;
endTime = currentTime + timeToDraw; // workout when the end time is;
lastDataPoint = 0; // set the data position to the start;
averageframeTime = 0; // no frames counted so frame time is zero
} else {
frameCount += 1; // count the frames
// get the average frame time
averageframeTime = (currentTime - startTime) / frameCount;
}
// get the time this frame
// will most likely be displayed
// then calculate how long
// till the end
timeLeft = endTime - Math.min(endTime, currentTime + averageframeTime / 2);
// now get where we should
// be when the frame is presented
pointPos = Math.floor(pointsPerMS * (timeToDraw - timeLeft));
// now draw the points from where we last left of
// till the new pos;
ctx.lineWidth = 4;
ctx.strokeStyle = 'blue';
ctx.beginPath();
ctx.moveTo( // move to first point
lastDataPoint * xStep + startX,
array_1[lastDataPoint] + yOffset
);
// draw each line from the last drawn to the new position
for (i = lastDataPoint + 1; i <= pointPos && i < numberPoints; i++) {
// Add the line segment
ctx.lineTo(
i * xStep + startX,
array_1[i] + yOffset
);
}
ctx.stroke(); // execute the render commands
lastDataPoint = pointPos; // update the last point
if (pointPos < numberPoints) { // are we there yet???
requestAnimationFrame(drawWave); // no so request another frame
}else{
// if you want to repeat the animation
setTimeout(drawTimedLine , repeatAfter );
}
}
// start the line animation with delay if needed
setTimeout(drawWave,startDelay);
}
// use this if you want it to start as soon as page is ready.
document.addEventListener("DOMContentLoaded",drawTimedLine);
// or use if you want it to start when page has images loaded and is ready
// document.addEventListener("load",drawTimedLine);
I have also added the ability to repeat the animation. If not needed just remove that code
My original answer
Dont know what the problem is with speed as it runs quite well on my machine.
To set up a better start use
function startFunction(){
// your code
}
document.addEventListener("DOMContentLoaded",startFunction);
This will wait until the page has loaded and parsed the page. Images and other media may not have loaded but the page is ready to be manipulated.
Not sure what you mean with 5 seconds. Assuming you may want the thing to sart in 5 seconds.
The following will do that.
document.addEventListener("DOMContentLoaded",function() {setTimeout(startFunction,5000);});
I would ask why plot the graph one entry at a time with requestAnimationFrame 1250 is not that many lines to draw. If you add ctx.beginPath() ctx.moveTo(/*first point*/) then loop all points with ctx.moveTo(/*points*/) then ctx.stroke() will run realtime on but the slowest of devices.
BTW ctx.lineWidth is a Number not a string. Also you have two context? Use the one context for the canvas. Remove ctxt and just use ctx and finally you don't need to add type='text/javascript' to the script tag as Javascript is the default.
1) It cannot take that long to draw 1000 lines, even 100000 lines won't take more than 10 ms on any decent Browser. Look else where the time is lost.
2) The core issue of your code is that it lacks modularity. Split your code into a few clear functions, group the parameters into a few objects only, name and indent things properly.
Below an (incomplete but working) example of how this might look.
var cv, ctx;
var data = null;
var debug = true;
// ---------------------------------------
// define here all graphic related parameters
var gfxParams = {
canvasWidth: 600,
canvasHeight: 600,
gridColor: '#A66',
gridSpacing: 10,
gridLineWidth: 0.5,
gridStrongLinesEvery: 5,
lineColor: '#AEB',
lastLineColor: '#8A9' // , ...
};
// define here all animation related parameters
var animationParams = {
duration: 5,
startTime: -1
}
// ---------------------------------------
// main
// ---------------------------------------
window.onload = function() {
data = getData();
setupCanvas(data);
launchAnimation();
}
// ---------------------------------------
//
function setupCanvas(data) {
cv = document.getElementById('cv');
cv.width = gfxParams.canvasWidth;
cv.height = gfxParams.canvasHeight;
ctx = cv.getContext('2d');
// here you should translate and scale the context
// so that it shows your data.
}
function drawGrid(ctx) {
var i = 0,
pos = 0,
lw = gfxParams.gridLineWidth;
ctx.fillStyle = gfxParams.gridColor;
var vLineCount = gfxParams.canvasWidth / gfxParams.gridSpacing;
for (i = 0; i < vLineCount; i++) {
pos = i * gfxParams.gridSpacing;
ctx.fillRect(pos, 0, lw, gfxParams.canvasHeight);
}
var hLineCount = gfxParams.canvasHeight / gfxParams.gridSpacing;
for (i = 0; i < hLineCount; i++) {
pos = i * gfxParams.gridSpacing;
ctx.fillRect(0, pos, gfxParams.canvasWidth, lw);
}
}
function animate() {
requestAnimationFrame(animate);
var now = Date.now();
// erase screen
ctx.clearRect(0, 0, gfxParams.canvasWidth, gfxParams.canvasHeight);
// draw grid
drawGrid(ctx);
// draw lines
var lastIndex = getLastDrawnIndex(data, now - animationParams.startTime);
drawLines(ctx, data, lastIndex);
if (debug) {
ctx.save();
ctx.fillStyle = '#000';
ctx.fillText(lastIndex + ' lines drawn. Time elapsed : ' + (now - animationParams.startTime), 10, 10);
ctx.restore();
}
}
// comment
function launchAnimation() {
requestAnimationFrame(animate);
animationParams.startTime = Date.now();
}
// comment
function getData() {
var newData = [];
for (var i = 0; i < 500; i++) {
newData.push([Math.random() * 600, Math.random() * 600]);
}
return newData;
}
// comment
function getLastDrawnIndex(data, timeElapsed_ms) {
var timeElapsed = timeElapsed_ms / 1000;
if (timeElapsed >= animationParams.duration) return data.length - 1;
return Math.floor(data.length * timeElapsed / animationParams.duration);
}
function drawLines(ctx, data, lastIndex) {
ctx.strokeStyle = gfxParams.lineColor;
// other ctx setup here.
for (var i = 0; i < lastIndex - 1; i++) {
drawLine(ctx, data[i], data[i + 1]);
}
ctx.strokeStyle = gfxParams.lastLineColor;
drawLine(ctx, data[lastIndex - 1], data[lastIndex]);
}
function drawLine(ctx, p1, p2) {
ctx.beginPath();
ctx.moveTo(p1[0], p1[1]);
ctx.lineTo(p2[0], p2[1]);
ctx.stroke();
}
<canvas id='cv'></canvas>

HTML5 canvas blinks while refreshing

I need to refresh an HTML5 canvas every two or three seconds.
setInterval(writeCanvas, 2000);
This canvas is filled with points and lines. Each abscissa and ordinate is stored in an XML file. So before updating the canvas I do an async request to the file on the server.
The problem is that the canvas blinks. I guess it disappears while the async request is running.
How could I get around this issue?
Here is the code of writeCanvas:
function drawLines(ctx, back, front, width, xArray, yArray) {
ctx.strokeStyle = back;
ctx.fillStyle = front;
ctx.lineWidth = width;
ctx.beginPath();
ctx.moveTo(xArray[0], yArray[0]);
for (var i=1; i<xArray.length; i++) {
ctx.lineTo(xArray[i],yArray[i]);
}
ctx.fill();
ctx.stroke();
ctx.closePath();
}
function drawPoint(ctx, back, front, x, y, radius, startAngle, endAngle) {
ctx.strokeStyle = back;
ctx.fillStyle = front;
ctx.beginPath();
ctx.arc(x,y,radius,startAngle,endAngle,endAngle);
ctx.fill();
ctx.stroke();
ctx.closePath();
}
function writeLabel(ctx, color, font, x, y, text) {
ctx.fillStyle = color;
ctx.font = font;
ctx.beginPath();
if(x < 0) {
x = 0;
}
ctx.fillText(text, x, y);
ctx.fill();
ctx.closePath();
}
function writeCanvas()
{
var elem = document.getElementById('profileCanvas');
if (!elem || !elem.getContext) {
return;
}
var ctx = elem.getContext('2d');
if (!ctx) {
return;
}
// apply the final size to the canvas
elem.setAttribute('width', canvasWidth);
elem.setAttribute('height', canvasHeight);
$.get('profileStatus.xml', function(xml) {
if(xml) {
var testPoints = new Array();
$(xml).find('TP').each(function() {
var selected = $(this).find('SELECTED:first').text();
if(selected == "YES") {
var name = $(this).find('MODULE_NAME:first').text();
var state = $(this).find('STATE:first').text();
var tp = new ProfileTp(name, state, selected);
testPoints.push(tp);
}
});
$.get('profile.xml', function(data) {
if(data) {
profileWidth = parseFloat($(data).find('MAIN > PROFILE > DIM_W').first().text());
profileHeight = parseFloat($(data).find('MAIN > PROFILE > DIM_H').first().text());
var backgroundColor = '#ddd';
var color = '#323232';
ctx.translate(0,canvasHeight);
var xArray = new Array();
var yArray = new Array();
$(data).find('PROFILE > POINT > X').each(function(){
var x=parseFloat($(this).text());
xArray.push(x);
});
$(data).find('PROFILE > POINT > Y').each(function(){
var y=parseFloat($(this).text());
yArray.push(y);
});
drawLines(ctx, backgroundColor, color, 2, xArray, yArray);
var finalArray = new Array();
$(data).find('TESTPOINTS > TP').each(function() {
var labelName = $(this).find('MODULE_NAME:first').text();
var tp = $.grep(testPoints, function(obj){ return obj.NAME == labelName; });
if(tp.length == 1) {
$(this).find('IHM').each(function(){
tp[0].LABEL_X = parseFloat($(this).find('LABEL > X:first').text());
tp[0].LABEL_Y = parseFloat($(this).find('LABEL > Y:first').text());
tp[0].MARKER_X = parseFloat($(this).find('MARKER > X:first').text());
tp[0].MARKER_Y = parseFloat($(this).find('MARKER >Y:first').text());
});
finalArray.push(tp[0]);
}
});
for(var i=0; i<finalArray.length; i++) {
writeLabel(ctx, color, fontSize+"px Arial",(finalArray[i].MARKER_X+finalArray[i].LABEL_X),(finalArray[i].MARKER_Y+finalArray[i].LABEL_Y), finalArray[i].NAME);
drawPoint(ctx, backgroundColor, color, finalArray[i].MARKER_X, finalArray[i].MARKER_Y, 8, 0, 2*Math.PI);
}
} else {
console.error('No XML test points returned');
}
});
}
});
}
There are two XML files. One contains all the points, lines and labels. The second contains only the points and labels that have to be displayed.
Setting a canvas' dimensions clears it entirely, so the lines :
elem.setAttribute('width', canvasWidth);
elem.setAttribute('height', canvasHeight);
are likely to make your canvas 'blink'. GET requests are asynchronous so the canvas is cleared way before points data are computed and drawn.
To fix this, change the dimensions inside your requests callbacks, right before drawing.
Crogo already mention the probable cause in the answer, but as a work around you could do:
if (elem.width !== canvasWidth || elem.height !== canvasHeight) {
// apply the final size to the canvas
elem.setAttribute('width', canvasWidth);
elem.setAttribute('height', canvasHeight);
}
The canvas size is only set if the size change.
You should also try to avoid using setInterval (what if client is on a slow/unstable connection that makes it take longer than 2 second to load data..). If the download is still in progress and setInterval triggers you will initiate another download while the first one is still downloading. You will also risk get "double drawings" to the canvas as these calls stack up in the event queue:
Rather trigger an setTimeout from inside your writeCanvas():
function writeCanvas()
{
//... load and draw
setTimeout(writeCanvas, 1500); //compensate for time
}
Of course, if the data MUST be loaded every two seconds this would be inaccurate (not that setInterval is.. they both give an estimate only).

Categories