Chrome SVG: Reusing animation element with fill="freeze" does not work as expected - svg

I am supporting some old SVG graphics that we have in our application. I am having some issues with animating the fill color of a rectangle, and I am wondering if anyone else has seen the same issue.
We setup an animate element on the rec which ends up looking like this:
<svg id="svgEle" xmlns="http://www.w3.org/2000/svg" version="1.1">
<rect id="rect"
width="100" height="100"
style="fill:#008000; stroke:#000000;">
<animate id="animate" fill="freeze"
attributeName="fill" attributeType="CSS"
begin="indefinite" dur="1s"></animate>
</rect>
</svg>
And then, depending on values from a webservice result, we change the color of the rect and attempt to animate the color change. Currently it seems as if Chrome is the only native SVG render that supports the beginElement function. The animation works perfect on the first run, but all subsequent attempts to update the animation do not behave as expected. They always seem to revert to the first animation's fill color.
I have created the following example to show what I mean: http://jsfiddle.net/ssawchenko/ARXbs/
In Chrome the rectangle SHOULD cycle through all 4 colors via an animation when you click on the button, but it does not. In IE9 animation is not supported, so the fill color is just changed directly.
I am ok with IE9 simply setting the fill, however, in Chrome the colors are completely busted. Does anyone know if this is a bug, or if there is a work around?
Thanks!

This bug also exhibits in SVG Edit.
<animate attributeName="opacity" begin="indefinite" dur="1" fill="freeze">
</animate>
If you draw rectangles on top of each other you will see they seem semitransparent when they should be fully opaque. I've seen that Chrome Canary doesn't exhibit this behaviour, so it might be fixed in the next release.
I think this filed bug is related.

Related

Space between SVG stroke and fill

Filling and stroking a circle with the same color and a stroke-width exceeding a certain size, produces a strange transparent region “between” the two paint regions. What is going on?
This is happening in both Chrome and Firefox, so it may be to spec, but I couldn’t find any language in the spec about this behavior.
Fiddle
<svg viewBox="0 0 300 300">
<circle cx="100" cy="100" r="8"
stroke="#000" stroke-width="40"
fill="#000"/>
</svg>
Produces this rendering:
As Robert Longson noted, the issue shows up when a stroke overlaps itself in such a way that it creates a donut-hole when you convert the stroke outline to a separate path (depending on the winding-order / fill-rule calculations).
The gap between the fill and stroke in your particular example is caused by the "inside" edge of the stroke extending across the entire fill region and out the other side.
It gets really weird when you have dashed strokes, as shown in the examples from Tavmjong Bah's discussion article.
This is, unfortunately, neither according to the SVG spec nor against the spec. Instead, the spec at this point of time has left the matter undefined.
SVG working group discussion is here.
At this point, WebKit, Blink, and Firefox on Mac/Android draw strokes with cut-outs, using the Skia graphics library or Apple's CoreGraphics.
IE/Edge and Firefox on Windows/Linux just draw the total stroke, without cut-outs, as do Inkscape and Illustrator and most PDF-rendering software (the PDF spec itself is non-committal).
Everyone I've discussed this with agrees that the cut-outs are a sub-optimal result. But with so many browsers using rendering engines that do it this way, the SVG working group wasn't willing to make the more-intuitive stroke behavior a strict requirement. So instead, the SVG 2 spec has a warning-to-authors with a sample figure:
At this point, the best prospect for making a change would be to file issues (or contribute code) on the Skia library. If it was changed, that puts pressure on Apple to update to match, and the SVG spec would be able to make it official.
I found that adding stroke-linecap="round" style="stroke-dasharray: 1000" fixes the issue by introducing virtual dashes
<svg viewBox="0 0 300 300">
<circle cx="100" cy="100" r="8"
stroke="#000" stroke-width="40"
fill="#0F0" stroke-linecap="round" style="stroke-dasharray: 1000" />
</svg>
It's an artifact because the stroke width is so big it crosses the centre of the circle. It shouldn't happen but it's easily avoided by increasing r and decreasing the stroke-width.

SVG word animation

I have a mobile application that involves moving of text in a marquee way. I used css3 animation and it looks laggy on the mobile. I choose to use svg as an animation. How can I implement a marquee animation in a svg. I am new in this.
Here is a simple animation with scrolling text. Hopefully this will get you started.
There are numerous tutorials on the web on how to do SVG animation. You could also read the SVG specification if you want more information.
Note that SMIL animation like this (SMIL is animation that uses the <animate> tag) does not work in IE. But you could use a library like FakeSmile if you need to support IE.
<svg width="500" height="100">
<text x="0" y="80" font-size="80">Here is some scrolling text
<animate attributeType="XML" attributeName="x"
values="520;-880;520" dur="15s" repeatCount="indefinite"/>
</text>
</svg>

SVG mask doesn't work if a media query is present

TL;DR: I need to mask out a portion of one rectangle in SVG, based on the size and position of another existing rectangle, which will be changing dynamically. A Chrome bug is blocking the mask + use approach I tried. How can I do a mask or inverted clip path based on an existing shape?
Full Overview:
I'm using D3.js, and I am using the brush control to add a brush to a rectangle in an embedded SVG. By default, this adds some extra elements to the SVG, including a rect with class extent that shows the size of the brushed area.
Rather than have the brush extent be rendered as a semi-transparent overlay on top of the rectangle, as in most D3 examples, I am trying to "cut out" the extent from a semi-transparent overlay, so that the brush area shows the true color below. Per this question, I am trying to do this with a mask element, with a child use element referencing the extent. With some D3 magic, I now have a structure like this:
<svg width="100" height="100">
<g class="brush-layer inverted">
<defs>
<mask id="mask835">
<rect fill="#fff" width="100%" height="100%"></rect>
<use fill="#000" xlink:href="#extent848"></use>
</mask>
</defs>
<g class="brush" style="pointer-events: none;">
<rect class="overlay" mask="url(#mask835)" width="100%" height="17"></rect>
<rect class="extent" x="30" width="52" height="17" id="extent848"></rect>
</g>
</g>
</svg>
This works great... sort of. It turns out that there appears to be a tricky Chrome bug, which I've filed here, which prevents the mask from being applied if there's a #media query in the CSS. You can see the working version here and the failing version here (fails in Chrome, works in FF).
I need this to work in Chrome, and can't drop the #media query. I also need to make the use element work, because D3 will automatically resize the extent rectangle, and that's the shape I need to mask out.
So, how can I mask out a portion of one rect, based on another rect, without using the mask + use strategy above?
One possible workaround might be to use a custom clip-path, but it's probably not going to be as elegant. Some examples of how to do do this with clip-path can be found in this question.

SVG Mask is pixelated on retina displays

I have a simple cut-out rectangle with text in the middle.
<svg>
<defs>
<mask id="mytext">
<rect width='100%' height='100%' fill='white'/>
<text>Welcome</text>
</mask>
</defs>
<rect width='100%' height='100%' fill='blue' mask="url(#mytext)"/>
</svg>
However when viewing from a retina display the text edges become pixelated.
It does't happen if I only use text without masking it, but as soon the mask is used it breaks everything out.
EDIT: By Retina Display I mean, iOS and OSX both latest versions. All Browsers. I believe it might be a pixel density issue.
The interesting is while having
<text fill='url(#mypattern)'>Welcome</text>
The text is rendered sharply perfect. The problem lies only with masks being applied.
Here it is a jsfiddle sample (please make sure to test on your retina display enabled device).
And here is a screenshot displaying the difference on iPhone (note that the edges of the text below and how pixelated it looks).

Using a clipping path with a positioned object in Webkit

Consider this simple SVG file:
<svg xmlns="http://www.w3.org/2000/svg" xmlns:x="http://www.w3.org/1999/xlink"
viewBox="0 0 353 150">
<defs>
<clipPath id="walk0"><rect width="44" height="70" /></clipPath>
<image id="img" x:href="http://phrogz.net/tmp/walking-girl2.png"
width="353" height="70" />
</defs>
<use x:href="#img" clip-path="url(#walk0)" />
<use x:href="#img" y="80" clip-path="url(#walk0)" />
</svg>
The intent is to have two copies of the spritesheet clipped to the same region, with the second copy 80 units lower down. This works as intended in Firefox (the clipping path is applied before the y offset). In Chrome and Safari, however, the second image is not shown. (The clipping path is applied using global SVG unit space, and hence shows an empty area of the image.)
1) Which one of these browsers is correct?, or
2) What is the simplest, standards-based way to achieve this goal?
I can work around the problem by using wrapping <g> elements with transforms; this works in both Firefox and Chrome. But I'm hoping that there's a simpler way to achieve the same results in a correct and cross-browser manner.
FWIW, I also tried setting clipPathUnits="objectBoundingBox" on the clipPath, but this always produced an unclipped image. This was true even when I wrapped the <image> in a <symbol> with an explicit viewBox, height and width and referenced that with the <use> instead of the <image>. Either I don't understand how objectBoundingBox is supposed to work, or support for it is currently broken. It is certainly possible that the answer is the former instead of the latter. ;)
The easiest, standards-compliant way to differentiate between these is to use the SVG test suite provided by W3.org. This suite provides tests for use structs that you can play with to determine compliance, among many others.
The problem is how your y value is being parsed, which is causing your figure to translate out of the second frame, but only in some browsers. This is the correct, cross-browser way to specify the desired translation:
<use x:href="#img" clip-path="url(#walk0)"transform="translate(0,80)"/>
I would assume the dubious parsing with respect to the current clipping pane is a regression.

Resources