Closed Martin-N closed 6 years ago
Hi @Martin-N, thank you for the comment.
Sorry, my English is poor. Do you mean that you want to append a leader line to a scrollable element to make it follow scrolling that element?
Hi @anseki
Yes, and so that the line is not visible outside it's container. See attached pic. The line should not be visible outside the orange block.
If I move the SVG element inside this container manually and give it a z-index, then it displays correctly as in it doesn't appear outside it's container and it scrolls with the content, but then it's position is off.
I see.
To allow definite lines drawing and positioning accurately, those should be positioned based on document. And those should avoid being affected by other elements or something.
The option that changes the structure makes many problems.
I think that is special case that a part of the line should be hidden.
So, use a mask or move the SVG element as you said, in your case.
Also, use position
method to follow to scrolling.
No reply came, and I close this issue.
Hi @anseki,
I'm currently working on a project where this feature could be very useful. Do you have any idea about modifying your code so that a div could be specified as base document where the whole svg stuff is added?
Hi @sarnold04, thank you for the comment. SVGs are now added to the document but you can move those. Note that the moving is not supported because those should avoid being affected by other elements or something.
Hi @anseki,
thanks for your quick response. I will move them after the lines have been added.
:smile:
Hi @anseki, in order for us to move the element manually, is it possible that you please expose an accessor to insProps[].svg? Then we could move the element cleanly, without having to search for it in the DOM.
Hi @b4nt0, thank you for the comment. The moving the element is not supported because that should avoid being affected by other elements or something. Therefore you can move the element by yourself (i.e. hacky method) only if you understand those and the structure of the DOM.
Hi @anseki, thank you for the explanation! I think the "hacky method" will not work well, since there's no reliable way to recognize the SVG. In order to avoid positioning and overlap issues, another method could probably work, such as clipping. This needs exposure of the SVG too though. What are you thoughts on this?
@b4nt0,
Sorry, my English is poor.
Do you mean that the querySelector
method could not get the SVG element?
Could you explain about your code?
Also, what do you want to do with the element? e.g. masking
@anseki your English is excellent :) What I mean is that the
Regarding my code to handle it - the code does not exist yet. I thought of clipping.
The querySelector
method can get a certain SVG element that was added last time.
However, that is hacky method as I said.
The easy way that is not hacky method to clip the line is the adding another window in current document (i.e. iframe
).
Since LeaderLine supports multiple windows, you can clip the line by adding the line to separated iframe
.
The svg elements are attached to the dom root node (e.g body), but in this example there is a scrolling element that isn't the body - it's a div with overflow deeper in the dom tree. Scrolling this pane doesn't reflect the position of the svg elements, as noted in this issue and others.
What is your recommended course of action for this problem, if any?
Hi @frumbert, thank you for the comment. This example may help you. https://github.com/anseki/leader-line/issues/54#issuecomment-500712640
I've taken steps to move the node into the scrolling element so that the overflow will crop/hide the svg lines as required. I've then used the negative transform you suggest (or negative margin which also works though less performant via repaints) to reposition the elements.
// 'scrollable' is my overflowing element; scrollableBbox is its bounding client rect
Array.from(document.querySelectorAll(".leader-line")).forEach(function(elem) {
elem.style.transform = "translate(-" + (scrollable.scrollTop + scrollableBbox.x) + "px, -" + scrollableBbox.y + "px)";
scrollable.appendChild(elem);
});
This is ok until you scroll at which point the setting line.position() repositions the top
style property without taking into account the scrollTop; and similar for the left
property.
I'm using PlainDraggable to move the nodes.
// 'end' is the draggable node
const draggable = new PlainDraggable(end, {
onMove: function () { line.position(); },
onMoveStart: function () { line.dash = { animation: true }; },
onDragEnd: function () { line.dash = false; },
autoScroll: end.closest(".overflow")
});
inside onMove
I have a reference to line
but it does't seem to have any exposed property referring to the <svg class='line-leader' ...
DOM element which the line is drawn by, which I would need in order to set the transform property again to take into account the scroll offset myself. Can I infer which <svg>
element a line
belongs to - or is it just nth-child?
Is there a reason the position()
method doesn't (or can't be made to) accept scrollTop / scrollLeft
when calculating the top
and left
style properties during its update?
I am currently keeping an array of the line objects and iterating obect and hoping they match the order of the svg
elements I moved into the scrollable node area. This seems pretty jank and breaks more places than it works, and means I'm reapply the transform
property ever time the AnimEvent/scroll event triggers, rather than just when the draggable node moves.
I could move the transform calculation back to the onMove function but then I still don't have a reference to the equivalent underlying svg
DOM element, and it doesn't really work anyway, for example
// 'index' is a number representing the draggable node in the loop that is being created
onMove: function () {
line.position();
const probableSvg = scrollable.querySelectorAll("svg.leader-line")[index];
const cs = getComputedStyle(probableSvg);
probableSvg.style.top = parseFloat(cs.top) + scrollable.scrollTop;
probableSvg.style.left = parseFloat(cs.left) + scrollableBbox.scrollLeft;
},
Hi @frumbert. Sorry, my English is poor. Do you mean that the example didn't help you? Could you show me your example by using e.g. https://jsfiddle.net/ ?
Attaching the leader line to a child object and then scrolling the object doesn't take into account the scrolling offset when calling line.position()
.
https://jsfiddle.net/frumbert/Lhpvmw7d/10/
How can I get the position()
method to respect the scrolling offset of the wrapper when it recalculates?
You don't need the position()
method that respects the scrolling offset because you already did that by using the wrapper. That is, you only have to fix the position of the wrapper.
And also, it seems that you misunderstood autoScroll
option.
https://jsfiddle.net/to5b4srx/
Yes this example is much clearer, and I can see my mistakes now. I was worried on the performace of calling getBoundingClientRect so frequently (e.g. every time onMove fires) but if I cache it or use AnimEvent the tracking position breaks - so I guess I'll have to live with it. Thanks for your assistance!
I'm glad if I could help you. :smile:
If you consider the performance, you can call the wrapperPosition()
only once only when that was scrolled.
Foe example:
https://jsfiddle.net/zqhv32a1/
Hmm, i thought I knew what my problem was until I put leader line into my box which has scrolling. The page itself never scrolls but a box within it does, so in the wrapperPosition function I offset by the scroll position of the overflowing container. Scrolling also updates the position of the wrapper.
I made a complete fiddle using all my current [unfinished] source, rather than a quick cut down example. Code needs a cleanup. https://jsfiddle.net/frumbert/m5acL241/2/
The steps to reproduce the issue I am seeing are:
The position of the last leader line is now incorrect but the other leader lines still appear in the correct positions.
Here is an animation showing what I see:
Hi @frumbert, did you read my comment?
Yes, I read your comment and your code and based my reply on it, as you can see by me adopting your code into my example. Thanks for taking the time.
Since posting my problem, I've gone back to the drawing board since leader-line obviously can't work properly when the svgs are appended somewhere other than the root - there are too many issues relating to scrolling. Perhaps you could mention in your documentation that moving the svgs from the body into an overflowing object isn't reccomended? It would save a lot of fiddling about.
I've re-engineered my example page so that there isn't a scrolling container and rather let the body element be the scrolling container - as you probably intended.
https://jsfiddle.net/frumbert/dL96gta5/3/ is effectively working as intended (nearly).
I think your first mistake is that you misunderstood getBoundingClientRect
method. Then you miscalculated the position.
Your second mistake is that you overlooked my comment that I said that I never recommend moving SVG elements because that is not supported.
It is better for you to use another library that you like because it seems that you don't need LeaderLine.
Hi @anseki, When I tried to vertical scroll the Links are going out of bound, I have tried with following
var elmSvgClip = document.getElementsByClassName('leader-line'), elmClipRect = document.getElementById('leader-line-46-mask-bg-rect'), posPoint = elmSvgClip.createSVGPoint();
But i'm getting elmSvgClip.createSVGPoint() is not a function error and weird behaviour of link. I have attached the screenshot of links for your reference, Can you help how we can fix this, By the way I'm creating the links dynamically..!
Hi @Mahesh9959-mahi, thank you for the comment. Try this:
console.log(elmSvgClip);
Maybe, elmSvgClip
is undefined
.
Ah, it is HTMLCollection
maybe.
Try the elmSvgClip[0]
instead.
while scrolling controller is not hitting the upadate()
Unfortunately your code didn't work. It seems that the code that you indicated is a part of code. To reproduce that, could you show me an example by using e.g. https://jsfiddle.net/ ?
https://jsfiddle.net/heuj7mso/ I have same issue what ever they discribed, But in my case AnimEvent getting not defined error and controller not hitting elmLine.style.clipPath = 'url(#clip)'; line
Hi @anseki,
Is there any way to change the lines from body to specific div, It's targeting the body that's why it's overlapping headers as well
You can do that, but it seems that you already did that. This is your code:
elemWrapper.appendChild(document.querySelector('body>.leader-line:last-of-type'))
These also may help you: https://github.com/anseki/leader-line/issues/25 https://github.com/anseki/leader-line/issues/54
Why AnimEvent is giving undefined, I have added as well
To reproduce that, could you show me an example by using e.g. https://jsfiddle.net/ ?
let rect_l=$('.note_page_div').offset().left; let rect_t=$('.note_page_div').offset().top; let rect_b=($('.note_page_div').offset().top+$('.note_page_div').height()+$('.note_page_div').scrollTop())+'px'; let rect_r=($('.note_page_div').offset().left+$('.note_page_div').width()+$('.note_page_div').scrollLeft())+'px'; for(let line of lines){ line.position(); } $('.leader-line').each(function(){ let svg_t=(rect_t-$(this).offset().top)+'px'; let svg_l=(rect_l-$(this).offset().left)+'px'; $(this)[0].style.clip='rect('+svg_t+','+rect_r+','+rect_b+','+svg_l+')' }) $('.leader-line-areaAnchor').each(function(){ let svg_t=(rect_t-$(this).offset().top)+'px'; let svg_l=(rect_l-$(this).offset().left)+'px'; $(this)[0].style.clip='rect('+svg_t+','+rect_r+','+rect_b+','+svg_l+')' })
Hi @whxleemdddd, thank you for the comment. What is that?
I created a leaderline class extension please check this https://github.com/AhmedAyachi/LeaderLine
Hi @AhmedAyachi, thank you for the comment. Unfortunately, many tests failed, However, your special library might be useful for your app. :smile:
There is no option to specify where to append the line SVG. It would be good to be able to specify a specific element / viewport to append the SVG.
This would fix the issue if you draw the lines inside a scrollable element. Currently if it is inside a scrollable element we have to run the position method while scrolling which isn't very performant and the line is drawn on top which makes it able to go outside the element instead of disappearing underneath while it is scrolled.