Re: Rendering of stroke-dasharray in special situations

Dear Olaf Hoffmann,

Thank you for your useful feedback on stroke-dash issues. First let us 
clarify that the WG sees stroke-dashing only as a pattern or sequence of 
dashes and gaps. Pattern not in a sense of the pattern
feature present in the SVG 1.1 full profile.

Additional comments are inside your text.

> Hello,
> Testing the animation abilities of SVG-viewers I recognised
> several difficulties with stroke-dasharray in special situations
> and in combination with other properties as stroke-linecap and
> stroke-linejoin.
> Some of them are just surprising, because it is clear for me with
> the specification, but wrong in many or all SVG-viewers,
> maybe because much information related to stroke-dasharray
> can just be found somewhere else in the specification, but
> not in the stroke-dasharray section.
> Complete defined and correct rendering of stroke-dasharray
> is difficult, because it is complex.
> Therefore maybe it is useful for developers and authors to
> clarify stroke-dasharray rendering to get soon consistent
> behaviour of different SVG-viewers.

> 1. Rendering of subpaths
> Should the stroke-dasharray pattern restart with the
> initial value of the pattern with the beginning of a
> subpath or should it continue with the pattern?
> In the stroke-dasharray section of the specification (1.1)
> it is not mentioned, how to handle the continuation of dasharray
> in subpaths, but in the path chapter we find in the moveto
> section (8.3.2):
> 'The "moveto" commands (M or m) establish a new current point.
> The effect is as if the "pen" were lifted and moved to a new location.'
> This sounds more as a continuation of dasharray as like a restart,
> but it is a very weak hint.
> Defines the specification with a certain behaviour for this case
> somewhere else?
> If not, can we interprete the quote as continuation?
> Shouldn't the stroke-dasharray section clarify the behaviour
> explicitly?
> Example:
> <path
>    d="M50,100 L850,100
>          M50,200 L850,200
>          M50,300 L850,300"
>    stroke="#00f" fill="none"
>    stroke-width="30"
>    stroke-dasharray="800,200" />
> Should the visual effect be like (behaviour of gecko 1.8...):
> <g  stroke="#00f" fill="none"
>        stroke-width="30"
>        stroke-dasharray="800,200">
> <path d="M50,100 L850,100" />
> <path d="M50,200 L850,200" stroke-dashoffset="-200" />
> <path d="M50,300 L850,300" stroke-dashoffset="-400" />
> </g>
> or like (behaviour of Opera, Adobe plugin):
> <g  stroke="#00f" fill="none" stroke-width="30">
> <path d="M50,100 L850,100" />
> <path d="M50,200 L850,200" />
> <path d="M50,300 L850,300" />
> </g>

The working group discussed this issue and found it worthwile specifying 
it in a future version of the full profile but doesn't want to dictate a 
behaviour in SVG 1.2  tiny. The reason is that viewer implementations 
often don't handle stroke-dashing themselvers but pass the path geometry 
to the underlying rendering library which handles the stroke-dashing. It 
would not be feasible for constrained mobile devices to split paths into 
subpaths for full control of the dashing behaviour.

We added wording to the specification, however, to recommend an SVG Tiny 
1.2 implementation to restart the stroke-dashoffset from scratch for 
each path segment taking into account the initial stroke-dashoffset 
value, with a note that SVG 1.2 Full might be stricter on this issue. 
This is a currently a should and not a must.

> 2. Definition of intervals for dashes and gaps
> If we have stroke-dasharray="800,200"
> belongs 800 to the dash or to the gap?
> This is getting important for stroke-dashoffset
> for paths with subpaths and for paths with edges
> and corners and for animation.
> I think it is useful to define this similar as for time
> intervals  in animation, this means in this example
> 0 belongs to a dash, 800 to a gap, 1000 to a dash
> and so on.

The specification states: "'stroke-dasharray' specifies the pattern of
dashes and gaps that shall be used to stroke paths. <dasharray> contains
a list of comma-separated (with optional white space) <length>s that
specify the lengths of alternating dashes and gaps that must be used."

This clearly states that an implementation must start with a dash and
continue with a gap. We think that the specification is clear enough and
that we don't need any additional wording. Additionally, the existing
implementations all handle this stroke-dash behaviour consistently.

> 3. Rendering of stroke-linecap
> The stroke-dasharray section defines dasharray as a
> pattern of dashes and gaps (therefore the dashes
> are no subpaths).
> Should the pattern continued forward and backward
> into the linecaps or should the stroke-linecap have the
> same behaviour as the related point of the stroke?
> Example:
> Should
> <path d="M100,100 L900,100"
>    stroke="#00f" fill="none"
>    stroke-width="160"
>    stroke-dasharray="40,40"
>    stroke-linecap="square" />
> look like
> <path d="M20,100 L980,100"
>    stroke="#00f" fill="none"
>    stroke-width="160"
>    stroke-dasharray="40,40"
>    stroke-linecap="butt" />
> or like
> <g stroke="#00f" fill="none" stroke-width="160">
> <path d="M100,100 L900,100" stroke-dasharray="40,40" />
> <path d="M20,100 L100,100" />
> </g>
> ?
> I prefer the first case, but this can get
> a little bit more complicate with stroke-linecap="round"
> and it needs a special rule for (sub)paths of zero length
> like

The working group believes that "dash-caps" should currently behave like
"linecaps" at the end of lines or paths.  It is however, true that this
behaviour is not yet exactly specified. This also implies that the
sequence of dashes and gaps does not apply for the "dash-caps".

We added the following sentence to the definition of the
stroke-dasharray attribute to clarify the behaviour:

"The computed value of the attribute 'stroke-linecap' shall be applied
to each dash when the attribute 'stroke-dasharray' is set to a value
other than 'none'."

> <path d="M100,100 L100,100"
>    stroke="#00f" fill="none"
>    stroke-width="160"
>    stroke-dasharray="40,40"
>    stroke-linecap="round" />
> (or with d="M100,100 z", both in
> combination with stroke-dasharray more
> useful as a subpath, not as a complete path
> of course).
> For this special case either the stroke-dasharray
> should be ignored or the value of  stroke-dasharray
> pattern at the position in the subpath should be
> used. Alternatively a radial pattern might be useful,
> using circular dashes. Then a starting position for
> the pattern has to be defined, either at r=0 or at
> r=stroke-width/2.

The spec already clarifies this behaviour in the definition of the
"stroke" attribute:

"A subpath (see Paths) consisting of a single moveto shall not be
stroked. A subpath consisting of a moveto and lineto to the same exact
location or a subpath consisting of a moveto and a closepath shall not
be stroked if the 'stroke-linecap' property has a value of butt and
shall be stroked if the 'stroke-linecap' property has a value of round
or square, producing respectively a circle or a square centered at the
given point."

Note that the working draft currently available to the public reads
slightly different in that we did not specify what happens in the case
of "square" linecaps. This is now addressed in the most recent working
draft as written above.

> 4. Rendering of stroke-linejoin (especially miter)
> If the path is not continuously differentiable
> (normally this means, there is a corner) at a
> point with a border between a dash and a gap,
> how should the stroke-linejoin be rendered?
> If we use the interval definition from 2, the
> behaviour of the pattern can be applied to the
> stroke-linejoin. Or should the stroke-linejoin
> be divided along the bisecting line half with a
> dash and half with a gap? Or should the
> stroke-dasharray be continued in the direction
> of the bisecting line?
> A detailed definition is especially useful for
> animation.
> And some examples for such an area with
> a border between a dash and a gap near such
> a corner might be very helpful for developers
> and authors to understand, how such corners
> have to look with different values for stroke-with
> and stroke-dasharray.

Good point. The working group discussed this issue. Most SVG tiny 
implementors can't control the behavior of the rendering library in this 
case, though. Therefore we decided not to dictate a behavior and revisit 
this issue when working on SVG 1.2 full.

> 5. stroke-dasharray as a pattern
> Many SVG-viewers display the dashes as something
> like subpathes (but not the gaps), but in the
> specification it is defined as a pattern.
> Therefore it seems to be useful to explicitly mention that:
> a) stroke-linecaps have not to be applied to the dashes
> and gaps themselves. If this is needed, in the
> specification 1.2 or 1.3 additional properties should
> be defined as stroke-dashcap and stroke-gapcap or
> more general something like stroke-dashborder and
> stroke-gapborder
> (this could define the behaviour of the border
> between a dash and a gap or a gap and a dash
> especially perpendicular to the stroke in more detail).
> b) the stroke-dasharray pattern is never outside of
> the stroke (if the pattern is covered with an identical
> path without a stroke-dasharray, nothing of the
> pattern will get visible.
> Other things happen, if stroke-linecap="square" is
> applied to the dashes).
> But if the specification does not mean stroke-dasharray as
> a (one-dimensional) pattern along a path, just as a
> simplification for defining subpaths, the words
> pattern, dash and gap should be avoided and
> replaced by subpath to avoid further confusion.

See answer to point 1 above (definition of pattern of dashes and gaps).

For the full profile it would be interesting to add an additional
attribute as you propose (stroke-dashcap), but for SVG 1.2 we don't want
to introduce this new attribute.


Andreas Neumann
Institute of Cartography
ETH Zurich
Wolfgang-Paulistrasse 15
CH-8093  Zurich, Switzerland

Phone: ++41-44-633 3031, Fax: ++41-44-633 1153

Received on Tuesday, 27 June 2006 09:45:40 UTC