Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ECharts server-side rendering SVG contains invalid font property #16127

Closed
htr3n opened this issue Nov 28, 2021 · 22 comments
Closed

ECharts server-side rendering SVG contains invalid font property #16127

htr3n opened this issue Nov 28, 2021 · 22 comments
Labels
bug en This issue is in English

Comments

@htr3n
Copy link

htr3n commented Nov 28, 2021

Version

5.2.2 (and 5.2.1)

Reproduction link

https://codesandbox.io/s/echarts-ssr-uxfju

Steps to reproduce

  1. Create a server-side rendering of ECharts (5.2.2) with JsDOM and Node Canvas
  2. Configure to render a simple chart to SVG
const echarts = require("echarts");
const { JSDOM } = require("jsdom");
const { createCanvas } = require("canvas");
const fs = require("fs");

const config = {
  option: {
    animation: false,
    fontSize: 10,
    fontFamily: "Arial",
    xAxis: {
      data: ["1493190351122"],
      axisLabel: {
        fontSize: 10,
        fontFamily: "Arial"
      }
    },
    yAxis: {
      name: "Y Axis",
      type: "value",
      nameTextStyle: {
        fontWeight: "bold",
        fontSize: 10,
        fontFamily: "Arial"
      }
    },
    series: [
      {
        type: "line",
        name: "Series 1",
        data: [39]
      }
    ]
  }
};

function render() {
  const ctx = createCanvas(1920, 1080);

  if (ctx) {
    ctx.font = "Arial";
  }

  echarts.setCanvasCreator(() => {
    return ctx;
  });

  const virtualDom = new JSDOM();
  global.window = virtualDom.window;
  global.document = virtualDom.window.document;
  const root = global.document.createElement("div");
  if (root) {
    root.style.cssText = "width: 1920px; height: 1080px;";
    Object.defineProperty(root, "clientWidth", { value: 1920 });
    Object.defineProperty(root, "clientHeight", { value: 1080 });
    let chart = echarts.init(root, null, {
      width: 1920,
      height: 1080,
      renderer: "svg"
    });
    if (chart) {
      chart.setOption(config.option);
      let result = root.querySelector("svg")?.outerHTML ?? null;
      chart.dispose();
      return result;
    }
  }
  return null;
}

const buffer = render();
console.log(buffer);

fs.writeFile(`output.svg`, buffer, function (err) {
  if (err) return console.log(err);
});

What is expected?

  1. The SVG <text> elements should have the correct font family as specified.
  2. The <text> elements inside the resulting SVG should have valid font specification inside style="".
<text xml:space="preserve" style="font: normal sans-serif 12px;">

What is actually happening?

  1. The SVG <text> elements do not have the correct font family as specified.
  2. The SVG's <text> elements contain invalid font specification so that the SVG text will be rendered incorrectly.
<text xml:space="preserve" style="font: sans-serif 12px normal normal normal 12px;">

Per CSS font property (see https://developer.mozilla.org/en-US/docs/Web/CSS/font), it should be

[ [ <'font-style'> || <font-variant-css21> || <'font-weight'> || <'font-stretch'> ]? <'font-size'> [ / <'line-height'> ]? <'font-family'> ] | caption | icon | menu | message-box | small-caption | status-bar

I found this bug when I tried to configure the Y axis nameTextStyle to bold and small size and realised that the font styles and weight I set there do not affect the outcome at all.

This issue is only seen with server-side rendering. I use an identical configuration for a React front-end, it works fine, produces valid CSS.

<text xml:space="preserve"
  fill="#101010"
  fill-opacity="1"
  stroke="none"
  transform="matrix(0,-1,1,0,27,122)"
  dominant-baseline="central"
  text-anchor="middle"
  x="0"
  y="-8.5"
  style="font: bold normal normal 12px Arial;">Axis Title
</text>
@echarts-bot
Copy link

echarts-bot bot commented Nov 28, 2021

Hi! We've received your issue and please be patient to get responded. 🎉
The average response time is expected to be within one day for weekdays.

In the meanwhile, please make sure that it contains a minimum reproducible demo and necessary images to illustrate. Otherwise, our committers will ask you to do so.

A minimum reproducible demo should contain as little data and components as possible but can still illustrate your problem. This is the best way for us to reproduce it and solve the problem faster.

You may also check out the API and chart option to get the answer.

If you don't get helped for a long time (over a week) or have an urgent question to ask, you may also send an email to [email protected]. Please attach the issue link if it's a technical question.

If you are interested in the project, you may also subscribe to our mailing list.

Have a nice day! 🍵

@echarts-bot echarts-bot bot added bug en This issue is in English pending We are not sure about whether this is a bug/new feature. waiting-for: community labels Nov 28, 2021
@htr3n htr3n changed the title ECharts server-side rendering SVG contains invalid font style specification ECharts server-side rendering SVG contains invalid font property Nov 28, 2021
@htr3n
Copy link
Author

htr3n commented Nov 29, 2021

After a few tests around setting font for server-side ECharts rendering, I realised it's pretty broken. For instance, I set the fontFamily property of chart option as 'Liberation Sans' which is available on Linux/AWS Node.js Lambda. The rendering produces something like style="font: Sans 9px normal normal normal 9px;", which drops Liberation. Due to spaces?

@htr3n
Copy link
Author

htr3n commented Nov 29, 2021

Just to confirm the bug regarding a font family with spaces. When I set fontFamily to FreeSans, it's correctly rendered to style="font: FreeSans 9px normal normal normal 9px;" in the <text> elements of the resulting SVG.

@plainheart
Copy link
Member

plainheart commented Nov 29, 2021

The font issue has been raised by #15064 and we've improved it in ecomfe/zrender#836. Please feel free to try to build from the next branch and then check if it works. Also, we add a new SSR in #15880, which needs no third-party framework to work.

If you don't want to build manually, you can also use the nightly version.

@htr3n
Copy link
Author

htr3n commented Nov 29, 2021

@plainheart thanks for your info. Unfortunately, the nightly build breaks my current implementation which worked fine with 5.2.2. The new built-in feature SSR looks interesting though. I will look into it.

@plainheart
Copy link
Member

Made a simple example, it's easy enough to get started. https://codepen.io/plainheart/pen/RwLbqye

@htr3n
Copy link
Author

htr3n commented Nov 29, 2021

Confirm that the font issue seems to be fixed with "echarts-nightly": "^5.3.0-dev.20211128". I'm wondering, when do you plan to release 5.3? Thanks

@plainheart
Copy link
Member

plainheart commented Nov 29, 2021

Thanks for your confirmation. Maybe about 1 month.

@plainheart plainheart removed the pending We are not sure about whether this is a bug/new feature. label Nov 29, 2021
@htr3n
Copy link
Author

htr3n commented Dec 1, 2021

@plainheart a bit off topic but the new SSR function with renderToSVGString() requires that echarts.init() must have width and height (maybe the same when using canvas). The generated SVG has width and height, how does that scale when fixed width and height are set? Does that defeat the purpose of SVG, supposed to be scalable? Thanks

@pissang
Copy link
Contributor

pissang commented Dec 1, 2021

@htr3n We are considering providing an option that can use viewBox instead of fixed width and height.

@htr3n
Copy link
Author

htr3n commented Dec 15, 2021

@pissang @plainheart Regarding the nightly build that you recommended, I've noticed a strange issue. I tried to load the legend icons as dataURI per documentation here: https://echarts.apache.org/en/option.html#legend.data.icon. The dataURI is a wrapper for an SVG icon.

    legend: {
        show: true,
        data: [
            {
                name: 'LegendIcon',
                icon: 'image://data:image/svg+xml;base64,PHN2ZyB4bWxuc....'
            }
        ]
    }

I use the same code on my React UI and it can be rendered successfully. But the new nightly build server-side rendering implementation renderToSVGString() raised an error: ReferenceError: HTMLImageElement is not defined. It seems it could not load the dataURI?

    "echarts-nightly": "^5.3.0-dev.20211212",

Updated:

If I replace the dataURI 'image://data:image/svg...' with SVG path, for instance, taken from ECharts web site

icon: 'path://M30.9,53.2C16.8,53.2,5.3,41.7,5.3,27.6S16.8,2,30.9,2C45,2,56.4,13.5,56.4,27.6S45,53.2,30.9,53.2z M30.9,3.5C17.6,3.5,6.8,14.4,6.8,27.6c0,13.3,10.8,24.1,24.101,24.1C44.2,51.7,55,40.9,55,27.6C54.9,14.4,44.1,3.5,30.9,3.5z M36.9,35.8c0,0.601-0.4,1-0.9,1h-1.3c-0.5,0-0.9-0.399-0.9-1V19.5c0-0.6,0.4-1,0.9-1H36c0.5,0,0.9,0.4,0.9,1V35.8z M27.8,35.8 c0,0.601-0.4,1-0.9,1h-1.3c-0.5,0-0.9-0.399-0.9-1V19.5c0-0.6,0.4-1,0.9-1H27c0.5,0,0.9,0.4,0.9,1L27.8,35.8L27.8,35.8z'

then it works.

My wild guess is that, the dataURI needs a Canvas to render properly?

In case of using SVG path data, path://M... is not sufficient to set SVG styles such as stroke (colour) and stroke-width.

@plainheart
Copy link
Member

@htr3n
Copy link
Author

htr3n commented Dec 16, 2021

@plainheart Does that mean my guess is correct? The legend icon needs a Canvas to render properly, doesn't it?

@htr3n
Copy link
Author

htr3n commented Dec 16, 2021

Perhaps I can provide more details into the error after catching it

Failed to render graph due to ReferenceError: HTMLImageElement is not defined
    at brushSVGImage (/.../lambda/node_modules/echarts-nightly/dist/echarts.js:41046:30)
    at brush$1 (/.../lambda/node_modules/echarts-nightly/dist/echarts.js:41131:20)
    at SVGPainter._paintList (/.../lambda/node_modules/echarts-nightly/dist/echarts.js:41772:31)
    at SVGPainter.renderToVNode (/.../lambda/node_modules/echarts-nightly/dist/echarts.js:41692:18)
    at SVGPainter.renderToString (/.../lambda/node_modules/echarts-nightly/dist/echarts.js:41719:39)
    at ECharts.renderToSVGString (/.../lambda/node_modules/echarts-nightly/dist/echarts.js:29889:24)
    at n (/.../lambda/dist/dev.js:2:36414)
    at c (/.../lambda/dist/dev.js:2:37712)
    at n (/.../lambda/dist/dev.js:2:50942)
    at l (/.../lambda/dist/dev.js:2:51931)

@htr3n
Copy link
Author

htr3n commented Dec 16, 2021

Following up on the legend icon issue, if I use SVG path data path://M..., the rendering works and ECharts generates some SVG code like this

<path d="M 0 3.7391 L 5.4348 7 M 0 10.2609 L 5.4348 7 L 7.6087 7 M 9.7826 7 L 11.9565 7 M 14.1304 7 L 16.3043 7 M 18.4783 7 L 20.6522 7 L 25 3.7391 M 20.6522 7 L 25 10.2609" fill="#5f4890" fill-opacity="1" stroke="none" transform="matrix(1,0,0,1,616.5208,5)"></path>

How do I set the attributes stroke or stroke-width of that SVG element <path d="..."/> as it seems ECharts render engine (zrender) already transformed the input SVG path into something else?

I've looked left and right into the documentation https://echarts.apache.org/en/option.html#legend.data.icon but could not find any settings?

@htr3n
Copy link
Author

htr3n commented Dec 17, 2021

Should I report a bug regarding the legend icon image://data:image... with the new engine implementation?

@plainheart
Copy link
Member

No need to do that. We will look into this issue.

@htr3n
Copy link
Author

htr3n commented Jan 26, 2022

@plainheart Is this fixed in the release 5.3.0?

@plainheart
Copy link
Member

@htr3n It should be fixed in 5.3.0. Please try it again. Let us know if you still have issues.

@htr3n
Copy link
Author

htr3n commented Jan 30, 2022

@plainheart Just confirm the issue with invalid font properties is fixed in 5.3.0. I think we should split the issue with the legend icon image://data:image... so that this ticket can be closed?

@plainheart
Copy link
Member

@htr3n Sorry for my late reply. Just checked this icon issue with the latest version, it seems to be working for me. How is it on your side?

@htr3n
Copy link
Author

htr3n commented Mar 15, 2022

@plainheart Hi, sorry for my late reply. I can confirm it's fixed in 5.3.0

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug en This issue is in English
Projects
None yet
Development

No branches or pull requests

3 participants