Bug (?) svg circle Hover

Hi all !
Seems that hover on svg element “circle” isn’t working (Mac, Ps 22.3.1)

According to this link, some svg behaviour can be uncanny:
https://www.adobe.io/photoshop/uxp/uxp/known-issues/

  • Not all SVG files are supported by UXP. UXP’s SVG renderer is targeted for simple icons and the like; complex SVGs may fail to render completely, or may render in unexpected ways. The SVG renderer will improve in the future.
    (…)
  • Many SVGs are known to render in odd ways in the UI. These issues will be addressed in the future, but we would love to hear your reports of any SVGs that don’t work, and how you fixed it.

Would someone be kind enought to test this?

Cheers!

HTML:

<svg width="100" height="100">
  <circle id="circle1" cx="15" cy="50" r="10" fill="red" />
  <circle id="circle2" cx="55" cy="50" r="10" fill="green" />
</svg>

CSS:

#circle1:hover {
  fill: blue;
}

JS:

document.getElementById('circle2')
  .addEventListener('click', function(e) {
  e.currentTarget.setAttribute('fill', 'magenta');
});

Expected behaviour:

  • the red circle when hover should turn blue
  • the green circle when clicked should turn magenta
1 Like

Hi,

I encountered the same issue.

My workaround was something like this:

<svg width="100" height="100" id="svgEl">
  <circle id="circle1" cx="15" cy="50" r="10" fill="red" />
</svg>
#svgEl:hover > #circle1 {
    fill: blue;
}

It seems only the hover of the outer svg element is registered.

I encountered the same issue, I partially bypassed the problem as tomzag, but there are cases where it is complicated to solve in this way.
hope this bug is fixed

@tomzag , @svumme , thank you guys !
Good to know that someone else pumped into this too.
Issues remains if you have several circle elements in the <svg> container: it’s not possible to have the hover respond to each circle individually… oh well… I’ll have to do without it then… Hoping this gets fixed somewhere down the line…
Cheers!

Hi @kerrishotts do you know this problem will be fixed? working with div does not solve the problem, the position displacements of a div element are not smooth, for example I had created a slider with divs and I cannot move the cursor with step = 1

div should be as positionable as the SVG elements – can you share the code you’re using so I can take look?

(cc @pkrishna for hover states on SVG elements)

@kerrishotts
this is the difference. (on the left the cursor is done with a div,
on the right the one I did with svg, note the saturation values). I also made a color wheel with two svg
cursor, but it wasn’t easy for me. Now I should create curves where I can add many points and it gets even more complicated.

https://youtu.be/xMyfvLkqfmk

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 divs. (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:

3 Likes

@kerrishotts thank you very much, I solved it! i put the div inside the svg and now it’s fluid.
forgive my ignorance i thought that inside svg the div would not listen to the events!!

1 Like

That’s a really cool demo!

@kerrishotts i noticed that SVGPathElement
it does not have the getPointAtLength () and getTotalLength () functions which would be useful for finding the coordinates of the generated curves. is it a bug? is there an alternative to find the Y coordinates of an X point?

UXP doesn’t provide these methods on SVG paths. (FYI @pkrishna – backlog request)

You might have good luck with the svg-path-properties node module though. Their minified js bundle seems to work OK inside UXP, once loaded as a script.

I don’t know about performance here, but logging to the console didn’t take any appreciable time, and looping over the entire length by one to generate an array of points took ~90ms for a the above path, so seems like it should be fine.

1 Like

@kerrishotts thanks you are very kind, I tried and it works very well !!!