You should definitely be able to get much better granularity than what you’re seeing here. It almost looks as if the event handler is maybe on the wrong element – the circle jumps when the mouse pointer is at the edge of the circle’s bounds – but when the circle is on the edge and the pointer is well outside the circle, the movement is much smoother.
Let’s look at the Bezier curve example I built ( uxp-photoshop-plugin-samples/ui-kitchen-sink/bezier.js at shotts/uxp-6.0 · AdobeDocs/uxp-photoshop-plugin-samples · GitHub).
The resulting DOM structure looks like this:
<div id="bezier1" style="position: relative; height: 500px; width: 500px; border: 1px solid white;">
<div class="cc-bezier-editor" style="width: 100%; position: absolute; height: 100%; top: 0px; right: 0px; bottom: 0px; left: 0px;">
<svg viewBox="0 0 498 498"><!-- SVG paths for both bezier curves --></svg>
<div class="cc-bezier-point" data-key="ep1" tabindex="0" style="top: 498px; left: 0px;"></div>
<div class="cc-bezier-point" data-key="cc1" tabindex="0" style="top: 49.8px; left: 49.8px;"></div>
<div class="cc-bezier-point" data-key="cc2" tabindex="0" style="top: 49.8px; left: 448.2px;"></div>
<div class="cc-bezier-point" data-key="ep2" tabindex="0" style="top: 0px; left: 498px;"></div>
</div>
</div>
Notes about the code:
First, .cc-bezier-editor
is the container that is listening for all mouse events. There’s no mouse handling for the .cc-bezier-point
directly – it’s all on the outer container. This container also contains both the SVG components & the div
s. (From your video, it looks like your event handler may not be on the right container – perhaps one level too deep, such that the control points are actually obscuring the mouse events from your handler)
Second, each control node is styled visually but only participates with mouse handling insofar as the data-key
attribute can tell the event handler which control node the user intends to modify.
Events are registered on the container, but there is some shared state that has to be managed to remember what the user is doing here (maybe less so for your color selector – the bezier editor has four control points, so… more complex logic here.)
pointerdown
is responsible for seeing if the user is starting a “drag” operation. If the event’s target is one of the .cc-bezier-point
elements, we can determine which node the user wants to interact with. We’ll store that node & the coordinates for future reference.
pointermove
handles the drag operation. Note that it’s going all the time, not just during a drag operation. It’s listening for the mouse update, and if no node was selected for edit (or if no buttons are down), it just bails. Only if we remember a node from pointerdown
will we continue. If that’s true – we compute the new position (because this is mapping to a bezier curve, the maths here is a little more complex) and update both the bezier curve & the control points with the new location information.
Note: we don’t pay attention to the event target any further while in pointermove
because we don’t want the user to switch control nodes when they get too close to another node. So we only check which node the user intends to edit on pointerdown
.
pointerup
just cleans up our internal state when the user releases the mouse button.
redraw
handles all the updates within the container – from updating the SVG path information to setting the new position for the control points. It gets called on every pointermove
.
The above will result in smooth movement for the control points, as seen in the following video: