const svgns = "http://www.w3.org/2000/svg";
export default class Counter {
constructor(svg) {
this.svg = svg;
this.selectedClass = 'selected';
}
dataSelector(troopNumber, allegiance) {
return `[data-number="${troopNumber}"][data-allegiance="${allegiance}"]`;
}
selector(troopNumber, allegiance) {
return `.counter${this.dataSelector(troopNumber, allegiance)}`;
}
position(x, y) {
return `g[data-x="${x}"][data-y="${y}"]`;
}
counterPosition(x, y) {
return `.counter[data-x="${x}"][data-x="${y}"]`;
}
traceSelector(troopNumber, allegiance) {
return `polyline.move-trace${this.dataSelector(troopNumber, allegiance)}`;
}
getCounters() {
return this.svg.querySelectorAll(`.counter[data-allegiance][data-number]:not(.clone)`);
}
getClones(al, n) {
return this.svg.querySelectorAll(`.counter.clone[data-allegiance="${al}"][data-number="${n}"]`);
}
getCounter(al, n) {
return this.svg.querySelector(`.counter[data-allegiance="${al}"][data-number="${n}"]:not(.clone)`);
}
getCounterAndClones(al, n) {
return this.svg.querySelectorAll(`.counter[data-allegiance="${al}"][data-number="${n}"]`);
}
getTrace({ dataset: { allegiance, number } }) {
return this.svg.querySelector(this.traceSelector(number, allegiance));
}
getCellPosition(cell) {
let pt = new DOMPoint(0, 0),
transform = getComputedStyle(cell).transform.match(/-?\d+\.?\d*/g),
mtx = new DOMMatrix(transform);
pt = pt.matrixTransform(mtx);
transform = getComputedStyle(cell.parentElement).transform.match(/-?\d+\.?\d*/g);
mtx = new DOMMatrix(transform);
pt = pt.matrixTransform(mtx);
return pt;
}
getBoard() {
return this.svg.querySelector('.board');
}
place(selected, cell) {
const { allegiance: troopAllegiance, number: troopNumber } = selected.dataset;
let points,
counterNodeList = this.getCounterAndClones(troopAllegiance, troopNumber);
if (counterNodeList.length > 0 && selected.parentElement.hasAttribute('data-x')) {
let trace = this.svg.querySelector(this.traceSelector(troopNumber, troopAllegiance));
let prevCoords = [
selected.parentElement.dataset.x,
selected.parentElement.parentElement.dataset.y
]
let clone = selected.cloneNode(true);
clone.classList.remove(this.selectedClass);
clone.classList.add('clone');
selected.dataset.previous = prevCoords;
selected.parentElement.appendChild(clone);
cell.appendChild(selected);
selected.childNodes.forEach(n => {
if (n.classList.contains('removed')) {
n.remove();
} else if ('preexisting' in n.dataset) {
delete n.dataset.preexisting;
}
});
let previous = this.getCellPosition(clone.parentElement),
current = this.getCellPosition(selected.parentElement);
if (!trace) {
trace = document.createElementNS(svgns, 'polyline');
points = `${previous.x},${previous.y} ${current.x},${current.y}`;
trace.dataset.number = troopNumber;
trace.dataset.allegiance = troopAllegiance;
trace.classList.add('move-trace');
this.getBoard().prepend(trace);
} else {
points = `${trace.getAttribute('points')} ${current.x},${current.y}`;
}
trace.setAttributeNS(null, 'points', points);
} else {
selected.removeAttribute('data-x');
cell.appendChild(selected);
}
}
removeClones({ dataset: { allegiance, number }}) {
this.getClones(allegiance, number).forEach(el => {
el.remove()
});
}
endMove(el) {
const { number, allegiance } = el.dataset,
trace = this.svg.querySelector(this.traceSelector(number, allegiance)),
proneCounter = el.querySelector('[href="#counter-prone"]');
if (trace) {
trace.remove();
}
delete el.dataset.previous;
if (proneCounter) {
proneCounter.dataset.preexisting = '';
}
this.removeClones(el);
}
hasProne(counter) {
return !!counter.querySelector('[href="#counter-prone"]');
}
toggleProne(counter) {
let proneCounter = counter.querySelector('[href="#counter-prone"]');
if (!proneCounter) {
proneCounter = document.createElementNS(svgns, 'use');
proneCounter.setAttributeNS(null, 'href', '#counter-prone');
counter.appendChild(proneCounter);
} else if ('preexisting' in proneCounter.dataset) {
proneCounter.classList.toggle('removed');
} else {
proneCounter.remove();
}
}
}