Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Cut out one SVG <path> out of another one

Tags:

image

vector

svg

I have several SVG paths looking like this:

M204.21121687607624,196.94037184487675L329.92080751248244,195.46306542867487A130,130,0,0,0,244.46261863233696,77.83995929783192Z
M198.39145828733604,195.04941765207442L235.83285625620988,75.03597952801854A130,130,0,0,0,97.55860203112616,119.9640082076644Z

I now want to add another path, but, instead of adding it to the shape, cut it out from the previous paths. How can I accomplish this?

I couldn't find any information on this in the SVG docs - thanks for your help!

like image 296
eWolf Avatar asked Dec 17 '22 22:12

eWolf


1 Answers

To expand on Tobias Snoad's answer, picking up the pen with the Move command and drawing a second shape in the opposite direction (as Brian Hempel pointed out), will remove that section from the original path. This is due to the fill-rule:evenodd (default) as explained in this answer.

Here's an example that will draw a 10x10 box and then reverse a 6x6 box inside it:

<svg xmlns="http://wwww3org/2000/svg" height="200" viewBox="0,0,10,10">
  <path d="M 0,0 h 10 v 10 h -10 z
           M 2,2 v  6 h  6 v  -6 z" /> 
</svg>

Which will produce the second box in the image below, with each point numbered and arrowed so you can see direction:

Path Orientation

Here's a running demo is Stack Snippets

svg path.shape {
  fill: green;
  stroke: #1b1b1b;
  stroke-width: .5px;
}
svg path.arrow {
  fill: yellow;
  stroke: black;
  stroke-width: .1px;
}
svg text {
  font-size: .8px;
  font-family: monospace;
  stroke: navy;
  stroke-width: .1px;
  text-anchor: middle;
  alignment-baseline: middle;
}
svg circle {
  r: .5;
  stroke: navy;
  stroke-width: .1px;
  fill: yellow;
}
<svg xmlns="http://wwww3org/2000/svg" height="200" viewBox="-2,-2,14,14">

  <defs>
    <marker id='arrow' orient="auto"  
          refX='-.9' refY='1'
          markerWidth='2' markerHeight='2' >
      <!-- triangle pointing right (+x) -->
      <path d='M 0,0 V 2 L 1,1 Z' class="arrow"/>
    </marker>
  </defs>    

  <path d="M 0,0 h 10 v 10 h -10 z
           M 2,2 h  6 v  6 h  -6 z"  
        marker-mid='url(#arrow)' class="shape" />
                             
    <circle cx="0" cy="0" />                  
    <text    x="0"  y="0" > 1</text>    
    <circle cx="10" cy="0" />                  
    <text    x="10"  y="0" > 2</text>  
    <circle cx="10" cy="10" />                  
    <text    x="10"  y="10" > 3</text>  
    <circle cx="0" cy="10" />                  
    <text    x="0"  y="10" > 4</text>  
    <circle cx="2" cy="2" />                  
    <text    x="2"  y="2" > 5</text>  
    <circle cx="8" cy="2" />                  
    <text    x="8"  y="2" > 6</text>  
    <circle cx="8" cy="8" />                  
    <text    x="8"  y="8" > 7</text>  
    <circle cx="2" cy="8" />                  
    <text    x="2"  y="8" > 8</text>  
</svg>

<svg xmlns="http://wwww3org/2000/svg" height="200" viewBox="-2,-2,14,14">
 
  <path d="M 0,0 h 10 v 10 h -10 z
           M 2,2 v  6 h  6 v  -6 z" 
        marker-mid='url(#arrow)' class="shape" /> 
   
    <circle cx="0" cy="0" />                  
    <text    x="0"  y="0" > 1</text>    
    <circle cx="10" cy="0" />                  
    <text    x="10"  y="0" > 2</text>  
    <circle cx="10" cy="10" />                  
    <text    x="10"  y="10" > 3</text>  
    <circle cx="0" cy="10" />                  
    <text    x="0"  y="10" > 4</text>  
    <circle cx="2" cy="2" />                  
    <text    x="2"  y="2" > 5</text>  
    <circle cx="2" cy="8" />                  
    <text    x="2"  y="8" > 6</text>      
    <circle cx="8" cy="8" />                  
    <text    x="8"  y="8" > 7</text>  
    <circle cx="8" cy="2" />                  
    <text    x="8"  y="2" > 8</text>  
</svg>

SVG Path Command Refresher

Two Variations:

  • M 100,150 Uppercase (Absolute) - Move to exact coordinates 100,150 (x,y)
  • m 100,150 Lowercase (Relative) - Move the pen 100 down and 150 right of where you are

Straight Commands:

  • M x,y - Pick the pen up and Move it to the point x,y
  • L x,y - Draw a straight Line to the point x,y
  • H x - Draw a line Horizontally to the right by x
  • V y - Draw a line Vertically down by y
  • Z|z - Closes the path by drawing a straight line back to the start (last M location)
    NOTE: Z is completely optional - it's just a shortcut to get back to the starting point

Curved Commands:

  • C cX1,cY1 cX2,cY2 eX,eY - Draw a Bezier Curve based on Two bezier controls point and end at the coordinates eX,eY
  • S cX2,cY2 eX,eY - Draw a Simplifed Curve based on the previous S|C control point and One specified bezier control point and end at the coordinates eX,eY
  • Q cX2,cY2 eX,eY - Draw a Quadratic Curve based on One bezier control point and end at the coordinates eX,eY
  • T eX,eY - Draw a Terminal Quadratic Curve based on the previous bezier control point and end at the coordinates eX,eY
  • A rX,rY rotation, arc, sweep, eX,eY - Draw an Elliptical Arc for an oval with the specified width rX and height rY. Define the rotation with degrees and direction with 0|1 for arc and sweep and end at the coordinates eX,eY

TIP: In most instances you can simplify the precision of any automatically generated path points without sacrificing any human discernibility, even when scaled heavily. You can do a regex find ([0-9]*)(\.[0-9]*) and replace with $1 to remove any trailing decimals. You can also format each command on it's own line with find \s*([a-zA-z])\s* and replace with \n$1 .

Further Reading:

  • MDN - SVG Tutorial Paths
  • The SVG path Syntax: An Illustrated Guide
  • How to place arrow head triangles on SVG lines?
  • How To Create SVG Arrowheads and Polymarkers
  • SVG center text in circle
like image 155
KyleMit Avatar answered Mar 05 '23 03:03

KyleMit