How do you get p5.js into a website? - javascript
I have searched nearly all over the internet, and i've gotten pretty close to an answer, but I still can't figure out how to use p5.js in a website. To be more specific, i want to be able to perhaps create a weebly, and have it display p5 code. i know it involves the website loading the p5.js through a file or the online file, and the sketch.js. If there is no way to use p5.js on the web, is there any way to use processing code in general(or something similar) on the internet? Thanks
Follow these instructions: http://p5js.org/get-started/
Or these instructions: https://github.com/processing/p5.js/wiki/Embedding-p5.js
In other words, you need to create an html file that uses p5.js, which you should already have.
Then you need to upload that html file, along with any resources you're using, to some kind of web host.
You might also want to check out Processing.js, which comes with the standard Processing editor.
creat html file and a sketch.js file
in your html file you can put in a starter template and then add p5js in the sketch.js
check the docs here
// All the paths
var paths = [];
// Are we painting?
var painting = false;
// How long until the next circle
var next = 0;
// Where are we now and where were we?
var current;
var previous;
function setup() {
createCanvas(720, 400);
current = createVector(0,0);
previous = createVector(0,0);
};
function draw() {
background(200);
// If it's time for a new point
if (millis() > next && painting) {
// Grab mouse position
current.x = mouseX;
current.y = mouseY;
// New particle's force is based on mouse movement
var force = p5.Vector.sub(current, previous);
force.mult(0.05);
// Add new particle
paths[paths.length - 1].add(current, force);
// Schedule next circle
next = millis() + random(100);
// Store mouse values
previous.x = current.x;
previous.y = current.y;
}
// Draw all paths
for( var i = 0; i < paths.length; i++) {
paths[i].update();
paths[i].display();
}
}
// Start it up
function mousePressed() {
next = 0;
painting = true;
previous.x = mouseX;
previous.y = mouseY;
paths.push(new Path());
}
// Stop
function mouseReleased() {
painting = false;
}
// A Path is a list of particles
function Path() {
this.particles = [];
this.hue = random(100);
}
Path.prototype.add = function(position, force) {
// Add a new particle with a position, force, and hue
this.particles.push(new Particle(position, force, this.hue));
}
// Display plath
Path.prototype.update = function() {
for (var i = 0; i < this.particles.length; i++) {
this.particles[i].update();
}
}
// Display plath
Path.prototype.display = function() {
// Loop through backwards
for (var i = this.particles.length - 1; i >= 0; i--) {
// If we shold remove it
if (this.particles[i].lifespan <= 0) {
this.particles.splice(i, 1);
// Otherwise, display it
} else {
this.particles[i].display(this.particles[i+1]);
}
}
}
// Particles along the path
function Particle(position, force, hue) {
this.position = createVector(position.x, position.y);
this.velocity = createVector(force.x, force.y);
this.drag = 0.95;
this.lifespan = 255;
}
Particle.prototype.update = function() {
// Move it
this.position.add(this.velocity);
// Slow it down
this.velocity.mult(this.drag);
// Fade it out
this.lifespan--;
}
// Draw particle and connect it with a line
// Draw a line to another
Particle.prototype.display = function(other) {
stroke(0, this.lifespan);
fill(0, this.lifespan/2);
ellipse(this.position.x,this.position.y, 8, 8);
// If we need to draw a line
if (other) {
line(this.position.x, this.position.y, other.position.x, other.position.y);
}
}
<html>
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.6.0/p5.js"></script>
<script src="sketch.js"></script>
</head>
<body>
</body>
</html>
If you are creating your sketch using the editor for Mac or Windows (Version 0.5.7 (0.5.7) as of this writing), go to "Save As" and the editor will export your "web ready" files.
Your saved file will have the same name as your sketch and will include an index.html and sketch.js file along with a "libraries" folder. You can post the .html and .js files as-is and inspect the .html for links to the p5 .js libraries.
<script src="libraries/p5.js" type="text/javascript"></script>
<script src="libraries/p5.dom.js" type="text/javascript"></script>
<script src="libraries/p5.sound.js" type="text/javascript"></script>
<script src="sketch.js" type="text/javascript"></script>
Related
Add local storage to save canvas drawing
I do not know how to add local storage to save the drawing made on the canvas so when the page is reloaded the existing drawing is loaded onto the canvas through local storafe. I do not have must experience so would appreciate if someone could edit my code with the local storage addition. Many thanks in advance! Here is my JS: var canvas, ctx, brush = { x: 0, y: 0, color: '#000000', size: 10, down: false, }, strokes = [], currentStroke = null; function redraw () { ctx.clearRect(0, 0, canvas.width(), canvas.height()); ctx.lineCap = 'round'; for (var i = 0; i < strokes.length; i++) { var s =strokes[i]; ctx.strokeStyle = s.color; ctx.lineWidth = s.size; ctx.beginPath(); ctx.moveTo(s.points[0].x, s.points[0].y); for (var j = 0; j < s.points.length; j++){ var p = s.points[j]; ctx.lineTo(p.x, p.y); } ctx.stroke(); } } function init () { canvas = $('#draw'); canvas.attr({ width: window.innerWidth, height: window.innerHeight, }); ctx = canvas[0].getContext('2d'); function mouseEvent (e){ brush.x = e.pageX; brush.y = e.pageY; currentStroke.points.push({ x: brush.x, y: brush.y, }); redraw(); } canvas.mousedown(function (e){ brush.down = true; currentStroke = { color: brush.color, size: brush.size, points: [], }; strokes.push(currentStroke); mouseEvent(e); }) .mouseup(function (e) { brush.down = false; mouseEvent(e); currentStroke = null; }) .mousemove(function (e) { if (brush.down) mouseEvent(e); }); $('#save-btn').click(function () { window.open(canvas[0].toDataURL()); }); $('#undo-btn').click(function (){ strokes.pop(); redraw(); }); $('#clear-btn').click(function (){ strokes = []; redraw(); }); $('#color-picker').on('input', function () { brush.color = this.value; }); $('#brush-size').on('input', function () { brush.size = this.value; }); } $(init);
Canvas.js will save the canvas as an image to the localStorage which is not helpful in your case as you're storing the mouse events in an array. If you're looking for a solution which lets continue the drawing on canvas along with restoring old (saved) elements, what you would need is storing of the canvas elements (strokes array in your case) in the localStorage and restoring, redrawing the canvas. Here's a demo doing that: JS FIDDLE DEMO Draw anything on the canvas. Click on the "Save to local storage" button at the bottom. Refresh the page. To clear localStorage, clear the browser cache. Relevant code changes: Added a button in HTML to save to local storage <button id="save-to-local-storage"> Save to local storage </button> Saving the strokes array to the localStorage on above button click. $('#save-to-local-storage').click(function () { localStorage.setItem('canvas_strokes', JSON.stringify(strokes)); }); On page refresh, check if localStorage has items set and if YES, redraw the canvas: // check if localstorage has an array of strokes saved if(localStorage.getItem('canvas_strokes')) { strokes = JSON.parse(localStorage.getItem('canvas_strokes')); redraw(); } Let me know if you have any questions. Hope this helps. :)
Using the Canvas.js helper you can simply do: const canvas = new Canvas( 'my-canvas' ); canvas.saveToStorage( 'balls' ); where my-canvas is the canvas id balls is the key to save it as To later restore a canvas state: const canvas = new Canvas( 'my-canvas' ); canvas.restoreFromStorage( 'balls' ); Load Canvas.js: <script type="text/javascript" src="https://gustavgenberg.github.io/handy-front-end/Canvas.js"> EDIT After reading the below post (Thank you #Shashank), ive made a jsfiddle with the complete code to achieve continous drawing. It automatically saves the last stroke on mouseup and loads it in on refresh. Check it out! It uses Canvas.js and Pointer.js: https://jsfiddle.net/wk5ttqa2/ EDIT 2 Just for fun... this is as simple as it can get really: https://jsfiddle.net/GustavGenberg/1929f15t/1/ Note that it does not draw complete lines when moving fast (depends on framerate)...
Phaser JS walk up tile based stairs
I'm creating a small 2d-minecraft clone, in Phaser js, on my own as a learning experience. So far I have gotten player movement and random level seeds to work ok. I am using Phasers P2JS engine and have sprites that are box based. What I'm struggling with now Is I want the player to be able to walk unhindered up small elevations, (1-tile high) but I don't have any good idea of how I should Implement this. I have tried changing the bounding box of the player so that it had a slope at the bottom but this gets me in to a bunch of trouble with wall climbing. I want a way to do this where it gets as seamless as possible. Preferably the player speed is not altered much by climbing the steps. I am concidering writing some kind of collision detection function to handle this but I am uncertain if this is the best way to do it. Thanks for your help. Below is my code and an image that shows the kind of step I want to beable to walk up. Its the first elevation to the left in the image. var pablo = require('../generators/pablo.js'); var destiny = {}; var socket; var player; var jumpButton; var levelCollisionGroup; var playerCollisionGroup; destiny.create = function () { console.info("game loaded"); // World this.game.world.setBounds(0, 0, 4000, 1000); this.game.physics.startSystem(Phaser.Physics.P2JS); this.game.physics.p2.gravity.y = 600; this.game.physics.p2.applySpringForces= false; this.game.physics.p2.applyDamping= false; this.game.physics.p2.restitution = 0; this.game.physics.p2.friction = 0.01; // Player playerCollisionGroup = this.game.physics.p2.createCollisionGroup(); player = this.game.add.sprite(this.game.world.centerX, 800, 'player'); this.game.physics.p2.enable(player,true); player.body.fixedRotation = true; player.body.setCollisionGroup(playerCollisionGroup); player.body.mass = 2; // Camera this.game.camera.follow(player); this.game.camera.deadzone = new Phaser.Rectangle(200, 0, 400, 100); // Controls jumpButton = this.game.input.keyboard.addKey(Phaser.Keyboard.SPACEBAR); leftButton = this.game.input.keyboard.addKey(Phaser.Keyboard.A); rightButton = this.game.input.keyboard.addKey(Phaser.Keyboard.D); // Level levelCollisionGroup = this.game.physics.p2.createCollisionGroup(); this.game.physics.p2.updateBoundsCollisionGroup(); for (i = 0; i < 280; i = i + 1) { var block; var height = pablo.getHeight(i); for(j = 0; j < height; j = j + 1){ if(j === height-1){ block = this.game.add.sprite(15*i, 993-15*j, 'grass'); } else { block = this.game.add.sprite(15*i, 993-15*j, 'dirt'); } block.width = 15; block.height = 15; this.game.physics.p2.enable(block); block.body.static=true; block.body.immovable = true; block.body.collides([levelCollisionGroup, playerCollisionGroup]); block.body.setCollisionGroup(levelCollisionGroup); if(j == height){ } } } player.body.collides(levelCollisionGroup); this.game.stage.backgroundColor = "#5599CC"; }; destiny.update = function() { player.body.velocity.x=0; if (leftButton.isDown) { player.body.velocity.x = -200; } else if (rightButton.isDown) { player.body.velocity.x = 200; } if (jumpButton.isDown && this.checkIfCanJump()) { player.body.velocity.y = -400; } }; destiny.render = function() { this.game.debug.cameraInfo(this.game.camera, 32, 32); this.game.debug.spriteCoords(player, 32, 550); }; destiny.checkIfCanJump = function() { var result = false; for (var i=0; i < this.game.physics.p2.world.narrowphase.contactEquations.length; i++) { var c = this.game.physics.p2.world.narrowphase.contactEquations[i]; if (c.bodyA === player.body.data || c.bodyB === player.body.data) { var d = p2.vec2.dot(c.normalA, p2.vec2.fromValues(0, 1)); if (c.bodyA === player.body.data) { d *= -1; } if (d > 0.5) { result = true; } } } return result; }; module.exports = destiny; ===================== Edit ===================== I have now tried creating slopes of the edge pieces when generating the world. But I realized that this makes me have to regenerate the world when I later add the feature for hacking away blocks. Thus this is not the solution. I think I will need to do some collision detection and move the player up when I hit an edge. But I'm not quite sure how to do this in phaser. Any help is still appreciated. !!! Here is an image of what not to do !!!
Emanuele Feronato has a post on replicating the game Magick in Phaser. There he covers the case of a block colliding with a barrier/wall, with the ability of the block to climb one level up. You can check the tutorial, but what he appears to be doing is checking to see if the diagonal tile is empty (in other words, is it just a 'step' up), and if it is, running a 'jump' function, which looks more like a climb. Depending upon how you want your character to step, you could potentially look at both the next tile (on the x-axis) as well as the one after it to check for the height. So for example, if moving right and the next tile is flat, but the second tile has a step, you might start moving your character up on the y-axis.
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 continuously stroking lines
I want to draw some continuously growing lines in HTML5 and Javascript. Here is what I want to do: A point located at the center of my screen will have 3 lines growing (120 degree to each other) to a certain length, say 50 pix, then each of this 3 vertex will become a new center and have another 3 lines. (I couldnt post images due to low reputation I have, hopefully you know what I mean abt the image here...) I already written the function to have a array of all the points I need as the centers, starting from the center of my screen. I am thinking to write a loop over this array to draw the lines. I DO NOT want to directly use the stroke so that the line just appears on the screen. I want to have something like the the lines are drawn bit by bit (bad english here, please excuse my english) until it reaches the pre-defined length. However my code dont work quite well here, it only displays all the center points and only the last center point has the movement to have the 3 lines to grow... I need to know the correct way to do this... many thanks in advance! (please ignore the variable time or startTime in my code... ) <script> window.requestAnimFrame = (function(callback) { return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame || function(callback) { window.setTimeout(callback, 1000 / 60); }; })(); var canvas = document.getElementById('myCanvas'); canvas.width= window.innerWidth; canvas.height= window.innerHeight; var context = canvas.getContext('2d'); var totalLength = 50; var centreSet = new Array(); var counter = 0; var centre = { x: canvas.width / 2, y: canvas.height / 2, }; var myLine = { length : 0, color : 'grey', lineWidth : 0.5, }; function drawLine(centre, context, mylength) { context.beginPath(); context.moveTo(centre.x, centre.y); context.lineTo(centre.x, centre.y - mylength); context.moveTo(centre.x, centre.y); context.lineTo(centre.x - 0.866 * mylength, centre.y + mylength/2); context.moveTo(centre.x, centre.y); context.lineTo(centre.x + 0.866 * mylength, centre.y + mylength/2); context.lineWidth = myLine.lineWidth; context.strokeStyle = myLine.color; context.closePath(); context.stroke(); } function startAnimate(centre, canvas, context, startTime, mylength) { // update var time = (new Date()).getTime() - startTime; var linearSpeed = 5; // pixels / second var newX = linearSpeed / 10; if(mylength < totalLength) { mylength = mylength + newX; // clear //context.clearRect(0, 0, canvas.width, canvas.height); drawLine(centre, context, mylength); // request new frame requestAnimFrame(function() { startAnimate(centre, canvas, context, startTime, mylength); }); } } function animate(centre, canvas, context, startTime){ //create array to have all the center points centreSet = getCentres(); for (var i = 0; i < centreSet.length; i++){ //pass the x and y values in a object for each center we have in the array centre.x = str2x(centreSet[i]); centre.y = str2y(centreSet[i]); startAnimate(centre, canvas, context, startTime, 0); } } setTimeout(function() { var startTime = (new Date()).getTime(); animate(centre, canvas, context, startTime); }, 1000); I just edited your code, I added the following part: var length = 0; for(var i = 0; i < 380; i++){ window.setTimeout(function() {drawFrame(length);},16.67); length = length + 0.25; } I expect the screen appears to draw the incremental lines bit by bit until it reaches the length I want. However, it seems like the whole incremental process is not shown and it only shows the finished drawing. Can anyone tell me why?
Regarding your followup question about why your animation loop fails By putting your setTimeout in a for-loop, each new setTimeout is cancelling the previous setTimeout. So you’re just left with the very last setTimeout running to completion. In an animation loop, you typically do 3 things during each "frame": Change some data to reflect how the new frame is different from the previous frame. Draw the frame. Test if the animation is complete. If not, do another frame (go to #1). The setTimeout function is used to do the last part of #3 (do another frame) So setTimeout is really acting as your animation loop. --- Your for-loop is not needed. This is how you would restructure your code to follow this pattern: var length=0; var maxLength=50; function draw(){ // make the line .25 longer length=length+.25; // draw drawFrame(length); // test if the line is fully extended // if not, call setTimeout again // setTimeout(draw,100) will call this same draw() function in 100ms if(length<maxLength){ setTimeout(draw,100); } }
[Edited: to include spawning of child objects after lines reach terminal distance] In your code you were not spawning new center points when the lines reached their maximum extension. I would suggest that each of your centre objects have at least this much information in order to spawn a new set of centre objects when their lines reach terminal length: var newCentrePoint={ x:x, y:y, maxLength:newMaxLength, growLength:growLength, currentLength:0, isActive:true } The x,y are the centerpoint’s coordinates. maxLength is the maximum extension of the 3 lines before they are terminated. growLength is the amount by which each line will grow in each new frame. currentLength is the current length of the line. isActive is a flag indicating if this point is growing lines (true) or if it’s terminated (false) Then when each line reaches terminal length you can spawn a new set of lines like this: // spawns 3 new centre points – default values are for testing function spawn(point,newMaxLength,newColor,growLength,newLineWidth){ var max=newMaxLength||point.maxLength/2; var color=newColor|| (colors[++colorIndex%(colors.length)]); var grow=growLength||point.growLength/2; var lw=newLineWidth||point.lineWidth-1; // new center points are spawned at the termination points of the 3 current lines newPoint((point.x),(point.y-point.maxLength),max,color,grow,lw); newPoint((point.x-0.866*point.maxLength),(point.y+point.maxLength/2),max,color,grow,lw); newPoint((point.x+0.866*point.maxLength),(point.y+point.maxLength/2),max,color,grow,lw); } // creates a new point object and puts in the centreSet array for processing function newPoint(x,y,newMaxLength,newColor,growLength,newLineWidth){ var newPt={ x:x, y:y, maxLength:newMaxLength, color:newColor, lineWidth:newLineWidth, growLength:growLength, currentLength:0, isActive:true } centreSet.push(newPt); } Here is code and a Fiddle: http://jsfiddle.net/m1erickson/Vc8Gf/ <!doctype html> <html> <head> <link rel="stylesheet" type="text/css" media="all" href="css/reset.css" /> <!-- reset css --> <script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script> <style> body{ background-color: ivory; } canvas{border:1px solid red;} </style> <script> $(function(){ var canvas=document.getElementById("canvas"); var context = canvas.getContext('2d'); // colors var colors=["red","blue","gold","purple","green"]; var colorIndex=0; // var centreSet=[] var generations=1; // seed point newPoint(canvas.width/2,canvas.height/2,100,"red",15); // start draw(); // function draw(){ // context.clearRect(0,0,canvas.width,canvas.height); // for(var i=0;i<centreSet.length;i++){ // var centre=centreSet[i]; // if(centre.isActive){ // centre.currentLength+=centre.growLength; // if(centre.currentLength>=centre.maxLength){ centre.isActive=false; centre.currentLength=centre.maxLength; spawn(centre); } } // drawLines(centre); } // if(generations<120){ setTimeout(draw,500); }else{ context.font="18pt Verdana"; context.fillText("Finished 120 generations",40,350); } } function spawn(point,newMaxLength,newColor,growLength,newLineWidth){ var max=newMaxLength||point.maxLength/2; var color=newColor|| (colors[++colorIndex%(colors.length)]); var grow=growLength||point.growLength/2; var lw=newLineWidth||point.lineWidth-1; newPoint((point.x),(point.y-point.maxLength),max,color,grow,lw); newPoint((point.x-0.866*point.maxLength),(point.y+point.maxLength/2),max,color,grow,lw); newPoint((point.x+0.866*point.maxLength),(point.y+point.maxLength/2),max,color,grow,lw); generations++; } function newPoint(x,y,newMaxLength,newColor,growLength,newLineWidth){ var newPt={ x:x, y:y, maxLength:newMaxLength, color:newColor, lineWidth:newLineWidth, growLength:growLength, currentLength:0, isActive:true } centreSet.push(newPt); } function drawLines(centre) { var length=centre.currentLength; // context.beginPath(); context.moveTo(centre.x, centre.y); context.lineTo(centre.x, centre.y - length); // context.moveTo(centre.x, centre.y); context.lineTo(centre.x - 0.866 * length, centre.y + length/2); // context.moveTo(centre.x, centre.y); context.lineTo(centre.x + 0.866 * length, centre.y + length/2); // context.strokeStyle=centre.color; context.lineWidth = centre.lineWidth; context.stroke(); } }); // end $(function(){}); </script> </head> <body> <canvas id="canvas" width=400 height=400></canvas> </body> </html>
HTML 5 Canvas Image Rendering
First time poster here but definitely not a first time reader. My question is aimed directly at this portion of code I have. I am currently learning how HTML 5 canvases work and am designing my own RPG style game for a University project. After looking around I found some good tutorials on this guys blog, I have followed his code and triple checked it but images are now showing up. I tried putting an alert() before and after when the image is called to the canvas under drawMap(). It works before the image is drawn but not after, leading me to believe it is something to do with my image rendering. Can someone double check my code and see what is going on? It's driving me insane! <canvas id="game-viewport" width="760" height="440"></canvas> <script> window.onload = init; var map = Array([0,0],[0,0],[0,0],[0,0]); var tileSize = 40; tileTypes = Array("grass.png"); tileImage = new Array(); var loaded = 0; var loadTimer; function loadImage(){ for(i = 0; i < tileTypes.length; i++){ tileImage[i] = new Image(); tileImage[i].src = "./game/lib/icons/own_icons/" + tileTypes[i]; tileImage[i].onload = function(){ loaded++; } } } function loadAll(){ if(loaded == tileTypes.length){ clearInterval(loadTimer); drawMap(); } } function drawMap(){ var mapX = 80; var mapY = 10; for(i = 0; i < map.length; i++){ for(j = 0; j < map[i].length; j++){ var drawTile = map[i][j]; var xPos = (i - j) * tileSize; var yPos = (i + j) * tileSize; ctx.drawImage(tileImage[drawTile], xPos, yPos); } } } function init(){ var canvas = document.getElementById('game-viewport') var ctx = canvas.getContext('2d'); loadImage(); loadTimer = setInterval(loadAll, 100); } </script>
The only problem is that ctx is not defined in your drawMap function. Either pass ctx in to the function as an argument or make it a global variable. I was lazy and did the second, but you should really do the first. Working code: http://jsfiddle.net/YUddC/ You really should have the Chrome debugger (or whatever browser you use) on 100% of the time you're developing.. If you did, you'd see an error saying that ctx is not defined in drawMap. If you're using Chrome and press F12 to open developer tools and go to the scripts tab, you'd see this: Which makes the problem pretty clear!