1

I am trying to make an irregular curve line for the progress graph to show on my website. I've tried it using jQuery and I got sin wave successfully but I want to achieve an irregular wave line like shown in the image below. How can I achieve it?

See the following image. Sample image of what I want

html code

<canvas height="500" width="600" id="my_canvas"></canvas>

jQuery Code

var my_canvas=$('#my_canvas').get(0);
var gctx = my_canvas.getContext("2d");
gctx.stroke();
gctx.beginPath();
gctx.moveTo(10, 125);
gctx.lineWidth=1;
gctx.strokeStyle= '#f00040';
var x = [];
var y = [];
for (var angle = 0; angle <590; angle+=1){
gctx.lineJoin = 'round';
y.push(125 - 120*( Math.sin(( Math.PI/180 ) * angle)));
x.push(10 + angle);
gctx.lineTo((10 + angle),((125 - 120*( Math.sin(( Math.PI/180 ) * 
angle)))));
}
gctx.stroke();
4
  • When you say "draw", are you referring to animation? Commented Jul 17, 2019 at 5:36
  • Thanks for pointing it out, I've corrected the question. Commented Jul 17, 2019 at 6:07
  • How important is it that the progress amount and/or timing be accurate? If you're only interested in a visual cue to indicate that something's loading, it's better to use an "indeterminate" graphic like a spinning circle or a similar sprite. But if it's mandatory that the position of the progress bar be meaningful, that's a huuuuge leap in complexity. Commented Jul 18, 2019 at 8:14
  • If you're happy with a basic animation that loops until a task has finished, check out loading.io for some inspiration. Commented Jul 18, 2019 at 8:17

1 Answer 1

2

This is how I would do it: In order to draw the curve I need a set of points. I will use quadratic bezier curve where the points (except the first and the last) are control points. Since apparently you need to animate the stroke I've done it using SVG. For the animation I'm using CSS as explained here: How SVG Line Animation Works

//An array of points used to draw the curve
let points = [
  {
    x: 10,
    y: 24
  },
  {
    x: 70,
    y: 110
  },
  {
    x: 117,
    y: 10
  },
  {
    x: 130,
    y: 142
  },
  {
    x: 200,
    y: 70
  },
  {
    x: 270,
    y: 143
  },
  {
    x: 320,
    y: 24
  }
];


// a function that draws the curve using the points as control points

function drawCurve(points) {
  //find the first midpoint and move to it
  var p = {};
  p.x = points[0].x;
  p.y = points[0].y;

  let d = `M${p.x}, ${p.y}`;
  //curve through the rest, stopping at each midpoint
  for (var i = 0; i < points.length - 2; i++) {
    var mp = {};
    mp.x = (points[i].x + points[i + 1].x) / 2;
    mp.y = (points[i].y + points[i + 1].y) / 2;
    d += `Q${points[i].x},${points[i].y},${mp.x},${mp.y}`;
  }
  //curve through the last point, back to the first midpoint
  d += `Q${points[points.length - 2].x},${points[points.length - 2].y}, ${
  points[points.length - 1].x
},${points[points.length - 1].y}`;
  track.setAttributeNS(null, "d", d);
  
  
  //for the animation
  //1. get the total path length
  let pathLength = track.getTotalLength();
  //2. set the stroke-dasharray and the stroke-dashoffset for the animation
  theUse.style.strokeDasharray = pathLength;
  theUse.style.strokeDashoffset = pathLength;
}

drawCurve(points);

function randomIntFromInterval(mn, mx) {
  return ~~(Math.random() * (mx - mn + 1) + mn);
}
#base{ 
  stroke:#ccc;
  stroke-width:5px;
  fill:none;
}

#theUse{
  stroke:black;
  stroke-width:1px;
  fill:none;
  animation: dash 5s linear forwards;
}


@keyframes dash {
  to {
    stroke-dashoffset: 0;
  }
}
<svg viewBox="0 0 330 200"  id="svg">
  <defs>
    <path id="track"  /></defs>
    
<use xlink:href="#track" id="base"  />    
<use xlink:href="#track" id="theUse"  /> 
    
</svg>

Sign up to request clarification or add additional context in comments.

5 Comments

This won't help if the progress amount needs to be set programmatically (e.g., tweening two-thirds of the way along a curve to indicate ~65% completion). You can hack the CSSOM to modify the @keyframes at runtime, but you're better off setting the progress position purely through JavaScript.
See Alhadis/De-Casteljau for a solution I prepared several years earlier (or Alhadis/Utilis for the spiffy ES6+ version of the function. Note that midpoints with non-continuous tangents (sharp corners or so-called "bezier corners") will require special handling.
any idea how i would create a "goop" that slimes down from the top of the page i.e. the wave stretches in random places as the wave edge descends to the bottom of the screen from top (like this)? i am very inexperienced with canvas, but ive been doing some reading and quadriatic bezier curves seem to me to be the type of curve to use? what i wanna do is generate a random wave and use it while the page loads to drip and expose the content
since the starting point is supposedly the last point in the subpath for quadriatic bezier curves, does it simply boil down to chaining a bunch of quadriatics together and then randomly adjusting the control points of each quadriatic?
Please read about The Gooey Effect. Try something. If you don't manage ask a different question. I'll be glad to help.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.