thisbeyond / solid-dnd

A lightweight, performant, extensible drag and drop toolkit for Solid JS.
https://solid-dnd.com
MIT License
505 stars 35 forks source link

Draggable SVG shape moves faster than pointer #88

Closed stefanadelbert closed 1 year ago

stefanadelbert commented 1 year ago

When dragging a polygon drawn on an SVG canvas, it moves faster than the mouse pointer, apparently influenced by the size of the SVG viewBox (the smaller the viewBox, the "faster" the shape moves). It's as if the movement of the mouse pointer in screen pixels is being amplified by the "magnification" of the viewBox.

Here is an example of this behaviour, https://stackblitz.com/edit/github-q2jpqr?file=src%2Froutes%2Findex.tsx.

martinpengellyphillips commented 1 year ago

Interesting one. I haven't tried with svg before. I'll have a look, but I guess one thing would be to modify the transform by a scaling parameter? You can add custom transform modifiers on drag - see the custom transformer example.

stefanadelbert commented 1 year ago

Thanks for the tip. I'd thought about a transform, but was wondering if there was something else I was missing.

I have got the scaling working using a transform, in that I can see it counteracting the viewBox "magnification". I've added a scaled route to the example project at https://stackblitz.com/edit/github-q2jpqr which demonstrates this.

But the trick is going to be picking the right values for the X and Y scaling factors (which will be different from one another). Selecting those factors will depend on the size in pixels of the SVG canvas, i.e. there needs to be a translation from screen space to canvas space.

I'm such a novice, so any additional advice would be welcome.

stefanadelbert commented 1 year ago

I have managed to solve this by simply passing a ref to the SVG canvas to each draggable element. The draggable element can then query the SVG element clientWidth and -Height and use those to scale the transform. A shockingly simple solution! See the "Scaled Transform" page of the demo app at https://stackblitz.com/edit/github-q2jpqr.

I also got this working using a custom transformer which again scales the movement using a container width a height from a ref to the SVG canvas. See the "Scaled Trasformer" page of the demo app at https://stackblitz.com/edit/github-q2jpqr.

LostKobrakai commented 4 months ago

I ran into this as well. One can use svgEl.getScreenCTM() or svgChild.ownerSVGElement.getScreenCTM() or svgChild.getCTM() to get a transform matrix with all the necessary information to convert between screen pixels and the svg's coordinate system