I was trying to create these shapes moving, the shape is made up of a semicircle and a symmetric upper arc & lower arc. They should be just the shape in front but now there are line like a tail dragging behind when they move. The output shape with unknown tail

It seems like these lines are from the moveTo part of upper and lower arcs, but I can’t figure out how to solve it. Where should I change to get rid of it?

function Fish(x, y, dx, dy, radius){ this.x = x; this.y = y; this.dx = dx; this.dy = dy; this.radius = 30; this.draw = function(){ c.beginPath(); c.arc(this.x/0.6, this.y, this.radius, Math.PI * 1.5, Math.PI * 0.5, false) //Upper Arc c.moveTo(this.x, this.y); c.arc(this.x/0.6, this.y+(3*this.radius), this.radius*4, Math.PI * 229/180, Math.PI * 1.5, false) //Lower Arc c.moveTo(this.x, this.y); c.arc(this.x/0.6, this.y-(3*this.radius), this.radius*4, Math.PI * 131/180 , Math.PI * 0.5, true) c.strokeStyle = "green"; c.stroke(); }

This is because the `arc`

method internally traces a `lineTo`

from the current pointer’s position to the beginning of the arc (defined by cx, cy **and** startAngle).

To workaround that, you need to `moveTo`

that position.

Here is a simpler demonstration using a demi-circle with the `startAngle`

set at 0 rad:

const canvas = document.createElement( "canvas" ); document.body.append( canvas ); const ctx = canvas.getContext( "2d" ); ctx.lineWidth = 2; const cx = 50; const cy = 50; const rad = 30; ctx.beginPath(); ctx.moveTo( cx, cy ); ctx.arc( cx, cy, rad, 0, Math.PI ); ctx.strokeStyle = "red"; ctx.stroke(); ctx.translate( 80, 0 ); const first_point_x = cx + rad; // startAngle is 0 // so we just have to add 'rad' // to find the x coord ctx.beginPath(); ctx.moveTo( first_point_x, cy ); ctx.arc( cx, cy, rad, 0, Math.PI ); ctx.strokeStyle = "green"; ctx.stroke();

So you would have to calculate the coordinates of the point where your arc will start and `moveTo`

that point.

This is doable, but I’m not the best with trigo and your values are quite complex, so instead, here is a workaround using Path2D objects.

If the `arc`

command is the first of the sub-path, it will directly `moveTo`

that initial point (since there isn’t a “current pointer’s position” yet).

So we can initialize all our arcs as standalone Path2D objects, made only of these `arc`

commands. Then we just have to merge these Path2D objects into a last one and draw that:

const canvas = document.createElement("canvas"); document.body.append(canvas); const c = canvas.getContext("2d"); c.lineWidth = 2; const fish = new Fish(150, 50, 50, 50, 50); fish.draw(); function Fish(x, y, dx, dy, radius) { this.x = x; this.y = y; this.dx = dx; this.dy = dy; this.radius = 30; this.draw = function() { const p1 = new Path2D(); p1.arc(this.x / 0.6, this.y, this.radius, Math.PI * 1.5, Math.PI * 0.5, false) //Upper Arc const p2 = new Path2D(); p2.arc(this.x / 0.6, this.y + (3 * this.radius), this.radius * 4, Math.PI * 229 / 180, Math.PI * 1.5, false) //Lower Arc const p3 = new Path2D(); p3.arc(this.x / 0.6, this.y - (3 * this.radius), this.radius * 4, Math.PI * 131 / 180, Math.PI * 0.5, true) // merge in a single Path2D object const path = new Path2D(); path.addPath(p1); path.addPath(p2); path.addPath(p3); c.strokeStyle = "green"; c.stroke(path); } }

But in your case you can achieve the expected result quite easily, by changing the order in which you draw your Path and by never calling `moveTo`

.

const canvas = document.createElement("canvas"); document.body.append(canvas); const c = canvas.getContext("2d"); c.lineWidth = 2; const fish = new Fish(150, 50, 50, 50, 50); fish.draw(); function Fish(x, y, dx, dy, radius) { this.x = x; this.y = y; this.dx = dx; this.dy = dy; this.radius = 30; this.draw = function() { c.beginPath(); c.arc(this.x / 0.6, this.y, this.radius, Math.PI * 1.5, Math.PI * 0.5, false) // Lower Arc c.arc(this.x / 0.6, this.y - (3 * this.radius), this.radius * 4, Math.PI * 0.5, Math.PI * 131 / 180, false) // Upper Arc // (inverse startAngle and endAngle + switch swipe to false) c.arc(this.x / 0.6, this.y + (3 * this.radius), this.radius * 4, Math.PI * 229 / 180, Math.PI * 1.5, false) c.strokeStyle = "green"; c.stroke(); } }