I'm creating a hex based map generator and as part of that I am trying to - on the client side - draw "rivers", lines that travel through the centres of the hexes that the server end calculates have rivers.
Here are the relevant variables (this works it gets values inserted by django from the server end I've tested it it all works fine)
// The optional populators
const rivers = {{ rivers |safe}};
const cities = {{ cities |safe}};
const roads = {{roads |safe}};
// Constants for our angles and scales, starting with scale 5
const a = Math.PI/3;
var r = 5;
And here is the function that draws the rivers
// Function that draws Rivers
function DrawRivers(){
// For each river in the rivers
for (var river of rivers) {
// Set up point tracking
let x_coord = r river[0][0] * (r (r * Math.cos(a)));
let y_coord = r river[0][1] * (r (r*Math.sin(a)));
if (river[0][0] % 2 == 1) {
y_off = y_coord;
} else { // If it's an even number of tiles in the row it'll be the lower part
y_off = y_coord r * Math.sin(a);
}
ctx.beginPath();
ctx.lineWidth = r;
ctx.strokeStyle = "#000000";
ctx.moveTo(x_coord, Math.round(y_off))
// For each point in the river
for (var river_hex of river){
let x_coord = r river[0][0] * (r (r * Math.cos(a)));
let y_coord = r river[0][1] * (r (r*Math.sin(a)));
if (river[0][0] % 2 == 1) {
y_off = y_coord;
} else { // If it's an even number of tiles in the row it'll be the lower part
y_off = y_coord r * Math.sin(a);
}
ctx.lineTo(x_coord, Math.round(y_off))
}
ctx.closePath();
ctx.stroke();
}
}
However when I run this code the lines do not draw. I've stepped through the code and everything seems like it works; there aren't any points where the code doesn't have the required variables, it's just when the ctx.stroke() command is called it doesn't actually draw the line.
Can someone else see where I've gone wrong? Because I honestly can't...
CodePudding user response:
In your inner loop "For each point in the river" you are only using river[0]
, not river_hex
(likely a copy-paste error), so you ended up drawing a single point.
You can simplify your code (and make less copy-paste mistakes ;-) ) by moving the hex-to-screen coordinate computation to a separate function, and by using an old-school for loop so you don't need to handle the first moveTo
separately.
const rivers = [
[
[0, 0],
[1, 0],
[1, 1],
[1, 2],
[1, 3],
[1, 4],
[2, 4],
[3, 5],
[4, 5],
],
];
const a = Math.PI / 3;
var r = 15;
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
function convertCoordinate(hex) {
const [hexX, hexY] = hex;
const x_coord = r hexX * (r (r * Math.cos(a)));
let y_coord = r hexY * (r (r * Math.sin(a)));
if (hexX % 2 !== 1) {
// If it's an even number of tiles in the row it'll be the lower part
y_coord = r * Math.sin(a);
}
return [x_coord, y_coord];
}
// Function that draws Rivers
function DrawRivers() {
// For each river in the rivers
for (var river of rivers) {
ctx.lineWidth = r;
ctx.strokeStyle = '#000000';
ctx.beginPath();
// For each point in the river
for (let i = 0; i < river.length; i ) {
const [x, y] = convertCoordinate(river[i]);
if (i === 0) ctx.moveTo(x, y);
else ctx.lineTo(x, y);
}
// Not quite sure if a river should be closed...
// ctx.closePath();
ctx.stroke();
}
}
DrawRivers();
canvas {
border: 1px solid orange;
}
<canvas id="canvas" width="500" height="500"></canvas>