This is the code below to reproduce
<svg focused="true" width="338.35" height="338.35" version="1.2" viewBox="0 0 1200 1600" style="overflow:visible;">
<g onclick="alert(2)" transform="translate(0,0) rotate(0,375.7469534186119,500.9959378914826)">
<rect width="600" height="800" fill="red"></rect>
</g>
<g onclick="alert(1)" transform="translate(1537.23915382511058,0) rotate(0,375.7469534186119,500.9959378914826)">
<rect width="600" height="800"></rect>
</g>
</svg>
Fiddle http://jsfiddle.net/fb6swzba/
When a box clicked, it alerts a number. As you see, the red box works in both browsers. On chrome, both red and black box works. But on Safari red box works, but black box is not reactive at all.
When rect is out of the width defined in SVG, it's visible on the browser as style overflow:visible does that. But it's not clickable on safari browsers however the same example works in Chrome.
Related
Let's say you have a list of coordinates like so:
2942852.602193035 472992.4195375803
How would you go about scaling these down so that they fit in an svg. Coordinates like 294.2852602193035 472.9924195375803 would fit, but scaling my lines to (.0001) with the scale property on my lines doesnt seem to work. It is fairly intricate linework. Does anyone have any suggestions?
Here's where you can check out some code:
https://snack.expo.io/_-0M6dRP5
<Svg
height="1920"
width="1080"
fill="none"
viewBox="294.2852602193035 472.9924195375803 897.8977111047134 1329.2074627304683"
preserveAspectRatio='none'>
{//this rectangle shows up }
<Rect x="294.285534094599" y="472.6193465770291" width="300" height="300"
fill="blue" onPress={()=>{alert('achoo!')}}/>
{//this one doesn't, even without the transform matrix}
<G transform="matrix(1,0,0,-1,0,0)" scale="0.0001">
<Rect x="2942855.34094599" y="472619.3465770291" width="300" height="300"
fill="red" onPress={()=>{alert('achoo!')}}/>
</G>
</Svg>
I created a minimal example to demonstrate a Chrome bug I recently ran into:
const main = document.getElementById('main');
const topHover = document.getElementById('top-hover');
topHover.addEventListener('mouseenter', function(e) {
main.setAttribute('clip-path', 'url(#top-clip)');
});
topHover.addEventListener('mouseleave', function(e) {
main.setAttribute('clip-path', 'url(#everything)');
});
const bottomHover = document.getElementById('bottom-hover');
bottomHover.addEventListener('mouseenter', function(e) {
main.setAttribute('clip-path', 'url(#bottom-clip)');
});
bottomHover.addEventListener('mouseleave', function(e) {
main.setAttribute('clip-path', 'url(#everything)');
});
//main.setAttribute('clip-path', 'url(#everything)');
#main {
fill: #51D2C3;
}
#bg {
fill: #E1F5F2;
}
#top-hover {
fill: none;
}
#bottom-hover {
fill: none;
}
<svg height="200" width="300">
<path id="bg" d='M100 50 h50 v50 h50 v50 h-50 v50 h-50 v-50 h-50 v-50 h50 z'></path>
<path id="main" clip-path='url(#everything)' d='M100 50 h50 v50 h50 v50 h-50 v50 h-50 v-50 h-50 v-50 h50 z'></path>
<g>
<clipPath id="everything"></clipPath>
<rect id="top-hover" pointer-events="all" x="50" y="50" width="150" height="75"></rect>
<clipPath id="top-clip">
<use href="#top-hover"></use>
</clipPath>
<rect id="bottom-hover" pointer-events="all" x="50" y="125" width="150" height="75"></rect>
<clipPath id="bottom-clip">
<use href="#bottom-hover"></use>
</clipPath>
</g>
</svg>
The bug seems to be in how Chrome treats clip-path that's created at the same time as SVG element creation. It seems that whatever is applied to SVG element as initial clip-path becomes a permanent implicit clip-path that can't be unset via JavaScript. I reported it already here: https://bugs.chromium.org/p/chromium/issues/detail?id=1045915
in Chrome hover states don't work.
in Firefox they work as expected.
if you remove clip-path property from object with id="main" in HTML/SVG portion, and set it programmatically via JavaScript (see commented out line), hovering works as expected in Chrome as well.
if you don't set initial clip-path at all, hovering works as expected in Chrome (aside from starting out in "on" state for all regions)
if you change initial clip-path to something else (update HTML/SVG clip-path for id="main" element to either url(#top-clip) or url(#bottom-clip)), only the initially non-clipped region will render when new clip-path is applied.
From this, I conclude that that Chrome erroneously treats clip-path that's set at the time of SVG element creation as a permanent implicit clip-path that's applied on top of current clip-path.
This is a simplified example of my actual logic. In my logic I'm creating the above definition via d3.js, adding a delay to applying clip-path (even something as low as a microsecond), seems to solve the issue but seems like a hack. Is there a cleaner workaround or an alternative way to define similar functionality that mitigates this bug?
I am trying to animate the radius of the circle #mask-hole-2 with javascript. So that it animates the radius from 0 to 175px. But i dont know how to do this in a common way. I cant use css cause there seems to be another specification used on firefox for animating masks with css.
<svg width="400" height="300">
<defs>
<mask id="hole">
<circle id="mask-hole-1" cx="165" cy="156.5" r="165" fill="white" />
<rect id="mask-hole-3" width="100%" height="100%" fill="white"/>
<circle id="mask-hole-2" cx="165" cy="156.5" r="145" />
</mask>
</defs>
<image width="400" height="300"
xlink:href="http://lorempixel.com/400/300/sports/"
mask="url(#hole)"/>
</svg>
I want #mask-hole-1 to change its radius within 2 seconds from 0 to 175. After 2s #mask-hole-2 should change its radius from 0 to 175 also.
Would be nice if the animation works smooth. Any help is appreciated.
I have a JavaScript app that works with svg components. I have svg groups as:
<svg id="canvas" width="100%" height="100%" viewBox="0 0 1500 500">
<g class="node-element" x="0" y="0" height="20" width="300" id="node-c87">
<text class="node-element-text" x="12" y="15">person:object</text>
<image x="0" y="4" width="11" height="11" xlink:href="assets/images/object-icon.png"></image>
</g>
<g class="nested-group">
<g class="node-element" x="50" y="100" height="20" width="300" id="node-c87">
<text class="node-element-text" x="12" y="15">person:object</text>
<image x="0" y="4" width="11" height="11" xlink:href="assets/images/object-icon.png"></image>
</g>
</g>
</svg>
And I have defined CSS as follows(CSS on svg groups acts on all child elements of <g>.
.node-element {
display: inline;
}
.node-element :active {
opacity: 0.5;
}
.node-element:hover {
opacity: 0.5;
}
The problem is that it does not work properly in Firefox, whereas it works fine in Chrome. Why and how to fix it?
The node elements are in a tree-like structure where x values differ based on rank. In Firefox, the hover does not properly work on the first couple of node-elements. But works fine on the rest of the node-elements, regardless of the x values.
UPDATE: The problem was actually caused by a foreignObject component, which I have set the elements to display:none. The hover was actually working on the hidden component than the desired element. It was solved by setting the display:none to the foreignObject.
But I would like to know why this was acting differently in the two browsers, Chrome and Firefox?
You probably need to have all look at css pointer-events, documented here. With that you can specify what »region« of your graphic is used for hovers. This can be the AABB (axis aligned Bounding box, nothing or the shape of the graphic).
The problem was actually caused by a foreignObject component, which I have set the elements to display:none. The hover was actually working on the hidden component than the desired element. It was solved by setting the display:none to the foreignObject.
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="1300" height="900" viewBox="0 0 750 300" id="mainsvg">
<g>
<defs>
<pattern x="0" y="0" width="1.6" id="smallGrid" height="1.6" patternUnits="userSpaceOnUse">
<path d="M 10 0 L 0 0 0 10" id="smallgridbox" fill="none" stroke="rgb(8,24,77)" stroke-width="1"></path>
</pattern>
<pattern width="16" id="grid" height="16" patternUnits="userSpaceOnUse" x="687.47" y="0" shape-rendering="geometricPrecision">
<rect fill="url(#smallGrid)" width="16" height="16" fill-opacity="0.5"></rect>
<path d="M 100 0 L 0 0 0 100" id="largegridbox" fill="none" stroke="rgb(8,24,77)" stroke-width="1"></path>
</pattern>
</defs>
<rect fill="url(#grid)" width="1375" height="773" x="0" y="0" fill-opacity="0.5"></rect>
</g>
</svg>
Here is the JS Fiddle: http://jsfiddle.net/KashifMKH/L46j18fo/6/
It works fine in Mozilla Firefox, but not in Chrome. Zoom it at large and then compare the results in Mozilla and Chrome: you will see the difference clearly. How can I fix it?
I played around with your fiddle in chromium. That the gridlines become blurry if one zoomes in, appears also to me.
So I »manually« changed the viewBox in the html code so that the svg is scaled initially. Fiddle
Result: No blurry Gridlines.
So I think it is quiet obvious that chrom - e/ium does not rerender the pattern if the viewBox changes. You could try to update the viewBox by using the direct DOM-Binding:
var vb = a.viewBox.baseVal;
vb.x = ...
vb.y = ...
If that does not work I would try to use transforms and if that does not work, I think you cannot use <pattern> to create the grid and <use> elements, created by Javascript are the next option.