Web Dev Solutions

Catalin Mititiuc

const svgns = "http://www.w3.org/2000/svg"; export default class Counter { #board; constructor(svg, board) { this.svg = svg; this.#board = board; this.selectedClass = 'selected'; } dataSelector({ dataset: { allegiance, number }}) { return `[data-number="${number}"][data-allegiance="${allegiance}"]`; } position(x, y) { return `g[data-x="${x}"][data-y="${y}"]`; } counterPosition(x, y) { return `.counter[data-x="${x}"][data-x="${y}"]`; } traceSelector(counter) { return `polyline.move-trace${this.dataSelector(counter)}`; } getClones(counter) { return this.svg.querySelectorAll(`.counter.clone${this.dataSelector(counter)}`); } getCounter(selected) { return this.svg.querySelector(`.counter${this.dataSelector(selected)}:not(.clone)`); } getCounterAndClones(counter) { return this.svg.querySelectorAll(`.counter${this.dataSelector(counter)}`); } getTrace(counter) { return this.svg.querySelector(this.traceSelector(counter)); } 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) { let points, counterNodeList = this.getCounterAndClones(selected); if (counterNodeList.length > 0 && selected.parentElement.hasAttribute('data-x')) { let trace = this.svg.querySelector(this.traceSelector(selected)); 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 = selected.dataset.number; trace.dataset.allegiance = selected.dataset.allegiance; 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(counter) { this.getClones(counter).forEach(c => c.remove()); } endMove(counter) { const trace = this.svg.querySelector(this.traceSelector(counter)), proneCounter = counter.querySelector('[href="#counter-prone"]'); if (trace) { trace.remove(); } delete counter.dataset.previous; if (proneCounter) { proneCounter.dataset.preexisting = ''; } this.removeClones(counter); } 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(); } } }