UNPKG

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
"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