More refactor of firing arcs module
This commit is contained in:
parent
6ef3ee2892
commit
0577330264
@ -147,6 +147,7 @@ polygon.firing-arc[data-allegiance="liao"] {
|
|||||||
#lines polyline, #lines line {
|
#lines polyline, #lines line {
|
||||||
fill: none;
|
fill: none;
|
||||||
stroke: black;
|
stroke: black;
|
||||||
|
stroke-width: 0.5;
|
||||||
}
|
}
|
||||||
|
|
||||||
#lines line {
|
#lines line {
|
||||||
|
@ -46,8 +46,6 @@
|
|||||||
</g>
|
</g>
|
||||||
|
|
||||||
<g class="board">
|
<g class="board">
|
||||||
<g id="test-arcs">
|
|
||||||
</g>
|
|
||||||
<g id="firing-arcs">
|
<g id="firing-arcs">
|
||||||
<g id="shapes"/>
|
<g id="shapes"/>
|
||||||
<g id="lines"/>
|
<g id="lines"/>
|
||||||
|
Before Width: | Height: | Size: 81 KiB After Width: | Height: | Size: 81 KiB |
@ -19,7 +19,7 @@ const svgns = "http://www.w3.org/2000/svg",
|
|||||||
liao: false
|
liao: false
|
||||||
},
|
},
|
||||||
|
|
||||||
clippedFiringArcRadius = 100;
|
clippedFiringArcRadius = 25;
|
||||||
|
|
||||||
let svg;
|
let svg;
|
||||||
|
|
||||||
@ -38,7 +38,7 @@ function calculateAngle(xDiff, yDiff) {
|
|||||||
return angle;
|
return angle;
|
||||||
}
|
}
|
||||||
|
|
||||||
function edgePoint([x1, y1], [x2, y2], { minX = 0, minY = 0, maxX, maxY } = {}) {
|
function edgePoint({ x: x1, y: y1 }, { x: x2, y: y2 }, { x: [minX, maxX], y: [minY, maxY] }) {
|
||||||
const xDiff = x2 - x1,
|
const xDiff = x2 - x1,
|
||||||
yDiff = y2 - y1,
|
yDiff = y2 - y1,
|
||||||
xIntercept = y => (y - y1) * xDiff / yDiff + x1,
|
xIntercept = y => (y - y1) * xDiff / yDiff + x1,
|
||||||
@ -64,50 +64,69 @@ function edgePoint([x1, y1], [x2, y2], { minX = 0, minY = 0, maxX, maxY } = {})
|
|||||||
pointCoords = y <= maxY ? [minX, y] : [xIntercept(maxY), maxY];
|
pointCoords = y <= maxY ? [minX, y] : [xIntercept(maxY), maxY];
|
||||||
}
|
}
|
||||||
|
|
||||||
return pointCoords;
|
return new Point(...pointCoords);
|
||||||
}
|
}
|
||||||
|
|
||||||
function position(activeFiringArc, activeFiringArcOutline, aim, grid, e) {
|
class Point {
|
||||||
|
constructor(x = 0, y = 0) {
|
||||||
|
this.x = +x;
|
||||||
|
this.y = +y;
|
||||||
|
}
|
||||||
|
|
||||||
|
toString() {
|
||||||
|
return `${this.x},${this.y}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function position(e, firingArc, firingArcOutline, aimLine, grid) {
|
||||||
// TODO: handle exactly horizontal and vertical lines?
|
// TODO: handle exactly horizontal and vertical lines?
|
||||||
|
|
||||||
let pt = new DOMPoint(e.clientX, e.clientY);
|
let pointer = new DOMPoint(e.clientX, e.clientY);
|
||||||
let { x: pointerX, y: pointerY } = pt.matrixTransform(grid.getScreenCTM().inverse());
|
let pointerPt = pointer.matrixTransform(grid.getScreenCTM().inverse());
|
||||||
|
|
||||||
|
let pivotPt = new Point(aimLine.getAttribute('x1'), aimLine.getAttribute('y1'));
|
||||||
|
|
||||||
let pivotPt = [x1, y1] = [aim.getAttribute('x1'), aim.getAttribute('y1')].map(n => parseFloat(n));
|
|
||||||
let { x, y, width, height } = grid.getBBox();
|
let { x, y, width, height } = grid.getBBox();
|
||||||
let [minX, minY, maxX, maxY] = [x, y, x + width, y + height];
|
|
||||||
let bounds = { minX, minY, maxX, maxY };
|
|
||||||
let cornerPoints = [[x, y], [x + width, y], [x + width, y + height], [x, y + height]];
|
|
||||||
|
|
||||||
let aimPt = [x2, y2] = edgePoint(pivotPt, [pointerX, pointerY], bounds);
|
const bounds = {
|
||||||
|
x: [x, x + width],
|
||||||
|
y: [y, y + height]
|
||||||
|
}
|
||||||
|
|
||||||
aim.setAttributeNS(null, 'x2', x2);
|
let cornerPoints = [
|
||||||
aim.setAttributeNS(null, 'y2', y2);
|
[x, y],
|
||||||
|
[x + width, y],
|
||||||
|
[x + width, y + height],
|
||||||
|
[x, y + height]
|
||||||
|
].map(([x, y]) => new Point(x, y));
|
||||||
|
|
||||||
let angle = calculateAngle(x2 - x1, y2 - y1);
|
let aimPt = edgePoint(pivotPt, pointerPt, bounds);
|
||||||
let arcAngle = arcSize[activeFiringArc.dataset.size];
|
aimLine.setAttributeNS(null, 'x2', aimPt.x);
|
||||||
let distance = Math.sqrt((x2 - x1) ** 2 + (y2 - y1) ** 2);
|
aimLine.setAttributeNS(null, 'y2', aimPt.y);
|
||||||
|
|
||||||
|
let angle = calculateAngle(aimPt.x - pivotPt.x, aimPt.y - pivotPt.y);
|
||||||
|
let arcAngle = arcSize[firingArc.dataset.size];
|
||||||
|
let distance = Math.sqrt((aimPt.x - pivotPt.x) ** 2 + (aimPt.y - pivotPt.y) ** 2);
|
||||||
let yDelta = distance * Math.cos(angle) * Math.tan(arcAngle);
|
let yDelta = distance * Math.cos(angle) * Math.tan(arcAngle);
|
||||||
let xDelta = distance * Math.sin(angle) * Math.tan(arcAngle);
|
let xDelta = distance * Math.sin(angle) * Math.tan(arcAngle);
|
||||||
|
|
||||||
let [newY1, newX1] = [y2 - yDelta, x2 - xDelta];
|
let arcPt1 = new Point(aimPt.x - xDelta, aimPt.y - yDelta);
|
||||||
let [newY2, newX2] = [y2 + yDelta, x2 + xDelta];
|
let arcPt2 = new Point(aimPt.x + xDelta, aimPt.y + yDelta);
|
||||||
|
|
||||||
let arcPt1 = [newX1, newY1] = edgePoint(pivotPt, [newX1, newY1], bounds);
|
arcPt1 = edgePoint(pivotPt, arcPt1, bounds);
|
||||||
let arcPt2 = [newX2, newY2] = edgePoint(pivotPt, [newX2, newY2], bounds);
|
arcPt2 = edgePoint(pivotPt, arcPt2, bounds);
|
||||||
|
|
||||||
activeFiringArcOutline.setAttributeNS(null, 'points', `${newX1},${newY1} ${x1},${y1} ${newX2},${newY2}`);
|
firingArcOutline.setAttributeNS(null, 'points', `${arcPt1} ${pivotPt} ${arcPt2}`);
|
||||||
|
|
||||||
function touchSameEdge([x1, y1], [x2, y2]) {
|
function touchSameEdge({ x: x1, y: y1 }, { x: x2, y: y2 }) {
|
||||||
return x1 === x2 || y1 === y2;
|
return x1 === x2 || y1 === y2;
|
||||||
}
|
}
|
||||||
|
|
||||||
function touchOrthogonalEdges([x1, y1], [x2, y2]) {
|
function touchOrthogonalEdges({ x: x1, y: y1 }, { x: x2, y: y2 }) {
|
||||||
let xLimit = [minX, maxX], yLimit = [minY, maxY];
|
return (bounds.x.includes(x1) && bounds.y.includes(y2)) || (bounds.y.includes(y1) && bounds.x.includes(x2));
|
||||||
return (xLimit.includes(x1) && yLimit.includes(y2)) || (yLimit.includes(y1) && xLimit.includes(x2));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function shareValue([x1, y1], [x2, y2]) {
|
function shareValue({ x: x1, y: y1 }, { x: x2, y: y2 }) {
|
||||||
return x1 === x2 || y1 === y2;
|
return x1 === x2 || y1 === y2;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -115,25 +134,24 @@ function position(activeFiringArc, activeFiringArcOutline, aim, grid, e) {
|
|||||||
// if they share an x value, we will look for corner y value
|
// if they share an x value, we will look for corner y value
|
||||||
// if they share a y value, we will look for corner x value
|
// if they share a y value, we will look for corner x value
|
||||||
// is aim pt non-shared value greater or less than arcpt non-shared value?
|
// is aim pt non-shared value greater or less than arcpt non-shared value?
|
||||||
function findSharedValue(pt, ...pts) {
|
function findWhichCorners(pt, ...pts) {
|
||||||
const sharedValPt = pts.find(([ptX, ptY]) => pt.includes(ptX) || pt.includes(ptY));
|
const ptVals = Object.values(pt),
|
||||||
|
sharedValPt = pts.find(({ x, y }) => ptVals.includes(x) || ptVals.includes(y));
|
||||||
|
|
||||||
if (!sharedValPt) {
|
if (!sharedValPt) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const limits = [[minX, maxX], [minY, maxY]],
|
const nonSharedValKey = pt.x === sharedValPt.x ? 'x' : 'y';
|
||||||
nonSharedValIndex = pt[0] === sharedValPt[0] ? 1 : 0;
|
|
||||||
|
|
||||||
let cornerVal;
|
let cornerVal;
|
||||||
|
|
||||||
if (pt[nonSharedValIndex] < sharedValPt[nonSharedValIndex]) {
|
if (pt[nonSharedValKey] < sharedValPt[nonSharedValKey]) {
|
||||||
cornerVal = Math.min(...limits[nonSharedValIndex])
|
cornerVal = Math.min(...bounds[nonSharedValKey]);
|
||||||
} else {
|
} else {
|
||||||
cornerVal = Math.max(...limits[nonSharedValIndex]);
|
cornerVal = Math.max(...bounds[nonSharedValKey]);
|
||||||
}
|
}
|
||||||
|
|
||||||
return cornerPoints.filter(cp => cp[nonSharedValIndex] === cornerVal);
|
return cornerPoints.filter(cp => cp[nonSharedValKey] === cornerVal);
|
||||||
}
|
}
|
||||||
|
|
||||||
let points;
|
let points;
|
||||||
@ -155,7 +173,7 @@ function position(activeFiringArc, activeFiringArcOutline, aim, grid, e) {
|
|||||||
} else {
|
} else {
|
||||||
if (touchSameEdge(aimPt, arcPt1) || touchSameEdge(aimPt, arcPt2)) {
|
if (touchSameEdge(aimPt, arcPt1) || touchSameEdge(aimPt, arcPt2)) {
|
||||||
// 2-corner case, aim and an arc point touch the same edge
|
// 2-corner case, aim and an arc point touch the same edge
|
||||||
points = findSharedValue(aimPt, arcPt1, arcPt2);
|
points = findWhichCorners(aimPt, arcPt1, arcPt2);
|
||||||
let index = points.findIndex(cp => shareValue(cp, arcPt2));
|
let index = points.findIndex(cp => shareValue(cp, arcPt2));
|
||||||
points.splice(index + 1, 0, arcPt2, pivotPt, arcPt1);
|
points.splice(index + 1, 0, arcPt2, pivotPt, arcPt1);
|
||||||
} else {
|
} else {
|
||||||
@ -166,7 +184,7 @@ function position(activeFiringArc, activeFiringArcOutline, aim, grid, e) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
activeFiringArc.setAttributeNS(null, 'points', points.join(' '));
|
firingArc.setAttributeNS(null, 'points', points.join(' '));
|
||||||
}
|
}
|
||||||
|
|
||||||
function setDataAttrs({ dataset: { allegiance, number }}, el) {
|
function setDataAttrs({ dataset: { allegiance, number }}, el) {
|
||||||
@ -179,7 +197,7 @@ function getClipPathId({ dataset: { allegiance, number }}) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function getUnclipped() {
|
function getUnclipped() {
|
||||||
return svg.querySelectorAll('#firing-arcs polygon:not([clip-path])');
|
return svg.querySelectorAll('#firing-arcs :not([clip-path])');
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function (el) {
|
export default function (el) {
|
||||||
@ -192,25 +210,23 @@ export default function (el) {
|
|||||||
let outlineLayer = svg.querySelector('#lines');
|
let outlineLayer = svg.querySelector('#lines');
|
||||||
let arcContainer = svg.querySelector('#firing-arcs');
|
let arcContainer = svg.querySelector('#firing-arcs');
|
||||||
let grid = svg.querySelector('.grid');
|
let grid = svg.querySelector('.grid');
|
||||||
let points = `${x},${y} ${x},${y} ${x},${y}`;
|
|
||||||
|
|
||||||
let aim = document.createElementNS(svgns, 'line');
|
let aimLine = document.createElementNS(svgns, 'line');
|
||||||
aim.setAttributeNS(null, 'x1', x);
|
aimLine.setAttributeNS(null, 'x1', x);
|
||||||
aim.setAttributeNS(null, 'y1', y);
|
aimLine.setAttributeNS(null, 'y1', y);
|
||||||
aim.setAttributeNS(null, 'x2', x);
|
aimLine.setAttributeNS(null, 'x2', x);
|
||||||
aim.setAttributeNS(null, 'y2', y);
|
aimLine.setAttributeNS(null, 'y2', y);
|
||||||
outlineLayer.appendChild(aim);
|
outlineLayer.appendChild(aimLine);
|
||||||
|
|
||||||
let firingArc = document.createElementNS(svgns, 'polygon');
|
let firingArc = document.createElementNS(svgns, 'polygon');
|
||||||
let firingArcOutline = document.createElementNS(svgns, 'polyline');
|
|
||||||
|
|
||||||
setDataAttrs(counter, firingArc);
|
setDataAttrs(counter, firingArc);
|
||||||
|
firingArc.setAttributeNS(null, 'points', `${x},${y}`);
|
||||||
firingArc.dataset.size = size;
|
firingArc.dataset.size = size;
|
||||||
firingArc.classList.add('firing-arc', 'active');
|
firingArc.classList.add('firing-arc', 'active');
|
||||||
firingArc.setAttributeNS(null, 'points', points);
|
|
||||||
|
|
||||||
|
let firingArcOutline = document.createElementNS(svgns, 'polyline');
|
||||||
setDataAttrs(counter, firingArcOutline);
|
setDataAttrs(counter, firingArcOutline);
|
||||||
firingArcOutline.setAttributeNS(null, 'points', points);
|
firingArcOutline.setAttributeNS(null, 'points', `${x},${y}`);
|
||||||
|
|
||||||
let clipShape = document.createElementNS(svgns, 'circle');
|
let clipShape = document.createElementNS(svgns, 'circle');
|
||||||
clipShape.setAttributeNS(null, 'cx', x);
|
clipShape.setAttributeNS(null, 'cx', x);
|
||||||
@ -226,31 +242,29 @@ export default function (el) {
|
|||||||
arcLayer.appendChild(firingArc);
|
arcLayer.appendChild(firingArc);
|
||||||
outlineLayer.appendChild(firingArcOutline);
|
outlineLayer.appendChild(firingArcOutline);
|
||||||
|
|
||||||
const positionListener = position.bind(svg, firingArc, firingArcOutline, aim, grid);
|
// const positionListener = position.bind(svg, firingArc, firingArcOutline, aim, grid);
|
||||||
|
function positionListener(e) {
|
||||||
|
position(e, firingArc, firingArcOutline, aimLine, grid);
|
||||||
|
}
|
||||||
|
|
||||||
let firingArcPlacementListener = e => {
|
let placementListener = e => {
|
||||||
svg.querySelectorAll('.firing-arc.active').forEach(el => el.classList.remove('active'));
|
|
||||||
grid.removeAttribute('style');
|
grid.removeAttribute('style');
|
||||||
|
aimLine.remove();
|
||||||
|
svg.querySelectorAll('.firing-arc.active').forEach(el => el.classList.remove('active'));
|
||||||
svg.removeEventListener('mousemove', positionListener);
|
svg.removeEventListener('mousemove', positionListener);
|
||||||
firingArc.removeEventListener('click', firingArcPlacementListener);
|
|
||||||
firingArc.removeEventListener('contextmenu', cancelFiringArcPlacement);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let cancelFiringArcPlacement = e => {
|
let cancelPlacementListener = e => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
firingArc.removeEventListener('click', firingArcPlacementListener);
|
|
||||||
firingArc.removeEventListener('contextmenu', cancelFiringArcPlacement);
|
|
||||||
|
|
||||||
this.get(counter).forEach(fa => fa.remove());
|
this.get(counter).forEach(fa => fa.remove());
|
||||||
|
|
||||||
grid.removeAttribute('style');
|
grid.removeAttribute('style');
|
||||||
svg.removeEventListener('mousemove', positionListener);
|
svg.removeEventListener('mousemove', positionListener);
|
||||||
};
|
};
|
||||||
|
|
||||||
grid.style.pointerEvents = 'none';
|
grid.style.pointerEvents = 'none';
|
||||||
firingArc.addEventListener('click', firingArcPlacementListener);
|
firingArc.addEventListener('click', placementListener, { once: true });
|
||||||
firingArc.addEventListener('contextmenu', cancelFiringArcPlacement);
|
firingArc.addEventListener('contextmenu', cancelPlacementListener, { once: true });
|
||||||
svg.addEventListener('mousemove', positionListener);
|
svg.addEventListener('mousemove', positionListener);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -281,7 +295,6 @@ export default function (el) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
this.clipAll = function () {
|
this.clipAll = function () {
|
||||||
console.log('clipall')
|
|
||||||
let unclipped = getUnclipped();
|
let unclipped = getUnclipped();
|
||||||
|
|
||||||
unclipped.forEach(el => {
|
unclipped.forEach(el => {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user