I want to create a keyframe simulation using SVG, the idea is that the objects in the animation/simulation have particular positions (or line lengths) at particular times. So for example, I may have divided the 1-minute simulation into 60 1-second intervals. I want to do three things:
(a) be able to play the 60-frame simulation frame by frame
(b) be able to select any frame by clicking on a frame button (imagine 60 small rectangles at the bottom of the screen, each representing a particular frame)
(c) be able to step forwards or backwards from a given frame
What would be good ways to do this using SVG?
For example, imagine I have two circles moving around. At each time T (from 1 to 60) each of the circles has a location and radius and visibility (it might be invisible during one or more frames). How do I structure the SVG file?
Note that I would like to avoid using Javascript (ECMA) to do this. I am hoping for a pure SVG solution.
I fear you might be out of luck doing this without JavaScript. In theory, it's perfectly possible to do with SMIL animation, unfortunately support is not so good or at least very inconsistent. If you want to try anyway or if you're happy to make it work in a specific browser, this might give you a starting point:
<svg xmlns="http://www.w3.org/2000/svg" width="110" height="230">
<!-- some moving circle -->
<circle cx="50" cy="50" r="50">
<set id="a0" attributeName="cy" to="50" begin="start.click; r0.click"/>
<set id="a1" attributeName="cy" to="75" begin="a0.begin+1s; r1.click"/>
<set id="a2" attributeName="cy" to="100" begin="a1.begin+1s; r2.click"/>
<set id="a3" attributeName="cy" to="125" begin="a2.begin+1s; r3.click"/>
</circle>
<!-- Rects to address certain frames -->
<g fill="#d44">
<rect id="r0" width="20" height="20" y="180"/>
<rect id="r1" width="20" height="20" y="180" x="30"/>
<rect id="r2" width="20" height="20" y="180" x="60"/>
<rect id="r3" width="20" height="20" y="180" x="90"/>
</g>
<!-- Play button-->
<polygon id="start" points="40,210 70,220 40,230" fill="#6d6"/>
</svg>
This attempts to solve your points (a) and (b), but I think it only works as intended in classic non-Blink Opera. I'm not sure whether FakeSmile can help you get more consistent behavior.
Related
This is the example https://codesandbox.io/s/4xwv953mv0
There are three lines. The original one is hidden the second linked to it by id xlink:href="#line", the third links the second the same way.
Move the slider, the lines will go up in the Chrome, and only one will go up in the Firefox.
If it is a Firefox bug what to do? Is there a way to update SVG with Vue?
Yes. This is a known Firefox bug. Firefox bug report here and here.
There is a simple fix here though. Just change your second use so that it points to the <line> directly, rather than at the <use>.
<use
id="Svg"
xlink:href="#line"
transform="translate(40,10)"
></use>
As an aside. I recommend that you put your line in a <defs> section, rather than hiding it with display:none. This is what <defs> is for, and using display:none can have unintended consequences in some cases.
<defs>
<line
id="line"
x1="0"
y1="0"
x2="100"
:y2="value"
vector-effect="non-scaling-stroke"
/>
</defs>
I have an page with an interactive SVG which looks fine on all browsers (Firefox, Chrome, even IE/Edge) except Safari where everything affected by one of the SVG filters turns into a fuzzy mush (looks like something rendered onto a low-resolution canvas which got scaled up using bilinear interpolation).
Here now a small test case where the problem also appears:
<svg>
<defs>
<filter id="filter" y="-100" x="-100" height="300" width="300">
<feGaussianBlur in="SourceAlpha" stdDeviation="3.5"></feGaussianBlur>
<feColorMatrix type="matrix" values="0 0 0 2 0 0 0 0 2 0 0 0 0 0 0 0 0 0 1 0" result="lightenedBlur"></feColorMatrix>
<feMerge>
<feMergeNode in="lightenedBlur"></feMergeNode>
<feMergeNode in="SourceGraphic"></feMergeNode>
</feMerge>
</filter>
</defs>
<g>
<rect x="10" y="10" width="100" height="100" fill="blue" filter="url(#filter)"></rect>
</g>
</svg>
How it looks on Apple Safari 11 (on OS X 10.13):
Compare that to Google Chrome and Mozilla Firefox respectively:
When looking at other SVG filter demo pages on the web though the effect apparently isn't there. Not quite sure what exactly causes it. What I noticed is that the issue becomes more apparent the larger the filter area is (controlled through the width/height attributes of <filter>).
Is this a known issue? Under what circumstances does it occur? What are reasonable workarounds?
This is not a bug. Safari is punishing you for incorrect syntax in your filter declaration:
<filter id="filter" y="-100" x="-100" height="300" width="300">
According to spec, this should be read as height="30000%" and width="30000%". Safari is saying "ok I guess you meant this" and adjusting the filter resolution automatically so it doesn't allocate a huge piece of memory to this very large buffer -> hence crappy resolution.
If you meant 300% - then you need to put 300%. This is one fix:
<filter id="filter" y="-100%" x="-100%" height="300%" width="300%">
If you meant 300px (really userSpace units) - then this is another fix:
<filter id="filter" y="100" x="-100" height="300" width="300" filterUnits="userSpaceOnUse">
You must explicitly tell Safari that you mean pixels by specifying userSpaceOnUse (otherwise it uses the silent default objectBoundingBox)
Another fix - is to over-ride Safari's filter resolution adjustment by explicitly specifying a filterRes. filterRes has been deprecated in the new Filters 1.0 spec and already removed from latest Chrome & Firefox, but Safari still supports it. Since this will result in a big memory hit(and it's hard to believe that you meant to size your filter as you did) - this is not recommended. But whatever - for completeness.
<filter id="filter" y="-100" x="-100" height="300" width="300" filterRes="100000">
(Two other minor notes - you can make your filters less wordy by using self-closing elements. And the blur adjustment you're doing doesn't lighten the blur, it just dials up the opacity fwiw.)
I've run into an issue on older versions of firefox, (in particular 38.2.1)
where a D3 animation of and SVG component results in rendering issues ( looks like its just not repainting the background).
a Minimal example below
https://jsfiddle.net/4n2f9g81/2/
<svg width="600" height="600">
<g transform="translate(36, 24)">
<g class="group" transform="translate(200)" >
<circle class="circle" fill="white" r="20" stroke-width="2" stroke="#7ab800"></circle>
<g class="label" >
<line y1="-25" y2="-40" stroke="#7ab800" stroke-width="1" shape-rendering="crispEdges"></line>
<text text-anchor="middle" class="peer-label position" y="-45" style="-moz-opacity:0">label text</text>
</g>
</g>
</g>
</svg>
d3.select('.group').transition().duration(5000).attr("transform", "translate(0,100)");
It only occurs when the g element with the class label has some content.. if it's empty or hidden there's no corruption and the animation works fine. since it works in more recent version (and in other browsers) I assume I've hit a firefox bug which has since been resolved.
I'd like to know if there's a workaround for this on these older versions. I've tried a couple of things like forcing a background fill or forcing opacity, but not had any success as yet.
I'm just starting to deal with Svg, so Im not really aware how to deal with all the effect,
I'm looking to do an small effect animation, exactly like this website: http://www.resanova.fr/
The idea would be to scale my svg image from the bottom to the top like you can see on this website.
I've try the following:
<animateTransform attributeType="xml"
attributeName="transform"
type="scale"
from="0"
to="1"
dur="0.5s" fill="freeze" />
But without success, that just does a normal scale effect instead of the bottom to top . . ..
--EDIT--
Please fidn attach my svg on jsfiddle if it helps :)
https://jsfiddle.net/v3p9gLjx/3/
No matter what I try, I can't get this SVG gradient to work properly in the most recent Safari (5.1.7) on Windows:
<svg xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="none" viewBox="0 0 1920 200">
<linearGradient id="g186" gradientUnits="userSpaceOnUse" x1="0%" y1="0%" x2="0" y2="200">
<stop stop-color="#0A306A" offset="0"/><stop stop-color="#030C1B" offset="1"/>
</linearGradient>
<rect x="0" y="0" width="1920" height="200" fill="url(#g186)" />
</svg>`
JSFiddle:
http://jsfiddle.net/wumnb/1/ (Note that the browser may throw an XSS warning because of the base64-encoded SVG)
When I include -webkit-background-size: 100% 200px; with and/or without the -webkit-, it re-sizes the SVG, but it looks significantly lighter than every other browser; almost as if it was cropping a full-page version of the SVG from the top to 200px from the top.
I've tried both answers from the other two questions I could find, but neither is working.
It turns out that preserveAspectRatio="none" needs to be preserveAspectRatio="xMidYMax meet" with viewbox set to the wanted dimensions. Sadly, this doesn't allow for percentages, but it's better than nothing.
W3 documentation for preserveAspectRatio.
EDIT: Upon playing with this more, I've discovered that background position is really weird in Safari. The xM(in|id|ax)yM(in|id|ax) part of the preserveAspectRatio seem to determine where the SVG will go on the page, rather than do what's described on W3.
It appears (to me at least) that xMidYMax is the equivalent of background-position: center bottom; and xMinyMin is the equivalent of background-position: center top;