clientIO / joint

A proven SVG-based JavaScript diagramming library powering exceptional UIs

Home Page:https://jointjs.com

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

[Bug]: Safari doesn't render link arrow markers after loading data

frnora opened this issue · comments

What happened?

Hi,

There is some issue with the markers (not) rendering on Safari, take a look at this image directly from the demo page:
Screen Shot 2023-09-07 at 19 05 01

The markers appear again when you reconnect the link (or create a new one) but it doesn't work after loading the data. Any ideas?
(Safari Version 16.6)

Version

3.7

What browsers are you seeing the problem on?

Safari

What operating system are you seeing the problem on?

Mac

When you are using Safari, there is a bug where SVG Markers are not rendered if they are added asynchronously in the next animation frame.

Here is the minimal reproducible case: https://jsfiddle.net/kumilingus/k90h2Lt1/

The issue has been reported. We are currently waiting for the Safari team to address it.

In the meantime, you need to apply a workaround - there are a lot of ways, but it's important to somehow trigger the browser update of the SVG again.

  • The issue is not happening when the async paper option is set to false
  • The issue can be resolved for instance by hiding the paper and showing it again (see below).
paper.freeze();
graph.fromJSON(graphJSON);
paper.unfreeze({
    afterRender: function() {
        paper.el.style.display = 'none';
        requestAnimationFrame(() => paper.el.style.display = '');
        paper.unfreeze();
    }
});

The above code doesn't fire afterRender for me, tho. In update updateViewsAsync the condition checking for the id of the update evaluates to false (update.id is null). The subsequent calls don't get the afterRender fn anymore in the opt object.

If the graph is empty, the afterRender callback will not trigger.

You need to check if the graph is empty or check if there are any updates scheduled.

Am I misunderstanding this?
Can the graph be empty after fromJSON if the json contains cells? I.e.:

paper.freeze();
graph.fromJSON(graphJSON);
console.log(graph.getCells()); // <- correctly logs the cells
paper.unfreeze({
    afterRender: function() {
        paper.el.style.display = 'none';
        requestAnimationFrame(() => paper.el.style.display = '');
        paper.unfreeze();
    }
});

No. Empty in the sense of graph.getCells().length > 0.

Eh... so it should work in the above example if the graph has cells?
paper._updates.priorities.some(updates => !joint.util.isEmpty(updates)); returns true.

I am not using the viewport options, btw, if there is any connection.

The hasScheduledUpdates() method has been already added to JointJS.

if (paper.hasScheduledUpdates()) {
  paper.unfreeze({
      afterRender: function() {
          paper.el.style.display = 'none';
          requestAnimationFrame(() => paper.el.style.display = '');
          paper.unfreeze();
      }
  });
} else {
    paper.el.style.display = 'none';
    requestAnimationFrame(() => paper.el.style.display = '');
    paper.unfreeze();
}

If this is not helping, please provide steps to reproduce.

Sadly, that doesn't work. Same problem: gets to the if condition but then the afterRender doesn't fire.

I will try to come up with a case to reproduce.

I narrowed down the problem: It doesn't fire because there is another call coming in right after the load to set the router (the call may or may not happen but in my test cases it always happens) so it is:

  1. app.load() (freeze, fromJSON, unfreeze with afterRender)
  2. app.setDefaultRouter(...) which looks like this:
// ... some other stuff that doesn't matter
paper.freeze();
links.forEach(link => {
    link.findView(paper).requestConnectionUpdate();
});
paper.unfreeze();

This blocks the afterRender from the first (load's) unfreeze call. Should it?

paper.unfreeze({ afterRender: () => console.log('Hello'); });
paper.unfreeze();

"Hello" is never called. The second unfreeze cancels the first call.