1

I have a nodejs lambda function running on AWS that should generate a PDF for download. It has taken some time to get all of these parts working, it's very disappointing that i am unable to fix the text in the SVG output correctly.

I am using Vega for charts and React-pdf/renderer.

1 - The charts look good if i save them to s3 directly from Vega, then download and view it.

2 - The in the final PDF SVG text in the chart is not arranged correctly.

enter image description here enter image description here

Since React-pdf/renderer has it's own type of SVG components, i am converting the svg to json using svg-parser (https://www.npmjs.com/package/svg-parser).

This is the json object from svg-parser - https://pastebin.com/UAbRimdn.

This is the text element that appears to match the SVG properties.

{
  "type": "element",
  "tagName": "g",
  "properties": {
    "class": "mark-text role-mark title",
    "role": "graphics-object",
    "aria-roledescription": "text mark container"
  },
  "children": [
    {
      "type": "element",
      "tagName": "text",
      "properties": {
        "text-anchor": "middle",
        "transform": "translate(35.5,-4.199999999999996)",
        "font-family": "sans-serif",
        "font-size": "4.8px",
        "fill": "#000000",
        "opacity": 1
      },
      "children": [
        {
          "type": "text",
          "value": "ATSI Participation"
        }
      ]
    }
  ]
}

This is the SVG from Vega - https://pastebin.com/6pZ8qsxF

Here is the same text element from the SVG (which renders correctly)

<g class="mark-text role-mark title" role="graphics-object" aria-roledescription="text mark container">
  <text text-anchor="middle" transform="translate(35.5,-4.199999999999996)" font-family="sans-serif" font-size="4.8px" fill="#000000" opacity="1">ATSI Participation</text>
</g>

This is my very simple normal svg to react-pdf/render converter. The text seems to be causing the problems. It's missing the correct location and the fonts, which would suggest styles in general.

import React from "react";
import { Path, Svg, Text, G } from "@react-pdf/renderer";
import { parse } from "svg-parser";

const convertJsonToPdfComponent = (jsonElement: any) => {
  if (jsonElement.type === "element") {
    const { tagName, properties, children } = jsonElement;
    console.log("Converting element", tagName, properties, children);
    // Handle different types of elements
    switch (tagName) {
      case "svg":
        console.log("SVG properties", properties);
        return (
          <Svg {...properties}>
            {children?.map((child: any) => convertJsonToPdfComponent(child))}
          </Svg>
        );
      case "g":
        console.log("G properties", properties);
        return (
          <G {...properties}>
            {children?.map((child: any) => convertJsonToPdfComponent(child))}
          </G>
        );
      case "path":
        console.log("Path properties", properties);
        return (
          <Path {...properties}>
            {children?.map((child: any) => convertJsonToPdfComponent(child))}
          </Path>
        );
      case "text":
        console.log("Text properties", properties);
        return (
          <Text {...properties}>
            {children?.map((child: any) => convertJsonToPdfComponent(child))}
          </Text>
        );
      default:
        return null;
    }
  } else if (jsonElement.type === "text") {
    return jsonElement.value;
  }
  return null;
};

export const recursivelyConvertJsonToPdfComponents = (svgString: string) => {
  console.log("Parsing SVG");
  const svgObject = parse(svgString);
  return svgObject.children.map((child: any) =>
    convertJsonToPdfComponent(child)
  );
};

WebSight
  • 640
  • 2
  • 12
  • 27

0 Answers0