I want to animate a growing line based on a dataset, I want the line to grow each time the program finds DAE in a Row of the third column.
Here is my p5js code here
let data;
let font;
let direction;
let montant;
let annee;
function preload() {
data=loadTable('data/subvention.csv','csv','header',chargementOK,chargementERROR);
font = loadFont("data/opensans.ttf");
}
function setup() {
createCanvas(700, 700);
}
function draw() {
background(1);
let nbDAE=0;
for (let i = 0; i < data.getRowCount(); i++) {
direction = data.getString(i, "direction");
if (direction == "DAE") {
nbDAE++;
fill(255);
rect(350, 700- nbDAE*12, 20, 700);
}
}
}
function chargementOK(mesData){
print("chargement OK");
print(mesData);
}
function chargementERROR(){
print("BUGG");
}
The problem is I think I did everything right but I'm not getting any animation from it, the line just appears and code keeps on going forever.
I need some help to figure out how to properly animate the growing line.
The draw() loop is executed 60 times per second, and in each loop, you have another loop wich totalizes all the values.
If you want to animate, you need to use a counter and increment it each draw() loop.
Initialization of counter and nbDAE should be at the exterior of the draw() loop.
function draw() {
background(0);
direction = data.getString(compteur, "direction");
if (direction == "DAE") {
nbDAE++;
}
fill(255);
rect(350, 700- nbDAE*12, 20, 700);
compteur += 1;
if (compteur >= data.getRowCount()) {
noLoop();
}
}
I had worked on your previous question : here on the p5js web editor
And on your previous question, the problem of csv file : In french, the separator is semicolon (;) and not comma (,). So, in the loadTable() function, the extension should be 'ssv' and not 'csv' (semicolon-separated values)
Related
I'll like to make some elements in an array appear at different times, the time will be decreasing over time (so the elements will appear faster and faster). I had tried with setTimeout and setInterval with no luck, I think it is because I'm looping through the array.
Here's a simple p5.js example that should hopefully point you in the right direction.
I'm calling the setTimeout function for every object on initialisation. The delay of the timeout is incremented by a value incrementor which decreases each iteration.
let circles = [];
let count = 100;
let incrementor = 500;
let delay = 500;
function setup() {
createCanvas(400, 400);
for (let i = 0; i < count; i++) {
let circle = {
x: random(width),
y: random(height),
show: false,
}
incrementor *= 0.9;
delay += incrementor;
setTimeout(() => circle.show = true, delay);
circles.push(circle);
}
}
function draw() {
background(220);
noStroke()
fill(0, 128, 128);
for (let circle of circles) {
if (circle.show) {
ellipse(circle.x, circle.y, 10, 10);
}
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.0/p5.min.js"></script>
You cannot achieve that via intervals. Yet, it's possible with recursive timeouts. For example, let's say that the time is decreasing by 2x:
const initialDuration = 10000;
function someAnimation(duration) {
// Your animation code here...
setTimeout(() => someAnimation(duration / 2), duration);
}
someAnimation(initialDuration);
This is my code that I tried. The ball is jumping when I pressing "up arrow key" or "space bar".The problem is that I am unable to move ball little bit forward when ball jumped.Can anybody help me please?
let jumper;
function setup() {
createCanvas(400, 400);
jumper = new Jumper();
}
function draw() {
clear();
jumper.run();
push();
fill(217);
textFont('Avenir');
textAlign(CENTER,CENTER);
textSize(33);
text('space bar to jump', width>>1, height*0.15);
pop();
}
function keyPressed() {
jumper.vel.y = -4;
jumper.vel.x=+5;
}
I set up a very basic example of what I think you might be working towards:
let jumper;
function setup() {
createCanvas(400, 400);
jumper = new Jumper();
}
function draw() {
clear();
jumper.run();
push();
fill(217);
textFont('Avenir');
textAlign(CENTER,CENTER);
textSize(33);
text('space bar to jump', width>>1, height*0.15);
pop();
}
function keyPressed() {
jumper.x+=5;
}
class Jumper {
constructor() {
this.x = 10;
this.y = height/2;
}
run() {
ellipse(this.x, this.y, 10, 10);
}
}
<script src="https://cdn.jsdelivr.net/npm/p5#0.10.2/lib/p5.js"></script>
#Dishant was correct in that your code had a typo in where you did jumper.vel.x =+ 5 which is basically just setting the position of the jumper to the x position of 5. When what you want is to actually make the jumper move 5 pixels forward - in my example this done using jumper.x += 5 but you'd of course use jumper.vel.x += 5 as that code wasn't shown in your question!
You need to remove the bug in the second last line.
jumper.vel.x += 5;
I am learning user input through mouse in p5.js and i want to create a square by 4 line method on 4 different clicks , 1 click for each line and the last click completing the square.
below code is for 2 lines but the are both running at the same time and i cannot understand the if command to separately run them .
function setup() {
createCanvas(400, 400);
background(220);
}
function draw() {
}
function mousePressed()
{
line(width/20,height/40,mouseX,mouseY);
line(pmouseX,pmouseY,mouseX,mouseY);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.9.0/p5.js"></script>
You've to store the points to a list. If the list contains 4 elements and the mouse is clicked again, clear the list:
var pts = [];
function mousePressed()
{
if (pts.length == 4) {
pts = [];
}
pts.push([mouseX, mouseY])
}
Do all the drawing continuously in draw(). Clear the background. Draw the liens between the points ins a loop. If the number of point is 4, the draw a line from the last point to the 1st point.
Additionally you can draw a "rubber" line from the last point to the current mouse position, if there is at least 1 point in the list:
function draw() {
background(220);
// draw the lines between the points
for (var i=0; i < pts.length-1; ++i) {
line(pts[i][0], pts[i][1], pts[i+1][0], pts[i+1][1]);
}
var close = pts.length == 4;
if (close) {
// draw line from 1st point to at point
line(pts[pts.length-1][0], pts[pts.length-1][1], pts[0][0], pts[0][1]);
}
else if (pts.length > 0) {
// draw a rubber line from last point to the mouse
line(pts[pts.length-1][0], pts[pts.length-1][1], mouseX,mouseY);
}
}
See the example
function setup() {
createCanvas(400, 400);
}
var pts = [];
function mousePressed()
{
if (pts.length == 4) {
pts = [];
}
pts.push([mouseX, mouseY])
}
function draw() {
background(220);
// draw the lines between the points
for (var i=0; i < pts.length-1; ++i) {
line(pts[i][0], pts[i][1], pts[i+1][0], pts[i+1][1]);
}
var close = pts.length == 4;
if (close) {
// draw line from 1st point to at point
line(pts[pts.length-1][0], pts[pts.length-1][1], pts[0][0], pts[0][1]);
}
else if (pts.length > 0) {
// draw a rubber line from last point to the mouse
line(pts[pts.length-1][0], pts[pts.length-1][1], mouseX,mouseY);
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.9.0/p5.js"></script>
var context = document.getElementById("canvas").getContext("2d");
for(var i = 0; i< savedMove.length; i++){
doSetTimeout(i);
}
function doSetTimeout(i) {
setInterval(function() { animate(savedMove[i][0], savedMove[i][1]); }, 100);
}
function animate(xPos, yPos) {
context.fillStyle = "red";
context.fillRect(xPos, yPos, 5, 5);
}
I have every x and y position move inside of 2D array (savedMove) and I want to draw with array information with delay. But Canvas does not draw this. I keep debugging but I cannot figure out the problem.
You're setting savedMove.length timers to tick parallelly every 100 milliseconds. I'm pretty sure this is not what you want, though it's hard to guess what it is. First I would change setInterval to setTimeout and make them fire at different times, 100 ms away from each other:
function doSetTimeout(i) {
setTimeout(function() { animate(savedMove[i][0], savedMove[i][1]); }, 100 * i);
}
Note that this is not the best way to do it, but certainly better than the original code.
Then you can debug it, 'cause you might draw out of the visible canvas:
console.log("canvas size:", document.getElementById("canvas").width, document.getElementById("canvas").height);
function animate(xPos, yPos) {
context.fillStyle = "red";
context.fillRect(xPos, yPos, 5, 5);
console.log("animate:", xPos, yPos);
}
I change the text color with requestAnimationFrame(animate); function:
requestAnimationFrame(animate);
function animate(time){
... // change text color here
if (offset_s < offset_e) {requestAnimationFrame(animate);}
}
offset_s and offset_s indicates start and end positions of the text for color change. In some cases the animation should last for 2 seconds, but in order cases - for 5 seconds, but offset_e - offset_s could be the same in these two cases. What can I do to control the speed of animation based on given time in seconds/milliseconds?
From the tags of the question i can only see that you animate something drawn on canvas and thats why u cannot use css-animation or jquery-animation.
You have to control the length of the animation by calculating the time difference.
u can do it similar to this example
function start_animate(duration) {
var requestID;
var startTime =null;
var time ;
var animate = function(time) {
time = new Date().getTime(); //millisecond-timstamp
if (startTime === null) {
startTime = time;
}
var progress = time - startTime;
if (progress < duration ) {
if(offset_s < offset_e){
// change text color here
}
requestID= requestAnimationFrame(animate);
}
else{
cancelAnimationFrame(requestID);
}
requestID=requestAnimationFrame(animate);
}
animate();
}
trigger your animation and call start_animate(2000) //duration in millisecond 1000=1 sec
You should separate concerns clearly.
Have a single requestAnimationFrame running, which computes the current animation time and calls every update and draw related functions.
Then your animations would be handled by a function (or class instance if you go OOP) that deals with the current animation time.
Just some direction for the code :
var animationTime = -1;
var _lastAnimationTime = -1;
function launchAnimation() {
requestAnimationFrame(_launchAnimation);
}
function _launchAnimation(time) {
animationTime = 0;
_lastAnimationTime = time;
requestAnimationFrame(animate);
}
function animate(time){
requestAnimationFrame(animate);
var dt = time - _lastAnimationTime ;
_lastAnimationTime = time;
animationTime += dt;
// here call every draw / update functions
// ...
animationHandler.update(animationTime);
animationHandler.draw(context);
}
To start your 'engine', just call launchAnimation then you'll have a valid animationTime and dt to deal with.
I'd make animationHandler an instance of an AnimationHandler class, that allows to add/remove/update/draw animations.
I suggest to use setInterval function in JavaScript.
requestAnimationFrame really needs some 'ugly' calculations. Don't
believe me? Scroll up, you will see...
So, to make setInterval function as handy as rAF(requestAnimationFrame) store the function inside of variable. Here is an example:
var gameLoop = setInterval(function() {
update();
draw();
if (gameOver)
clearInterval(gameLoop);
}, 1000/FPS);
given way, you can control your FPS and pick correct velocity for your objects.
I typically do something like
es6
constructor() {
this.draw();
}
draw() {
const fps30 = 1000 / 30;
const fps60 = 1000 / 60;
window.requestAnimationFrame(() => {
setTimeout(this.draw.bind(this), fps30);
});
}
es5
function DrawingProgram() {
this.draw();
}
DrawingProgram.prototype.draw = function() {
var fps30 = 1000/30;
var fps60 = 1000/60;
var self = this;
window.requestAnimationFrame(function() {
window.setTimeout(function() {
self.draw(); // you could also use apply/call here if you want
}, fps30)
});
}