- From: Maxim Shemanarev <mcseem@antigrain.com>
- Date: Tue, 21 Jun 2005 12:02:49 -0400
- To: <www-svg@w3.org>
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