[Bug]: Safari doesn't render link arrow markers after loading data
frnora opened this issue · 11 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:
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 tofalse
- 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:
- app.load() (freeze, fromJSON, unfreeze with afterRender)
- 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.
Fixed in v4.0.4
.