Lorp / samsa

Variable font inspector
https://lorp.github.io/samsa/
Apache License 2.0
243 stars 23 forks source link

svgPath() method not working like GUI #70

Closed tomasdev closed 2 years ago

tomasdev commented 2 years ago

I have a variable font of icons that have a FILL axis. When trying the same combination of axes values in the inspector (https://lorp.github.io/samsa/src/samsa-gui.html) I get the proper result. When doing it via code, it seems to glitch some curves.

From GUI:

Screen Shot 2022-01-20 at 7 35 18 PM

From svgPath():

<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 960 960">
  <path fill="#000" d="M446 271L521 271L521 438L689 438L689 513L521 513L521 689L446 689L446 513L271 513L271 438L446 438ZM480 61Q391 61 314.5 93Q238 125 181.5 181.5Q125 238 93 314.5Q61 391 61 480Q61 569 93 645.5Q125 722 181.5 778Q238 834 314.5 866.5Q391 899 480 899Q569 899 645.5 866.5Q722 834 778 778Q834 722 866.5 645.5Q899 569 899 480Q899 391 866.5 314.5Q834 238 778 181.5Q722 125 645.5 93Q569 61 480 61M480 153Q344 153 248.5 248.5Q153 344 153 480Q153 615 248.5 711Q344 807 480 807Q615 807 711 711Q807 615 807 480Q807 344 711 248.5Q615 153 480 153M480 139Q620 139 720.5 239Q821 339 821 480Q821 620 720.5 720.5Q620 821 480 821Q339 821 239 720.5Q139 620 139 480Q139 339 239 239Q339 139 480 139"/>
</svg>
Screen Shot 2022-01-20 at 7 46 10 PM

Any tips, pointers?

tomasdev commented 2 years ago

FWIW this is how I generate the SVG:

function getSvgPathData(font, glyph, tuple) {
  const instance = font.instances[0];

  if (!instance) {
    throw new Error('SamsaFont was not able to fetch font instances.');
  }

  let iglyph;

  instance.tuple = tuple;

  if (glyph.numContours < 0) {
    iglyph = glyph.decompose(instance.tuple, undefined);
  } else {
    iglyph = glyph.instantiate(null, instance, undefined);
  }

  const viewbox = getViewbox(iglyph);

  return `<svg xmlns="https://www.w3.org/2000/svg"
        width="32"
        height="32"
        viewBox="0 0 ${viewbox.width} ${viewbox.height}">
    <path d="${iglyph.svgPath()}"/>
  </svg>`
}

And the path from GUI is:

M480 52Q390 52 312.5 85Q235 118 176.5 176.5Q118 235 85 312.5Q52 390 52 480Q52 571 85 649Q118 727 176.5 784.5Q235 842 312.5 875Q390 908 480 908Q571 908 649 875Q727 842 784.5 784.5Q842 727 875 649Q908 571 908 480Q908 390 875 312.5Q842 235 784.5 176.5Q727 118 649 85Q571 52 480 52M437 267L529 267L529 432L693 432L693 523L529 523L529 693L437 693L437 523L267 523L267 432L437 432Z

Quick update: the right sidebar does produce the same artifacts if I create the instance with the given axes, even though the big preview doesn't.

Screen Shot 2022-01-20 at 7 54 42 PM
tomasdev commented 2 years ago

Turns out these lines are important (and the reason for the difference)

  if (font.featureVariations) {
    let substituteGlyphId = glyph.featureVariationsGlyphId(tuple);
    if (substituteGlyphId !== undefined) {
      glyph = font.glyphs[substituteGlyphId];
    }
  }
Lorp commented 2 years ago

Glad you sorted it out. Let me know if you have recommendations for improving the API.

BTW I’m glad to have taken a look at your SVG. It seems that Samsa is not closing subpaths using "Z", when its last point is off-curve. It’s important to use "Z" in all cases in case the path is stroked, otherwise you get end-cap rather than join effects.