arrowjoin
Version:
ArrowJoin is a creative and functional React library that effortlessly connects two React components with a sleek arrow.
271 lines • 14.6 kB
JavaScript
"use strict";
var __assign = (this && this.__assign) || function () {
__assign = Object.assign || function(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
t[p] = s[p];
}
return t;
};
return __assign.apply(this, arguments);
};
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
if (ar || !(i in from)) {
if (!ar) ar = Array.prototype.slice.call(from, 0, i);
ar[i] = from[i];
}
}
return to.concat(ar || Array.prototype.slice.call(from));
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
var react_1 = __importStar(require("react"));
var useXarrowProps_1 = __importDefault(require("./useXarrowProps"));
var Xwrapper_1 = require("../Xwrapper");
var propTypes_1 = __importDefault(require("./propTypes"));
var GetPosition_1 = require("./utils/GetPosition");
var Xarrow = function (props) {
var _a;
var mainRef = (0, react_1.useRef)({
svgRef: (0, react_1.useRef)(null),
lineRef: (0, react_1.useRef)(null),
headRef: (0, react_1.useRef)(null),
tailRef: (0, react_1.useRef)(null),
lineDrawAnimRef: (0, react_1.useRef)(null),
lineDashAnimRef: (0, react_1.useRef)(null),
headOpacityAnimRef: (0, react_1.useRef)(null),
});
var _b = mainRef.current, svgRef = _b.svgRef, lineRef = _b.lineRef, headRef = _b.headRef, lineDrawAnimRef = _b.lineDrawAnimRef, lineDashAnimRef = _b.lineDashAnimRef, headOpacityAnimRef = _b.headOpacityAnimRef;
(0, react_1.useContext)(Xwrapper_1.XarrowContext);
// @ts-ignore
var xProps = (0, useXarrowProps_1.default)(props, mainRef.current);
var propsRefs = xProps[0];
var labels = propsRefs.labels, lineColor = propsRefs.lineColor, headColor = propsRefs.headColor, tailColor = propsRefs.tailColor, strokeWidth = propsRefs.strokeWidth, showHead = propsRefs.showHead, showTail = propsRefs.showTail, dashness = propsRefs.dashness, headShape = propsRefs.headShape, tailShape = propsRefs.tailShape, showXarrow = propsRefs.showXarrow, animateDrawing = propsRefs.animateDrawing, zIndex = propsRefs.zIndex, passProps = propsRefs.passProps, arrowBodyProps = propsRefs.arrowBodyProps, arrowHeadProps = propsRefs.arrowHeadProps, arrowTailProps = propsRefs.arrowTailProps, SVGcanvasProps = propsRefs.SVGcanvasProps, divContainerProps = propsRefs.divContainerProps, divContainerStyle = propsRefs.divContainerStyle, SVGcanvasStyle = propsRefs.SVGcanvasStyle, _debug = propsRefs._debug, shouldUpdatePosition = propsRefs.shouldUpdatePosition;
animateDrawing = props.animateDrawing;
var _c = (0, react_1.useState)(!animateDrawing), drawAnimEnded = _c[0], setDrawAnimEnded = _c[1];
var _d = (0, react_1.useState)({}), setRender = _d[1];
var forceRerender = function () { return setRender({}); };
var _e = (0, react_1.useState)({
//initial state
cx0: 0,
cy0: 0,
cw: 0,
ch: 0,
x1: 0,
y1: 0,
x2: 0,
y2: 0,
dx: 0,
dy: 0,
absDx: 0,
absDy: 0,
cpx1: 0,
cpy1: 0,
cpx2: 0,
cpy2: 0,
headOrient: 0,
tailOrient: 0,
arrowHeadOffset: { x: 0, y: 0 },
arrowTailOffset: { x: 0, y: 0 },
headOffset: 0,
excRight: 0,
excLeft: 0,
excUp: 0,
excDown: 0,
startPoints: [],
endPoints: [],
mainDivPos: { x: 0, y: 0 },
xSign: 1,
ySign: 1,
lineLength: 0,
fHeadSize: 1,
fTailSize: 1,
arrowPath: "",
labelStartPos: { x: 0, y: 0 },
labelMiddlePos: { x: 0, y: 0 },
labelEndPos: { x: 0, y: 0 },
}), st = _e[0], setSt = _e[1];
/**
* The Main logic of path calculation for the arrow.
* calculate new path, adjusting canvas, and set state based on given properties.
* */
(0, react_1.useLayoutEffect)(function () {
if (shouldUpdatePosition.current) {
// log('xarrow getPosition');
var pos = (0, GetPosition_1.getPosition)(xProps, mainRef);
// log('pos', pos);
setSt(pos);
shouldUpdatePosition.current = false;
}
});
// log('st', st);
var xOffsetHead = st.x2 - st.arrowHeadOffset.x;
var yOffsetHead = st.y2 - st.arrowHeadOffset.y;
var xOffsetTail = st.x1 - st.arrowTailOffset.x;
var yOffsetTail = st.y1 - st.arrowTailOffset.y;
var dashoffset = dashness.strokeLen + dashness.nonStrokeLen;
var animDirection = 1;
if (dashness.animation < 0) {
dashness.animation *= -1;
animDirection = -1;
}
var dashArray, animation, animRepeatCount, animStartValue, animEndValue = 0;
if (animateDrawing && drawAnimEnded == false) {
if (typeof animateDrawing === 'boolean')
animateDrawing = 1;
animation = animateDrawing + 's';
dashArray = st.lineLength;
animStartValue = st.lineLength;
animRepeatCount = 1;
if (animateDrawing < 0) {
_a = [animEndValue, animStartValue], animStartValue = _a[0], animEndValue = _a[1];
animation = animateDrawing * -1 + 's';
}
}
else {
dashArray = "".concat(dashness.strokeLen, " ").concat(dashness.nonStrokeLen);
animation = "".concat(1 / dashness.animation, "s");
animStartValue = dashoffset * animDirection;
animRepeatCount = 'indefinite';
animEndValue = 0;
}
// handle draw animation
(0, react_1.useLayoutEffect)(function () {
if (lineRef.current)
setSt(function (prevSt) {
var _a, _b;
return (__assign(__assign({}, prevSt), { lineLength: (_b = (_a = lineRef.current) === null || _a === void 0 ? void 0 : _a.getTotalLength()) !== null && _b !== void 0 ? _b : 0 }));
});
}, [lineRef.current]);
// set all props on first render
(0, react_1.useEffect)(function () {
var monitorDOMchanges = function () {
window.addEventListener('resize', forceRerender);
var handleDrawAmimEnd = function () {
var _a, _b;
setDrawAnimEnded(true);
// @ts-ignore
(_a = headOpacityAnimRef.current) === null || _a === void 0 ? void 0 : _a.beginElement();
// @ts-ignore
(_b = lineDashAnimRef.current) === null || _b === void 0 ? void 0 : _b.beginElement();
};
var handleDrawAmimBegin = function () { return (headRef.current.style.opacity = '0'); };
if (lineDrawAnimRef.current && headRef.current) {
lineDrawAnimRef.current.addEventListener('endEvent', handleDrawAmimEnd);
lineDrawAnimRef.current.addEventListener('beginEvent', handleDrawAmimBegin);
}
return function () {
window.removeEventListener('resize', forceRerender);
if (lineDrawAnimRef.current) {
lineDrawAnimRef.current.removeEventListener('endEvent', handleDrawAmimEnd);
if (headRef.current)
lineDrawAnimRef.current.removeEventListener('beginEvent', handleDrawAmimBegin);
}
};
};
var cleanMonitorDOMchanges = monitorDOMchanges();
return function () {
setDrawAnimEnded(false);
cleanMonitorDOMchanges();
};
}, [showXarrow]);
//todo: could make some advanced generic typescript inferring. for example get type from headShape.elem:T and
// tailShape.elem:K force the type for passProps,arrowHeadProps,arrowTailProps property. for now `as any` is used to
// avoid typescript conflicts
// so todo- fix all the `passProps as any` assertions
return (react_1.default.createElement("div", __assign({}, divContainerProps, { style: __assign({ position: 'absolute', zIndex: zIndex }, divContainerStyle) }), showXarrow ? (react_1.default.createElement(react_1.default.Fragment, null,
react_1.default.createElement("svg", __assign({ ref: svgRef, width: st.cw, height: st.ch, onClick: function () {
if (props.onClick) {
props.onClick(lineRef);
}
}, style: __assign({ position: 'absolute', cursor: 'pointer', left: st.cx0, top: st.cy0, pointerEvents: 'none', border: _debug ? '1px dashed yellow' : null }, SVGcanvasStyle), overflow: "auto" }, SVGcanvasProps),
react_1.default.createElement("path", __assign({ ref: lineRef, d: st.arrowPath, stroke: lineColor, strokeDasharray: dashArray, className: props.className,
// strokeDasharray={'0 0'}
strokeWidth: strokeWidth, fill: "transparent", pointerEvents: "visibleStroke" }, passProps, arrowBodyProps, { onClick: function () {
if (props.onClick) {
props.onClick(lineRef);
}
} }),
react_1.default.createElement(react_1.default.Fragment, null, drawAnimEnded ? (react_1.default.createElement(react_1.default.Fragment, null, dashness.animation ? (react_1.default.createElement("animate", { ref: lineDashAnimRef, attributeName: "stroke-dashoffset", values: "".concat(dashoffset * animDirection, ";0"), dur: "".concat(1 / dashness.animation, "s"), repeatCount: "indefinite" })) : null)) : (react_1.default.createElement(react_1.default.Fragment, null, animateDrawing ? (react_1.default.createElement("animate", { ref: lineDrawAnimRef, id: "svgEndAnimate", attributeName: "stroke-dashoffset", values: "".concat(animStartValue, ";").concat(animEndValue), dur: animation, repeatCount: animRepeatCount })) : null)))),
showTail ? (react_1.default.createElement("g", __assign({ fill: tailColor, pointerEvents: "auto", transform: "translate(".concat(xOffsetTail, ",").concat(yOffsetTail, ") rotate(").concat(st.tailOrient, ") scale(").concat(st.fTailSize, ")") }, passProps, arrowTailProps), tailShape.svgElem)) : null,
showHead ? (react_1.default.createElement("g", __assign({ ref: headRef,
// d={normalArrowShape}
fill: headColor, pointerEvents: "auto", transform: "translate(".concat(xOffsetHead, ",").concat(yOffsetHead, ") rotate(").concat(st.headOrient, ") scale(").concat(st.fHeadSize, ")"), opacity: animateDrawing && !drawAnimEnded ? 0 : 1 }, passProps, arrowHeadProps),
react_1.default.createElement("animate", { ref: headOpacityAnimRef, dur: '0.4', attributeName: "opacity", from: "0", to: "1", begin: "indefinite", repeatCount: "0", fill: "freeze" }),
headShape.svgElem)) : null,
_debug ? (react_1.default.createElement(react_1.default.Fragment, null,
react_1.default.createElement("circle", { r: "5", cx: st.cpx1, cy: st.cpy1, fill: "green" }),
react_1.default.createElement("circle", { r: "5", cx: st.cpx2, cy: st.cpy2, fill: "blue" }),
react_1.default.createElement("rect", { x: st.excLeft, y: st.excUp, width: st.absDx, height: st.absDy, fill: "none", stroke: "pink", strokeWidth: "2px" }))) : null),
labels.start ? (react_1.default.createElement("div", { style: {
transform: st.dx < 0
? 'translate(-100% , -50%)'
: 'translate(-0% , -50%)',
width: 'max-content',
position: 'absolute',
left: st.cx0 + st.labelStartPos.x,
top: st.cy0 + st.labelStartPos.y - strokeWidth - 5,
} }, labels.start)) : null,
labels.middle ? (react_1.default.createElement("div", { style: {
display: 'table',
width: 'max-content',
transform: 'translate(-50% , -50%)',
position: 'absolute',
left: st.cx0 + st.labelMiddlePos.x,
top: st.cy0 + st.labelMiddlePos.y,
} }, labels.middle)) : null,
labels.end ? (react_1.default.createElement("div", { style: {
transform: st.dx > 0
? 'translate(-100% , -50%)'
: 'translate(-0% , -50%)',
width: 'max-content',
position: 'absolute',
left: st.cx0 + st.labelEndPos.x,
top: st.cy0 + st.labelEndPos.y + strokeWidth + 5,
} }, labels.end)) : null,
_debug ? (react_1.default.createElement(react_1.default.Fragment, null, __spreadArray(__spreadArray([], st.startPoints, true), st.endPoints, true).map(function (p, i) {
return (react_1.default.createElement("div", { key: i, style: {
background: 'gray',
opacity: 0.5,
borderRadius: '50%',
transform: 'translate(-50%, -50%)',
height: 5,
width: 5,
position: 'absolute',
left: p.x - st.mainDivPos.x,
top: p.y - st.mainDivPos.y,
} }));
}))) : null)) : null));
};
//////////////////////////////
// propTypes
Xarrow.propTypes = propTypes_1.default;
exports.default = Xarrow;
//# sourceMappingURL=Xarrow.js.map