SVG inverse marker mask/clip-path - svg

I've tried unsuccessfully to replace the white triangle, the marker-start, with an inverse mask/clip-path in order to cut the end of the arrow in shape of the marker instead of painting it white.
Not sure if marker masks can be defined.
<svg xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg" id="mySVG" viewBox="-100 0 200 200" height="600" width="700">
<defs>
<marker refY="0.5" refX="0.0" markerHeight="4" markerWidth="2" orient="auto" id="head">
<path fill="#D0D0D0" d="M0,0 L0.5,0.5 L0,1 L-0.5,0.5 Z"/>
</marker>
<marker refY="0.6" refX="0.1" markerHeight="4" markerWidth="2" orient="auto" id="tail">
<clip-Path id="cp1" d="M0 0 V1.3 L0.6 0.6 Z">
<path fill="white" d="M0 0 V1.3 L0.6 0.6 Z" />
<clip-Path>
</marker>
</defs>
<path id="myArrow" marker-start="url(#tail)" marker-end="url(#head)" d="M -66.38265586443396 22.21132594835645 A 70 70 0 0 0 66.38265586443396 22.21132594835645" fill="none" stroke="#D0D0D0" stroke-width="8" clip-path="url(#cp1)"/>

Markers are independent symbols which are positioned and drawn at the various points in the path after the path has been drawn.
It sounds like you are trying to use them to clip out bits of the path. This is futile. That's not how markers work, I'm afraid.

Related

Using clip-path to remove 37px from 4 svg lines in the circle

What I'm trying to do is remove the svg lines in the middle of the circle.
How would this be done using clip-path?
Taking this:
https://i.imgur.com/DGX3Yji.png
And turning it to this:
https://i.imgur.com/gg4XFUq.png
Code:
https://jsfiddle.net/5r1dg4hx/3/
https://i.imgur.com/SGzGzaE.png
<svg class="stack" aria-hidden="true" width="260" height="194" viewbox="0 0 260 194">
<line stroke="teal" x1="131" y1="40" x2="130" y2="149"></line>
<line stroke="dodgerblue" x1="91" y1="133" x2="170" y2="58"></line>
<line stroke="purple" x1="77" y1="95" x2="185" y2="96"></line>
<line stroke="green" x1="169" y1="135" x2="93" y2="56"></line>
<circle class="outer" cx="131" cy="95" r="55"></circle>
<circle cx="130" cy="95.40" r="20.8"></circle>
You will need to draw a path with a hole for the clipping path:
<path d="M0,0 0,194 260,194 260,0 0,0
M150.8, 95.40A20.8, 20.8 0 0 1 109.2 95.40A20.8, 20.8 0 0 1 150.8, 95.40" />
The first part of the path (M0,0 0,194 260,194 260,0 0,0) is drawing a rectangle as big as the svg canvas. The second part (M150.8, 95.40A20.8, 20.8 0 0 1 109.2 95.40A20.8, 20.8 0 0 1 150.8, 95.40) is drawing a circle as big as the inner circle and in the same position.
Next you wrap the lines in a group and you clip the group.
svg{border:1px solid;}
circle{fill:none;stroke:black}
<svg class="stack" aria-hidden="true" width="260" height="194" viewbox="0 0 260 194">
<defs>
<clipPath id="clip">
<path d="M0,0 0,194
260,194 260,0 0,0 M150.8, 95.40A20.8, 20.8 0 0 1 109.2 95.40A20.8, 20.8 0 0 1 150.8, 95.40" />
</clipPath>
</defs>
<g clip-path="url(#clip)">
<line stroke="teal" x1="131" y1="40" x2="130" y2="149"></line>
<line stroke="dodgerblue" x1="91" y1="133" x2="170" y2="58"></line>
<line stroke="purple" x1="77" y1="95" x2="185" y2="96"></line>
<line stroke="green" x1="169" y1="135" x2="93" y2="56"></line>
</g>
<circle class="outer" cx="131" cy="95" r="55"></circle>
<circle cx="130" cy="95.40" r="20.8"></circle>
</svg>

svg object didn't work along with the path Why not?

Why didn't work along with path line?
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="595px" height="841px" viewBox="0 0 595px 841px" enable-background="new 0 0 595 841" xml:space="preserve"
style="border:1px solid green">
<g id="car">
<path fill="#00CC92" d="M405.1,607.225c0,0,1.731-1.022,9.084-1.086c0.466-0.007,9.269-8.254,9.678-8.561
c0.99-0.767,1.194-1.284,3.667-1.476c3.028,0,20.601-0.025,20.601-0.025s6.229-0.332,7.736,2.434
c0.479,0.575,4.434,7.237,4.503,7.596c0,0,0.135,0.159,0.333,0.498c0.472,0.805,1.341,3.723,1.813,6.777
c0.052,0.191,0.09,0.383,0.09,0.588v3.354c0,1.232-1.003,2.236-2.236,2.236h-0.102c0.064-0.365,0.102-0.734,0.102-1.119
c0-3.705-3.002-6.707-6.707-6.707s-6.707,3.002-6.707,6.707c0,0.385,0.038,0.754,0.103,1.119h-29.271
c0.064-0.365,0.103-0.734,0.103-1.119c0-3.705-3.003-6.707-6.708-6.707s-6.707,3.002-6.707,6.707c0,0.385,0.038,0.754,0.103,1.119
h-2.338c-1.233,0-2.236-1.004-2.236-2.236v-3.354C400.002,613.97,399.728,610.13,405.1,607.225z M442.483,605.027l11.307-0.556
l-1.246-2.798c0,0-0.767-2.235-3.354-2.235s-6.707,0-6.707,0V605.027z M421.076,606.298l3.296-0.217
c0.716-1.591,1.546-2.459,2.306-2.612c0.92-0.192,1.311,0.798,1.311,0.798v1.571l12.258-0.805v-5.558
c0,0-10.725-0.038-11.843-0.038s-2.689,1.954-2.689,1.954L421.076,606.298z M458.133,618.441c0,2.473-1.999,4.473-4.472,4.473
s-4.472-2-4.472-4.473c0-2.471,1.999-4.471,4.472-4.471S458.133,615.97,458.133,618.441z M415.653,618.441
c0,2.473-1.999,4.473-4.472,4.473c-2.472,0-4.472-2-4.472-4.473c0-2.471,2-4.471,4.472-4.471
C413.654,613.97,415.653,615.97,415.653,618.441z">
</path>
</g>
<path fill="none" id="motionPath" stroke="green" stroke-width="8"
d="M400,618c0,0-127,66-112-52s134-264-90-251s-63-117-56-170"></path>
<animateMotion xlink:href="#car" dur="5s" begin="click" fill="freeze" >
<mpath xlink:href="#motionPath"></mpath>
</animateMotion>
</svg>
The problem you are having is due to the fact that the position of the car on the page is added to the (animated) position along the path. So when you click the car, it jumps to effectively:
(motionPath.x + car.x, motionPath.y + car.y)
To fix this, you have to do one of two things:
position the motion path so it starts at (0,0) on the page (the top left), or
position the car at (0,0).
Since you want the car to start where it is on the page, so you can click on it, you are basically forced to choose option #1.
In the example below I've changed the motion path to one that starts at (0,0). I've just used a simple line because I don't have the time to work out the new coordinates for your whole path.
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="595px" height="841px" viewBox="0 0 595px 841px" enable-background="new 0 0 595 841" xml:space="preserve"
style="border:1px solid green">
<g>
<path id="car"
fill="#00CC92" d="M405.1,607.225c0,0,1.731-1.022,9.084-1.086c0.466-0.007,9.269-8.254,9.678-8.561
c0.99-0.767,1.194-1.284,3.667-1.476c3.028,0,20.601-0.025,20.601-0.025s6.229-0.332,7.736,2.434
c0.479,0.575,4.434,7.237,4.503,7.596c0,0,0.135,0.159,0.333,0.498c0.472,0.805,1.341,3.723,1.813,6.777
c0.052,0.191,0.09,0.383,0.09,0.588v3.354c0,1.232-1.003,2.236-2.236,2.236h-0.102c0.064-0.365,0.102-0.734,0.102-1.119
c0-3.705-3.002-6.707-6.707-6.707s-6.707,3.002-6.707,6.707c0,0.385,0.038,0.754,0.103,1.119h-29.271
c0.064-0.365,0.103-0.734,0.103-1.119c0-3.705-3.003-6.707-6.708-6.707s-6.707,3.002-6.707,6.707c0,0.385,0.038,0.754,0.103,1.119
h-2.338c-1.233,0-2.236-1.004-2.236-2.236v-3.354C400.002,613.97,399.728,610.13,405.1,607.225z M442.483,605.027l11.307-0.556
l-1.246-2.798c0,0-0.767-2.235-3.354-2.235s-6.707,0-6.707,0V605.027z M421.076,606.298l3.296-0.217
c0.716-1.591,1.546-2.459,2.306-2.612c0.92-0.192,1.311,0.798,1.311,0.798v1.571l12.258-0.805v-5.558
c0,0-10.725-0.038-11.843-0.038s-2.689,1.954-2.689,1.954L421.076,606.298z M458.133,618.441c0,2.473-1.999,4.473-4.472,4.473
s-4.472-2-4.472-4.473c0-2.471,1.999-4.471,4.472-4.471S458.133,615.97,458.133,618.441z M415.653,618.441
c0,2.473-1.999,4.473-4.472,4.473c-2.472,0-4.472-2-4.472-4.473c0-2.471,2-4.471,4.472-4.471
C413.654,613.97,415.653,615.97,415.653,618.441z">
</path>
</g>
<path fill="none" id="motionPath" stroke="green" stroke-width="8"
d="M 0,0 L -250,-470" transform="translate(431,609)"></path>
<animateMotion xlink:href="#car" dur="5s" begin="click" fill="freeze" >
<mpath xlink:href="#motionPath"></mpath>
</animateMotion>
</svg>
You may be wondering why, if the motion path has been moved, why it still being displayed in the same place? The reason is that is that I've added a transform to the motion path so the start corresponds to the centre of the car, which is at approximately (431,609). This doesn't affect the animateMotion because it only cares about what's in the d attribute. It ignores the transform attribute.
Update
Another alternative is to just position both the path and the car so that they start at (0,0). Then wrap the whole thing in a group that you transform to the final position. That allows you to also use the rotate attribute in your animation.
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
width="595px" height="841px" viewBox="0 0 595 841"
style="border:1px solid green">
<g transform="translate(431,609)">
<g id="car">
<path transform="translate(-431,-626)"
fill="#00CC92" d="M405.1,607.225c0,0,1.731-1.022,9.084-1.086c0.466-0.007,9.269-8.254,9.678-8.561
c0.99-0.767,1.194-1.284,3.667-1.476c3.028,0,20.601-0.025,20.601-0.025s6.229-0.332,7.736,2.434
c0.479,0.575,4.434,7.237,4.503,7.596c0,0,0.135,0.159,0.333,0.498c0.472,0.805,1.341,3.723,1.813,6.777
c0.052,0.191,0.09,0.383,0.09,0.588v3.354c0,1.232-1.003,2.236-2.236,2.236h-0.102c0.064-0.365,0.102-0.734,0.102-1.119
c0-3.705-3.002-6.707-6.707-6.707s-6.707,3.002-6.707,6.707c0,0.385,0.038,0.754,0.103,1.119h-29.271
c0.064-0.365,0.103-0.734,0.103-1.119c0-3.705-3.003-6.707-6.708-6.707s-6.707,3.002-6.707,6.707c0,0.385,0.038,0.754,0.103,1.119
h-2.338c-1.233,0-2.236-1.004-2.236-2.236v-3.354C400.002,613.97,399.728,610.13,405.1,607.225z M442.483,605.027l11.307-0.556
l-1.246-2.798c0,0-0.767-2.235-3.354-2.235s-6.707,0-6.707,0V605.027z M421.076,606.298l3.296-0.217
c0.716-1.591,1.546-2.459,2.306-2.612c0.92-0.192,1.311,0.798,1.311,0.798v1.571l12.258-0.805v-5.558
c0,0-10.725-0.038-11.843-0.038s-2.689,1.954-2.689,1.954L421.076,606.298z M458.133,618.441c0,2.473-1.999,4.473-4.472,4.473
s-4.472-2-4.472-4.473c0-2.471,1.999-4.471,4.472-4.471S458.133,615.97,458.133,618.441z M415.653,618.441
c0,2.473-1.999,4.473-4.472,4.473c-2.472,0-4.472-2-4.472-4.473c0-2.471,2-4.471,4.472-4.471
C413.654,613.97,415.653,615.97,415.653,618.441z">
</path>
</g>
<path fill="none" id="motionPath" stroke="green" stroke-width="8"
d="M 0,0 L -250,-470"/>
<animateMotion xlink:href="#car" dur="5s" begin="click" fill="freeze"
rotate="auto-reverse">
<mpath xlink:href="#motionPath"></mpath>
</animateMotion>
</g>
</svg>

SVG absolute line marker size

I've got a bunch of SVGs representing a trip using a polyline.
I'm using non-scaling-stroke vector effect to make sure that each of the polylines is rendered with an absolute width. So when the viewBox's dimension changes, the width of the polyline does not.
At the ends of the mentioned polylines, I wanted to put markers. I would like to have the markers absolutely sized as well. I thought this should be easy by setting the marker units to strokeWidth.
In contrast to what happens with the stroke of the polyline, the size of the markers at the end of a polyline, does change along with the size of the viewBox.
Below I've included an example in where I used simple circles for markers.
<svg preserveAspectRatio="xMidYMid" xmlns="http://www.w3.org/2000/svg" viewBox="131890.80533333332 85178.93015415945 198.25991111111944 205.10300513348193">
<defs>
<marker id="end" markerHeight="4" markerUnits="strokeWidth" markerWidth="4" orient="0deg" refX="8" refY="16" viewBox="0 0 16 20">
<circle cx="8" cy="16" fill="#000" r="4"></circle>
</marker>
<marker id="start" markerHeight="4" markerUnits="strokeWidth" markerWidth="4" orient="0deg" refX="8" refY="16" viewBox="0 0 16 20">
<circle cx="8" cy="16" fill="#000" r="4"></circle>
</marker>
</defs>
<g>
<polyline fill="none" marker-end="url(#end)" marker-start="url(#start)" stroke="#000" stroke-linejoin="round" stroke-width="3" vector-effect="non-scaling-stroke" points="132089.06524444444, 85384.03315929293 131890.80533333332, 85178.93015415945">
</polyline>
</g>
</svg>
<svg preserveAspectRatio="xMidYMid" xmlns="http://www.w3.org/2000/svg" viewBox="132038.56071111112 85364.68902323228 50.557866666669725 19.330493533576373">
<defs>
<marker id="end" markerHeight="4" markerUnits="strokeWidth" markerWidth="4" orient="0deg" refX="8" refY="16" viewBox="0 0 16 20">
<circle cx="8" cy="16" fill="#000" r="4"></circle>
</marker>
<marker id="start" markerHeight="4" markerUnits="strokeWidth" markerWidth="4" orient="0deg" refX="8" refY="16" viewBox="0 0 16 20">
<circle cx="8" cy="16" fill="#000" r="4"></circle>
</marker>
</defs>
<g>
<polyline fill="none" marker-end="url(#end)" marker-start="url(#start)" stroke="#000" stroke-linejoin="round" stroke-width="3" vector-effect="non-scaling-stroke" points="132038.56071111112, 85364.68902323228 132089.1185777778, 85384.01951676585">
</polyline>
</g>
</svg>
See also: https://jsfiddle.net/u4bmupza/3/
Am I missing some SVG attributes or should I calculate the size of the markers manually?
vector-effect="non-scaling-stroke was first introduced in SVG 1.2 Tiny. That was a subset of SVG intended for for mobile devices with limited power. SVG 1.2 didn't have markers, so this issue wasn't a problem.
vector-effect was about the only thing from SVG 1.2 Tiny that browsers ended up implementing. Unfortunately, this problem was obviously missed at that time, and I guess no one has bothered to report it as a bug. Though I've seen it asked about on S.O. previously.
The good news is that the SVG2 spec specifically notes it as something that should be addressed, though that doesn't help you now.

Can strokes be used as part of clip-paths in SVGs?

I am in the middle of writing SVG output from MuPDF, and I've run up against what seems to be a limitation in the capabilities of SVG. I thought I'd ask here in case this was a known problem with a known workaround (or in case I'm doing something stupid!)
I have the following SVG:
<?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 xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="21.59cm" height="27.94cm" viewBox="0 0 600 600">
<path stroke-width="12" fill="none" stroke="#0000ff" d="M 150 300 L 80 300 L 80 370 L 150 370 " />
<clipPath id="cp0">
<path stroke-width="12" fill="none" stroke="#000000" d="M 150 300 L 80 300 L 80 370 L 150 370 " />
</clipPath>
<g clip-path="url(#cp0)">
<rect fill="#ff0000" x="0" y="0" width="600" height="600"/>
</g>
</svg>
This draws a stroked path (shaped like '[' in blue). Then it sets the same path to be a clipping path, and fills the clipping path in red.
I was hoping that the clipping path would be set to the stroked version of the path, and hence the red shape would exactly overwrite the blue one. In my tests here however, the "fill or strokedness" of the path is ignored, and the path is "filled" - hence I get a red square drawn within the blue shape.
Is there a way to get the behaviour I was hoping for? Or am I going to have to write code to manually flatten and stroke paths before outputting them to SVG?
Thanks in advance for any replies!
Clip-paths in svg are meant to be just the shape, not the traits of the shape, so in other words you'll not get the stroke included. What you can do is use a mask instead, setting the stroke of the path in the mask to white.
Here's an example:
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" viewBox="0 0 600 600">
<defs>
<mask id="m0" maskUnits="userSpaceOnUse" x="0" y="0" width="600" height="600">
<path fill="none" stroke="white" stroke-width="5" d="M 150 300 L 80 300 L 80 370 L 150 370" />
</mask>
</defs>
<path stroke-width="12" fill="none" stroke="#0000ff" d="M 150 300 L 80 300 L 80 370 L 150 370 " />
<g mask="url(#m0)">
<rect fill="yellow" x="0" y="0" width="600" height="600" />
</g>
</svg>

Image not shown as svg marker

I have written the following code to display a triangle at the end of polyline and an image at the start of that.
Running this svg it just shows the triangle at the end but the image is not being displayed.
What am i missing here...
<svg width="120" height="120" viewBox="0 0 120 120"
xmlns="http://www.w3.org/2000/svg" version="1.1"
xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<marker id="Image"
viewBox="0 0 10 10"
refX="5" refY="5"
markerWidth="6"
markerHeight="6"
orient="auto">
<path d="M 0 0 L 10 10 L 10 0 L 0 0 z" />
</marker>
</defs>
<polyline points="10,90 50,80 90,20"
fill="none" stroke="black"
stroke-width="2"
marker-end="url(#Triangle)" marker-start="url(#Image)"/>
</svg>
There is no marker with the id Triangle, so it isn't showing that. It is therefore only showing the Image marker (which happens to be a triangle).

Resources