SU3
SU3

Reputation: 5387

SVG marker is not displaying completely

I'm trying to get an arrow marker to display at the end of a line, but for some reason, this doesn't work in any browser I have or any graphics viewer or editor, except for Inkscape.

Can anyone tell me what I'm doing wrong?

<?xml version="1.0" encoding="UTF-8" ?>
<svg xmlns="http://www.w3.org/2000/svg"
  viewBox="0 0 500 500" width="500" height="500"
  style="stroke: rgb(0, 0, 0); fill: none; stroke-linecap: round; stroke-linejoin: round;">
  <defs>
    <marker id="arrow" refX="-2.33" refY="0" orient="auto">
      <path d="m 0,0 -5,2 q 1.5,-2 0,-4 z"
        style="fill: rgb(0, 0, 0); stroke-width: 1;"
        transform="scale(0.6667 0.6667)" />
    </marker>
  </defs>

  <g transform="translate(20 20)">
    <path d="m 0,0 100,0" style="stroke-width: 3; marker-end: url(#arrow);" />
  </g>
</svg>

Update

The right viewBox (without scaling the path inside the marker) is "-5.5 -2.5 6 5". The 4 parameters of the viewBox are min-x, min-y, width, and height. They have to take into account whatever stroke-width the marker's elements may have, hence the extra 0.5 that I needed on either side.

Turns out, markerHeight and markerWidth are important to set, because the default value for both is 3. That's why the arrow was coming out too small in my earlier attempt. For 1-to-1 scaling, they should be the same as the last two numbers in the viewBox.

All of the viewBox, markerHeight, and markerWidth need to be adjusted accordingly when scaling elements inside the marker.

Here's a complete solution based on the answer and the comments for posterity:

<svg xmlns="http://www.w3.org/2000/svg"
  viewBox="0 0 30 10" width="300" height="100"
  style="stroke: #000000; fill: none; stroke-linecap: round; stroke-linejoin: round;">
  <defs>
    <marker id="arrow" refX="-1.333" refY="0"
      orient="auto" markerUnits="strokeWidth"
      viewBox="-3.667 -1.667 4 3.333"
      markerWidth="4" markerHeight="3.333"
    >
      <path d="m 0,0 -5,2 q 1.5,-2 0,-4 z"
        style="fill: #000000; stroke-width: 1;"
        transform="scale(0.667)"
      />
    </marker>
  </defs>

  <g transform="translate(5 5)">
    <path d="m 0,0 10,0" style="stroke-width: 1.5; marker-end: url(#arrow);" />
  </g>
  <g transform="translate(25 5)">
    <path d="m 0,0 -5,2 q 1.5,-2 0,-4 z"
      style="fill: rgb(0, 0, 0); stroke-width: 1;" />
  </g>
</svg>

enter image description here

Upvotes: 0

Views: 889

Answers (1)

Robert Longson
Robert Longson

Reputation: 123985

The simplest thing is probably to add a viewBox to the marker so the shape is actually drawn in the marker canvas and not outside it.

<svg xmlns="http://www.w3.org/2000/svg"
  viewBox="0 0 500 500" width="500" height="500"
  style="stroke: rgb(0, 0, 0); fill: none; stroke-linecap: round; stroke-linejoin: round;">
  <defs>
    <marker id="arrow" refX="-2.33" refY="0" orient="auto" viewBox="-3 -3 5 5">
      <path d="m 0,0 -5,2 q 1.5,-2 0,-4 z"
        style="fill: rgb(0, 0, 0); stroke-width: 1;"
        transform="scale(0.6667 0.6667)" />
    </marker>
  </defs>

  <g transform="translate(20 20)">
    <path d="m 0,0 100,0" style="stroke-width: 3; marker-end: url(#arrow);" />
  </g>
</svg>

Upvotes: 2

Related Questions