Search code examples
javascripthtmlsvgmathjax

SVG Path incorrect size and position


I am generating an SVG document and have a library generating SVG from LaTeX.

<svg xmlns="http://www.w3.org/2000/svg" version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:svgjs="http://svgjs.dev/svgjs" width="500px" height="300px" id="svgSurface">
   <svg viewBox="0 -883.9 1186.6 883.9" x="0" y="0" width="100">
      <defs>
         <path id="MJX-1-TEX-N-31" d="M213 578L200 573Q186 568 160 563T102 556H83V602H102Q149 604 189 617T245 641T273 663Q275 666 285 666Q294 666 302 660V361L303 61Q310 54 315 52T339 48T401 46H427V0H416Q395 3 257 3Q121 3 100 0H88V46H114Q136 46 152 46T177 47T193 50T201 52T207 57T213 61V578Z"></path>
         <path id="MJX-1-TEX-N-48" d="M128 622Q121 629 117 631T101 634T58 637H25V683H36Q57 680 180 680Q315 680 324 683H335V637H302Q262 636 251 634T233 622L232 500V378H517V622Q510 629 506 631T490 634T447 637H414V683H425Q446 680 569 680Q704 680 713 683H724V637H691Q651 636 640 634T622 622V61Q628 51 639 49T691 46H724V0H713Q692 3 569 3Q434 3 425 0H414V46H447Q489 47 498 49T517 61V332H232V197L233 61Q239 51 250 49T302 46H335V0H324Q303 3 180 3Q45 3 36 0H25V46H58Q100 47 109 49T128 61V622Z"></path>
      </defs>
      <g stroke="currentColor" fill="currentColor" stroke-width="0" transform="matrix(1,0,0,-1,0,0)">
         <g data-mml-node="math">
            <g data-mml-node="msup">
               <g data-mml-node="mi"></g>
               <g data-mml-node="TeXAtom" transform="translate(33,413) scale(0.707)" data-mjx-texclass="ORD">
                  <g data-mml-node="mn">
                     <use data-c="31" xlink:href="#MJX-1-TEX-N-31"></use>
                  </g>
               </g>
            </g>
            <g data-mml-node="mtext" transform="translate(436.6,0)">
               <use data-c="48" xlink:href="#MJX-1-TEX-N-48"></use>
            </g>
         </g>
      </g>
   </svg>
</svg>

It is essentially a group which references a path in defs. I want to be able to resize the entire embedded SVG part. I set the x and y, nothing happens, I set the width to 100 and it resizes, not to 100 but to 90.something and changes the height too? I understand <g> fills its container, but it appears to be effecting the container too?

https://jsfiddle.net/thk9cago/

I expect the content in the embedded SVG to resize and position subject to the x, y and width properties.


Solution

  • The first thing to note is that the embedded SVG has a viewBox attribute, which has several consequences. First, it means that if you specify one of its dimensions and not the other, then the second dimension will be scaled to maintain the aspect ratio, just as happens with an image. So when you set the width to 100, the height is scaled as well.

    Second, it means that the positioning of the nested SVG is determined by the preserveAspectRatio attribute. This says how to place and scale the nested SVG within the surrounding one. The default is xMidYMid, which should center the nested SVG within the outer one. Apparently, however, setting width overrides the x positioning, and it ends up left-aligned (similarly, setting height would override the default y positioning). You may want to use preserveAspectRatio="xMinYMin" to have the nested svg places at the upper left-hand corner:

    <svg xmlns="http://www.w3.org/2000/svg" version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:svgjs="http://svgjs.dev/svgjs" width="500px" height="300px" id="svgSurface" style="background-color: yellow; border: 1px solid black">
       <svg viewBox="0 -883.9 1186.6 883.9" x="0" y="0" width="100" preserveAspectRatio="xMinYMin">
          <defs>
             <path id="MJX-1-TEX-N-31" d="M213 578L200 573Q186 568 160 563T102 556H83V602H102Q149 604 189 617T245 641T273 663Q275 666 285 666Q294 666 302 660V361L303 61Q310 54 315 52T339 48T401 46H427V0H416Q395 3 257 3Q121 3 100 0H88V46H114Q136 46 152 46T177 47T193 50T201 52T207 57T213 61V578Z"></path>
             <path id="MJX-1-TEX-N-48" d="M128 622Q121 629 117 631T101 634T58 637H25V683H36Q57 680 180 680Q315 680 324 683H335V637H302Q262 636 251 634T233 622L232 500V378H517V622Q510 629 506 631T490 634T447 637H414V683H425Q446 680 569 680Q704 680 713 683H724V637H691Q651 636 640 634T622 622V61Q628 51 639 49T691 46H724V0H713Q692 3 569 3Q434 3 425 0H414V46H447Q489 47 498 49T517 61V332H232V197L233 61Q239 51 250 49T302 46H335V0H324Q303 3 180 3Q45 3 36 0H25V46H58Q100 47 109 49T128 61V622Z"></path>
          </defs>
          <g stroke="currentColor" fill="currentColor" stroke-width="0" transform="matrix(1,0,0,-1,0,0)">
             <g data-mml-node="math">
                <g data-mml-node="msup">
                   <g data-mml-node="mi"></g>
                   <g data-mml-node="TeXAtom" transform="translate(33,413) scale(0.707)" data-mjx-texclass="ORD">
                      <g data-mml-node="mn">
                         <use data-c="31" xlink:href="#MJX-1-TEX-N-31"></use>
                      </g>
                   </g>
                </g>
                <g data-mml-node="mtext" transform="translate(436.6,0)">
                   <use data-c="48" xlink:href="#MJX-1-TEX-N-48"></use>
                </g>
             </g>
          </g>
       </svg>
    </svg>

    Your x and y attributes are working, but they are relative to the default position (which in your case was flush left and centered vertically). With the xMinYMin setting, they are relative to the upper left, as in the following example:

    <svg xmlns="http://www.w3.org/2000/svg" version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:svgjs="http://svgjs.dev/svgjs" width="500px" height="300px" id="svgSurface" style="background-color: yellow; border: 1px solid black">
       <svg viewBox="0 -883.9 1186.6 883.9" x="150" y="75" width="100" preserveAspectRatio="xMinYMin">
          <defs>
             <path id="MJX-1-TEX-N-31" d="M213 578L200 573Q186 568 160 563T102 556H83V602H102Q149 604 189 617T245 641T273 663Q275 666 285 666Q294 666 302 660V361L303 61Q310 54 315 52T339 48T401 46H427V0H416Q395 3 257 3Q121 3 100 0H88V46H114Q136 46 152 46T177 47T193 50T201 52T207 57T213 61V578Z"></path>
             <path id="MJX-1-TEX-N-48" d="M128 622Q121 629 117 631T101 634T58 637H25V683H36Q57 680 180 680Q315 680 324 683H335V637H302Q262 636 251 634T233 622L232 500V378H517V622Q510 629 506 631T490 634T447 637H414V683H425Q446 680 569 680Q704 680 713 683H724V637H691Q651 636 640 634T622 622V61Q628 51 639 49T691 46H724V0H713Q692 3 569 3Q434 3 425 0H414V46H447Q489 47 498 49T517 61V332H232V197L233 61Q239 51 250 49T302 46H335V0H324Q303 3 180 3Q45 3 36 0H25V46H58Q100 47 109 49T128 61V622Z"></path>
          </defs>
          <g stroke="currentColor" fill="currentColor" stroke-width="0" transform="matrix(1,0,0,-1,0,0)">
             <g data-mml-node="math">
                <g data-mml-node="msup">
                   <g data-mml-node="mi"></g>
                   <g data-mml-node="TeXAtom" transform="translate(33,413) scale(0.707)" data-mjx-texclass="ORD">
                      <g data-mml-node="mn">
                         <use data-c="31" xlink:href="#MJX-1-TEX-N-31"></use>
                      </g>
                   </g>
                </g>
                <g data-mml-node="mtext" transform="translate(436.6,0)">
                   <use data-c="48" xlink:href="#MJX-1-TEX-N-48"></use>
                </g>
             </g>
          </g>
       </svg>
    </svg>

    The width is also working, but note that what is being scaled is the viewBox, not the bounding box of the content, which may be larger or smaller. Note that in your case, it looks like you have used something like {}^1\mathrm{H} to obtain your output, so there is a little space before the superscript 1, as TeX puts a little space between the base (even when empty) and the superscript. You can see this in the following example, that just has the inner SVG with a background color.

       <svg viewBox="0 -883.9 1186.6 883.9" width="100" style="background-color:red">
          <defs>
             <path id="MJX-1-TEX-N-31" d="M213 578L200 573Q186 568 160 563T102 556H83V602H102Q149 604 189 617T245 641T273 663Q275 666 285 666Q294 666 302 660V361L303 61Q310 54 315 52T339 48T401 46H427V0H416Q395 3 257 3Q121 3 100 0H88V46H114Q136 46 152 46T177 47T193 50T201 52T207 57T213 61V578Z"></path>
             <path id="MJX-1-TEX-N-48" d="M128 622Q121 629 117 631T101 634T58 637H25V683H36Q57 680 180 680Q315 680 324 683H335V637H302Q262 636 251 634T233 622L232 500V378H517V622Q510 629 506 631T490 634T447 637H414V683H425Q446 680 569 680Q704 680 713 683H724V637H691Q651 636 640 634T622 622V61Q628 51 639 49T691 46H724V0H713Q692 3 569 3Q434 3 425 0H414V46H447Q489 47 498 49T517 61V332H232V197L233 61Q239 51 250 49T302 46H335V0H324Q303 3 180 3Q45 3 36 0H25V46H58Q100 47 109 49T128 61V622Z"></path>
          </defs>
          <g stroke="currentColor" fill="currentColor" stroke-width="0" transform="matrix(1,0,0,-1,0,0)">
             <g data-mml-node="math">
                <g data-mml-node="msup">
                   <g data-mml-node="mi"></g>
                   <g data-mml-node="TeXAtom" transform="translate(33,413) scale(0.707)" data-mjx-texclass="ORD">
                      <g data-mml-node="mn">
                         <use data-c="31" xlink:href="#MJX-1-TEX-N-31"></use>
                      </g>
                   </g>
                </g>
                <g data-mml-node="mtext" transform="translate(436.6,0)">
                   <use data-c="48" xlink:href="#MJX-1-TEX-N-48"></use>
                </g>
             </g>
          </g>
       </svg>

    The DOM inspector may be giving you the width of the content, not the viewBox, which is about 91px.

    Finally, note that if you give both width and height attributes, the aspect ration is maintained (as is required by the default preserveAspectRatio setting), so even though the svg element will have a different size, the contents will have the original aspect ratio and will scale to the largest size that fits within the width and height settings. For example:

       <svg viewBox="0 -883.9 1186.6 883.9" width="75" height="150" style="background-color:red">
          <defs>
             <path id="MJX-1-TEX-N-31" d="M213 578L200 573Q186 568 160 563T102 556H83V602H102Q149 604 189 617T245 641T273 663Q275 666 285 666Q294 666 302 660V361L303 61Q310 54 315 52T339 48T401 46H427V0H416Q395 3 257 3Q121 3 100 0H88V46H114Q136 46 152 46T177 47T193 50T201 52T207 57T213 61V578Z"></path>
             <path id="MJX-1-TEX-N-48" d="M128 622Q121 629 117 631T101 634T58 637H25V683H36Q57 680 180 680Q315 680 324 683H335V637H302Q262 636 251 634T233 622L232 500V378H517V622Q510 629 506 631T490 634T447 637H414V683H425Q446 680 569 680Q704 680 713 683H724V637H691Q651 636 640 634T622 622V61Q628 51 639 49T691 46H724V0H713Q692 3 569 3Q434 3 425 0H414V46H447Q489 47 498 49T517 61V332H232V197L233 61Q239 51 250 49T302 46H335V0H324Q303 3 180 3Q45 3 36 0H25V46H58Q100 47 109 49T128 61V622Z"></path>
          </defs>
          <g stroke="currentColor" fill="currentColor" stroke-width="0" transform="matrix(1,0,0,-1,0,0)">
             <g data-mml-node="math">
                <g data-mml-node="msup">
                   <g data-mml-node="mi"></g>
                   <g data-mml-node="TeXAtom" transform="translate(33,413) scale(0.707)" data-mjx-texclass="ORD">
                      <g data-mml-node="mn">
                         <use data-c="31" xlink:href="#MJX-1-TEX-N-31"></use>
                      </g>
                   </g>
                </g>
                <g data-mml-node="mtext" transform="translate(436.6,0)">
                   <use data-c="48" xlink:href="#MJX-1-TEX-N-48"></use>
                </g>
             </g>
          </g>
       </svg>

    If you want to scale both dimensions independently, you need to use preserveAspectRatio="none".

       <svg viewBox="0 -883.9 1186.6 883.9" width="75" height="150" preserveAspectRatio="none" style="background-color:red">
          <defs>
             <path id="MJX-1-TEX-N-31" d="M213 578L200 573Q186 568 160 563T102 556H83V602H102Q149 604 189 617T245 641T273 663Q275 666 285 666Q294 666 302 660V361L303 61Q310 54 315 52T339 48T401 46H427V0H416Q395 3 257 3Q121 3 100 0H88V46H114Q136 46 152 46T177 47T193 50T201 52T207 57T213 61V578Z"></path>
             <path id="MJX-1-TEX-N-48" d="M128 622Q121 629 117 631T101 634T58 637H25V683H36Q57 680 180 680Q315 680 324 683H335V637H302Q262 636 251 634T233 622L232 500V378H517V622Q510 629 506 631T490 634T447 637H414V683H425Q446 680 569 680Q704 680 713 683H724V637H691Q651 636 640 634T622 622V61Q628 51 639 49T691 46H724V0H713Q692 3 569 3Q434 3 425 0H414V46H447Q489 47 498 49T517 61V332H232V197L233 61Q239 51 250 49T302 46H335V0H324Q303 3 180 3Q45 3 36 0H25V46H58Q100 47 109 49T128 61V622Z"></path>
          </defs>
          <g stroke="currentColor" fill="currentColor" stroke-width="0" transform="matrix(1,0,0,-1,0,0)">
             <g data-mml-node="math">
                <g data-mml-node="msup">
                   <g data-mml-node="mi"></g>
                   <g data-mml-node="TeXAtom" transform="translate(33,413) scale(0.707)" data-mjx-texclass="ORD">
                      <g data-mml-node="mn">
                         <use data-c="31" xlink:href="#MJX-1-TEX-N-31"></use>
                      </g>
                   </g>
                </g>
                <g data-mml-node="mtext" transform="translate(436.6,0)">
                   <use data-c="48" xlink:href="#MJX-1-TEX-N-48"></use>
                </g>
             </g>
          </g>
       </svg>

    I hope that clarifies the situation that you are experiencing.