Skip to content

Commit

Permalink
fix(react-charting): resolve css variables in svg image data (#33538)
Browse files Browse the repository at this point in the history
  • Loading branch information
krkshitij authored Jan 2, 2025
1 parent c9574db commit 6bd14a9
Show file tree
Hide file tree
Showing 3 changed files with 25 additions and 5 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "patch",
"comment": "fix: resolve css variables in svg image data",
"packageName": "@fluentui/react-charting",
"email": "[email protected]",
"dependentChangeType": "patch"
}
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ export const DeclarativeChart: React.FunctionComponent<DeclarativeChartProps> =
const exportAsImage = React.useCallback(
(opts?: IImageExportOptions) => {
return toImage(chartRef.current?.chartContainer, {
background: theme.palette.white,
background: theme.semanticColors.bodyBackground,
...opts,
});
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ export function toImage(chartContainer?: HTMLElement | null, opts: IImageExportO
}

try {
const background = 'white'; // Background is coming as --var(xxx) when used with v8 wrapper in v9
const background =
typeof opts.background === 'string' ? resolveCSSVariables(chartContainer, opts.background) : 'transparent';
const svg = toSVG(chartContainer, background);

const svgData = new XMLSerializer().serializeToString(svg.node);
Expand Down Expand Up @@ -65,7 +66,7 @@ function toSVG(chartContainer: HTMLElement, background: string) {

const svgElements = svg.getElementsByTagName('*');
const styleSheets = document.styleSheets;
const styleRules: string[] = [];
let styleRules: string = '';

for (let i = svgElements.length - 1; i--; ) {
svgElements[i].classList.forEach(className => {
Expand All @@ -81,14 +82,15 @@ function toSVG(chartContainer: HTMLElement, background: string) {
const hasClassName = selectorText.split(' ').some(word => classNames.has(word));

if (hasClassName) {
styleRules.push(rules[j].cssText);
styleRules += rules[j].cssText + ' ';
}
}
}
}
styleRules = resolveCSSVariables(chartContainer, styleRules);

const xmlDocument = new DOMParser().parseFromString('<svg></svg>', 'image/svg+xml');
const styleNode = xmlDocument.createCDATASection(styleRules.join(' '));
const styleNode = xmlDocument.createCDATASection(styleRules);
clonedSvg.insert('defs', ':first-child').append('style').attr('type', 'text/css').node()!.appendChild(styleNode);

clonedSvg.attr('width', w1).attr('height', h1).attr('viewBox', `0 0 ${w1} ${h1}`);
Expand Down Expand Up @@ -161,12 +163,14 @@ function cloneLegendsToSVG(chartContainer: HTMLElement, svgWidth: number, svgHei
textOffset = 8;
}

const { color: textColor } = getComputedStyle(legendText!);
legendItem
.append('text')
.attr('x', legendX + textOffset)
.attr('y', svgHeight + legendY + 8)
.attr('dominant-baseline', 'hanging')
.attr('class', legendText!.getAttribute('class'))
.attr('fill', textColor)
.text(legendText!.textContent);
legendX += legendWidth;
}
Expand All @@ -192,6 +196,15 @@ function cloneLegendsToSVG(chartContainer: HTMLElement, svgWidth: number, svgHei
};
}

const cssVarRegExp = /var\((--[a-zA-Z0-9\-]+)\)/g;

function resolveCSSVariables(chartContainer: HTMLElement, styleRules: string) {
const containerStyles = getComputedStyle(chartContainer);
return styleRules.replace(cssVarRegExp, (match, group1) => {
return containerStyles.getPropertyValue(group1);
});
}

function svgToPng(svgDataUrl: string, opts: IImageExportOptions = {}): Promise<string> {
return new Promise((resolve, reject) => {
const scale = opts.scale || 1;
Expand Down

0 comments on commit 6bd14a9

Please sign in to comment.