anseki / leader-line

Draw a leader line in your web page.
http://anseki.github.io/leader-line/
MIT License
2.99k stars 416 forks source link

Add lines to particular div instead of window itself #54

Closed manojdcoder closed 5 years ago

manojdcoder commented 5 years ago

Is it possible to configure the parent container (which is window by default)? Only portions of my screen is scrollable, so the arrows overlap with main content when the start / end point is scrolled behind the main content.

Thanks for the wonderful library!

anseki commented 5 years ago

Hi @manojdcoder, thank you for your comment.

The lines are added to <body> element, not window. 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.

Could you explain your case (e.g. with image)? Then, I might be able to help you.

Or, you can move the element to another element from <body> if you really want it. However it is not supported.

manojdcoder commented 5 years ago

Thanks for the quick response @anseki

I have a tab based application, the tabs are fixed at top - Screenshot 01

The content inside tab will be scrollable, so while scrolling the lines are shown above tab headers & menu as it's drawn on document - Screenshot 02

Any thoughts how this issue can be resolved?

anseki commented 5 years ago

The most easy way to solve the issue is the using <iframe> element for the scrollable area. The <iframe> element has own document, therefore the lines are added to the document of <iframe> element.

manojdcoder commented 5 years ago

The application is huge and built using ExtJS, I doubt about separating this one tab content & all it's functionality into separate application (then only I may able to load it into iframe).

Is there any other solution? How hard it will be to move the lines from body to particular div, I tried it once but it completely broke the positioning.

anseki commented 5 years ago

I see. You can move the SVG element to another element from <body> if you really want it. For example:

document.getElementById('container').appendChild(document.querySelector('.leader-line'));

Note that it is not supported.

manojdcoder commented 5 years ago

@anseki Doing so collapses the layout, I see you have already mentioned it's not supported.

Do you have an estimate to implement the support for setting custom parent element while creating line, we can work it out if that's within my budget.

anseki commented 5 years ago

As I said, that option that changes the structure makes many problems. Why you can work it out? That is, what's different about the appendChild method and the option that changes container element?

manojdcoder commented 5 years ago

Using appendChild doesn't position the lines properly.

manojdcoder commented 5 years ago

It turns out the lines were not positioned properly because my container element has a fixed space left at top for headers / menu bar. If I remove that, the line is positioned properly. May be I will have to adjust the SVG's top position accordingly once it's rendered.

anseki commented 5 years ago

Sorry, my English is poor. I mean, what's different about the using appendChild method and the option to change container element? I couldn't understand why you can solve the issue by the option and not using appendChild method.

manojdcoder commented 5 years ago

Yes, I can solve it with appendChild.

But the only problem is that the top position of the SVG element is incorrect, that is because the container element has a fixed space left at the top, something like (top: 140px). If I reduce this space from SVG's top position, then it looks good.

anseki commented 5 years ago

Why the position problem is solved by the option? That is, what's different about the appendChild method and the option that changes container element?

anseki commented 5 years ago

You said that the issue is solved by the option but I don't think so because the position issue is caused by your style definitions. To avoid being affected by something (e.g. your style definitions), the lines should be positioned based on document. (See https://github.com/anseki/leader-line/issues/54#issuecomment-498088482) In other words, if you understand your page (or app) (e.g. style definitions) and you can adjust those (e.g. position) as necessary, you can move the lines to another element that you want. That is, if you can't adjust that, you should not move the lines regardless of the ways (using appendChild method or the option to change the container). The results are the same.

Another way, you can use clip (mask) if you understand SVG. For example: https://jsfiddle.net/heuj7mso/

manojdcoder commented 5 years ago

I get your point, thanks for the fiddle. I will debug further with these inputs and update here.

anseki commented 5 years ago

Do you mean that the example did not work? Please tell me that problem, then I will find the bug which makes the problem, and I debug that.

manojdcoder commented 5 years ago

Sorry I meant that example seems nice and might work. I will give it a go, in case if it fails, I will write a sample fiddle for you to take a look at the issue.

anseki commented 5 years ago

I see. I hope that the example helps you. :smile:

manojdcoder commented 5 years ago

If it's not too much, may I ask you to update the example with multiple lines, at least with two. There should be one clip path for each line?

anseki commented 5 years ago

Are there multiple lines in one scrollable frame?

manojdcoder commented 5 years ago

Yes, it's like a flow diagram so there will be multiple lines connecting multiple points within the scrollable frame.

anseki commented 5 years ago

A shape of the clip can be shared if there is one scrollable frame. And reference is required to separate the position of each line. https://jsfiddle.net/z5qw7a91/ Also, this example doesn't use Screen-CTM.

anseki commented 5 years ago

FYI, this is an example for the appendChild method that I suggested before. https://jsfiddle.net/op2gnk0t/

manojdcoder commented 5 years ago

appendChild seems to be the perfect solution except when I the start / end element is moved post creation of the line and line.position() is called.

In my application, user will be able to drag and move the start / end elements anywhere within the scrollable region. As per docs, I used line.position() but that doesn't seem to work as expected.

In order to demonstrate the issue, I have updated the fiddle - https://jsfiddle.net/cvyu0e42/

Thank you for your continuous support and patience!

anseki commented 5 years ago

Unfortunately your code didn't work. Maybe you wanted to move the element to top: 55px after 1 second, right? You have to specify '55px' (not 55) for style.top property. https://jsfiddle.net/9d3hoyfL/

manojdcoder commented 5 years ago

It was not only top, but also scrollTo. line.position() doesn't position properly when the document is scrolled.

https://jsfiddle.net/bnszo96r/

anseki commented 5 years ago

The position method worked correctly. You should solve that when you understand why the wrapper is required. (See: https://github.com/anseki/leader-line/issues/54#issuecomment-498088482)

The example code does not consider that the position is changed. You have to only update the position of the wrapper also when the position of the line is updated. https://jsfiddle.net/1Lanrmct/ (The style.top is not required because it is moved by wrapper only.)

Note that this fixPosition function updates the transform property twice per every calling. If you want performance for your app, you'd better save current position to check new position.

manojdcoder commented 5 years ago

Thanks, updating the position of wrapper solved the issue.

anseki commented 5 years ago

I'm glad if I could help you. :smile: FYI, this is an example for considering performance that I said. https://jsfiddle.net/d8ehp1qz/

manojdcoder commented 5 years ago

@anseki I'm applying some scale on the parent div to simulate zoom in / out in which case I'm unable to apply the right transformation on the wrapper div. I have tried several options so far, nothing worked out. Do you have any thoughts?

https://jsfiddle.net/goasn5tq/

anseki commented 5 years ago

That is very simple. Maybe you are misunderstanding the transform. That affects an element's appearance, and that never changes the element itself. See: https://developer.mozilla.org/en-US/docs/Web/CSS/transform-function

Therefore, the element's moving also be affected. For example, when you specify transform: scale(1.5), an element that was moved 10 pixels is shown as moving 15 pixels in the screen. If you want to move the element 10 pixels in the screen (i.e. scaled distance), you have to specify 10 / 1.5 pixels. Or you can move that before it is scaled.

anseki commented 5 years ago

For example: https://jsfiddle.net/quLx6p37/

anseki commented 5 years ago

No reply came. :cry: However that should have already solved.

manojdcoder commented 5 years ago

Sorry, I couldn't get back sooner as I was given other priority items.

I really appreciate your support here, the above solution works but it's very laggy did not exactly suit my requirements.

User will be able to drag and move the start and end elements on the screen, when they do the position should be recalculated. The given solution requires resetting transform every time which makes the UI very slow and the line path is not accurate sometimes.

Is there any other workaround you could think of which may not require resetting transform (zoom) on parent element?

anseki commented 5 years ago

Yes, of course the resetting the transform is not required as I said.

manojdcoder commented 5 years ago

Sorry, I tried that already (commented the code for resetting transform on frame) but lines seems not positioned properly.

https://jsfiddle.net/x9whqteo/

anseki commented 5 years ago

Of course the lines are not positioned properly if you comment out the code because the second way was designed for positioning without scaling. Maybe you are misunderstanding the two ways I indicated. See again: https://github.com/anseki/leader-line/issues/54#issuecomment-504363557

anseki commented 5 years ago

BTW, perhaps, did you call the fixPosition function frequently when the user drags an element? If so, is that really required? That is laggy naturally if you call the fixPosition function wastefully.

manojdcoder commented 5 years ago

I will try to apply the math (distance / scale). And yes I have to call fixPosition as long user drags the start / end point in order to keep the line moving along.

anseki commented 5 years ago

I don't know why you call the fixPosition function when the user drags an element, anyway that should be solved if you remove the resetting the transform.

manojdcoder commented 5 years ago

As I already mentioned, the lines should move along with the start / end point as user drag it, so I have to call fixPosition on every move to make the lines follow the moving points.

It may take a while for me to work on this transform, I will update you once I do. Thanks for the support.

anseki commented 5 years ago

I mean, I don't know why you call the fixPosition function that fixes the wrapper and resets the transform. I don't know whether that is required for the dragging or not. Anyway that has no problem maybe even if that is called because that is replaced for the scaling.

logicalravii commented 5 years ago

hello @anseki and @manojdcoder i was also facing the same issue of scrolling and i have solved it using appendTo method of jquery, i know whenever we use this method line position collapsed from original position but when i have used svg.leader-line { position: fixed },
it solved my issue, may be it can help anyone using that library, and i also want to thank @anseki for that library.

anseki commented 5 years ago

Hi @logicalravii, thank you for your comment. Do you mean that a problem was solved by adding that CSS declaration to the example? And what is the problem in your case? That is, is there a problem in the example? In other words, do you mean that this issue is not solved by the solution I proposed? If so, could you show me an example in https://jsfiddle.net/ ?

manojdcoder commented 5 years ago

@anseki I was able to solve the improper positioning when a scale is applied on parent div, with the solution you had pointed out.

Yet, I'm back with another issue due to this approach - appending SVG to specific div. Unless .remove() is called, there is disconnected element exception thrown upon resizing window. If I do call remove, then there it throws exception too as the SVG is moved to a div but the remove method tries to remove it from document. Since the variable (insProps) that holds the active lines are encapsulated, it seems impossible to handle this situation without editing the library itself - may be use,

props.svg.parentNde.removeChild(props.svg);

instead of

props.baseWindow.document.body.removeChild(props.svg);

Do you have any other suggestion?

anseki commented 5 years ago

Hi @manojdcoder,

So, your code doesn't work. What is props? Also parentNde. Could you show me an example in https://jsfiddle.net/ ?

logicalravii commented 5 years ago

@anseki sorry for late response, The issue was whenever we place lines inside the particular div, the position of lines collapse and set on random location. And when changed the css of lines as I have described above, it fixed now lines stick to where they should be, and I can't replicate it on jsfiddle because of the complexity, thanks.

anseki commented 5 years ago

Hi @logicalravii, thank you for the reply. I don't recommend your solution using CSS because that should make other problems. I recommend the solution I proposed.

manojdcoder commented 5 years ago

@anseki I was referring to this line of code.

https://jsfiddle.net/57qbu2ag/

anseki commented 5 years ago

Do you mean that the parentNde is written in the source code?

manojdcoder commented 5 years ago

Yes, remove() method tries to remove the line from document but we removed from document and inserted it into a div to solve the other issue. I may want to remove one specific line form a number of lines drawn on interface. So appending the line before remove may not work as there is no way to select identify SVG of specific line.