Making animateMotion (and similar elements) easier to use

Hello all,

I have been trying to get up to speed on the state of SVG2 and recent
mailing list discussions.  I came across a couple threads related to
<animateMotion> that sparked the following proposals:

- Add `refX` and `refY` attributes for <animateMotion>

- Allow `auto + <angle>` values for `rotate` in <animateMotion> and
`orient` in <marker>

-  Add a `startOffset` attribute to <animateMotion>, and a `wrap` attribute
for <animateMotion> and <textPath>

- Allow <mPath> and <textPath> elements to reference basic shapes


All would have the goal of making <animateMotion> easier to use, with only
minor extra implementation (I hope), while encouraging similarity in
language between conceptually similar elements.  Details and background
below.

Sincerely,
Amelia Bellamy-Royds

--------------

Proposal 1:  Add `refX` and `refY` attributes for <animateMotion>
---------------

In August 2014, Sara Soueidan started a thread asking about the "weird
behaviour" of certain shapes when a motion path is applied [1]; the problem
stemmed from the fact the shapes weren't centered on (0,0).  After others
debugged by adding a nested transform, Dirk Shulze commented [2] "It is not
very intuitive for users though." Nikos Andronikos replied [3] with the
suggestion:

> How about an animation origin attribute that can be set to a specific co-ordinate,
or could be set to some keyword that will use the center point of the
bounding box of the object? This would just be a more author friendly way
of setting the translation.


I think that is a great idea, which would make many animations much easier.

An author-friendly option would be to borrow the `refX` and `refY`
attributes from <marker> elements. They would have a directly equivalent
meaning conceptually, representing the coordinates (as numbers or lengths)
in the positioned graphic's coordinate system that should align with the
relevant position on the path.

For implementation, it would simply be a matter of adding a supplemental
translation to the animateMotion position. Default values would be (0,0) so
backwards compatibility would be maintained.

Creating an automatic way to set the origin to the center of the object's
bounding box would be more complex, requiring new keyword syntax. I'm not
sure it would be worth the complexity, since the center of the bounding box
is not a particularly meaningful coordinate for many complex shapes.

Alternatives: The SMIL specification defines an `origin` attribute for
<animateMotion>, the exact functionality of which is to be set by the host
language [4]. It is not implemented in SVG. There are benefits (and
consistency with the rest of <animateMotion> syntax) to using a single
attribute for the x,y coordinate. However, the `origin` attribute is
defined as the origin for the *motion coordinates*, not for the shape. I
personally find this confusing when applied to path-based motion. If this
behaviour was desired, it would be more consistent to use a transform on
`<animateMotion>` or `<mPath>`.

[1]: http://lists.w3.org/Archives/Public/www-svg/2014Aug/0000.html
[2]: http://lists.w3.org/Archives/Public/www-svg/2014Aug/0005.html
[3]: http://lists.w3.org/Archives/Public/www-svg/2014Aug/0006.html
[4]: http://www.w3.org/TR/SMIL3/smil-animation.html#adef-origin

--------------

Proposal 2: Allow `auto + <angle>` values for `rotate` in <animateMotion>
and `orient` in <marker>
---------------

This one comes from my own frustrations.  While putting together an example
where a static element is initially positioned with the Y-axis tangent to a
path (i.e., X-axis normal to the path) [5], and then moves along it, I
discovered that the only way to keep the correct orientation is to use a
supplemental <set> transformation to rotate the element 90 degrees.

The current options for <animateMotion> `rotate` are fixed angle, auto
(meaning the x-axis is tangent to the curve), or auto-reverse (rotated 180
degrees from auto).  I'm not sure what use case prompted the inclusion of
`auto-reverse` over `auto-normal`, but rather than suggest a series of new
keywords, I would propose allowing auto rotation *plus* an arbitrary
rotation offset.

My proposed syntax would be based on the offset syntax for animation
begin/end attributes: the keyword "auto", optional whitespace, "+" or "-",
optional whitespace, and then an angle measurement.

Similarly, for <marker> the options for `orient` are currently (SVG1.1)
auto or fixed angle.  The latest SVG2 draft adds the keyword
`auto-start-reverse` to mean "rotate 180 when used as a start marker" [6],
which seems rather specific and confusing (what if you defined the shape
for the start marker and want it to rotate for the end?).

A `auto + <angle>` setting for markers, in combination with an xlink:href
form of duplicating marker contents while changing maker parameters, would
allow you to easily create rotated versions of a marker without
restrictions.  For example, maybe you could have start and end markers to
be upright, but vertex or edge markers to follow the path direction.  I
realize that this is a broader use of <marker href="#otherMarker" /> than
is currently proposed for SVG2.  However, it is consistent with usage in
patterns, filters, etc., where a reference is used to create a copy for
which attributes can be over-written.

[5]: http://codepen.io/AmeliaBR/pen/JIBqf
[6]: http://www.w3.org/TR/SVG2/painting.html#OrientAttribute

--------------

Proposal 3: Add a `startOffset` attribute to <mPath>, and a `wrap`
attribute for <animateMotion> and <textPath>
--------------

Proposal 4: Allow <mPath> and <textPath> elements to reference basic shapes
--------------

In a thread from December 2012 [7], David Dailey asked if <animateMotion>
could be extended to allow <mPath> elements to reference basic shapes
instead of paths, for example to easily animate circular motion.  In
response, Cameron McCormack and Alex Danilo suggested that it should be
straightforward, given that SVG2 will clearly define the canonical path
representation of every basic shape for stroke dasharray purposes.  However
Dirk Schulze noted that the path start point defined for each shape
wouldn't necessarily be the one you want to use for motion, and there would
need to be an equivalent to the dasharray offset.

There is also use case for an arbitrary offset for animate motion in
general: complex closed paths may be generated by WYSIWIG editors or
geo-data programs in a way that doesn't match the animation goals.  It *is*
possible to create smooth motion along a closed path, from an arbitrary
start point, using keyPoints and keyTimes [8], but it isn't exactly
author-friendly.

The `startOffset` attribute is already defined for <textPath>, and accepts
lengths or percentages of the path length.  I propose re-using the
attribute for <animateMotion>.  I also propose a second attribute, applied
to <textPath> or <animateMotion>, called `wrap`, and accepting one or two
keywords:

- `wrap` or `no-wrap` (default), to indicate whether the motion or text
should continue from the end of the path to the beginning.

- `forward` (default) or `reverse`, meaning that the path should be
followed in reverse direction from how it is defined.  This would be
different from simply running the animation backwards, as the winding order
of the path -- and therefore the auto orientation -- would also be
reversed.  (Anything else would result in backwards text for <textPath>.)


Wrapping would be most useful for closed paths, but would apply to open
paths, in the same way that both motion and text apply to a discontinuous
path.  Reversing would be useful for basic shapes or shapes generated by an
editor, but this is one area where I really don't know how easy or
difficult implementation would be.  Depending on how the relevant
properties or calculated, it might require calculating (and storing in
memory) a completely new path with the reversed geometry.

Finally, it would be clearly specified that `startOffset` could allow any
values, including negative values.  The current <textPath> specifications
(1.1 or 2) don't specifically disallow this, but testing in Chrome showed
that negative values were clamped to 0.  If `wrap` is specified, negative
values or values greater than path length would wrap around logically.  For
`no-wrap` paths, the effect for text of a negative/too large startOffset
would be similar to what happens currently if text extends past the start
or end of the path -- it gets clipped accordingly.  For motion, the
calculated position would be transitioned according to the animation rules,
but the graphic would only be drawn if the position was between 0 and 100%.

Likewise, `keyPoints` on <animateMotion> would allow values outside the
[0,1] interval, with a similar wrapping or clipping effect.  I'm not sure
whether it makes more sense to have `keyPoints` override `startOffset` or
to add the offset to each point.

In the absence of `keyPoints` or `keyTimes` on <animateMotion>:

- `forward no-wrap` (i.e., default) motion would proceed from startOffset
to 100%, interpolated over the full duration of the animation.

- `reverse no-wrap` motion would proceed from startOffset to 0%,
interpolated over the full duration.

- `wrap` motion would proceed over the full length of the wrapped path
(complete loop), in the direction specified.


With this addition, and the canonical definitions of paths for basic
shapes, I don't see any further obstacle to allowing both <mPath> and
<textPath> to reference basic shapes.

[7]: http://lists.w3.org/Archives/Public/www-svg/2012Dec/0101.html
[8]: http://codepen.io/AmeliaBR/pen/ewvrC?editors=110

Received on Tuesday, 14 October 2014 02:55:00 UTC