17

I have a little svg widget whose purpose is to display a list of angles (see image).

Right now, the angles are line elements, which only have a stroke and no fill. But now I'd like to have an "inside fill" color and a "stroke/border" around it. I'm guessing the line element can't handle this, so what should I use instead?

Notice that the line-endcap of the line's stroke is rounded. I'd like to maintain this effect in the solution.

Angle Line

<svg height="160" version="1.1" viewBox="-0.6 -0.6 1.2 1.2" width="160" xmlns="http://www.w3.org/2000/svg">
  <g>
    <g>
      <circle class="sensorShape" cx="0" cy="0" fill="#FFF" r="0.4" stroke="black" stroke-width="0.015"/>
      <line stroke="black" stroke-width="0.015" x1="0" x2="0" y1="-0.4" y2="0.4"/>
      <line stroke="black" stroke-width="0.015" x1="-0.4" x2="0.4" y1="0" y2="0"/>
    </g>
    <g class="lsNorthAngleHandsContainer">
      <line data-angle="348" stroke="red" stroke-linecap="round" stroke-width="0.04" transform="rotate(348)" x1="0" x2="0" y1="0" y2="-0.4"/>
      <text font-size="0.08" transform="translate(-0.02316467632710395,-0.45125904029352226)">
        348
      </text>
    </g>
  </g>
</svg>
Tony R
  • 11,224
  • 23
  • 76
  • 101

5 Answers5

23

Add a second line, with same coordinates but thinner line width:

<g class="lsNorthAngleHandsContainer">
  <line data-angle="348" stroke="red" stroke-linecap="round" stroke-width="0.04" transform="rotate(348)" x1="0" x2="0" y1="0" y2="-0.4"/>
  <line data-angle="348" stroke="yellow" stroke-linecap="round" stroke-width="0.025" transform="rotate(348)" x1="0" x2="0" y1="0" y2="-0.4"/>
Janne
  • 979
  • 4
  • 13
5

I found elegant solution inspired by illustration to W3C article about filling and stroking. Basically, you move path to definitions and use this definition to draw two elements:

<svg width="200" height="200" viewBox="0 0 100 100">
    <defs>
        <line id="line1" x1="25" x2="75" y1="25" y2="75"/>
    </defs>
    <use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#line1" class="stroke"></use>
    <use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#line1" class="line"></use>
</svg>

By using <defs> and <use> you can change only path element to update both lines. JSFiddle demo

kirschpirogge
  • 357
  • 4
  • 12
4

It looks like your line is opaque, so you can just draw a thin line with the "inside" color on top of the thicker line with the "outside" color.

Gabe
  • 84,912
  • 12
  • 139
  • 238
  • Thanks, that's a good idea. But how would I make sure that the "top" line is centered exactly in the center of the "bottom" line? – Tony R Jan 13 '12 at 03:17
  • 1
    Just use the same coordinates with a thinner line width. With rounded caps it will look correct. – Janne Jan 13 '12 at 03:31
  • Ah, now that I think about it I believe you are correct! Thanks Janne. – Tony R Jan 13 '12 at 03:33
3

You could use a rect with rounded corners, but the math changes a bit:

  <rect data-angle="348" stroke="red" stroke-linecap="round" stroke-width="0.02" fill="#FF0" transform="rotate(348, 0, 0)" x="-0.02"  y="-0.4" width=".06" height=".4" rx=".03" ry=".03"/>

http://jsfiddle.net/RNAuP/

methodofaction
  • 70,885
  • 21
  • 151
  • 164
  • That's what I originally thought the solution would be. However, yours doesn't look as good as Janne's. The start and end points of the rect aren't lining up perfectly at the center of the circle and on the circle outline. – Tony R Jan 13 '12 at 03:41
  • If you can get it to line up correctly this solution seems easier to manipulate (say if I wanted to dynamically add/remove the outline, which I do). So, this becomes unwieldy for a different reason... you have to use the midpoint of each "short side" of the rect. – Tony R Jan 13 '12 at 03:43
  • It's a question of arithmetic, you must substract the border width from the rotation center http://jsfiddle.net/F5e74/, I frankly believe that two lines is a more simple solution. – methodofaction Jan 13 '12 at 03:49
  • Ya! That's a little better, but it still isn't perfect... Originally I had the center of the half-circle endpoint lining up with the center of the big circle and its outline. +1 for the effort =) – Tony R Jan 13 '12 at 03:54
0

You can also do it with a path, even though it's tricky around the round bits:

<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" [
  <!-- I often use entities to be able to change lot of numbers at once in static SVG, also kind of makes the paths more readable.
       Obvisouly, if you're generating the path you can use the same variables in code to append to d -->
  <!ENTITY handFill "0.01">
  <!ENTITY handFill2 "0.02"><!-- Should be 2 * handFill to be centered -->
  <!ENTITY handStroke "0.005"><!-- Should be less than handFill2 to not hide fill -->
]>
<svg height="160" version="1.1" viewBox="-0.6 -0.6 1.2 1.2" width="160" xmlns="http://www.w3.org/2000/svg">
  <g>
    <g>
      <circle class="sensorShape" cx="0" cy="0" fill="#FFF" r="0.4" stroke="black" stroke-width="0.015"/>
      <line stroke="black" stroke-width="0.015" x1="0" x2="0" y1="-0.4" y2="0.4"/>
      <line stroke="black" stroke-width="0.015" x1="-0.4" x2="0.4" y1="0" y2="0"/>
    </g>
    <g class="lsNorthAngleHandsContainer">
      <path d="
        M -&handFill;,0 l0,-0.4
        a &handFill;,&handFill; 0 0,1 &handFill2;,0
        l 0,0.4
        a &handFill;,&handFill; 0 0,1 -&handFill2;,0
      " stroke="red" stroke-linecap="round" stroke-width="&handStroke;" fill="yellow" transform="rotate(348)" />
      <text font-size="0.08" transform="translate(-0.02316467632710395,-0.45125904029352226)">
        348
      </text>
    </g>
  </g>
</svg>
TWiStErRob
  • 44,762
  • 26
  • 170
  • 254