react-xarrows
Advanced tools
Comparing version 1.4.1 to 1.4.2
113
lib/index.js
@@ -35,12 +35,12 @@ var __rest = (this && this.__rest) || function (s, e) { | ||
}; | ||
const findAllChildrens = (child, parent) => { | ||
const findAllChildren = (child, parent) => { | ||
if (child === parent) | ||
return []; | ||
let childrens = []; | ||
let children = []; | ||
let childParent = child.parentElement; | ||
while (childParent !== parent) { | ||
childrens.push(childParent); | ||
children.push(childParent); | ||
childParent = childParent.parentElement; | ||
} | ||
return childrens; | ||
return children; | ||
}; | ||
@@ -52,3 +52,3 @@ const getElementByPropGiven = (ref) => { | ||
if (myRef === null) | ||
throw Error(`'${ref}' is not an id of element in the dom. make sure you provided currect id or provide a React reference to element instead.`); | ||
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.`); | ||
} | ||
@@ -61,3 +61,3 @@ else | ||
you tried to render Xarrow before one of the anchors. | ||
please provide correct react refernce or provide id instead.`); | ||
please provide correct react reference or provide id instead.`); | ||
return myRef; | ||
@@ -81,4 +81,4 @@ }; | ||
const [prevProps, setPrevProps] = useState(null); | ||
const [anchorsParents, setAnchorsParents] = useState(null); //list childrens of the common ascestor of the arrow with start and end until start or end | ||
const [commonAncestor, setCommonAncestor] = useState(null); //list childrens of the common ascestor of the arrow with start and end until start or end | ||
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 | ||
const updateIfNeeded = () => { | ||
@@ -92,3 +92,5 @@ if (checkIfAnchorsRefsChanged()) { | ||
initProps(); | ||
setPrevPosState(getAnchorsPos()); | ||
let posState = getAnchorsPos(); | ||
setPrevPosState(posState); | ||
updatePosition(posState); | ||
} | ||
@@ -101,2 +103,3 @@ } | ||
setPrevPosState(posState); | ||
updatePosition(posState); | ||
} | ||
@@ -126,11 +129,11 @@ } | ||
}; | ||
const initParentsChildrens = () => { | ||
const initParentsChildren = () => { | ||
let anchorsCommonAncestor = findCommonAncestor(anchorsRefs.start, anchorsRefs.end); | ||
let allAncestor = findCommonAncestor(anchorsCommonAncestor, selfRef.current); | ||
let allAncestorChildrensStart = findAllChildrens(anchorsRefs.start, allAncestor); | ||
let allAncestorChildrensEnd = findAllChildrens(anchorsRefs.end, allAncestor); | ||
let allAncestorChildrenStart = findAllChildren(anchorsRefs.start, allAncestor); | ||
let allAncestorChildrenEnd = findAllChildren(anchorsRefs.end, allAncestor); | ||
setCommonAncestor(allAncestor); | ||
setAnchorsParents({ | ||
start: allAncestorChildrensStart, | ||
end: allAncestorChildrensEnd, | ||
start: allAncestorChildrenStart, | ||
end: allAncestorChildrenEnd, | ||
}); | ||
@@ -141,12 +144,12 @@ let allAncestorPosStyle = window.getComputedStyle(allAncestor).position; | ||
(allAncestor.scrollHeight > allAncestor.clientHeight || allAncestor.scrollWidth > allAncestor.clientWidth)) | ||
console.warn(`Xarrow warning: it is recomnded to set common ancestor positioning style to 'relative',this will prevent rerender on every scroll event. | ||
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 triggerd. | ||
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 ((allAncestorChildrensStart.length > 0 || allAncestorChildrensEnd.length > 0) && | ||
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([...allAncestorChildrensStart, ...allAncestorChildrensEnd], _.isEqual), `\nto disable this warnings set consoleWarning property to false`); | ||
on these elements`, _.uniqWith([...allAncestorChildrenStart, ...allAncestorChildrenEnd], _.isEqual), `\nto disable this warnings set consoleWarning property to false`); | ||
} | ||
@@ -239,3 +242,3 @@ }; | ||
useEffect(() => { | ||
// equilavent to componentDidMount | ||
// equivalent to componentDidMount | ||
// console.log("xarrow mounted"); | ||
@@ -251,5 +254,5 @@ initProps(); | ||
useEffect(() => { | ||
// Heppens only at mounting (or props changed) after anchorsRefs initialized | ||
// Happens only at mounting (or props changed) after anchorsRefs initialized | ||
if (anchorsRefs.start) { | ||
initParentsChildrens(); | ||
initParentsChildren(); | ||
} | ||
@@ -267,8 +270,7 @@ }, [anchorsRefs]); | ||
}, [anchorsParents]); | ||
// useEffect(() => { | ||
// // triggers position update when prevPosState changed(can happen in any render) | ||
// if (prevPosState) updatePosition(prevPosState); | ||
// }, [prevPosState]); | ||
useEffect(() => { | ||
// triggers position update when prevPosState changed(can heppen in any render) | ||
if (prevPosState) | ||
updatePosition(prevPosState); | ||
}, [prevPosState]); | ||
useEffect(() => { | ||
// console.log("xarrow rendered!"); | ||
@@ -371,3 +373,3 @@ updateIfNeeded(); | ||
const updatePosition = (positions) => { | ||
// Do NOT call thie function directly. | ||
// Do NOT call this function directly. | ||
// you should set position by 'setPrevPosState(posState)' and that will trigger | ||
@@ -393,3 +395,3 @@ // this function in the useEffect hook. | ||
let anchorChoice = Array.isArray(anchor) ? anchor : [anchor]; | ||
//now map each item in the list to relevent object | ||
//now map each item in the list to relevant object | ||
let anchorChoiceMapped = anchorChoice.map((anchorChoice) => { | ||
@@ -411,4 +413,4 @@ if (typeOf(anchorChoice) === "string") { | ||
}); | ||
//now build the object that represents the users possablities for diffrent anchors | ||
let anchorPossabilities = []; | ||
//now build the object that represents the users possibilities for different anchors | ||
let anchorPossibilities = []; | ||
if (anchorChoiceMapped.map((a) => a.position).includes("auto")) { | ||
@@ -420,3 +422,3 @@ let autoAnchor = anchorChoiceMapped.find((a) => a.position === "auto"); | ||
offset.bottomness += autoAnchor.offset.bottomness; | ||
anchorPossabilities.push({ position: anchor, offset }); | ||
anchorPossibilities.push({ position: anchor, offset }); | ||
}); | ||
@@ -429,7 +431,7 @@ } | ||
offset.bottomness += customAnchor.offset.bottomness; | ||
anchorPossabilities.push({ position: customAnchor.position, offset }); | ||
anchorPossibilities.push({ position: customAnchor.position, offset }); | ||
}); | ||
} | ||
// now preper this list of anchors to object expected by the `getShortestLine` function | ||
let points = anchorPossabilities.map((pos) => ({ | ||
// now prepare this list of anchors to object expected by the `getShortestLine` function | ||
let points = anchorPossibilities.map((pos) => ({ | ||
x: anchorPos.x + pos.offset.rightness, | ||
@@ -450,3 +452,3 @@ y: anchorPos.y + pos.offset.bottomness, | ||
const getShortestLine = (sPoints, ePoints) => { | ||
// closes tPair Of Points which feet to the specifed anchors | ||
// closes tPair Of Points which feet to the specified anchors | ||
let minDist = Infinity, d = Infinity; | ||
@@ -500,3 +502,3 @@ let closestPair; | ||
//////////////////////////////////// | ||
// arrow curveness and arrowhead placement calculations | ||
// arrow curviness and arrowhead placement calculations | ||
let xHeadOffset = 0; | ||
@@ -557,7 +559,7 @@ let yHeadOffset = 0; | ||
let cpx1 = x1, cpy1 = y1, cpx2 = x2, cpy2 = y2; | ||
let curvesPossabilties = {}; | ||
let curvesPossibilities = {}; | ||
if (path === "smooth") | ||
curvesPossabilties = { | ||
curvesPossibilities = { | ||
hh: () => { | ||
//horizinatl - from right to left or the opposite | ||
//horizontal - from right to left or the opposite | ||
cpx1 += absDx * cu * xSign; | ||
@@ -576,3 +578,3 @@ cpx2 -= absDx * cu * xSign; | ||
hv: () => { | ||
// start horizintaly then verticaly | ||
// start horizontally then vertically | ||
// from v side to h side | ||
@@ -583,3 +585,3 @@ cpx1 += absDx * cu * xSign; | ||
vh: () => { | ||
// start verticaly then horizintaly | ||
// start vertically then horizontally | ||
// from h side to v side | ||
@@ -591,3 +593,3 @@ cpy1 += absDy * cu * ySign; | ||
else if (path === "grid") { | ||
curvesPossabilties = { | ||
curvesPossibilities = { | ||
hh: () => { | ||
@@ -609,22 +611,22 @@ cpx1 += (absDx * 0.5 - headOffset / 2) * xSign; | ||
} | ||
let choosedCurveness = ""; | ||
let selectedCurviness = ""; | ||
if (["left", "right"].includes(startAnchor)) | ||
choosedCurveness += "h"; | ||
selectedCurviness += "h"; | ||
else if (["bottom", "top"].includes(startAnchor)) | ||
choosedCurveness += "v"; | ||
selectedCurviness += "v"; | ||
else if (startAnchor === "middle") | ||
choosedCurveness += "m"; | ||
selectedCurviness += "m"; | ||
if (["left", "right"].includes(endAnchor)) | ||
choosedCurveness += "h"; | ||
selectedCurviness += "h"; | ||
else if (["bottom", "top"].includes(endAnchor)) | ||
choosedCurveness += "v"; | ||
selectedCurviness += "v"; | ||
else if (endAnchor === "middle") | ||
choosedCurveness += "m"; | ||
selectedCurviness += "m"; | ||
if (absDx > absDy) | ||
choosedCurveness = choosedCurveness.replace(/m/g, "h"); | ||
selectedCurviness = selectedCurviness.replace(/m/g, "h"); | ||
else | ||
choosedCurveness = choosedCurveness.replace(/m/g, "v"); | ||
curvesPossabilties[choosedCurveness](); | ||
selectedCurviness = selectedCurviness.replace(/m/g, "v"); | ||
curvesPossibilities[selectedCurviness](); | ||
//////////////////////////////////// | ||
// Buzier curve calcualtions | ||
// Buzier curve calculations | ||
// bzCurve function: bz = (1−t)^3*p1 + 3(1−t)^2*t*p2 +3(1−t)*t^2*p3 + t^3*p4 | ||
@@ -729,2 +731,3 @@ // dt(bz) = -3 p1 (1 - t)^2 + 3 p2 (1 - t)^2 - 6 p2 (1 - t) t + 6 p3 (1 - t) t - 3 p3 t^2 + 3 p4 t^2 | ||
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" } }, | ||
@@ -741,3 +744,5 @@ React.createElement("svg", Object.assign({ ref: selfRef, width: st.cw, height: st.ch, style: { | ||
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, style: { pointerEvents: "all" }, transform: `translate(${xOffsetHead},${yOffsetHead}) rotate(${st.headOrient})` }, props.passProps, arrowHead))), | ||
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="all" | ||
transform: `translate(${xOffsetHead},${yOffsetHead}) rotate(${st.headOrient})` }, props.passProps, arrowHead))), | ||
labelStart ? (React.createElement("div", { style: { | ||
@@ -744,0 +749,0 @@ transform: st.dx < 0 ? "translate(-100% , -50%)" : "translate(-0% , -50%)", |
{ | ||
"name": "react-xarrows", | ||
"version": "1.4.1", | ||
"version": "1.4.2", | ||
"author": "Eliav Louski", | ||
@@ -5,0 +5,0 @@ "description": "Draw arrows (or lines) between components in React!", |
@@ -7,5 +7,5 @@ # react-xarrows | ||
This library is all about customizable and relaible arrows(or lines) between DOM elements in React. | ||
This library is all about customizable and reliable arrows(or lines) between DOM elements in React. | ||
I've needed such a components in one of my projects - and found out(surprisingly enough) that there is no such(good) lib, so I've decided to create one from scrate, and share it. | ||
I've needed such a components in one of my projects - and found out(surprisingly enough) that there is no such(good) lib, so I've decided to create one from scratch, and share it. | ||
@@ -20,22 +20,2 @@ now (since v1.1.4) i can say, after a lot of tests and improvements- the arrows should work and act naturally under any normal circumstances(but don't try put some negative curveness ha?). | ||
#### what to expect | ||
- this arrows will rerender and will update the arrows position whenever needed(not like other similar npm libraries). | ||
- works no matter where the Xarrow component placed in the DOM relative to his anchors. | ||
- works no matter what the type of elemnts the anchors are (like div,p, h1, and so on). | ||
- nice intellij suggestinons will apear when working with Xarrow. | ||
- nice errors and warnings. | ||
- works inside scrollable windows(no matter how many - or even if any anchor element inside diffrent nested scrolling windows). | ||
- you can give this component simple props or more detailed ones for more custom behavior and looking. | ||
- please see the examples below to understand better the using and features. | ||
#### what to NOT expect | ||
- keep in mind that this is React component ,so you should adopt React best practices. | ||
1. place the Xarrow under the relevent ancestor(of 'start' and 'end' element), so when the anchors elements rerenders so do Xarrow(in simple cases the component will rerender anyway because of DOM listerns i've added,but keep in mind),however, in most cases it will work normally anyway. | ||
2. it is recommended to provide react refs over Id's. it is more consitent, reliable, and this is the recommended way providing refs to DOM elements in React(over Id's which uses getElementById under the hood),by if you choose to stick with id's make sure you rendering xarrow after you render his anchors. | ||
- if your component uses 3rd components that uses animations and transformations that changes the anchors DOM positions - the xarrow will not rerender to the latest animated points, but to the firstest. you need to trigger update after all animations ended(this is not something i can monitor - so its up to you). | ||
## installation | ||
@@ -87,5 +67,5 @@ | ||
### types defenitions | ||
### types definitions | ||
the properties the xarrow component recieves is as follow: | ||
the properties the xarrow component receives is as follow: | ||
@@ -140,3 +120,3 @@ ```jsx | ||
you can keep things simple or provide more detailed props for more custom behavior - the API except both. | ||
for example - you can provide `label:"middleLable"` and the string will apear as middle label or customize the labels as you please: `label:{end:{text:"end",extra:{fill:"red",dx:-10}}}`. | ||
for example - you can provide `label:"middleLabel"` and the string will appear as middle label or customize the labels as you please: `label:{end:{text:"end",extra:{fill:"red",dx:-10}}}`. | ||
see typescript types above for detailed descriptions of what type excepts every prop. | ||
@@ -152,3 +132,3 @@ | ||
`auto` will choose automatically the path with the smallest length. | ||
can also be a list of possible anchors. if list is provided - the minimal length anchors will be choosed from the list. | ||
can also be a list of possible anchors. if list is provided - the minimal length anchors will be choose from the list. | ||
you can also offset each anchor passing `offset`. | ||
@@ -164,3 +144,3 @@ examples: | ||
can be a string that will default to be at the middle or an object that decribes where to place label and how to customize it. see `label` at `xarrowPropsType` above. | ||
can be a string that will default to be at the middle or an object that describes where to place label and how to customize it. see `label` at `xarrowPropsType` above. | ||
examples: | ||
@@ -170,7 +150,7 @@ | ||
- `label=<div style={{ fontSize: "1.3em", fontFamily: "fantasy", fontStyle: "italic" }}>styled middle label</div>` | ||
- `label={{ start:"I'm start label",middle: "middleLable",end:<div style={{ fontSize: "1.3em", fontFamily: "fantasy", fontStyle: "italic" }}>big end label</div> }}` | ||
- `label={{ start:"I'm start label",middle: "middleLabel",end:<div style={{ fontSize: "1.3em", fontFamily: "fantasy", fontStyle: "italic" }}>big end label</div> }}` | ||
#### color,lineColor and headColor | ||
color defines color for all the arrow include head. if lineColor or headColor is given so it overides color specificaly for line or head. | ||
color defines color for all the arrow include head. if lineColor or headColor is given so it overrides color specifically for line or head. | ||
examples: | ||
@@ -195,3 +175,3 @@ | ||
`path` can be one of: `"smooth" | "grid" | "straight"`, and it controls the path arrow is drawn, exactly how thier name suggest. | ||
`path` can be one of: `"smooth" | "grid" | "straight"`, and it controls the path arrow is drawn, exactly how their name suggest. | ||
examples: | ||
@@ -201,3 +181,3 @@ | ||
#### curvness | ||
#### curveness | ||
@@ -207,5 +187,5 @@ defines how much the lines curve. | ||
- `curvness={false}` will make the line stright without curves(exacly like path='straight'). | ||
- `curvness={true}` will choose defualt values of curvness. | ||
- `curvness={2}` will make Xarrow extra curved. | ||
- `curveness={false}` will make the line straight without curves(exactly like path='straight'). | ||
- `curveness={true}` will choose default values of curveness. | ||
- `curveness={2}` will make Xarrow extra curved. | ||
@@ -215,3 +195,3 @@ #### dashness | ||
can make the arrow dashed and can even animate. | ||
if true default values(for dashness) are choosed. if object is passed then default values are choosed execpt what passed. | ||
if true default values(for dashness) are choose. if object is passed then default values are choose except what passed. | ||
examples: | ||
@@ -242,3 +222,3 @@ | ||
will extend the svg canvas at all sides. can be usefull if for some reason the arrow(or labels) is cutted though to small svg canvas(should be used in advanced custom arrows, for example if you used `dx` to move one of the labels and at exceeded the canvas). | ||
will extend the svg canvas at all sides. can be useful if for some reason the arrow(or labels) is cut though to small svg canvas(should be used in advanced custom arrows, for example if you used `dx` to move one of the labels and at exceeded the canvas). | ||
example: `advanced= {{extendSVGcanvas: 30 }}` - will extended svg canvas in all sides by 30 pixels. | ||
@@ -248,4 +228,4 @@ | ||
if you wish you can pass props specipically to either the body of the arrow,or his head,or even the svg canvas which contains both of them. | ||
note that `arrowBody` and `arrowHead` recives props of svg path element and `SVGcanvas` recives props of svg element. | ||
if you wish you can pass props specifically to either the body of the arrow,or his head,or even the svg canvas which contains both of them. | ||
note that `arrowBody` and `arrowHead` receives props of svg path element and `SVGcanvas` receives props of svg element. | ||
examples: | ||
@@ -264,7 +244,7 @@ | ||
you can register the xarrow to DOM event as you please. each time a event that his registed will fire the xarrow component will update his position and will call `callback` (if provided). (NOTE - planned to be removed) | ||
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 | ||
default props is as folows: | ||
default props is as follows: | ||
@@ -297,1 +277,2 @@ ```jsx | ||
1.4.0 - changed `label` property API and added `path` property. | ||
1.4.1-2 - minor bug fixes, performance improvement. |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
823
79072
264