svg_animate 0.6.1
svg_animate: ^0.6.1 copied to clipboard
Animated SVG for Flutter. Plays SMIL and CSS keyframe animations as a drop-in companion to SvgPicture from flutter_svg.
0.6.1 #
-
Says which version to depend on. Getting started still read
svg_animate: ^0.3.2, and below 1.0.0 a caret constraint pins the minor, so anyone who copied that line resolved to 0.3.8 and nothing since. Nothing in the code changed for this; the README and the description on pub.dev come from whatever version is published, which is why it needs one. -
Opens the package description with "Animated SVG", which is the phrase people search for and which it did not contain. Searching pub.dev for
animated svgput this package ninth, whilesmilput it second — a word only somebody who already knows the format would type.
0.6.0 #
-
Holds still when the platform asks for less motion. Somebody who finds movement uncomfortable turns Reduce Motion on in their system settings, which reaches Flutter as
MediaQuery.disableAnimationsOf, and nothing in this package read it: the animation played anyway. A picture now loads as usual, draws its first frame and starts no ticker. PassrespectReduceMotion: falsefor an animation that carries information rather than decorating, since a still spinner reads as a frozen app. Only starting on its own is given up; a controller told to play plays either way.This also gives a widget test a way to settle. A looping animation never does, so
pumpAndSettleon a screen carrying one times out and says nothing about which widget kept it awake; wrapping it in aMediaQuerythat asks for less motion holds the first frame. The README has both. -
Stops an element that follows a motion path from spinning once every loop. A heading comes from
atan2, which answers in (-180, 180], so it jumps by almost a whole turn the moment the direction of travel crosses 180 degrees — which is whenever the element is moving leftwards. Keyframes are interpolated linearly, so the step either side of that jump read as "turn 356 degrees back the other way" rather than "carry on turning four", and the element spun through most of a revolution in a fraction of a second. Whole turns are now added so that a run of headings stays continuous; the orientation each keyframe describes is unchanged. Affectsrotate="auto"androtate="auto-reverse"on<animateMotion>andoffset-rotate: autoon a CSS motion path. Any closed path was hit once a loop, since a closed path's heading winds a whole turn and so has to cross the seam somewhere. -
Takes the heading of a motion path from a segment that has one. A segment with no length has no direction, and
atan2(0, 0)answers zero rather than saying so, which pointed a tracking element to the right for as long as a sample sat there. Such segments come from theZof a path whose last curve already ended where it started, and from the move between two subpaths. -
Reads every spelling of
offset-rotate. The keyword was inferred from a minus sign anywhere in the value, soauto -30degwas mistaken for a reversal and turned the element 150 degrees instead of -30.reverse <angle>was not recognised at all and lost both the reversal and the heading, arriving as a plain fixed angle.
0.5.1 #
- Lets the shared cache go when the system asks for memory back. Flutter throws away every decoded image at that point; compiled animations are the larger half of what this package holds — megabytes rather than kilobytes — and nothing was letting go of them, so an app that had been pushed into the background sat on all of it while the system looked for something to reclaim. A picture that is already on screen holds its own frames and goes on playing; it pays again only if it is rebuilt.
0.5.0 #
-
Names what was animated when an animation draws the same picture every frame, and says which layer dropped it.
neverChangessaid only that something the renderer could not express was animated, which sends somebody back to read the whole file. It now lists the attributes, and for the two known cases says where each one goes wrong: an animateddnever reaches the frames, because path data is not a value this package interpolates, while an animatedstroke-dashoffsetreaches them correctly and is dropped byvector_graphics, which carries no dash offset. The dash offset case also carries the way round it — animatingstroke-dasharrayfrom0 LtoL 0draws a path on and does compile. -
Adds a diagnostic for a
clip-pathover<text>. The clip does not reach the letters: they are drawn in full whatever it says, so a wipe or a reveal over text stays fully drawn from the first frame to the last, with every value changing as it should and nothing to report. Clipping shapes works, so the same effect over shapes, or the text converted to paths, both compile. -
Recompiles an animation when the app is hot reloaded, so that editing an SVG and reloading shows the edit. An animation is cached under what identifies its source — an asset's name, a file's path — and never under its contents, so a file that had changed on disk went on finding the animation compiled from what it used to say, and only a full restart cleared it. Flutter has the same problem with images and solves it the same way round:
PaintingBinding.evictthrows away every decoded image when an asset changes. Debug builds only; there is no hot reload to serve in a release build and recompiling there would be pure cost. -
Adds a diagnostic for an animation that compiled to more than 4 MB. It says how large it is, over how many frames, how many of those are different pictures, and which of
frameRateandmaxFrameschanges it. Compiling is where this package spends, and the bill arrives as memory, as a slow first frame, or on the web as a frozen tab — none of which points back at the SVG that caused it.SvgAnimateDiagnosticKindgains a value, so aswitchover it that was exhaustive is not any more.
0.4.0 #
-
Adds
speedandreversetoAnimatedSvgController. Playback could be started, paused and seeked, but only ever ran forwards and only ever at the timing the file declares, so showing an animation at half speed meant editing the SVG. Neither costs anything: the frames are compiled once and are not compiled again, so only how long playback takes to walk through them changes. An animation that repeats keeps repeating backwards, whichAnimationController.repeatwill not do on its own. -
Tells a controller's listeners that playback has stopped when it stops because the animation ran out.
isPlayingwent to false and nothing said so, so a play button driven by anAnimatedSvgControllerwent on showing a pause icon after the animation it drives had finished, until something else happened to rebuild it. -
Says what to do about a dropped
<filter>, where there is something to do.vector_graphicscannot blur one element inside a picture, but Flutter can blur the picture, andAnimatedSvgPicturealready takes animageBuilder. A filter that is a singlefeGaussianBlur— which is what an exported glow or soft shadow usually is — now reports theImageFilteredthat approximates it, carrying thestdDeviationthe file asked for. Anything else, including a document that uses more than one filter, goes on saying that nothing can be done rather than sending somebody after a substitution that will not look like what they asked for.
0.3.8 #
- Adds
precacheAnimatedSvg, which compiles an animation into the shared cache before anything shows it. Compiling is the expensive part of drawing an animated SVG and it happened when the picture was first built, so a large document showed a placeholder, then a still first frame, and only then moved. There was no way to do that work on the screen before, because the key the picture looks an animation up under was private andcompileAnimatedSvgcompiled without caching.AnimatedSvgCacheKeyis exported with it, which also makesAnimationCache's[]andevictusable: both take a key, and until now there was no way to build one.
0.3.7 #
- Keeps a rounded rectangle's corner radius inside the size it is drawn at. SVG
clamps a radius larger than half the side it rounds down to half that side, so
a rect of zero width draws nothing;
vector_graphics_compileruses the radius as authored, and the two rounded ends cross over one another into a bow tie. Anything that grows a rounded bar from nothing showed it — including the progress bar in this package's own example and in its README — for as long as the bar was narrower than twice its radius. Worth fixing in flutter/packages too, where it would also fix still SVGs drawn throughflutter_svg; the code here can only reach what it compiles itself.
0.3.6 #
-
Says what an SVG asked for that will not happen, instead of leaving it to be deduced. An animation that does not play looks exactly like one that has not started: a still picture and no error, whatever the reason. Every compiled animation now carries
diagnostics, and a debug build prints them the first time the SVG is compiled. Five things get reported: a document with no animation in it, and whether it carries a<script>that an editor exported its animation into; an animation whose every frame drew the same picture, which is what a morphingddoes; an<image>pointing anywhere other than adata:URI, which the compiler leaves out of every frame without complaining; a<filter>, which is not drawn; and an animation sampled below the frame rate asked for becausemaxFrameswould not stretch that far. SetsvgAnimateReportDiagnosticsto false to silence the printing. -
Publishes for the web again, and for WebAssembly with it.
dart:iowas imported for the file loader'sFile, and an import of it anywhere in the library is enough for the whole package to be analysed as not supporting the web: pub.dev listed five platforms while the README promised six and described what the package does on the sixth. That import now resolves to a stand-in where there is nodart:io, the wayflutter_svgdoes it. Nothing about behaviour changes — a web build already compiled — and a file loader still cannot be built on the web, because there are still no files there. -
Documents
AnimationCache.maximumSizeBytes,currentSizeBytesandAnimatedSvgFrames.distinctFrameCountin the README, which went on describing the cache as bounded by a count of entries alone: the model 0.3.4 replaced precisely because a count says so little about how much memory is held.
0.3.5 #
- Keeps one copy of any frame that repeats, rather than one per sampling point.
Frames repeat whenever the document holds still — a
<set>, a discretecalcMode, a CSSsteps()timing function, a long gap between keyframes — so a one-second blink compiled at the default frame rate held sixty pictures where it draws two, and asteps(4)slide held sixty where it draws four. Nothing changes for an animation whose frames all differ: the compiled size of a 450x450 banner is unchanged to the byte, and the extra pass over its 300 frames does not measurably lengthen its 2.6 s compile. - Stops playing an animation that never changes what it draws. A document can
declare an animation the renderer cannot express — a morphing
d, say — which sampled to sixty identical pictures, reported itself as animated, and ran a ticker that repainted the same picture for as long as the widget was on screen.AnimatedSvgFrames.isAnimatednow counts pictures rather than sampling points, so nothing is started.distinctFrameCountreports how many there are, next toframeCount, which keeps its meaning as the resolution the timeline was sampled at.
0.3.4 #
- Bounds the animation cache by how much it is holding and not only by how many
animations it holds, through
AnimationCache.maximumSizeBytes, which defaults to 20 MiB. The count was the only limit, and how much an animation costs to hold has very little to do with how many there are: a spinner compiles to a few kilobytes and a banner carrying embedded bitmaps to several megabytes, so the default of ten entries was somewhere between 50 KB and 50 MB depending entirely on what an app happened to show. An animation larger than the whole budget is still kept, alone, rather than refused — refusing it would disable the cache for exactly the files whose recompilation is measured in seconds.AnimationCache.currentSizeBytesreports what is held.
0.3.3 #
- Shows the first frame while the rest are still being compiled, instead of a placeholder. Compiling every frame of a long animation is what the wait before it appears is made of, and the first frame alone is a fraction of that work: a 450x450 banner with embedded bitmaps now puts a picture on screen after 189 ms rather than 2.4 s, and starts moving once the rest arrive. The extra pass costs about 8% more total work on that file. Pictures waiting on the same animation share the first-frame pass between them, and an animation that is already compiled skips it altogether.
- Adds
AnimationCache's[]operator, which reports what is already compiled without compiling anything.
0.3.2 #
- Fixes a
@keyframesrule that declares onlytositting still. The missing end was filled in from the value the element carried, and an element that carried none got the other keyframe instead, so both ends agreed and nothing moved. It now falls back to the value the property has outside the animation: no rotation for a transform, fully opaque for an opacity. This is how nearly every CSS spinner is written —@keyframes spin { to { transform: rotate(360deg) } }— so it did not turn.
0.3.1 #
- Adds
compileAnimatedSvg, which compiles an animation without showing it.AnimatedSvgFramescould reportframeCountandcompiledByteSizebut there was no way to get hold of one, so an SVG that embeds raster images could not be measured before choosing a frame rate for it.
0.3.0 #
-
Stores what the compiled frames have in common once instead of in every frame. Consecutive frames describe the same document with a few numbers changed, and anything the SVG embeds sits at the front of each of them unchanged, so the run of bytes they all begin with is kept once and rebuilt into a frame when it is asked for. On a 450x450 banner carrying five embedded bitmaps this took the compiled animation from 27.5 MB to 5.1 MB at the default frame rate, and cost 0.1 ms per frame change to put back together. SVGs that embed nothing are unaffected either way.
-
Breaking:
AnimatedSvgFrames.framesis replaced byframeCountandframeAt, since the frames are no longer held whole.compiledByteSizereports how much memory they take, which is worth checking before raisingframeRateon an image-heavy SVG. -
Decodes an image embedded in an animated SVG once for the whole animation instead of once per frame. The renderer namespaces its image cache by the hash code of the loader it is handed, and every frame was handing it a different one. On a 450x450 banner carrying five embedded bitmaps this took the cost of a frame change from 6.8 ms to 1.4 ms, which is what an SVG with no images at all costs.
0.2.0 #
- Adds support for CSS motion paths:
offset-path: path(...)driven by an animatedoffset-distance, withoffset-rotate. This is how SVGator and similar tools express movement, so their exports now animate rather than scaling and rotating in place. - Expands a
<use>that points at an<image>into the image itself. The renderer loses an image's size when it is reached through a reference and then refuses to draw it, which failed the whole picture rather than that one element; SVG editors emit this shape whenever an image is placed more than once. - Fixes
offset-distanceand the otheroffset-*properties being written back into the compiled markup as presentation attributes, where nothing could use them.
0.1.0 #
- Initial release.