Last active
April 30, 2021 16:09
-
-
Save OliverLeighC/1ff2b801a45257af97aa3ed11022a319 to your computer and use it in GitHub Desktop.
React-PDF Svg Chart Options
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<svg xmlns:xlink=\"http://www.w3.org/1999/xlink\" version=\"1.1\" class=\"highcharts-root\" style=\"font-family:Helvetica;font-size:20px;\" xmlns=\"http://www.w3.org/2000/svg\" width=\"1000\" height=\"800\" viewBox=\"0 0 1000 800\"><desc>Created with Highcharts 9.0.1</desc><defs><clipPath id=\"highcharts-hn7jjeq-91-\"><rect x=\"0\" y=\"0\" width=\"980\" height=\"737\" fill=\"none\"></rect></clipPath></defs><rect fill=\"#ffffff\" class=\"highcharts-background\" x=\"0\" y=\"0\" width=\"1000\" height=\"800\" rx=\"0\" ry=\"0\"></rect><rect fill=\"none\" class=\"highcharts-plot-background\" x=\"10\" y=\"48\" width=\"980\" height=\"737\"></rect><rect fill=\"none\" class=\"highcharts-plot-border\" data-z-index=\"1\" x=\"10\" y=\"48\" width=\"980\" height=\"737\"></rect><g class=\"highcharts-series-group\" data-z-index=\"3\"><g class=\"highcharts-series highcharts-series-0 highcharts-pie-series\" data-z-index=\"0.1\" opacity=\"1\" transform=\"translate(10,48) scale(1 1)\"><path fill=\"none\" d=\"M 490 10 A 358.5 358.5 0 1 1 489.64150005974983 10.00017924998508 M 490 368.5 A 0 0 0 1 0 490 368.5\" class=\"highcharts-empty-series\" stroke=\"#cccccc\" stroke-width=\"1\"></path></g><g class=\"highcharts-markers highcharts-series-0 highcharts-pie-series\" data-z-index=\"0.1\" opacity=\"1\" transform=\"translate(10,48) scale(1 1)\"></g></g><text x=\"500\" text-anchor=\"middle\" class=\"highcharts-title\" data-z-index=\"4\" style=\"color:#333333;font-size:18px;fill:#333333;\" y=\"24\"></text><text x=\"500\" text-anchor=\"middle\" class=\"highcharts-subtitle\" data-z-index=\"4\" style=\"color:#666666;font-size:20px;fill:#666666;\" y=\"30\">As Of Apr-2021</text><text x=\"10\" text-anchor=\"start\" class=\"highcharts-caption\" data-z-index=\"4\" style=\"color:#666666;fill:#666666;\" y=\"803\"></text><g class=\"highcharts-data-labels highcharts-series-0 highcharts-pie-series\" data-z-index=\"6\" opacity=\"1\" transform=\"translate(10,48) scale(1 1)\"></g><g class=\"highcharts-legend\" data-z-index=\"7\"><rect fill=\"none\" class=\"highcharts-legend-box\" rx=\"0\" ry=\"0\" x=\"0\" y=\"0\" width=\"8\" height=\"8\" visibility=\"hidden\"></rect><g data-z-index=\"1\"><g></g></g></g></svg> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* eslint-disable no-console */ | |
import { useMemo, createElement } from "react"; | |
import { parse, TextNode, ElementNode, RootNode } from "svg-parser"; | |
const supportedStyleProps = [ | |
"color", | |
"dominantBaseline", | |
"fill", | |
"fillOpacity", | |
"fillRule", | |
"opacity", | |
"stroke", | |
"strokeWidth", | |
"strokeOpacity", | |
"strokeLinecap", | |
"strokeDasharray", | |
"transform", | |
"textAnchor", | |
"visibility" | |
] | |
function isElementNode(node: TextNode | ElementNode): node is ElementNode { | |
return node.type === 'element' | |
} | |
function removeLineBreaks(text?: string | number | boolean) { | |
if (typeof text === 'string') { | |
return text.replace(/(\r\n|\n|\r)/gm, "") | |
} | |
return text; | |
} | |
// https://dev.to/qausim/convert-html-inline-styles-to-a-style-object-for-react-components-2cbi | |
const formatStringToCamelCase = (str: string) => { | |
const splitted = str.split("-"); | |
if (splitted.length === 1) return splitted[0]; | |
return ( | |
splitted[0] + | |
splitted | |
.slice(1) | |
.map((word) => word[0].toUpperCase() + word.slice(1)) | |
.join("") | |
); | |
}; | |
export const getStyleObjectFromString = (str: string | null) => { | |
const style: any = {}; | |
if (!str) return {}; | |
str.split(";").forEach((el) => { | |
const [property, value] = el.split(":"); | |
if (!property) return; | |
if (property === "cursor") return; | |
const formattedProperty = formatStringToCamelCase(property.trim()); | |
if (supportedStyleProps.includes(formattedProperty)) { | |
style[formattedProperty] = value.trim(); | |
} | |
}); | |
return style; | |
}; | |
function handleRelativePositioning(currentPosition: string | number, parentPosition?: number) { | |
let position = Number(currentPosition) ?? 0; | |
if (parentPosition) { | |
position += parentPosition | |
} | |
return position; | |
} | |
function getParentPosition(pos: number | string | undefined) { | |
if (!pos) return 0; | |
if (typeof pos === 'string') return Number(pos); | |
return pos; | |
} | |
function svgToJSXWithRelPositioning( | |
node: TextNode | ElementNode | string, parentX?: number, parentY?: number | |
): any { | |
if (typeof node === 'string') { | |
return removeLineBreaks(node); | |
} | |
if (!isElementNode(node)) { | |
return removeLineBreaks(node.value); | |
} | |
const elementName = node.tagName; | |
if (!elementName) { | |
console.log('NO TAG NAME: ', node); | |
return null; | |
} | |
let componentProps; | |
if (node.tagName === 'desc' || node.tagName === 'defs') return null; | |
if (node.properties !== undefined) { | |
if (node.tagName === "text" || node.tagName === "tspan") { | |
componentProps = { | |
x: handleRelativePositioning(node.properties.x, parentX), | |
y: handleRelativePositioning(node.properties.y, parentY), | |
textAnchor: node.properties['text-anchor'] | |
} | |
} else { | |
componentProps = { | |
x: handleRelativePositioning(node.properties.x, parentX), | |
y: handleRelativePositioning(node.properties.y, parentY), | |
...node.properties | |
} | |
} | |
if (node.properties.style) { | |
componentProps = { | |
...componentProps, | |
style: getStyleObjectFromString(node.properties.style as string) | |
} | |
} | |
} | |
let children; | |
if (node.children && node.children.length > 0) { | |
children = node.children.map( | |
(childNode) => | |
svgToJSXWithRelPositioning( | |
childNode, getParentPosition(node.properties?.x), getParentPosition(node.properties?.y) | |
) | |
) | |
} | |
return createElement(elementName.toUpperCase(), componentProps, children); | |
} | |
export const createSvgComponent = (svgXml: string) => { | |
if (!svgXml || svgXml === "") return null; | |
const svg = svgXml.replaceAll("px", "pt"); | |
const svgElement = useMemo(() => { | |
const parsed: RootNode = parse(svg); | |
return svgToJSXWithRelPositioning(parsed.children[0], 0); | |
}, [svgXml]); | |
return svgElement; | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment