Web Dev Solutions

Catalin Mititiuc

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(); } } }