/**
* @fileoverview Functions to draw a honeycomb board with hexes
* @author Robert Laing
* @module hexes
* @see {@link https://www.redblobgames.com/grids/hexagons/|Offset coordinates}
*/
/**
* Convert pointer x,y coordiantes to row and colum indexes (squares.xy2colrow).
* @function module:squares~xy2colrow
* @param {string} coordinatees - "odd-row", "even-row", "odd-col", "even-col"
* @param {number} x - event.offsetX
* @param {number} y - event.offsetY
* @param {number} spine - hex side length
* @returns {Array} [row, col] indexed from 0
*/
function xy2colrow(x, y, spine, coordinates) {
const height = spine*Math.sqrt(3);
let col;
let row;
switch (coordinates) {
case "odd-row":
row = Math.floor((y - (spine/4))/(1.5*spine));
if (row % 2 === 1) {
col = Math.floor((x/height) - 0.5);
} else {
col = Math.floor(x/height);
}
return [col, row];
case "even-row":
row = Math.floor((y - (spine/4))/(1.5*spine));
if (row % 2 === 0) {
col = Math.floor((x/height) - 0.5);
} else {
col = Math.floor(x/height);
}
return [col, row];
case "odd-col":
col = Math.floor((x - (spine/4))/(1.5*spine));
if (col % 2 === 1) {
row = Math.floor((y/height) - 0.5);
} else {
row = Math.floor(y/height);
}
return [col, row];
case "even-col":
col = Math.floor((x - (spine/4))/(1.5*spine));
if (col % 2 === 0) {
row = Math.floor((y/height) - 0.5);
} else {
row = Math.floor(y/height);
}
return [col, row];
}
}
/**
* Convert row and colum indexes to center x and y coordinates for drawing procedures (squares.rowcol2xy).
* Something I learnt from jslint writing this is "Don't declare variables in a switch."
* @function module:squares~colrow2xy
* @param {string} coordinatees - "odd-row", "even-row", "odd-col", "even-col"
* @param {number} row - indexed from 0
* @param {number} column - indexed from 0
* @param {number} spine - hex side length
* @returns {Array} [xCenter, yCenter] for canvas drawing procedures
*/
function colrow2xy(column, row, spine, coordinates) {
let xCenter;
let yCenter;
switch (coordinates) {
case "odd-row": // odd rows + 0.5 column
yCenter = ((1.5 * row) + 1) * spine;
xCenter = (row % 2 === 1) ?
((column * spine) + spine) * Math.sqrt(3) :
(column + 0.5) * spine * Math.sqrt(3);
return [xCenter, yCenter];
case "even-row": // even rows + 0.5 column
yCenter = ((1.5 * row) + 1) * spine;
xCenter = (row % 2 === 0) ?
((column * spine) + spine) * Math.sqrt(3) :
(column + 0.5) * spine * Math.sqrt(3);
return [xCenter, yCenter];
case "odd-col": // odd columns + 0.5*row
xCenter = ((1.5 * column) + 1) * spine;
yCenter = (column % 2 === 1) ?
((row * spine) + spine) * Math.sqrt(3) :
(row + 0.5) * spine * Math.sqrt(3);
return [xCenter, yCenter];
case "even-col": // even columns + 0.5*row
xCenter = ((1.5 * column) + 1) * spine;
yCenter = (column % 2 === 0) ?
((row * spine) + spine) * Math.sqrt(3) :
(row + 0.5) * spine * Math.sqrt(3);
return [xCenter, yCenter];
}
}
function path_flat(ctx, xCenter, yCenter, spine) {
let idx;
ctx.beginPath();
ctx.moveTo(xCenter + spine, yCenter);
for (idx = 1; idx < 6; idx += 1) {
ctx.lineTo( xCenter + (spine * Math.cos(idx * Math.PI/3))
, yCenter + (spine * Math.sin(idx * Math.PI/3))
);
}
ctx.closePath();
}
function path_pointy(ctx, xCenter, yCenter, spine) {
let idx;
ctx.beginPath();
ctx.moveTo(xCenter, yCenter + spine);
for (idx = 1; idx < 6; idx += 1) {
ctx.lineTo(xCenter + (spine * Math.sin(idx * Math.PI/3))
, yCenter + (spine * Math.cos(idx * Math.PI/3))
);
}
ctx.closePath();
}
/**
* Draw hexagon outline (hexes.stroke).
* odd/even means which rows "stick out"
* for "pointy" rows,
* @function module:hexes~stroke
* @param {string} coordinatees - "odd-row", "even-row", "odd-col", "even-col"
* @param {number} col_idx - indexed from 0
* @param {number} row_idx - indexed from 0
* @param {number} spine - hexagon side length (radius)
* @param {string} colour - for ctx.fillStyle
* @param {number} lineWidth - for ctx.lineWidth
*/
function stroke(ctx, col_idx, row_idx, coordinates, spine, colour, lineWidth) {
const [xCenter, yCenter] = colrow2xy(col_idx, row_idx, spine, coordinates);
if (coordinates === "even-row" || coordinates === "odd-row") {
path_pointy(ctx, xCenter, yCenter, spine);
} else {
path_flat(ctx, xCenter, yCenter, spine);
}
ctx.lineWidth = lineWidth;
ctx.strokeStyle = colour;
ctx.stroke();
}
/**
* Fill hexagon (hexes.fill).
* odd/even means which rows "stick out"
* for "pointy" rows,
* @function module:hexes~stroke
* @param {string} coordinatees - "odd-row", "even-row", "odd-col", "even-col"
* @param {number} row - indexed from 0
* @param {number} column - indexed from 0
* @param {number} spine - hexagon side length (radius)
* @param {string} colour - for ctx.fillStyle
*/
function fill(ctx, col_idx, row_idx, coordinates, spine, colour) {
const [xCenter, yCenter] = colrow2xy(col_idx, row_idx, spine, coordinates);
if (coordinates === "even-row" || coordinates === "odd-row") {
path_pointy(ctx, xCenter, yCenter, spine);
} else {
path_flat(ctx, xCenter, yCenter, spine);
}
ctx.fillStyle = colour;
ctx.fill();
}
export default Object.freeze({xy2colrow, colrow2xy, stroke, fill});