arrowjoin
Version:
ArrowJoin is a creative and functional React library that effortlessly connects two React components with a sleek arrow.
361 lines • 14.7 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.getPosition = void 0;
var anchors_1 = require("../anchors");
var index_1 = require("./index");
var lodash_1 = __importDefault(require("lodash"));
var constants_1 = require("../../constants");
var buzzier_1 = require("./buzzier");
/**
* The Main logic of path calculation for the arrow.
* calculate new path, adjusting canvas, and set state based on given properties.
* */
var getPosition = function (xProps, mainRef) {
var _a, _b;
var _c, _d;
var propsRefs = xProps[0], valVars = xProps[1];
var startAnchor = propsRefs.startAnchor, endAnchor = propsRefs.endAnchor, strokeWidth = propsRefs.strokeWidth, showHead = propsRefs.showHead, headSize = propsRefs.headSize, showTail = propsRefs.showTail, tailSize = propsRefs.tailSize, path = propsRefs.path, curveness = propsRefs.curveness, gridBreak = propsRefs.gridBreak, headShape = propsRefs.headShape, tailShape = propsRefs.tailShape, _extendSVGcanvas = propsRefs._extendSVGcanvas, _cpx1Offset = propsRefs._cpx1Offset, _cpy1Offset = propsRefs._cpy1Offset, _cpx2Offset = propsRefs._cpx2Offset, _cpy2Offset = propsRefs._cpy2Offset;
var startPos = valVars.startPos, endPos = valVars.endPos;
var _e = mainRef.current, svgRef = _e.svgRef, lineRef = _e.lineRef;
var headOrient = 0;
var tailOrient = 0;
// convert startAnchor and endAnchor to list of objects represents allowed anchors.
var startPoints = (0, anchors_1.calcAnchors)(startAnchor, startPos);
var endPoints = (0, anchors_1.calcAnchors)(endAnchor, endPos);
// choose the smallest path for 2 points from these possibilities.
var _f = (0, index_1.getShortestLine)(startPoints, endPoints), chosenStart = _f.chosenStart, chosenEnd = _f.chosenEnd;
var startAnchorPosition = chosenStart.anchor.position, endAnchorPosition = chosenEnd.anchor.position;
var startPoint = lodash_1.default.pick(chosenStart, ['x', 'y']), endPoint = lodash_1.default.pick(chosenEnd, ['x', 'y']);
var mainDivPos = (0, index_1.getSvgPos)(svgRef);
var cx0 = Math.min(startPoint.x, endPoint.x) - mainDivPos.x;
var cy0 = Math.min(startPoint.y, endPoint.y) - mainDivPos.y;
var dx = endPoint.x - startPoint.x;
var dy = endPoint.y - startPoint.y;
var absDx = Math.abs(endPoint.x - startPoint.x);
var absDy = Math.abs(endPoint.y - startPoint.y);
var xSign = dx > 0 ? 1 : -1;
var ySign = dy > 0 ? 1 : -1;
var _g = [
headShape.offsetForward,
tailShape.offsetForward,
], headOffset = _g[0], tailOffset = _g[1];
var fHeadSize = headSize * strokeWidth; //factored head size
var fTailSize = tailSize * strokeWidth; //factored head size
// const { current: _headBox } = headBox;
var xHeadOffset = 0;
var yHeadOffset = 0;
var xTailOffset = 0;
var yTailOffset = 0;
var _headOffset = fHeadSize * headOffset;
var _tailOffset = fTailSize * tailOffset;
var cu = Number(curveness);
// gridRadius = Number(gridRadius);
if (!constants_1.cPaths.includes(path))
path = 'smooth';
if (path === 'straight') {
cu = 0;
path = 'smooth';
}
var biggerSide = headSize > tailSize ? headSize : tailSize;
var _calc = strokeWidth + (strokeWidth * biggerSide) / 2;
var excRight = _calc;
var excLeft = _calc;
var excUp = _calc;
var excDown = _calc;
excLeft += Number(_extendSVGcanvas);
excRight += Number(_extendSVGcanvas);
excUp += Number(_extendSVGcanvas);
excDown += Number(_extendSVGcanvas);
////////////////////////////////////
// arrow point to point calculations
var x1 = 0, x2 = absDx, y1 = 0, y2 = absDy;
if (dx < 0)
_a = [x2, x1], x1 = _a[0], x2 = _a[1];
if (dy < 0)
_b = [y2, y1], y1 = _b[0], y2 = _b[1];
////////////////////////////////////
// arrow curviness and arrowhead placement calculations
if (cu === 0) {
// in case of straight path
var headAngel = Math.atan(absDy / absDx);
if (showHead) {
x2 -= fHeadSize * (1 - headOffset) * xSign * Math.cos(headAngel);
y2 -= fHeadSize * (1 - headOffset) * ySign * Math.sin(headAngel);
headAngel *= ySign;
if (xSign < 0)
headAngel = (Math.PI - headAngel * xSign) * xSign;
xHeadOffset =
Math.cos(headAngel) * _headOffset -
(Math.sin(headAngel) * fHeadSize) / 2;
yHeadOffset =
(Math.cos(headAngel) * fHeadSize) / 2 +
Math.sin(headAngel) * _headOffset;
headOrient = (headAngel * 180) / Math.PI;
}
var tailAngel = Math.atan(absDy / absDx);
if (showTail) {
x1 += fTailSize * (1 - tailOffset) * xSign * Math.cos(tailAngel);
y1 += fTailSize * (1 - tailOffset) * ySign * Math.sin(tailAngel);
tailAngel *= -ySign;
if (xSign > 0)
tailAngel = (Math.PI - tailAngel * xSign) * xSign;
xTailOffset =
Math.cos(tailAngel) * _tailOffset -
(Math.sin(tailAngel) * fTailSize) / 2;
yTailOffset =
(Math.cos(tailAngel) * fTailSize) / 2 +
Math.sin(tailAngel) * _tailOffset;
tailOrient = (tailAngel * 180) / Math.PI;
}
}
else {
// in case of smooth path
if (endAnchorPosition === 'middle') {
// in case a middle anchor is chosen for endAnchor choose from which side to attach to the middle of the element
if (absDx > absDy) {
endAnchorPosition = xSign ? 'left' : 'right';
}
else {
endAnchorPosition = ySign ? 'top' : 'bottom';
}
}
if (showHead) {
if (['left', 'right'].includes(endAnchorPosition)) {
xHeadOffset += _headOffset * xSign;
x2 -= fHeadSize * (1 - headOffset) * xSign; //same!
yHeadOffset += (fHeadSize * xSign) / 2;
if (endAnchorPosition === 'left') {
headOrient = 0;
if (xSign < 0)
headOrient += 180;
}
else {
headOrient = 180;
if (xSign > 0)
headOrient += 180;
}
}
else if (['top', 'bottom'].includes(endAnchorPosition)) {
xHeadOffset += (fHeadSize * -ySign) / 2;
yHeadOffset += _headOffset * ySign;
y2 -= fHeadSize * ySign - yHeadOffset;
if (endAnchorPosition === 'top') {
headOrient = 270;
if (ySign > 0)
headOrient += 180;
}
else {
headOrient = 90;
if (ySign < 0)
headOrient += 180;
}
}
}
}
if (showTail && cu !== 0) {
if (['left', 'right'].includes(startAnchorPosition)) {
xTailOffset += _tailOffset * -xSign;
x1 += fTailSize * xSign + xTailOffset;
yTailOffset += -(fTailSize * xSign) / 2;
if (startAnchorPosition === 'left') {
tailOrient = 180;
if (xSign < 0)
tailOrient += 180;
}
else {
tailOrient = 0;
if (xSign > 0)
tailOrient += 180;
}
}
else if (['top', 'bottom'].includes(startAnchorPosition)) {
yTailOffset += _tailOffset * -ySign;
y1 += fTailSize * ySign + yTailOffset;
xTailOffset += (fTailSize * ySign) / 2;
if (startAnchorPosition === 'top') {
tailOrient = 90;
if (ySign > 0)
tailOrient += 180;
}
else {
tailOrient = 270;
if (ySign < 0)
tailOrient += 180;
}
}
}
var arrowHeadOffset = { x: xHeadOffset, y: yHeadOffset };
var arrowTailOffset = { x: xTailOffset, y: yTailOffset };
var cpx1 = x1, cpy1 = y1, cpx2 = x2, cpy2 = y2;
var curvesPossibilities = {};
if (path === 'smooth')
curvesPossibilities = {
hh: function () {
//horizontal - from right to left or the opposite
cpx1 += absDx * cu * xSign;
cpx2 -= absDx * cu * xSign;
},
vv: function () {
//vertical - from top to bottom or opposite
cpy1 += absDy * cu * ySign;
cpy2 -= absDy * cu * ySign;
},
hv: function () {
// start horizontally then vertically
// from v side to h side
cpx1 += absDx * cu * xSign;
cpy2 -= absDy * cu * ySign;
},
vh: function () {
// start vertically then horizontally
// from h side to v side
cpy1 += absDy * cu * ySign;
cpx2 -= absDx * cu * xSign;
},
};
else if (path === 'grid') {
curvesPossibilities = {
hh: function () {
cpx1 += (absDx * gridBreak.relative + gridBreak.abs) * xSign;
cpx2 -= (absDx * (1 - gridBreak.relative) - gridBreak.abs) * xSign;
if (showHead) {
cpx1 -= ((fHeadSize * (1 - headOffset)) / 2) * xSign;
cpx2 += ((fHeadSize * (1 - headOffset)) / 2) * xSign;
}
if (showTail) {
cpx1 -= ((fTailSize * (1 - tailOffset)) / 2) * xSign;
cpx2 += ((fTailSize * (1 - tailOffset)) / 2) * xSign;
}
},
vv: function () {
cpy1 += (absDy * gridBreak.relative + gridBreak.abs) * ySign;
cpy2 -= (absDy * (1 - gridBreak.relative) - gridBreak.abs) * ySign;
if (showHead) {
cpy1 -= ((fHeadSize * (1 - headOffset)) / 2) * ySign;
cpy2 += ((fHeadSize * (1 - headOffset)) / 2) * ySign;
}
if (showTail) {
cpy1 -= ((fTailSize * (1 - tailOffset)) / 2) * ySign;
cpy2 += ((fTailSize * (1 - tailOffset)) / 2) * ySign;
}
},
hv: function () {
cpx1 = x2;
},
vh: function () {
cpy1 = y2;
},
};
}
// smart select best curve for the current anchors
var selectedCurviness = '';
if (['left', 'right'].includes(startAnchorPosition))
selectedCurviness += 'h';
else if (['bottom', 'top'].includes(startAnchorPosition))
selectedCurviness += 'v';
else if (startAnchorPosition === 'middle')
selectedCurviness += 'm';
if (['left', 'right'].includes(endAnchorPosition))
selectedCurviness += 'h';
else if (['bottom', 'top'].includes(endAnchorPosition))
selectedCurviness += 'v';
else if (endAnchorPosition === 'middle')
selectedCurviness += 'm';
if (absDx > absDy)
selectedCurviness = selectedCurviness.replace(/m/g, 'h');
else
selectedCurviness = selectedCurviness.replace(/m/g, 'v');
curvesPossibilities[selectedCurviness]();
cpx1 += _cpx1Offset;
cpy1 += _cpy1Offset;
cpx2 += _cpx2Offset;
cpy2 += _cpy2Offset;
////////////////////////////////////
// canvas smart size adjustments
var _h = (0, buzzier_1.buzzierMinSols)(x1, cpx1, cpx2, x2), xSol1 = _h[0], xSol2 = _h[1];
var _j = (0, buzzier_1.buzzierMinSols)(y1, cpy1, cpy2, y2), ySol1 = _j[0], ySol2 = _j[1];
if (xSol1 < 0)
excLeft += -xSol1;
if (xSol2 > absDx)
excRight += xSol2 - absDx;
if (ySol1 < 0)
excUp += -ySol1;
if (ySol2 > absDy)
excDown += ySol2 - absDy;
if (path === 'grid') {
excLeft += _calc;
excRight += _calc;
excUp += _calc;
excDown += _calc;
}
x1 += excLeft;
x2 += excLeft;
y1 += excUp;
y2 += excUp;
cpx1 += excLeft;
cpx2 += excLeft;
cpy1 += excUp;
cpy2 += excUp;
var cw = absDx + excLeft + excRight, ch = absDy + excUp + excDown;
cx0 -= excLeft;
cy0 -= excUp;
//labels
var bzx = (0, buzzier_1.bzFunction)(x1, cpx1, cpx2, x2);
var bzy = (0, buzzier_1.bzFunction)(y1, cpy1, cpy2, y2);
var labelStartPos = { x: bzx(0.01), y: bzy(0.01) };
var labelMiddlePos = { x: bzx(0.5), y: bzy(0.5) };
var labelEndPos = { x: bzx(0.99), y: bzy(0.99) };
var arrowPath;
if (path === 'grid') {
// todo: support gridRadius
// arrowPath = `M ${x1} ${y1} L ${cpx1 - 10} ${cpy1} a10,10 0 0 1 10,10
// L ${cpx2} ${cpy2 - 10} a10,10 0 0 0 10,10 L ${x2} ${y2}`;
arrowPath = "M ".concat(x1, " ").concat(y1, " L ").concat(cpx1, " ").concat(cpy1, " L ").concat(cpx2, " ").concat(cpy2, " ").concat(x2, " ").concat(y2);
}
else if (path === 'smooth')
arrowPath = "M ".concat(x1, " ").concat(y1, " C ").concat(cpx1, " ").concat(cpy1, ", ").concat(cpx2, " ").concat(cpy2, ", ").concat(x2, " ").concat(y2);
return {
cx0: cx0,
cy0: cy0,
x1: x1,
x2: x2,
y1: y1,
y2: y2,
cw: cw,
ch: ch,
cpx1: cpx1,
cpy1: cpy1,
cpx2: cpx2,
cpy2: cpy2,
dx: dx,
dy: dy,
absDx: absDx,
absDy: absDy,
headOrient: headOrient,
tailOrient: tailOrient,
labelStartPos: labelStartPos,
labelMiddlePos: labelMiddlePos,
labelEndPos: labelEndPos,
excLeft: excLeft,
excRight: excRight,
excUp: excUp,
excDown: excDown,
headOffset: _headOffset,
arrowHeadOffset: arrowHeadOffset,
arrowTailOffset: arrowTailOffset,
startPoints: startPoints,
endPoints: endPoints,
mainDivPos: mainDivPos,
xSign: xSign,
ySign: ySign,
lineLength: (_d = (_c = lineRef.current) === null || _c === void 0 ? void 0 : _c.getTotalLength()) !== null && _d !== void 0 ? _d : 0,
fHeadSize: fHeadSize,
fTailSize: fTailSize,
arrowPath: arrowPath,
};
};
exports.getPosition = getPosition;
//# sourceMappingURL=GetPosition.js.map