const svgns = "http://www.w3.org/2000/svg",
targetClassName = 'sight-line-target',
activeClassName = 'active';
function evenr_to_axial(x, y) {
return { q: x - (y + (y & 1)) / 2, r: y };
}
function axial_to_evenr(q, r) {
return { x: q + (r + (r & 1)) / 2, y: r };
}
function axial_distance(q1, r1, q2, r2) {
return (Math.abs(q1 - q2) + Math.abs(q1 + r1 - q2 - r2) + Math.abs(r1 - r2)) / 2;
}
function offset_distance(x1, y1, x2, y2) {
const { q: q1, r: r1 } = evenr_to_axial(x1, y1),
{ q: q2, r: r2 } = evenr_to_axial(x2, y2);
return axial_distance(q1, r1, q2, r2);
}
function cube_to_axial(q, r, _) {
return { q, r };
}
function axial_to_cube(q, r) {
return { q, r, s: -q - r };
}
function cube_round(q, r, s) {
let rQ = Math.round(q),
rR = Math.round(r),
rS = Math.round(s);
const q_diff = Math.abs(rQ - q),
r_diff = Math.abs(rR - r),
s_diff = Math.abs(rS - s);
if (q_diff > r_diff && q_diff > s_diff) {
rQ = -rR - rS;
} else if (r_diff > s_diff) {
rR = -rQ - rS;
} else {
rS = -rQ - rR;
}
return { q: rQ, r: rR, s: rS };
}
function axial_round(q, r) {
const cube = axial_to_cube(q, r),
round = cube_round(cube.q, cube.r, cube.s),
axial = cube_to_axial(round.q, round.r, round.s);
return { q: axial.q, r: axial.r };
}
function lerp(a, b, t) {
return a + (b - a) * t;
}
function axial_lerp(q1, r1, q2, r2, t) {
return { q: lerp(q1, q2, t), r: lerp(r1, r2, t) };
}
function linedraw(x1, y1, x2, y2) {
const axial1 = evenr_to_axial(x1, y1),
axial2 = evenr_to_axial(x2, y2),
n = offset_distance(x1, y1, x2, y2),
results = [];
for (let i = 0; i <= n; i++) {
const lerp = axial_lerp(axial1.q, axial1.r, axial2.q, axial2.r, 1.0 / n * i),
round = axial_round(lerp.q, lerp.r),
{ x, y } = axial_to_evenr(round.q, round.r);
results.push([x, y]);
}
return results;
}
export default class SightLine {
#board;
#lockTarget;
#activeHexes = [];
sightLine;
constructor(svg, board) {
this.svg = svg;
this.#board = board;
}
#drawHexes(...coords) {
this.#clearHexes()
if (this.distanceCallback) {
this.distanceCallback(offset_distance(...coords));
}
const lineCoords = linedraw(...coords),
selector = lineCoords
.map(([x, y]) => `g[data-y="${y}"] g[data-x="${x}"] use[href="#hex"]`)
.join(', '),
hexes = this.svg.querySelectorAll(selector);
hexes.forEach(p => p.classList.add(activeClassName));
this.#activeHexes = hexes;
}
#clearHexes() {
if (this.distanceCallback) {
this.distanceCallback();
}
this.#activeHexes.forEach(el => el.classList.remove(activeClassName));
this.#activeHexes = [];
}
clear() {
if (this.sightLine) {
this.sightLine.remove();
delete this.sightLine;
}
if (this.#lockTarget) {
this.#lockTarget.classList.remove(targetClassName);
this.#lockTarget = undefined;
}
this.#clearHexes();
}
draw(source, target) {
this.clear();
const sightLine = document.createElementNS(svgns, 'line');
sightLine.classList.add('sight-line');
sightLine.classList.add(activeClassName);
sightLine.setAttributeNS(null, 'x1', source.position.x);
sightLine.setAttributeNS(null, 'y1', source.position.y);
sightLine.setAttributeNS(null, 'x2', target.position.x);
sightLine.setAttributeNS(null, 'y2', target.position.y);
this.sightLine = sightLine;
this.#board.appendChild(sightLine);
this.#drawHexes(+source.index.x, +source.index.y, +target.index.x, +target.index.y);
}
update(source) {
const { dataset: { x }, parentElement: { dataset: { y }}} = this.#lockTarget;
this.sightLine.setAttributeNS(null, 'x1', source.position.x);
this.sightLine.setAttributeNS(null, 'y1', source.position.y);
this.#drawHexes(+source.index.x, +source.index.y, +x, +y);
}
toggleLock(cell) {
if (this.#lockTarget) {
this.sightLine.classList.add(activeClassName);
this.#lockTarget.classList.remove(targetClassName);
this.#lockTarget = undefined;
} else {
this.sightLine.classList.remove(activeClassName);
cell.classList.add(targetClassName);
this.#lockTarget = cell;
}
}
}