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.
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)
);
};