react-xarrows
Advanced tools
Comparing version 1.4.4 to 1.5.0
@@ -13,3 +13,3 @@ import React from "react"; | ||
headSize?: number; | ||
path: "smooth" | "grid" | "straight"; | ||
path?: "smooth" | "grid" | "straight"; | ||
curveness?: number; | ||
@@ -16,0 +16,0 @@ dashness?: boolean | { |
470
lib/index.js
@@ -1,85 +0,49 @@ | ||
var __rest = (this && this.__rest) || function (s, e) { | ||
var t = {}; | ||
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) | ||
t[p] = s[p]; | ||
if (s != null && typeof Object.getOwnPropertySymbols === "function") | ||
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) { | ||
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) | ||
t[p[i]] = s[p[i]]; | ||
} | ||
return t; | ||
"use strict"; | ||
//// @ts-nocheck | ||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { | ||
if (k2 === undefined) k2 = k; | ||
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); | ||
}) : (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.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); | ||
__setModuleDefault(result, mod); | ||
return result; | ||
}; | ||
import React, { useRef, useEffect, useState } from "react"; | ||
import _ from "lodash"; | ||
const findCommonAncestor = (elem, elem2) => { | ||
function parents(node) { | ||
var nodes = [node]; | ||
for (; node; node = node.parentNode) { | ||
nodes.unshift(node); | ||
} | ||
return nodes; | ||
} | ||
function commonAncestor(node1, node2) { | ||
var parents1 = parents(node1); | ||
var parents2 = parents(node2); | ||
// if (parents1[0] !== parents2[0]) throw new Error("No common ancestor!"); | ||
if (parents1[0] !== parents2[0]) | ||
throw new Error("No common ancestor!"); | ||
for (var i = 0; i < parents1.length; i++) { | ||
if (parents1[i] !== parents2[i]) | ||
return parents1[i - 1]; | ||
} | ||
} | ||
return commonAncestor(elem, elem2); | ||
var __importDefault = (this && this.__importDefault) || function (mod) { | ||
return (mod && mod.__esModule) ? mod : { "default": mod }; | ||
}; | ||
const findAllChildren = (child, parent) => { | ||
if (child === parent) | ||
return []; | ||
let children = []; | ||
let childParent = child.parentElement; | ||
while (childParent !== parent) { | ||
children.push(childParent); | ||
childParent = childParent.parentElement; | ||
} | ||
return children; | ||
}; | ||
const getElementByPropGiven = (ref) => { | ||
var myRef; | ||
if (typeof ref === "string") { | ||
myRef = document.getElementById(ref); | ||
if (myRef === null) | ||
throw Error(`'${ref}' is not an id of element in the dom. make sure you provided current id or provide a React reference to element instead.`); | ||
} | ||
else | ||
myRef = ref.current; | ||
if (myRef === null) | ||
throw Error(`'${ref}' is not a valid react reference to html element | ||
OR | ||
you tried to render Xarrow before one of the anchors. | ||
please provide correct react reference or provide id instead.`); | ||
return myRef; | ||
}; | ||
const typeOf = (arg) => { | ||
let type = typeof arg; | ||
if (type === "object") { | ||
if (arg === null) | ||
type = "null"; | ||
else if (Array.isArray(arg)) | ||
type = "array"; | ||
} | ||
return type; | ||
}; | ||
const Xarrow = (_a) => { | ||
var props = __rest(_a, []); | ||
const selfRef = useRef(null); | ||
const [anchorsRefs, setAnchorsRefs] = useState({ start: null, end: null }); | ||
const [prevPosState, setPrevPosState] = useState(null); | ||
const [prevProps, setPrevProps] = useState(null); | ||
const [anchorsParents, setAnchorsParents] = useState(null); //list children of the common ancestor of the arrow with start and end until start or end | ||
const [commonAncestor, setCommonAncestor] = useState(null); //list children of the common ancestor of the arrow with start and end until start or end | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const react_1 = __importStar(require("react")); | ||
const lodash_isequal_1 = __importDefault(require("lodash.isequal")); | ||
const lodash_pick_1 = __importDefault(require("lodash.pick")); | ||
const utils_1 = require("./utils"); | ||
const prop_types_1 = __importDefault(require("prop-types")); | ||
const Xarrow = (props) => { | ||
let { startAnchor, endAnchor, label, color, lineColor, headColor, strokeWidth, headSize, path, curveness, dashness, passProps, advanced, } = props; | ||
const selfRef = react_1.useRef(null); | ||
const [anchorsRefs, setAnchorsRefs] = react_1.useState({ start: null, end: null }); | ||
const [prevPosState, setPrevPosState] = react_1.useState(null); | ||
const [prevProps, setPrevProps] = react_1.useState(null); | ||
const updateIfNeeded = () => { | ||
if (checkIfAnchorsRefsChanged()) { | ||
// check if anchors refs changed | ||
const start = utils_1.getElementByPropGiven(props.start); | ||
const end = utils_1.getElementByPropGiven(props.end); | ||
// in case one of the elements does not mounted skip any update | ||
if (start == null || end == null) | ||
return; | ||
// if anchors changed re-set them | ||
if (!lodash_isequal_1.default(anchorsRefs, { start, end })) { | ||
initAnchorsRefs(); | ||
} | ||
else if (!_.isEqual(props, prevProps)) { | ||
else if (!lodash_isequal_1.default(props, prevProps)) { | ||
//first check if any properties changed | ||
@@ -96,3 +60,3 @@ if (prevProps) { | ||
let posState = getAnchorsPos(); | ||
if (!_.isEqual(prevPosState, posState)) { | ||
if (!lodash_isequal_1.default(prevPosState, posState)) { | ||
setPrevPosState(posState); | ||
@@ -103,169 +67,21 @@ updatePosition(posState); | ||
}; | ||
const checkIfAnchorsRefsChanged = () => { | ||
var start = getElementByPropGiven(props.start); | ||
var end = getElementByPropGiven(props.end); | ||
return !_.isEqual(anchorsRefs, { start, end }); | ||
}; | ||
const monitorDOMchanges = () => { | ||
[...anchorsParents.start, ...anchorsParents.end].forEach((elem) => { | ||
elem.addEventListener("scroll", updateIfNeeded); | ||
}); | ||
window.addEventListener("resize", updateIfNeeded); | ||
if (window.getComputedStyle(commonAncestor).position !== "relative") | ||
commonAncestor.addEventListener("scroll", updateIfNeeded); | ||
}; | ||
const cleanMonitorDOMchanges = () => { | ||
[...anchorsParents.start, ...anchorsParents.end].forEach((elem) => { | ||
elem.removeEventListener("scroll", updateIfNeeded); | ||
}); | ||
window.removeEventListener("resize", updateIfNeeded); | ||
if (window.getComputedStyle(commonAncestor).position === "relative") | ||
commonAncestor.removeEventListener("scroll", updateIfNeeded); | ||
}; | ||
const initParentsChildren = () => { | ||
let anchorsCommonAncestor = findCommonAncestor(anchorsRefs.start, anchorsRefs.end); | ||
let allAncestor = findCommonAncestor(anchorsCommonAncestor, selfRef.current); | ||
let allAncestorChildrenStart = findAllChildren(anchorsRefs.start, allAncestor); | ||
let allAncestorChildrenEnd = findAllChildren(anchorsRefs.end, allAncestor); | ||
setCommonAncestor(allAncestor); | ||
setAnchorsParents({ | ||
start: allAncestorChildrenStart, | ||
end: allAncestorChildrenEnd, | ||
}); | ||
let allAncestorPosStyle = window.getComputedStyle(allAncestor).position; | ||
if (props.consoleWarning) { | ||
if (allAncestorPosStyle !== "relative" && | ||
(allAncestor.scrollHeight > allAncestor.clientHeight || allAncestor.scrollWidth > allAncestor.clientWidth)) | ||
console.warn(`Xarrow warning: it is recommended to set common ancestor positioning style to 'relative',this will prevent rerender on every scroll event. | ||
change position style from '${allAncestorPosStyle}' to 'relative' of element `, allAncestor); | ||
if (selfRef.current.parentElement !== anchorsCommonAncestor) | ||
console.warn(`Xarrow warning: you placed Xarrow not as son of the common ancestor of 'start' component and 'end' component. | ||
the suggested element to put Xarrow inside of to prevent redundant rerenders iss `, anchorsCommonAncestor, " and not ", selfRef.current.parentElement, `if this was your intention set monitorDOMchanges to true so Xarrow will render whenever relevant DOM events are triggered. | ||
to disable this warnings set consoleWarning property to false`); | ||
if ((allAncestorChildrenStart.length > 0 || allAncestorChildrenEnd.length > 0) && | ||
props.monitorDOMchanges === false) | ||
console.warn(`Xarrow warning: set monitorDOMchanges to true - its possible that the positioning will get out of sync on DOM events(like scroll), | ||
on these elements`, _.uniqWith([...allAncestorChildrenStart, ...allAncestorChildrenEnd], _.isEqual), `\nto disable this warnings set consoleWarning property to false`); | ||
} | ||
}; | ||
const testUserGivenProperties = () => { | ||
const throwError = (errorMsg, consoleMsg) => { | ||
let err = Error("Xarrows: " + errorMsg); | ||
if (consoleMsg) | ||
console.error("xarrow error: ", ...consoleMsg); | ||
throw err; | ||
}; | ||
const typeCheck = (arg, allowedTypes, name) => { | ||
if (!allowedTypes.includes(typeOf(arg))) { | ||
throwError(`'${name}' property error.`, [ | ||
`'${name}' property should be from type ${allowedTypes.join(" or ")}, not`, | ||
typeOf(arg), | ||
]); | ||
} | ||
}; | ||
const valueCheck = (value, allowedValues, name) => { | ||
if (!allowedValues.includes(value)) { | ||
throwError(`'${name}' property error.`, [ | ||
`${name} =`, | ||
value, | ||
` but ${name} prop should be '${allowedValues.join("' or '")}', not`, | ||
"'" + value + "'", | ||
]); | ||
} | ||
}; | ||
const checkRef = (ref, name) => { | ||
typeCheck(ref, ["object", "string"], name); | ||
if (typeOf(ref) === "object") { | ||
if (!("current" in ref)) | ||
throwError(`'${name}' property error.`, [ | ||
`${name}=`, | ||
ref, | ||
`but '${name}' is not of type reference. maybe you set '${name}' property to other object and not to React reference?`, | ||
]); | ||
if (ref.current === null) | ||
throwError(`'${name}' property error`, [ | ||
`Make sure the reference to ${name} anchor are provided correctly. | ||
maybe you tried to render Xarrow before ${name} anchor?`, | ||
]); | ||
} | ||
}; | ||
const checkAnchor = (anchor, name) => { | ||
typeCheck(anchor, ["string", "array", "object"], name); | ||
if (typeOf(anchor) === "string") | ||
valueCheck(anchor, ["auto", "left", "right", "top", "bottom", "middle"], name); | ||
else if (typeOf(anchor) === "array") | ||
anchor.forEach((an) => valueCheck(an, ["auto", "left", "right", "top", "bottom", "middle"], name)); | ||
}; | ||
if (getElementByPropGiven(props.start) === getElementByPropGiven(props.end)) | ||
throwError(`'start' and 'end' props cannot point to the same element`, [ | ||
`'start' and 'end' props cannot point to the same element`, | ||
]); | ||
checkRef(props.start, "start"); | ||
checkRef(props.end, "end"); | ||
checkAnchor(props.startAnchor, "startAnchor"); | ||
checkAnchor(props.endAnchor, "endAnchor"); | ||
}; | ||
const triggerUpdate = (callback) => { | ||
updateIfNeeded(); | ||
if (callback) | ||
callback(); | ||
}; | ||
const initRegisterEvents = () => { | ||
props.registerEvents.forEach((re) => { | ||
var ref = getElementByPropGiven(re.ref); | ||
ref.addEventListener(re.eventName, () => triggerUpdate(re.callback)); | ||
}); | ||
}; | ||
const cleanRegisterEvents = () => { | ||
props.registerEvents.forEach((re) => { | ||
var ref = getElementByPropGiven(re.ref); | ||
ref.removeEventListener(re.eventName, () => triggerUpdate(re.callback)); | ||
}); | ||
}; | ||
const initAnchorsRefs = () => { | ||
var start = getElementByPropGiven(props.start); | ||
var end = getElementByPropGiven(props.end); | ||
const start = utils_1.getElementByPropGiven(props.start); | ||
const end = utils_1.getElementByPropGiven(props.end); | ||
setAnchorsRefs({ start, end }); | ||
}; | ||
const initProps = () => { | ||
testUserGivenProperties(); | ||
// initXarrowElemPos(); | ||
// testUserGivenProperties(); | ||
setPrevProps(props); | ||
}; | ||
useEffect(() => { | ||
// equivalent to componentDidMount | ||
react_1.useEffect(() => { | ||
// console.log("xarrow mounted"); | ||
initProps(); | ||
initRegisterEvents(); | ||
initAnchorsRefs(); | ||
return () => { | ||
// console.log("xarrow unmounted"); | ||
cleanRegisterEvents(); | ||
}; | ||
}, []); | ||
useEffect(() => { | ||
// Happens only at mounting (or props changed) after anchorsRefs initialized | ||
if (anchorsRefs.start) { | ||
initParentsChildren(); | ||
} | ||
}, [anchorsRefs]); | ||
useEffect(() => { | ||
// happens only at mounting after anchorsParents initialized | ||
if (anchorsParents && props.monitorDOMchanges) { | ||
monitorDOMchanges(); | ||
return () => { | ||
//cleanUp it unmounting! | ||
cleanMonitorDOMchanges(); | ||
}; | ||
} | ||
}, [anchorsParents]); | ||
// useEffect(() => { | ||
// // triggers position update when prevPosState changed(can happen in any render) | ||
// if (prevPosState) updatePosition(prevPosState); | ||
// }, [prevPosState]); | ||
useEffect(() => { | ||
react_1.useLayoutEffect(() => { | ||
// console.log("xarrow rendered!"); | ||
updateIfNeeded(); | ||
}); | ||
const [st, setSt] = useState({ | ||
const [st, setSt] = react_1.useState({ | ||
//initial state | ||
@@ -300,3 +116,2 @@ cx0: 0, | ||
}); | ||
let { color, lineColor, headColor, headSize, strokeWidth, dashness } = props; | ||
headSize = Number(headSize); | ||
@@ -309,4 +124,8 @@ strokeWidth = Number(strokeWidth); | ||
if (typeof dashness === "object") { | ||
dashStroke = dashness.strokeLen ? Number(dashness.strokeLen) : Number(strokeWidth) * 2; | ||
dashNone = dashness.strokeLen ? Number(dashness.nonStrokeLen) : Number(strokeWidth); | ||
dashStroke = dashness.strokeLen | ||
? Number(dashness.strokeLen) | ||
: Number(strokeWidth) * 2; | ||
dashNone = dashness.strokeLen | ||
? Number(dashness.nonStrokeLen) | ||
: Number(strokeWidth); | ||
animationSpeed = dashness.animation ? Number(dashness.animation) : null; | ||
@@ -326,18 +145,21 @@ } | ||
let labelStart = null, labelMiddle = null, labelEnd = null; | ||
if (props.label) { | ||
if (typeof props.label === "string" || "type" in props.label) | ||
labelMiddle = props.label; | ||
else if (["start", "middle", "end"].some((key) => key in props.label)) { | ||
props.label = props.label; | ||
({ start: labelStart, middle: labelMiddle, end: labelEnd } = props.label); | ||
if (label) { | ||
if (typeof label === "string" || "type" in label) | ||
labelMiddle = label; | ||
else if (["start", "middle", "end"].some((key) => key in label)) { | ||
label = label; | ||
({ start: labelStart, middle: labelMiddle, end: labelEnd } = label); | ||
} | ||
} | ||
let { passProps: adPassProps = { SVGcanvas: {}, arrowHead: {}, arrowBody: {} }, extendSVGcanvas: extendSVGcanvas = 0, } = props.advanced; | ||
let { passProps: adPassProps = { SVGcanvas: {}, arrowHead: {}, arrowBody: {} }, extendSVGcanvas: extendSVGcanvas = 0, } = advanced; | ||
let { SVGcanvas = {}, arrowBody = {}, arrowHead = {} } = adPassProps; | ||
const getSelfPos = () => { | ||
let { x: xarrowElemX, y: xarrowElemY } = selfRef.current.getBoundingClientRect(); | ||
let { left: xarrowElemX, top: xarrowElemY, } = selfRef.current.getBoundingClientRect(); | ||
let xarrowStyle = getComputedStyle(selfRef.current); | ||
let xarrowStyleLeft = Number(xarrowStyle.left.slice(0, -2)); | ||
let xarrowStyleTop = Number(xarrowStyle.top.slice(0, -2)); | ||
return { x: xarrowElemX - xarrowStyleLeft, y: xarrowElemY - xarrowStyleTop }; | ||
return { | ||
x: xarrowElemX - xarrowStyleLeft, | ||
y: xarrowElemY - xarrowStyleTop, | ||
}; | ||
}; | ||
@@ -367,5 +189,3 @@ const getAnchorsPos = () => { | ||
const updatePosition = (positions) => { | ||
// Do NOT call this function directly. | ||
// you should set position by 'setPrevPosState(posState)' and that will trigger | ||
// this function in the useEffect hook. | ||
// calculate new position and path and set state based on given properties | ||
let { start: sPos } = positions; | ||
@@ -375,3 +195,3 @@ let { end: ePos } = positions; | ||
////////////////////////////////////////////////////////////////////// | ||
// declare relevant functions for later | ||
// declare relevant functions for later use for start and end refs(instead doing all twice) | ||
const getAnchorsDefaultOffsets = (width, height) => { | ||
@@ -390,9 +210,14 @@ return { | ||
let anchorChoice = Array.isArray(anchor) ? anchor : [anchor]; | ||
if (anchorChoice.length == 0) | ||
anchorChoice = ["auto"]; | ||
//now map each item in the list to relevant object | ||
let anchorChoiceMapped = anchorChoice.map((anchorChoice) => { | ||
if (typeOf(anchorChoice) === "string") { | ||
if (utils_1.typeOf(anchorChoice) === "string") { | ||
anchorChoice = anchorChoice; | ||
return { position: anchorChoice, offset: { rightness: 0, bottomness: 0 } }; | ||
return { | ||
position: anchorChoice, | ||
offset: { rightness: 0, bottomness: 0 }, | ||
}; | ||
} | ||
else if (typeOf(anchorChoice) === "object") { | ||
else if (utils_1.typeOf(anchorChoice) === "object") { | ||
if (!anchorChoice.offset) | ||
@@ -428,3 +253,3 @@ anchorChoice.offset = { rightness: 0, bottomness: 0 }; | ||
// now prepare this list of anchors to object expected by the `getShortestLine` function | ||
let points = anchorPossibilities.map((pos) => ({ | ||
return anchorPossibilities.map((pos) => ({ | ||
x: anchorPos.x + pos.offset.rightness, | ||
@@ -434,8 +259,7 @@ y: anchorPos.y + pos.offset.bottomness, | ||
})); | ||
return points; | ||
}; | ||
//end declare functions | ||
///////////////////////////////////////////////////////////////////////////////////////// | ||
let startPointsObj = prepareAnchorLines(props.startAnchor, sPos); | ||
let endPointsObj = prepareAnchorLines(props.endAnchor, ePos); | ||
let startPointsObj = prepareAnchorLines(startAnchor, sPos); | ||
let endPointsObj = prepareAnchorLines(endAnchor, ePos); | ||
const dist = (p1, p2) => { | ||
@@ -461,4 +285,4 @@ //length of line | ||
let { startPointObj, endPointObj } = getShortestLine(startPointsObj, endPointsObj); | ||
let startAnchor = startPointObj.anchorPosition, endAnchor = endPointObj.anchorPosition; | ||
let startPoint = _.pick(startPointObj, ["x", "y"]), endPoint = _.pick(endPointObj, ["x", "y"]); | ||
let startAnchorPosition = startPointObj.anchorPosition, endAnchorPosition = endPointObj.anchorPosition; | ||
let startPoint = lodash_pick_1.default(startPointObj, ["x", "y"]), endPoint = lodash_pick_1.default(endPointObj, ["x", "y"]); | ||
let xarrowElemPos = getSelfPos(); | ||
@@ -474,4 +298,3 @@ let cx0 = Math.min(startPoint.x, endPoint.x) - xarrowElemPos.x; | ||
let headOffset = ((headSize * 3) / 4) * strokeWidth; | ||
let cu = Number(props.curveness); | ||
let { path } = props; | ||
let cu = Number(curveness); | ||
if (path === "straight") { | ||
@@ -491,3 +314,3 @@ cu = 0; | ||
// arrow point to point calculations | ||
let x1 = 0, x2 = absDx + 0, y1 = 0, y2 = absDy + 0; | ||
let x1 = 0, x2 = absDx, y1 = 0, y2 = absDy; | ||
if (dx < 0) | ||
@@ -508,20 +331,24 @@ [x1, x2] = [x2, x1]; | ||
headAngel = (Math.PI - headAngel * xSign) * xSign; | ||
xHeadOffset = ((Math.cos(headAngel) * headOffset) / 3 - (Math.sin(headAngel) * (headSize * strokeWidth)) / 2) * 1; | ||
yHeadOffset = ((Math.cos(headAngel) * (headSize * strokeWidth)) / 2 + (Math.sin(headAngel) * headOffset) / 3) * 1; | ||
xHeadOffset = | ||
(Math.cos(headAngel) * headOffset) / 3 - | ||
(Math.sin(headAngel) * (headSize * strokeWidth)) / 2; | ||
yHeadOffset = | ||
(Math.cos(headAngel) * (headSize * strokeWidth)) / 2 + | ||
(Math.sin(headAngel) * headOffset) / 3; | ||
headOrient = (headAngel * 180) / Math.PI; | ||
} | ||
else { | ||
if (endAnchor === "middle") { | ||
if (endAnchorPosition === "middle") { | ||
if (absDx > absDy) { | ||
endAnchor = xSign ? "left" : "right"; | ||
endAnchorPosition = xSign ? "left" : "right"; | ||
} | ||
else { | ||
endAnchor = ySign ? "top" : "bottom"; | ||
endAnchorPosition = ySign ? "top" : "bottom"; | ||
} | ||
} | ||
if (["left", "right"].includes(endAnchor)) { | ||
if (["left", "right"].includes(endAnchorPosition)) { | ||
x2 -= headOffset * xSign; | ||
xHeadOffset = (headOffset * xSign) / 3; | ||
yHeadOffset = (headSize * strokeWidth * xSign) / 2; | ||
if (endAnchor === "left") { | ||
if (endAnchorPosition === "left") { | ||
headOrient = 0; | ||
@@ -537,7 +364,7 @@ if (xSign < 0) | ||
} | ||
else if (["top", "bottom"].includes(endAnchor)) { | ||
else if (["top", "bottom"].includes(endAnchorPosition)) { | ||
yHeadOffset = (headOffset * ySign) / 3; | ||
xHeadOffset = (headSize * strokeWidth * -ySign) / 2; | ||
y2 -= headOffset * ySign; | ||
if (endAnchor === "top") { | ||
if (endAnchorPosition === "top") { | ||
headOrient = 270; | ||
@@ -605,13 +432,13 @@ if (ySign > 0) | ||
let selectedCurviness = ""; | ||
if (["left", "right"].includes(startAnchor)) | ||
if (["left", "right"].includes(startAnchorPosition)) | ||
selectedCurviness += "h"; | ||
else if (["bottom", "top"].includes(startAnchor)) | ||
else if (["bottom", "top"].includes(startAnchorPosition)) | ||
selectedCurviness += "v"; | ||
else if (startAnchor === "middle") | ||
else if (startAnchorPosition === "middle") | ||
selectedCurviness += "m"; | ||
if (["left", "right"].includes(endAnchor)) | ||
if (["left", "right"].includes(endAnchorPosition)) | ||
selectedCurviness += "h"; | ||
else if (["bottom", "top"].includes(endAnchor)) | ||
else if (["bottom", "top"].includes(endAnchorPosition)) | ||
selectedCurviness += "v"; | ||
else if (endAnchor === "middle") | ||
else if (endAnchorPosition === "middle") | ||
selectedCurviness += "m"; | ||
@@ -636,3 +463,4 @@ if (absDx > absDy) | ||
6 * cpx2 + | ||
Math.sqrt(Math.pow((6 * x1 - 12 * cpx1 + 6 * cpx2), 2) - 4 * (3 * cpx1 - 3 * x1) * (-3 * x1 + 9 * cpx1 - 9 * cpx2 + 3 * x2))) / | ||
Math.sqrt(Math.pow((6 * x1 - 12 * cpx1 + 6 * cpx2), 2) - | ||
4 * (3 * cpx1 - 3 * x1) * (-3 * x1 + 9 * cpx1 - 9 * cpx2 + 3 * x2))) / | ||
(2 * (-3 * x1 + 9 * cpx1 - 9 * cpx2 + 3 * x2)); | ||
@@ -642,3 +470,4 @@ let txSol2 = (-6 * x1 + | ||
6 * cpx2 - | ||
Math.sqrt(Math.pow((6 * x1 - 12 * cpx1 + 6 * cpx2), 2) - 4 * (3 * cpx1 - 3 * x1) * (-3 * x1 + 9 * cpx1 - 9 * cpx2 + 3 * x2))) / | ||
Math.sqrt(Math.pow((6 * x1 - 12 * cpx1 + 6 * cpx2), 2) - | ||
4 * (3 * cpx1 - 3 * x1) * (-3 * x1 + 9 * cpx1 - 9 * cpx2 + 3 * x2))) / | ||
(2 * (-3 * x1 + 9 * cpx1 - 9 * cpx2 + 3 * x2)); | ||
@@ -648,3 +477,4 @@ let tySol1 = (-6 * y1 + | ||
6 * cpy2 + | ||
Math.sqrt(Math.pow((6 * y1 - 12 * cpy1 + 6 * cpy2), 2) - 4 * (3 * cpy1 - 3 * y1) * (-3 * y1 + 9 * cpy1 - 9 * cpy2 + 3 * y2))) / | ||
Math.sqrt(Math.pow((6 * y1 - 12 * cpy1 + 6 * cpy2), 2) - | ||
4 * (3 * cpy1 - 3 * y1) * (-3 * y1 + 9 * cpy1 - 9 * cpy2 + 3 * y2))) / | ||
(2 * (-3 * y1 + 9 * cpy1 - 9 * cpy2 + 3 * y2)); | ||
@@ -654,6 +484,13 @@ let tySol2 = (-6 * y1 + | ||
6 * cpy2 - | ||
Math.sqrt(Math.pow((6 * y1 - 12 * cpy1 + 6 * cpy2), 2) - 4 * (3 * cpy1 - 3 * y1) * (-3 * y1 + 9 * cpy1 - 9 * cpy2 + 3 * y2))) / | ||
Math.sqrt(Math.pow((6 * y1 - 12 * cpy1 + 6 * cpy2), 2) - | ||
4 * (3 * cpy1 - 3 * y1) * (-3 * y1 + 9 * cpy1 - 9 * cpy2 + 3 * y2))) / | ||
(2 * (-3 * y1 + 9 * cpy1 - 9 * cpy2 + 3 * y2)); | ||
const bzx = (t) => Math.pow((1 - t), 3) * x1 + 3 * Math.pow((1 - t), 2) * t * cpx1 + 3 * (1 - t) * Math.pow(t, 2) * cpx2 + Math.pow(t, 3) * x2; | ||
const bzy = (t) => Math.pow((1 - t), 3) * y1 + 3 * Math.pow((1 - t), 2) * t * cpy1 + 3 * (1 - t) * Math.pow(t, 2) * cpy2 + Math.pow(t, 3) * y2; | ||
const bzx = (t) => Math.pow((1 - t), 3) * x1 + | ||
3 * Math.pow((1 - t), 2) * t * cpx1 + | ||
3 * (1 - t) * Math.pow(t, 2) * cpx2 + | ||
Math.pow(t, 3) * x2; | ||
const bzy = (t) => Math.pow((1 - t), 3) * y1 + | ||
3 * Math.pow((1 - t), 2) * t * cpy1 + | ||
3 * (1 - t) * Math.pow(t, 2) * cpy2 + | ||
Math.pow(t, 3) * y2; | ||
//////////////////////////////////// | ||
@@ -722,3 +559,2 @@ // canvas smart size adjustments | ||
let yOffsetHead = st.y2 - st.arrowHeadOffset.y; | ||
let { path = "smooth" } = props; | ||
let arrowPath = `M ${st.x1} ${st.y1} C ${st.cpx1} ${st.cpy1}, ${st.cpx2} ${st.cpy2}, ${st.x2} ${st.y2}`; | ||
@@ -729,5 +565,4 @@ if (path === "straight") | ||
arrowPath = `M ${st.x1} ${st.y1} L ${st.cpx1} ${st.cpy1} L ${st.cpx2} ${st.cpy2} L ${st.x2} ${st.y2}`; | ||
// console.log("test"); | ||
return (React.createElement("div", { style: { position: "absolute" } }, | ||
React.createElement("svg", Object.assign({ ref: selfRef, width: st.cw, height: st.ch, style: { | ||
return (react_1.default.createElement("div", { style: { position: "absolute" } }, | ||
react_1.default.createElement("svg", Object.assign({ ref: selfRef, width: st.cw, height: st.ch, style: { | ||
// border: "2px yellow dashed", | ||
@@ -739,9 +574,9 @@ position: "absolute", | ||
}, overflow: "auto" }, SVGcanvas), | ||
React.createElement("path", Object.assign({ d: arrowPath, stroke: lineColor, strokeDasharray: `${dashStroke} ${dashNone}`, strokeWidth: strokeWidth, fill: "transparent", | ||
react_1.default.createElement("path", Object.assign({ d: arrowPath, stroke: lineColor, strokeDasharray: `${dashStroke} ${dashNone}`, strokeWidth: strokeWidth, fill: "transparent", | ||
// markerEnd={`url(#${arrowHeadId})`} | ||
pointerEvents: "visibleStroke" }, props.passProps, arrowBody), animationSpeed ? (React.createElement("animate", { attributeName: "stroke-dashoffset", values: `${dashoffset * animationDirection};0`, dur: `${1 / animationSpeed}s`, repeatCount: "indefinite" })) : null), | ||
React.createElement("path", Object.assign({ d: `M 0 0 L ${fHeadSize} ${fHeadSize / 2} L 0 ${fHeadSize} L ${fHeadSize / 4} ${fHeadSize / 2} z`, fill: headColor, | ||
pointerEvents: "visibleStroke" }, passProps, arrowBody), animationSpeed ? (react_1.default.createElement("animate", { attributeName: "stroke-dashoffset", values: `${dashoffset * animationDirection};0`, dur: `${1 / animationSpeed}s`, repeatCount: "indefinite" })) : null), | ||
react_1.default.createElement("path", Object.assign({ d: `M 0 0 L ${fHeadSize} ${fHeadSize / 2} L 0 ${fHeadSize} L ${fHeadSize / 4} ${fHeadSize / 2} z`, fill: headColor, | ||
// pointerEvents="all" | ||
transform: `translate(${xOffsetHead},${yOffsetHead}) rotate(${st.headOrient})` }, props.passProps, arrowHead))), | ||
labelStart ? (React.createElement("div", { style: { | ||
transform: `translate(${xOffsetHead},${yOffsetHead}) rotate(${st.headOrient})` }, passProps, arrowHead))), | ||
labelStart ? (react_1.default.createElement("div", { style: { | ||
transform: st.dx < 0 ? "translate(-100% , -50%)" : "translate(-0% , -50%)", | ||
@@ -753,3 +588,3 @@ width: "max-content", | ||
} }, labelStart)) : null, | ||
labelMiddle ? (React.createElement("div", { style: { | ||
labelMiddle ? (react_1.default.createElement("div", { style: { | ||
display: "table", | ||
@@ -762,3 +597,3 @@ width: "max-content", | ||
} }, labelMiddle)) : null, | ||
labelEnd ? (React.createElement("div", { style: { | ||
labelEnd ? (react_1.default.createElement("div", { style: { | ||
transform: st.dx > 0 ? "translate(-100% , -50%)" : "translate(-0% , -50%)", | ||
@@ -771,2 +606,39 @@ width: "max-content", | ||
}; | ||
const pAnchorPositionType = prop_types_1.default.oneOf([ | ||
"middle", | ||
"left", | ||
"right", | ||
"top", | ||
"bottom", | ||
"auto", | ||
]); | ||
const pAnchorCustomPositionType = prop_types_1.default.shape({ | ||
position: pAnchorPositionType.isRequired, | ||
offset: prop_types_1.default.shape({ | ||
rightness: prop_types_1.default.number, | ||
bottomness: prop_types_1.default.number, | ||
}), | ||
}); | ||
const pAnchorType = prop_types_1.default.oneOfType([ | ||
pAnchorPositionType, | ||
pAnchorCustomPositionType, | ||
prop_types_1.default.arrayOf(prop_types_1.default.oneOfType([pAnchorPositionType, pAnchorCustomPositionType])), | ||
]); | ||
const pRefType = prop_types_1.default.oneOfType([prop_types_1.default.string, prop_types_1.default.object]); | ||
Xarrow.propTypes = { | ||
start: pRefType.isRequired, | ||
end: pRefType.isRequired, | ||
startAnchor: pAnchorType, | ||
endAnchor: pAnchorType, | ||
label: prop_types_1.default.oneOfType([prop_types_1.default.elementType, prop_types_1.default.object]), | ||
color: prop_types_1.default.string, | ||
lineColor: prop_types_1.default.string, | ||
headColor: prop_types_1.default.string, | ||
strokeWidth: prop_types_1.default.number, | ||
headSize: prop_types_1.default.number, | ||
path: prop_types_1.default.oneOf(["smooth", "grid", "straight"]), | ||
curveness: prop_types_1.default.number, | ||
dashness: prop_types_1.default.oneOfType([prop_types_1.default.bool, prop_types_1.default.object]), | ||
passProps: prop_types_1.default.object, | ||
}; | ||
Xarrow.defaultProps = { | ||
@@ -784,9 +656,9 @@ startAnchor: "auto", | ||
dashness: false, | ||
consoleWarning: false, | ||
passProps: {}, | ||
advanced: { extendSVGcanvas: 0, passProps: { arrowBody: {}, arrowHead: {}, SVGcanvas: {} } }, | ||
monitorDOMchanges: true, | ||
registerEvents: [], | ||
advanced: { | ||
extendSVGcanvas: 0, | ||
passProps: { arrowBody: {}, arrowHead: {}, SVGcanvas: {} }, | ||
}, | ||
}; | ||
export default Xarrow; | ||
exports.default = Xarrow; | ||
//# sourceMappingURL=index.js.map |
{ | ||
"name": "react-xarrows", | ||
"version": "1.4.4", | ||
"version": "1.5.0", | ||
"author": "Eliav Louski", | ||
@@ -30,3 +30,5 @@ "description": "Draw arrows (or lines) between components in React!", | ||
"dependencies": { | ||
"lodash": "^4.17.15" | ||
"lodash.isequal": "^4.5.0", | ||
"lodash.pick": "^4.4.0", | ||
"prop-types": "^15.7.2" | ||
}, | ||
@@ -38,2 +40,3 @@ "peerDependencies": { | ||
"@types/react": "^16.9.19", | ||
"react": "^16.12.0", | ||
"typescript": "^3.7.5" | ||
@@ -40,0 +43,0 @@ }, |
@@ -92,3 +92,2 @@ # react-xarrows | ||
dashness?: boolean | { strokeLen?: number; nonStrokeLen?: number; animation?: boolean | number }; | ||
consoleWarning?: boolean; | ||
passProps?: React.SVGProps<SVGPathElement>; | ||
@@ -103,4 +102,2 @@ advanced?: { | ||
}; | ||
monitorDOMchanges?: boolean; | ||
registerEvents?: registerEventsType[]; | ||
}; | ||
@@ -144,5 +141,5 @@ | ||
- `endAnchor="middle"` will choose anchor or the end of the line to in the middle of the element | ||
- `endAnchor="middle"` will set the anchor of the end of the line to the middle of the end element. | ||
- `endAnchor= { position: "auto", offset: { rightness: 20 } }` will choose automatic anchoring for end anchor but will offset it 20 pixels to the right after normal positioning. | ||
- `endAnchor= ["right", {position: "left", offset: {bottomness: -10}}]` only right and left anchors are allowed for endAnchor, and the left side will be offset 10 pixels up | ||
#### label | ||
@@ -214,6 +211,2 @@ | ||
#### consoleWarning | ||
we provide some nice warnings (and errors) whenever we detect issues. see 'Example3' at the examples codesandbox. | ||
#### advanced | ||
@@ -236,13 +229,2 @@ | ||
#### monitorDOMchanges | ||
A boolean. set this property to true to add relevant eventListeners to the DOM so the xarrow component will update anchors position whenever needed(scroll and resize and so on). (NOTE - maybe will removed in future updates ) | ||
examples: | ||
- `monitorDOMchanges={false}` will disable any DOM monitoring. | ||
#### registerEvents | ||
you can register the xarrow to DOM event as you please. each time a event that his registered will fire the xarrow component will update his position and will call `callback` (if provided). (NOTE - planned to be removed) | ||
### default props | ||
@@ -265,15 +247,8 @@ | ||
dashness: false, | ||
consoleWarning: false, | ||
passProps: {}, | ||
advanced: { extendSVGcanvas: 0, passProps: { arrowBody: {}, arrowHead: {}, SVGcanvas: {} } }, | ||
monitorDOMchanges: true, | ||
registerEvents: [], | ||
}; | ||
}; | ||
``` | ||
## Versions | ||
All version notes moved to [releases](https://github.com/Eliav2/react-xarrows/releases). | ||
1.4.0 - changed `label` property API and added `path` property. | ||
1.4.1-2 - minor bug fixes, performance improvement. | ||
See CHANGELOG.md in this repo. |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
11
71082
4
3
722
248
+ Addedlodash.isequal@^4.5.0
+ Addedlodash.pick@^4.4.0
+ Addedprop-types@^15.7.2
+ Addedjs-tokens@4.0.0(transitive)
+ Addedlodash.isequal@4.5.0(transitive)
+ Addedlodash.pick@4.4.0(transitive)
+ Addedloose-envify@1.4.0(transitive)
+ Addedobject-assign@4.1.1(transitive)
+ Addedprop-types@15.8.1(transitive)
+ Addedreact-is@16.13.1(transitive)
- Removedlodash@^4.17.15
- Removedlodash@4.17.21(transitive)