Source: hexes-2.js

/**
 * @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});