I'm having a hard time figuring out how to word this, so picture time.
I have points arranged in a circle, I know the x,y
coordinates for all of them.
I can iterate each point and draw a line between them, easy
//in a for each dot loop..
ctx.beginPath();
ctx.moveTo(startX, startY);
ctx.lineTo(endX, endY);
ctx.stroke();
This is where I'm up to now. The rest I can't figure out
While iterating a point, I'd like to create a "diversion" that alternates between left and right (as though you're looking from the one point towards the next point in the sequence).
I want to take the midpoint of that straight line between two points, shoot 90 degrees off either left or right (let's say i % 2
or something), travel set distance d
and place a point at the end location. The distance d
will be different for each point and I have determined values for each of them.
Then continue iterating each point while creating offset points at set distances alternating left or right from the reference of the midway line between two points.
When iterating a point, instead of drawing a straight line from startX, startY
to endX, endY
, I will draw 2 lines - one from startX, startY
to diversionX, diversionY
and one from that to endX, endY
. The final rendered result would be this.
What I'm really asking is for help with the offset dot placing, I didn't have a great relationship with geometry at school, forever this has haunted me.. Drawing paths is trivial, I just need to know the point coordinates where to draw to/from..
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
var pointSize = 5;
var points = [
[300, 50, 10], // x, y, offset point distance
[175, 80, 15],
[100, 185, 9],
[100, 315, 21],
[175, 420, 12],
[300, 460, 15],
[420, 420, 8],
[500, 315, 16],
[500, 185, 25],
[420, 80, 17]
];
for(var i = 0; i < points.length; i++) {
x = points[i][0];
y = points[i][1];
d = points[i][2]; // diversion length
// draw point
ctx.fillStyle = '#000000';
ctx.fillRect(x-(pointSize/2), y-(pointSize/2), pointSize, pointSize);
// draw temporary connecting line to next point
ctx.strokeStyle = '#d4d4d4';
nextPoint = points[(i + 1) % points.length];
ctx.beginPath();
ctx.moveTo(x, y);
ctx.lineWidth = 3;
ctx.lineTo(nextPoint[0], nextPoint[1]);
ctx.stroke();
// aaaaand I'm lost
// get midpoint of drawn line
// shoot off 90 degress to a side (i %2)
// travel distance of "d"
// get "d" x, y position
// draw lines between
// x,y and dx,dy
// dx,dy and nextX, nextY
}
<canvas id="canvas" width="600" height="600"></canvas>
Getting the center point of a line
mid.X = (start.X + end.X) / 2;
mid.Y = (start.Y + end.Y) / 2;
Getting a vector from two points
vec.X = end.X - start.X;
vec.Y = end.Y - start.Y;
Getting a vector form point => position
This is just like having a vector from 0, 0 to the point => your position so:
vec.X = mid.X;
vec.Y = mid.Y;
Turning by 90 degrees
// Depending on the direction you'd either have to negate the x or y component
const prevY = vec.Y;
vec.Y = vec.X;
vec.X = -prevY;
const prevY = vec.Y;
vec.Y = -vec.X;
vec.X = prevY;
Going a certain distance
// You have 'point' in your case the center point and the rotated vector 'vec'
// Here you first calculate the length of 'vec'
// then get dX and dY that you move per unit in the direction of 'vec'
// then you multiply that with the distance and get your offset
const vecLength = Math.sqrt(vec.X * vec.X + vec.Y * vec.Y);
const xOffset = vec.X / vecLength * distance;
const yOffset = vec.Y / vecLength * distance;
Add an offset (but I guess that's not the difficult part ;) )
point.X += xOffset;
point.Y += yOffset;
This is the implemented solution: There are a few temporary drawings just to make it a bit clearer what is happening at every step.
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
const pointSize = 5;
const points = [
[300, 50, 50], // x, y, offset point distance
[175, 80, 15],
[100, 185, 9],
[100, 315, 21],
[175, 420, 12],
[300, 460, 15],
[420, 420, 8],
[500, 315, 16],
[500, 185, 25],
[420, 80, 17]
];
for(let i = 0; i < points.length; i++) {
x = points[i][0];
y = points[i][1];
d = points[i][2]; // diversion length
// draw point
ctx.fillStyle = '#000000';
ctx.fillRect(x-(pointSize/2), y-(pointSize/2), pointSize, pointSize);
// draw temporary connecting line to next point
ctx.strokeStyle = '#d4d4d4';
nextPoint = points[(i + 1) % points.length];
ctx.beginPath();
ctx.moveTo(x, y);
ctx.lineWidth = 3;
ctx.lineTo(nextPoint[0], nextPoint[1]);
ctx.stroke();
const midX = (x + nextPoint[0]) / 2;
const midY = (y + nextPoint[1]) / 2;
// draw center point
ctx.fillStyle = '#00ff00';
ctx.fillRect(midX-(pointSize/2), midY-(pointSize/2), pointSize, pointSize);
const midXVec = nextPoint[0] - midX;
const midYVec = nextPoint[1] - midY;
const nMidXVec = i % 2 === 0 ? -midYVec : midYVec;
const nMidYVec = i % 2 === 0 ? midXVec : -midXVec;
// draw rotated vector from midpoint
ctx.strokeStyle = '#f1f1f1';
ctx.beginPath();
ctx.moveTo(midX, midY);
ctx.lineWidth = 3;
ctx.lineTo(midX + nMidXVec, midY + nMidYVec);
ctx.stroke();
const nMidLength = Math.sqrt(nMidXVec * nMidXVec + nMidYVec * nMidYVec);
const dXVec = nMidXVec / nMidLength * d;
const dYvec = nMidYVec / nMidLength * d;
const dX = midX + dXVec;
const dY = midY + dYvec;
// draw point dX, dY
ctx.fillStyle = '#ff0000';
ctx.fillRect(dX-(pointSize/2), dY-(pointSize/2), pointSize, pointSize);
// draw final lines
ctx.strokeStyle = '#000000';
ctx.beginPath();
ctx.moveTo(x, y);
ctx.lineWidth = 3;
ctx.lineTo(dX, dY);
ctx.lineTo(nextPoint[0], nextPoint[1]);
ctx.stroke();
}
<canvas id="canvas" width="600" height="600"></canvas>