Peter Rushforth
Peter Rushforth

Reputation: 43

Declaratively stroke a line with a composite line symbol using SVG

Is it possible to create a line symbol definition such that paths can be stroked with a composite stroke? I need to draw lines with the following symbol, and I don't want to have to create two paths to do that.

enter image description here

The spec can be found under "Recreational Boundary" in Feature Specifications, here: CanTopo map symbology definitions

Basically, the stroke has to be a dashed black line with an offset thicker green line underneath it, on the 'inside' of the polyline.

Upvotes: 1

Views: 212

Answers (1)

Michael Mullany
Michael Mullany

Reputation: 31750

You can do this with a morphology filter and some fanciness. This filter works by

  • Starting with a green dash-stroke and red fill
  • Then creating a layer with the red fill set to transparent (just stroke)
  • And a layer with the stroke set to transparent (just fill)
  • Then taking the dash-stroked path and dilating it until the gaps overlap :)
  • Adding a blur and an opacity clip to get a nice path (morphology results are usually pixelated and need a bit of help to look good)
  • Changing the original green stroke path to black
  • Overlaying the newly black stroke path on the fat green line we produced from morphology
  • Clipping the result with the original fill so we get the dash stroke at the edge of the main line rather than the middle.

In all, you're probably better off using two paths. But if you must... :)

<svg width="2000px" height="2000px" viewBox="0 0 4000 4000">
  <defs>
    <filter id="dual-line" primitiveUnits="userSpaceOnUse">
      <feColorMatrix result="just-stroke" type="matrix" values="0 0 0 0 0
                                           0 1 0 0 0 
                                           0 0 1 0 0 
                                           -1 0 0 1 0"/>
      
       <feColorMatrix in="SourceGraphic" result="just-fill" type="matrix" 
                                   values="0 0 0 0 1
                                           0 0 0 0 0 
                                           0 0 0 0 0 
                                           0 0 0 1 0"/>     
      
  
       <feMorphology in="just-stroke" operator="dilate" radius="10"/>
       <feGaussianBlur stdDeviation="6"/>
      <feComponentTransfer result="pre-outer">
        <feFuncA type="table" tableValues="0 0 0 0.95 .95 .95 .95 .95  1">
      </feComponentTransfer>
        
        <feColorMatrix result="blackstroke" in="just-stroke" type="matrix" values=" 0 0 0 0 0
                                                                0 0 0 0 0
                                                                0 0 0 0 0 
                                                                0 0 0 1 0"/>
        
       <feComposite operator="over" in2="pre-outer" in="blackstroke"/>
        <feComposite operator="in" in2="just-fill"/>
   
    </filter>
    </defs>
<g filter="url(#dual-line)">
  <path d="M100 800 C 400 100, 650 100, 950 800 S 1500 1500, 100 800" stroke-width="5" stroke="green" fill="red" stroke-dasharray="25, 5, 3, 5"/>
</g>
</svg>

Upvotes: 2

Related Questions