+ blockContextMenu: function(e) {
+ e.preventDefault();
+ e.stopPropagation();
+ return false;
+ },
+ cancelResetArrows: function() {
+ this.startArrow = null;
+ this.arrows = [];
+ this.circles = {};
+ const curCanvas = document.getElementById("arrowCanvas");
+ if (!!curCanvas) curCanvas.parentNode.removeChild(curCanvas);
+ },
+ coordsToXY: function(coords, top, left, squareWidth) {
+ return {
+ // [1] for x and [0] for y because conventions in rules are inversed.
+ x: (
+ left + window.scrollX +
+ (
+ squareWidth *
+ (this.orientation == 'w' ? coords[1] : (V.size.y - coords[1]))
+ )
+ ),
+ y: (
+ top + window.scrollY +
+ (
+ squareWidth *
+ (this.orientation == 'w' ? coords[0] : (V.size.x - coords[0]))
+ )
+ )
+ };
+ },
+ computeEndArrow: function(start, end, top, left, squareWidth) {
+ const endCoords = this.coordsToXY(end, top, left, squareWidth);
+ const delta = [endCoords.x - start.x, endCoords.y - start.y];
+ const dist = Math.sqrt(delta[0] * delta[0] + delta[1] * delta[1]);
+ // Simple heuristic for now, just remove 1/3 square.
+ // TODO: should depend on the orientation.
+ const fracSqWidth = squareWidth / 3;
+ return {
+ x: endCoords.x - delta[0] * fracSqWidth / dist,
+ y: endCoords.y - delta[1] * fracSqWidth / dist
+ };
+ },
+ drawCurrentArrow: function() {
+ const boardElt = document.getElementById("gamePosition");
+ const squareWidth = boardElt.offsetWidth / V.size.y;
+ const bPos = boardElt.getBoundingClientRect();
+ const aStart =
+ this.coordsToXY(
+ [this.startArrow[0] + 0.5, this.startArrow[1] + 0.5],
+ bPos.top, bPos.left, squareWidth);
+ const aEnd =
+ this.computeEndArrow(
+ aStart, [this.movingArrow[0] + 0.5, this.movingArrow[1] + 0.5],
+ bPos.top, bPos.left, squareWidth);
+ let currentArrow = document.getElementById("currentArrow");
+ const d =
+ "M" + aStart.x + "," + aStart.y + " " + "L" + aEnd.x + "," + aEnd.y;
+ const arrowWidth = squareWidth / 4;
+ if (!!currentArrow) currentArrow.setAttribute("d", d);
+ else {
+ let domArrow =
+ document.createElementNS("http://www.w3.org/2000/svg", "path");
+ domArrow.classList.add("svg-arrow");
+ domArrow.id = "currentArrow";
+ domArrow.setAttribute("d", d);
+ domArrow.style = "stroke-width:" + arrowWidth + "px";
+ document.getElementById("arrowCanvas")
+ .insertAdjacentElement("beforeend", domArrow);
+ }
+ },
+ addArrow: function(arrow) {
+ this.arrows.push(arrow);
+ // Also add to DOM:
+ const boardElt = document.getElementById("gamePosition");
+ const squareWidth = boardElt.offsetWidth / V.size.y;
+ const bPos = boardElt.getBoundingClientRect();
+ const newArrow =
+ this.getSvgArrow(arrow, bPos.top, bPos.left, squareWidth);
+ document.getElementById("arrowCanvas")
+ .insertAdjacentElement("beforeend", newArrow);
+ },
+ getSvgArrow: function(arrow, top, left, squareWidth) {
+ const aStart =
+ this.coordsToXY(
+ [arrow.start[0] + 0.5, arrow.start[1] + 0.5],
+ top, left, squareWidth);
+ const aEnd =
+ this.computeEndArrow(
+ aStart, [arrow.end[0] + 0.5, arrow.end[1] + 0.5],
+ top, left, squareWidth);
+ const arrowWidth = squareWidth / 4;
+ let path =
+ document.createElementNS("http://www.w3.org/2000/svg", "path");
+ path.classList.add("svg-arrow");
+ path.setAttribute(
+ "d",
+ "M" + aStart.x + "," + aStart.y + " " + "L" + aEnd.x + "," + aEnd.y
+ );
+ path.style = "stroke-width:" + arrowWidth + "px";
+ return path;
+ },
+ re_setDrawings: function() {
+ // Remove current canvas, if any
+ const curCanvas = document.getElementById("arrowCanvas");
+ if (!!curCanvas) curCanvas.parentNode.removeChild(curCanvas);
+ // Add some drawing on board (for some variants + arrows and circles)
+ const boardElt = document.getElementById("gamePosition");
+ const squareWidth = boardElt.offsetWidth / V.size.y;
+ const bPos = boardElt.getBoundingClientRect();
+ let svgArrows = [];
+ this.arrows.forEach(a => {
+ svgArrows.push(this.getSvgArrow(a, bPos.top, bPos.left, squareWidth));
+ });
+ let vLines = [];
+ if (!!V.Lines) {
+ V.Lines.forEach(line => {
+ const lStart =
+ this.coordsToXY(line[0], bPos.top, bPos.left, squareWidth);
+ const lEnd =
+ this.coordsToXY(line[1], bPos.top, bPos.left, squareWidth);
+ let path =
+ document.createElementNS("http://www.w3.org/2000/svg", "path");
+ if (line[0][0] == line[1][0] || line[0][1] == line[1][1])
+ path.classList.add("svg-line");
+ else
+ // "Diagonals" are drawn with a lighter color (TODO: generalize)
+ path.classList.add("svg-diag");
+ path.setAttribute(
+ "d",
+ "M" + lStart.x + "," + lStart.y + " " +
+ "L" + lEnd.x + "," + lEnd.y
+ );
+ vLines.push(path);
+ });
+ }
+ let arrowCanvas =
+ document.createElementNS("http://www.w3.org/2000/svg", "svg");
+ arrowCanvas.id = "arrowCanvas";
+ arrowCanvas.setAttribute("stroke", "none");
+ let defs =
+ document.createElementNS("http://www.w3.org/2000/svg", "defs");
+ const arrowWidth = squareWidth / 4;
+ let marker =
+ document.createElementNS("http://www.w3.org/2000/svg", "marker");
+ marker.id = "arrow";
+ marker.setAttribute("markerWidth", (2 * arrowWidth) + "px");
+ marker.setAttribute("markerHeight", (3 * arrowWidth) + "px");
+ marker.setAttribute("markerUnits", "userSpaceOnUse");
+ marker.setAttribute("refX", "0");
+ marker.setAttribute("refY", (1.5 * arrowWidth) + "px");
+ marker.setAttribute("orient", "auto");
+ let head =
+ document.createElementNS("http://www.w3.org/2000/svg", "path");
+ head.classList.add("arrow-head");
+ head.setAttribute(
+ "d",
+ "M0,0 L0," + (3 * arrowWidth) + " L" +
+ (2 * arrowWidth) + "," + (1.5 * arrowWidth) + " z"
+ );
+ marker.appendChild(head);
+ defs.appendChild(marker);
+ arrowCanvas.appendChild(defs);
+ svgArrows.concat(vLines).forEach(av => arrowCanvas.appendChild(av));
+ document.getElementById("rootBoardElement").appendChild(arrowCanvas);
+ },