panel: custom ReactiveHTML unable to render and process MouseEvent correctly

panel version 1.1.1 - Cytoscape.js ver. 3.25.0 rendered using ReactiveHTML, MacOS12.1, Safari 15.2

When using Panel v0.14.1, the component rendered correctly. Mouse clicks were functional and on target. When using Panel v1.1.1, the component can only render on certain layouts and mouse click did not work until manually resize the window. However, when the window scrolled away from original position, the mouse clicks were off target (usually by the same amount of pixels from the original position.

Complete, minimal, self-contained example code that reproduces the issue

from json.tool import main
import param
import panel as pn
from panel.reactive import ReactiveHTML

layouts = {'cose': {'name': 'cose'},
    'grid': {'name': 'grid'},
    'circle': {'name': 'circle'},
    'concentric': {'name': 'concentric'},
    'breadthfirst': {'name': 'breadthfirst'},
    'random': {'name': 'random'},
    'preset': {'name': 'preset'}
}

class Cytoscape(ReactiveHTML):
    layout_names = param.ObjectSelector(default='cose', doc="Layout Options to choose from.", objects=list(layouts.keys()))
    graph_layouts = param.Dict(default=layouts)
    style = param.List(doc="Use to set the styles of the nodes/edges")
    data = param.List(doc="Use to send node's data/attributes to Cytoscape")

    _template = """
        <div id="cy" style="width: 100%; height: 100%; position: relative; border: 1px solid"></div>
    """
    __javascript__ = ['assets/cytoscape.min.js']

    _scripts = {
        'render': """
            state.cy = cytoscape({
              container: cy,
              layout: {name: 'cose'}, //these layout will fail: grid, circle, concentric
              elements: [{data:{id:'A', label:'A'}},{data:{id:'B', label:'B'}}, {data:{source:'A', target:'B'}}],
              zoom: 1,
              pan: {x: 0, y: 0},
            });
            state.cy.on('click', function (evt) {
                console.log(evt.originalEvent, evt)
            });
        """,
        'remove': """
        delete state.cy
        """,
        'layout_names': """
            const layout = state.cy.layout(data.graph_layouts[data.layout_names])
            layout.run()
        """
    }

    _extension_name = 'cytoscape'

pn.extension('cytoscape', template='fast')

my_graph = Cytoscape(width=800, height=400)

widget_container = pn.Column(pn.pane.Markdown("## Title"))
app = pn.Column(widget_container).servable(target='main')
widget_container.append(pn.Row(my_graph.controls(['layout_names']), my_graph))

Initial render - Click on the top node (blue) - note the X-Y coord Panel Application

Scroll the window the right - Click on the same node - It is off target to the left (note the x-y coord). Panel Application

About this issue

  • Original URL
  • State: open
  • Created a year ago
  • Comments: 16 (1 by maintainers)

Most upvoted comments

I apologize - after review again, I was using Cytoscape version 3.23.0 to produce the above screenshot. I saw you used version 3.25.0, which I could NOT get it render if I create the object in the “render” block. You got it to render by creating it in the “after_layout” block. Version 3.25 had introduced new problems… However I was able to get the screenshot of the 'target element", as you can see in the log, it’s pointing at <div class="bk-Column">, which is the outer div contains the "Title, “controls”, and Cytoscape graph. Screen Shot 2023-07-07 at 3 04 46 PM

I’m so sorry about this. I’ve spoken too soon. I was testing on the older version of panel (0.14.2) and that’s why it worked. Using slot doesn’t solve the problem. With shadow DOM aside, If Cytoscape could base its position calculation on the “offsetX” and “offsetY”, that might solve a lot of problem. I will try to post this on the Cytoscape ticket…

Nevermind on that, for whatever reason, Cytoscape received the mouseEvent from the outer layer, thus the offsetX and offsetY are incorrect. However, when I wrapped the Cytoscape div with <user-card>, the user-card’s offsetX and Y appears to be correct. Example: <user-card id="userCard"> <div id="cy" style="width: 100%; height: 100%; position: relative; border: 1px solid"></div> </user-card>

state.cy.on('click', function (evt) {
                console.log(evt.originalEvent.offsetX, evt.originalEvent.offsetY)
                console.log(evt.originalEvent)
            });

userCard.onclick = e => console.log('userCard', e.offsetX, e.offsetY  )

I’m so sorry about this. I’ve spoken too soon. I was testing on the older version of panel (0.14.2) and that’s why it worked. Using slot doesn’t solve the problem. With shadow DOM aside, If Cytoscape could base its position calculation on the “offsetX” and “offsetY”, that might solve a lot of problem. I will try to post this on the Cytoscape ticket…

Wow indeed, great find.

@MarcSkovMadsen awesome find - I wrapped the div with <span slot="cy_slot"> and it worked. Also no errors when creating the “cy” object in the “render” block, which is great (creating the object in the “after_layout” block causes the graph to refresh too often). Thank you for your help!

I don’t know too much about ShadowDOM, but when review the mouse click event, I noticed the Target Element was on the outer div instead of the canvas,; thus, the coordinate information were not the same as in the other version of panel(v0.14.1).