More refactor of firing arc module
This commit is contained in:
parent
93ef00d180
commit
9d02591fac
@ -23,6 +23,17 @@ const svgns = "http://www.w3.org/2000/svg",
|
||||
|
||||
let svg;
|
||||
|
||||
class Point {
|
||||
constructor(x = 0, y = 0) {
|
||||
this.x = +x;
|
||||
this.y = +y;
|
||||
}
|
||||
|
||||
toString() {
|
||||
return `${this.x},${this.y}`;
|
||||
}
|
||||
}
|
||||
|
||||
function calculateAngle(xDiff, yDiff) {
|
||||
yDiff = -yDiff;
|
||||
let angle = Math.abs(Math.atan(yDiff / xDiff));
|
||||
@ -67,74 +78,35 @@ function edgePoint({ x: x1, y: y1 }, { x: x2, y: y2 }, { x: [minX, maxX], y: [mi
|
||||
return new Point(...pointCoords);
|
||||
}
|
||||
|
||||
class Point {
|
||||
constructor(x = 0, y = 0) {
|
||||
this.x = +x;
|
||||
this.y = +y;
|
||||
}
|
||||
|
||||
toString() {
|
||||
return `${this.x},${this.y}`;
|
||||
}
|
||||
function touchSameEdge({ x: x1, y: y1 }, { x: x2, y: y2 }) {
|
||||
return x1 === x2 || y1 === y2;
|
||||
}
|
||||
|
||||
function position(e, firingArc, firingArcOutline, aimLine, grid) {
|
||||
// TODO: handle exactly horizontal and vertical lines?
|
||||
function shareValue({ x: x1, y: y1 }, { x: x2, y: y2 }) {
|
||||
return x1 === x2 || y1 === y2;
|
||||
}
|
||||
|
||||
let pointer = new DOMPoint(e.clientX, e.clientY);
|
||||
let pointerPt = pointer.matrixTransform(grid.getScreenCTM().inverse());
|
||||
function touchOrthogonalEdges({ x: x1, y: y1 }, { x: x2, y: y2 }, bounds) {
|
||||
return (bounds.x.includes(x1) && bounds.y.includes(y2)) || (bounds.y.includes(y1) && bounds.x.includes(x2));
|
||||
}
|
||||
|
||||
let pivotPt = new Point(aimLine.getAttribute('x1'), aimLine.getAttribute('y1'));
|
||||
function getCornerPts({ x: [xMin, xMax], y: [yMin, yMax] }) {
|
||||
const corners = [[xMin, yMin], [xMax, yMin], [xMax, yMax], [xMin, yMax]];
|
||||
return corners.map(([x, y]) => new Point(x, y));
|
||||
}
|
||||
|
||||
let { x, y, width, height } = grid.getBBox();
|
||||
|
||||
const bounds = {
|
||||
function getBounds({ x, y, width, height }) {
|
||||
return {
|
||||
x: [x, x + width],
|
||||
y: [y, y + height]
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
let cornerPoints = [
|
||||
[x, y],
|
||||
[x + width, y],
|
||||
[x + width, y + height],
|
||||
[x, y + height]
|
||||
].map(([x, y]) => new Point(x, y));
|
||||
|
||||
let aimPt = edgePoint(pivotPt, pointerPt, bounds);
|
||||
aimLine.setAttributeNS(null, 'x2', aimPt.x);
|
||||
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 xDelta = distance * Math.sin(angle) * Math.tan(arcAngle);
|
||||
|
||||
let arcPt1 = new Point(aimPt.x - xDelta, aimPt.y - yDelta);
|
||||
let arcPt2 = new Point(aimPt.x + xDelta, aimPt.y + yDelta);
|
||||
|
||||
arcPt1 = edgePoint(pivotPt, arcPt1, bounds);
|
||||
arcPt2 = edgePoint(pivotPt, arcPt2, bounds);
|
||||
|
||||
firingArcOutline.setAttributeNS(null, 'points', `${arcPt1} ${pivotPt} ${arcPt2}`);
|
||||
|
||||
function touchSameEdge({ x: x1, y: y1 }, { x: x2, y: y2 }) {
|
||||
return x1 === x2 || y1 === y2;
|
||||
}
|
||||
|
||||
function touchOrthogonalEdges({ x: x1, y: y1 }, { x: x2, y: y2 }) {
|
||||
return (bounds.x.includes(x1) && bounds.y.includes(y2)) || (bounds.y.includes(y1) && bounds.x.includes(x2));
|
||||
}
|
||||
|
||||
function shareValue({ x: x1, y: y1 }, { x: x2, y: y2 }) {
|
||||
return x1 === x2 || y1 === y2;
|
||||
}
|
||||
|
||||
// which arcpt does aimpt share a value with?
|
||||
// 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
|
||||
// is aim pt non-shared value greater or less than arcpt non-shared value?
|
||||
function findWhichCorners(pt, ...pts) {
|
||||
// which arcpt does aimpt share a value with?
|
||||
// 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
|
||||
// is aim pt non-shared value greater or less than arcpt non-shared value?
|
||||
function findWhichTwoCorners(pt, bounds, ...pts) {
|
||||
const ptVals = Object.values(pt),
|
||||
sharedValPt = pts.find(({ x, y }) => ptVals.includes(x) || ptVals.includes(y));
|
||||
|
||||
@ -142,7 +114,7 @@ function position(e, firingArc, firingArcOutline, aimLine, grid) {
|
||||
return;
|
||||
}
|
||||
|
||||
const nonSharedValKey = pt.x === sharedValPt.x ? 'x' : 'y';
|
||||
const nonSharedValKey = pt.x === sharedValPt.x ? 'y' : 'x';
|
||||
let cornerVal;
|
||||
|
||||
if (pt[nonSharedValKey] < sharedValPt[nonSharedValKey]) {
|
||||
@ -151,40 +123,82 @@ function position(e, firingArc, firingArcOutline, aimLine, grid) {
|
||||
cornerVal = Math.max(...bounds[nonSharedValKey]);
|
||||
}
|
||||
|
||||
return cornerPoints.filter(cp => cp[nonSharedValKey] === cornerVal);
|
||||
}
|
||||
return getCornerPts(bounds).filter(cp => cp[nonSharedValKey] === cornerVal);
|
||||
}
|
||||
|
||||
function chooseCornerPoints(aimPt, arcPt1, arcPt2, bounds) {
|
||||
const cornerPoints = getCornerPts(bounds);
|
||||
|
||||
let points;
|
||||
|
||||
if (touchSameEdge(arcPt1, arcPt2)) {
|
||||
// 0-corner case
|
||||
points = [arcPt2, pivotPt, arcPt1];
|
||||
} else if (touchOrthogonalEdges(arcPt1, arcPt2)) {
|
||||
points = [];
|
||||
} else if (touchOrthogonalEdges(arcPt1, arcPt2, bounds)) {
|
||||
if (touchSameEdge(aimPt, arcPt1) || touchSameEdge(aimPt, arcPt2)) {
|
||||
// 1-corner case
|
||||
let cp = cornerPoints.find(cp => shareValue(cp, arcPt1) && shareValue(cp, arcPt2));
|
||||
points = [arcPt2, pivotPt, arcPt1, cp];
|
||||
points = [cp];
|
||||
} else {
|
||||
// 3-corner case
|
||||
points = cornerPoints.filter(cp => !shareValue(cp, arcPt1) || !shareValue(cp, arcPt2));
|
||||
let index = points.findIndex(cp => shareValue(cp, arcPt2));
|
||||
points.splice(index + 1, 0, arcPt2, pivotPt, arcPt1);
|
||||
}
|
||||
} else {
|
||||
if (touchSameEdge(aimPt, arcPt1) || touchSameEdge(aimPt, arcPt2)) {
|
||||
// 2-corner case, aim and an arc point touch the same edge
|
||||
points = findWhichCorners(aimPt, arcPt1, arcPt2);
|
||||
let index = points.findIndex(cp => shareValue(cp, arcPt2));
|
||||
points.splice(index + 1, 0, arcPt2, pivotPt, arcPt1);
|
||||
points = findWhichTwoCorners(aimPt, bounds, arcPt1, arcPt2);
|
||||
} else {
|
||||
// 2-corner case, aim and both arc points all touch different edges
|
||||
points = cornerPoints.filter(cp => shareValue(cp, aimPt) || shareValue(cp, aimPt));
|
||||
let index = points.findIndex(cp => shareValue(cp, arcPt2));
|
||||
points.splice(index + 1, 0, arcPt2, pivotPt, arcPt1);
|
||||
}
|
||||
}
|
||||
|
||||
firingArc.setAttributeNS(null, 'points', points.join(' '));
|
||||
return points;
|
||||
}
|
||||
|
||||
function orderPoints(arcPoints, cornerPoints) {
|
||||
if (cornerPoints.length === 0) {
|
||||
return arcPoints;
|
||||
}
|
||||
|
||||
const index = cornerPoints.findIndex(cp => shareValue(cp, arcPoints.at(0)));
|
||||
cornerPoints.splice(index + 1, 0, ...arcPoints);
|
||||
return cornerPoints;
|
||||
}
|
||||
|
||||
function calcArcLinePtDeltas(aimPt, pivotPt, { dataset: { size }}) {
|
||||
const angle = calculateAngle(aimPt.x - pivotPt.x, aimPt.y - pivotPt.y),
|
||||
arcAngle = arcSize[size],
|
||||
distance = Math.sqrt((aimPt.x - pivotPt.x) ** 2 + (aimPt.y - pivotPt.y) ** 2),
|
||||
yDelta = distance * Math.cos(angle) * Math.tan(arcAngle),
|
||||
xDelta = distance * Math.sin(angle) * Math.tan(arcAngle);
|
||||
|
||||
return { xDelta, yDelta };
|
||||
}
|
||||
|
||||
function position(e, firingArc, firingArcOutline, aimLine, grid) {
|
||||
// TODO: handle exactly horizontal and vertical lines?
|
||||
|
||||
const pointer = new DOMPoint(e.clientX, e.clientY),
|
||||
pointerPt = pointer.matrixTransform(grid.getScreenCTM().inverse()),
|
||||
pivotPt = new Point(aimLine.getAttribute('x1'), aimLine.getAttribute('y1')),
|
||||
|
||||
bounds = getBounds(grid.getBBox()),
|
||||
aimPt = edgePoint(pivotPt, pointerPt, bounds),
|
||||
|
||||
{ xDelta, yDelta } = calcArcLinePtDeltas(aimPt, pivotPt, firingArc),
|
||||
arcPt1 = edgePoint(pivotPt, new Point(aimPt.x - xDelta, aimPt.y - yDelta), bounds),
|
||||
arcPt2 = edgePoint(pivotPt, new Point(aimPt.x + xDelta, aimPt.y + yDelta), bounds),
|
||||
|
||||
outlinePoints = [arcPt2, pivotPt, arcPt1],
|
||||
cps = chooseCornerPoints(aimPt, arcPt1, arcPt2, bounds),
|
||||
arcPoints = orderPoints(outlinePoints, cps);
|
||||
|
||||
aimLine.setAttributeNS(null, 'x2', aimPt.x);
|
||||
aimLine.setAttributeNS(null, 'y2', aimPt.y);
|
||||
|
||||
firingArcOutline.setAttributeNS(null, 'points', outlinePoints.join(' '));
|
||||
firingArc.setAttributeNS(null, 'points', arcPoints.join(' '));
|
||||
}
|
||||
|
||||
function setDataAttrs({ dataset: { allegiance, number }}, el) {
|
||||
@ -242,7 +256,6 @@ export default function (el) {
|
||||
arcLayer.appendChild(firingArc);
|
||||
outlineLayer.appendChild(firingArcOutline);
|
||||
|
||||
// const positionListener = position.bind(svg, firingArc, firingArcOutline, aim, grid);
|
||||
function positionListener(e) {
|
||||
position(e, firingArc, firingArcOutline, aimLine, grid);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user