0

I have one line element and one path element. I would like to merge them into one path element, but I have no experience with svg drawing.

How can I marge these two svg elements into one viewport/viewBox where "top point" of vert-line-2 is joined with y2 of vert-line-1.

enter image description here

.svg-wrapper{
  width: 55px;
  height: 55px;
  font-size: 0;
}

.play-vert-line{
  width: 100%;
}

.line-join{
  position: relative;
  left: 25px;
  fill: none;
}
<div class="svg-wrapper">
   <svg class="play-vert-line" height="17">
      <defs>
         <linearGradient id="vert-gradient" gradientUnits="userSpaceOnUse" y1="0%" y2="100%" x1="0" x2="0">
            <stop stop-color="#3A9AFC"></stop>
            <stop stop-color="#3c3c3c"></stop>
         </linearGradient>
      </defs>
      <line id="vert-line-1" x1="50%" y1="0" x2="50%" y2="17" stroke="url(#vert-gradient)" stroke-width="2"></line>
   </svg>
   <svg class="line-join" height="15" width="15" viewBox="-1.3 0 15 15">
      <defs>
         <linearGradient id="vert-join-gradient" gradientUnits="userSpaceOnUse" y2="100%" x1="0" x2="0">
            <stop stop-color="#3A9AFC"></stop>
            <stop stop-color="#3c3c3c"></stop>
         </linearGradient>
      </defs>
      <path id="vert-line-2" d="M 11, 10 C 5, 10, 1, 6, 1, 0" stroke="url(#vert-join-gradient)" stroke-width="2"></path>
   </svg>
</div>
Matt
  • 8,195
  • 31
  • 115
  • 225
  • Define "merge". – ccprog Mar 01 '18 at 12:34
  • I mean creating one `path` element that looks exactly like `line` and `path` in code snippet. – Matt Mar 01 '18 at 12:47
  • Inkscape for example offers merge and union methods in its GUI: http://goinkscape.com/how-to-merge-objects-in-inkscape/ – feeela Mar 01 '18 at 12:55
  • The two are not part of the same viewport (root svg element). Define the geometrical relation between the two viewports. Discuss what happens on viewport resize, as the first one gives width in percentage. – ccprog Mar 01 '18 at 12:57
  • Thanks for the response, I edited my question again. `Viewport` should look like in the screenshot and "top point" of `path` is joined with `y2` attribute of `line`. – Matt Mar 01 '18 at 13:42

1 Answers1

5

Let's walk you through this step by step.

Resolve linear gradients

The linear gradients defining the strokes both have <stop> child elements that lack offset attributes. Thus, they are all at the default value 0. The net effet is that, since all parts of the stroke are on the positive side of the gradient vector origin, the strokes have a uniform color of #3c3c3c. fill:none has been moved to an attribute.

<div class="svg-wrapper">
   <svg class="play-vert-line" height="17">
      <line id="vert-line-1" x1="50%" y1="0" x2="50%" y2="17" stroke="#3c3c3c" stroke-width="2"></line>
   </svg>
   <svg class="line-join" height="15" width="15" viewBox="-1.3 0 15 15">
      <path id="vert-line-2" d="M 11, 10 C 5, 10, 1, 6, 1, 0"
            stroke="#3c3c3c" stroke-width="2" fill="none"></path>
   </svg>
</svg>

Move the two <svg> elements in one parent <svg>

div.svg-wrapper is exchanged for a svg element of the same size (55*55), and the two svgs are placed inside, positioned and sized as defined by the stylesheet. All Percentage values at this point are exchanged for absolute values.

It should be noted that formally, the inner svgs must define a overflow="hidden" attribute (implicitely defining a clip-path). It can be safely left off, since the grafical elements do not overflow their viewport.

<svg class="svg-wrapper" width="55" height="55" viewBox="0 0 55 55">
   <svg class="play-vert-line" height="17" width="55">
      <line id="vert-line-1" x1="27.5" y1="0" x2="27.5" y2="17" stroke="#3c3c3c" stroke-width="2"></line>
   </svg>
   <svg class="line-join" x="25" y="17" height="15" width="15" viewBox="-1.3 0 15 15">
      <path id="vert-line-2" d="M 11, 10 C 5, 10, 1, 6, 1, 0"
            stroke="#3c3c3c" stroke-width="2" fill="none"></path>
   </svg>
</svg>

Compute the equivalent transform of the child <svg>s

At this point, the inner svgs have their own viewports and own coordinate system. The transformation to the parent viewport can be computed following this algorithm. Then, the <svg> elements can be exchanged for <g> elements.

If there had been overflow, a clip-path attribute would have been necessary.

<svg class="svg-wrapper" width="55" height="55" viewBox="0 0 55 55">
   <g class="play-vert-line">
      <line id="vert-line-1" x1="27.5" y1="0" x2="27.5" y2="17" stroke="#3c3c3c" stroke-width="2"></line>
   </g>
   <g class="line-join" transform="translate(26.3, 17)">
      <path id="vert-line-2" d="M 11, 10 C 5, 10, 1, 6, 1, 0"
            stroke="#3c3c3c" stroke-width="2" fill="none"></path>
   </g>
</svg>

Apply the transform and convert line to path

Effectively, only the <path> element has transform applied. The group elements can be removed, and in the d attribute, every coordinate has to be recomputed: x' = x + dx, y' = y + dy.

To transform <line> to <path>, the d attribute must be written using the start and end coordinates of the line:

d="M <x1> <y1> L <x2> <y2>"

(The L command can be left off, as it is implied.)

<svg class="svg-wrapper" width="55" height="55" viewBox="0 0 55 55">
    <path id="vert-line-1" d="M 27.5 0 27.5 17" stroke="#3c3c3c" stroke-width="2"></path>
    <path id="vert-line-2" d="M 36.3, 27 C 31.3, 27, 27.3, 23, 27.3, 17"
          stroke="#3c3c3c" stroke-width="2" fill="none"></path>
</svg>

Merging and joing the two path elements

Since the two path elements are now expressed in the same coordinate systems and have the same presentation attributes (don't forget fill="none"), the d attributes can now simply be concatenated:

d="M 27.5 0 27.5 17 M 36.3, 27 C 31.3, 27, 27.3, 23, 27.3, 17"

Joining them has one further complication. The first subpath starts at the upper end, but the second starts on the lower. To join them in a top-to-bottom direction, the direction of the second subpath has to be reversed. In the special case of a C command, all coordinates can simply be reversed in order. For other commands (especially relative path commands), this could be more complicated.

d="M 27.5 0 27.5 17 M 27.3, 17 C 27.3, 23, 31.3, 27, 36.3, 27"

You did't say how to join the two subpaths. Let's assume a straight line.

<svg class="svg-wrapper" width="55" height="55" viewBox="0 0 55 55">
    <path id="vert-line" d="M 27.5 0 27.5 17 L 27.3, 17 C 27.3, 23, 31.3, 27, 36.3, 27"
          stroke="#3c3c3c" stroke-width="2" fill="none"></path>
</svg>
ccprog
  • 20,308
  • 4
  • 27
  • 44
  • Thank you for help. I wouldn't figure out this solution by myself. – Matt Mar 01 '18 at 14:43
  • I hope you learned that only the very, very special conditions of you use case made a solution even possible. – ccprog Mar 01 '18 at 14:46
  • Absolutely, I just changed the `viewport` to `width="100%" height="100%" viewBox="0 0 100 100"` and it works in relative units. – Matt Mar 02 '18 at 08:53