Markers and all

Hello SVG World,

My name is Maxim and I'm working on the Renesis project, http://gosvg.net

There are serious problems in the SVG specification with markers, such as 
arrowheads. I would say in SVG 1.1 they are totally useless. SVG 1.2 with 
its vectorEffects solves the problem, but it's very complex too.

Markers themselves are very useful to draw diagrams and schemes. But SVG 
specifies them in a pretty useless way and very inefficient in its 
implementation.

First, let us see a simple example:

<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
  "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="4in" height="2in"
     viewBox="0 0 4000 2000" version="1.1"
     xmlns="http://www.w3.org/2000/svg">
  <defs>
    <marker id="Triangle"
      viewBox="0 0 10 10" refX="0" refY="5"
      markerUnits="strokeWidth"
      markerWidth="4" markerHeight="3"
      orient="auto">
      <path d="M 0 0 L 10 5 L 0 10 z" />
    </marker>
  </defs>
  <rect x="10" y="10" width="3980" height="1980"
       fill="none" stroke="blue" stroke-width="10" />
  <desc>Placing an arrowhead at the end of a path.
  </desc>
  <path d="M 1000 750 L 2000 750 2500 1250"
        fill="none" stroke="green" stroke-width="100"
        marker-end="url(#Triangle)"
  />
</svg>

The result is as follows:
http://www.web-zaehler.de/resources/renesis/markers/marker1.png

And we see the first problem.

Problem 1.
It's impossible to draw the marker with the same color as the stroke. So, if 
I need to draw 10 lines with the same marker I still have to define 10 
different markers with colors that correspond to my stroke color.

Problem 2.
The second problem is connected with the first one and it's about a possible 
way of its implementation. Markers are rendered in a way similar to 
patterns. But first let us see, how SVG handles opacity.

<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
  "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="2in" height="2in"
     viewBox="0 0 2000 2000" version="1.1"
     xmlns="http://www.w3.org/2000/svg">
  <ellipse cx="1000" cy="500" rx="200" ry="100"
   stroke-width="100" stroke="red" stroke-opacity="0.5" fill-opacity="0.5"
  />
  <ellipse cx="1000" cy="1000" rx="200" ry="100"
   stroke-width="100" stroke="red" opacity="0.5"
  />
</svg>
http://www.web-zaehler.de/resources/renesis/markers/opacity1.png

The first (upper) ellipse is drawn with opacity=0.5 defined separately for 
the fill and stroke. The second one has "global" opacity=0.5. This 
difference is fundamental, because in the second case we have to create a 
separate buffer, render into it with opacity=1.0, and then blend it with the 
parent one using opacity=0.5. That's very inefficient. Well, theoretically 
we could do that using general vector clipping operations (Constructive Area 
Geometry), but it would be even less efficient in most cases.
And the very same thing is applicable to markers! It means in practice that 
the implementation shall render the marker in a separate buffer (in general 
case) and then put it over the parent buffer using image transformation 
methods (rotation, etc). It's not inefficient, it's terribly inefficient. 
Again, theoretically we could do everything with vectorial representation 
but considering all the details is's so hard that's practically impossible. 
That's that.
The following example illustrates it. Note that the mid-maker is clipped to 
its viewBox, and then rotated. It's not a big deal to clip it in its 
vectorial form and then rotate, but the specification of the opacity makes 
us use a separate buffer anyway.

<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
  "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="4in" height="2in"
     viewBox="0 0 4000 2000" version="1.1"
     xmlns="http://www.w3.org/2000/svg">
  <defs>
    <marker id="Triangle"
      viewBox="0 0 10 10" refX="0" refY="5"
      markerUnits="strokeWidth"
      markerWidth="4" markerHeight="3"
      orient="auto">
      <path d="M 0 0 L 10 5 L 0 10 z" />
    </marker>

    <marker id="Ellipse"
      viewBox="0 0 20 10" refX="10" refY="5"
      markerUnits="strokeWidth"
      markerWidth="4" markerHeight="3"
      orient="auto">
      <ellipse cx="10" cy="5" rx="10" ry="8"
      stroke-width="2" stroke="blue" opacity="0.5"
      />
    </marker>

  </defs>
  <rect x="10" y="10" width="3980" height="1980"
       fill="none" stroke="blue" stroke-width="10" />
  <desc>Placing an arrowhead at the end of a path.
  </desc>
  <path d="M 1000 750 L 2000 750 2500 1250"
        fill="none" stroke="green" stroke-width="100"
        marker-end="url(#Triangle)"
        marker-mid="url(#Ellipse)"
  />
</svg>
http://www.web-zaehler.de/resources/renesis/markers/marker2.png



Problem 3

The "marker-mid" is useles. I saw a lot of diagrams where there are lines 
with arrowheads and some markers in the middle of them. It's a very 
convenient way to display some additional properties (for example of the 
edges of a graph). But I have never saw diagrams with lines (polylines) and 
markers in each vertex of it.

So that, the following example doesn't essentially differ from the previous 
one. I only replaced the "L" command to "Q" (quadric cure). However, the 
middle marker disappeared.

<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
  "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="4in" height="2in"
     viewBox="0 0 4000 2000" version="1.1"
     xmlns="http://www.w3.org/2000/svg">
  <defs>
    <marker id="Triangle"
      viewBox="0 0 10 10" refX="0" refY="5"
      markerUnits="strokeWidth"
      markerWidth="4" markerHeight="3"
      orient="auto">
      <path d="M 0 0 L 10 5 L 0 10 z" />
    </marker>

    <marker id="Ellipse"
      viewBox="0 0 20 10" refX="10" refY="5"
      markerUnits="strokeWidth"
      markerWidth="4" markerHeight="3"
      orient="auto">
      <ellipse cx="10" cy="5" rx="10" ry="8"
      stroke-width="2" stroke="blue" opacity="0.5"
      />
    </marker>

  </defs>
  <rect x="10" y="10" width="3980" height="1980"
       fill="none" stroke="blue" stroke-width="10" />
  <desc>Placing an arrowhead at the end of a path.
  </desc>
  <path d="M 1000 750 Q 2000 750 2500 1250"
        fill="none" stroke="green" stroke-width="100"
        marker-end="url(#Triangle)"
        marker-mid="url(#Ellipse)"
  />
</svg>
http://www.web-zaehler.de/resources/renesis/markers/marker3.png




Problem 4

Markers in practice are mostly arrowheads. And I would like lines with 
arrows to point exactly to the ending coordinates. In other words, I'd like 
line (0,0,10,0) with an arrow to end exactly at point (0,10). I can set the 
reference point of the marker in such a way but it will look inaccurate 
because the line has a certain thickness.

<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
  "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="4in" height="2in"
     viewBox="0 0 4000 2000" version="1.1"
     xmlns="http://www.w3.org/2000/svg">
  <defs>
    <marker id="Triangle"
      viewBox="0 0 10 10" refX="10" refY="5"
      markerUnits="strokeWidth"
      markerWidth="4" markerHeight="3"
      orient="auto">
      <path d="M 0 0 L 10 5 L 0 10 z" />
    </marker>
  </defs>
  <rect x="10" y="10" width="3980" height="1980"
       fill="none" stroke="blue" stroke-width="10" />
  <desc>Placing an arrowhead at the end of a path.
  </desc>
  <path d="M 1000 750 L 2000 750 2500 1250"
        fill="none" stroke="green" stroke-width="100"
        marker-end="url(#Triangle)"
  />
  <circle cx="2500" cy="1250" r="20" fill="red"/>
</svg>
http://www.web-zaehler.de/resources/renesis/markers/marker4.png

The small red circle is the ending point. The only workaround is to shorten 
the path. In SVG 1.2 it's possible applying vectorEffects. In SVG 1.1 it's 
impossible at all. But vectorEffects are also expensive in general because 
they assume creating separate vector buffers for paths.


I suggest to change markers' behaviour in the following way:

1. Markers just add a vector path to the stroke and they are always rendered 
with the current stroke color/gradient/pattern. All color, stroke, and 
opacity properties in the marker definition are ignored.

2. "marker-mid" is always rendered in the middle of the path, but not in 
every vertex of it.

3. Add "shortenPathStart" and "shortenPathEnd" properties to the marker.

McSeem

Received on Wednesday, 22 June 2005 01:30:58 UTC