export function drawTextLayer(
canvas: HTMLCanvasElement,
container: HTMLElement,
relativeTo: HTMLElement,
): void {
const context = canvas.getContext('2d');
if (!context) {
return;
}
const rootRect = relativeTo.getBoundingClientRect();
const scaleX = canvas.width / rootRect.width;
const scaleY = canvas.height / rootRect.height;
const walker = document.createTreeWalker(
container,
NodeFilter.SHOW_TEXT,
);
context.save();
context.scale(scaleX, scaleY);
let node = walker.nextNode();
while (node) {
const text = node.textContent;
const parent = node.parentElement;
if (text?.trim() && parent) {
const range = document.createRange();
range.selectNodeContents(node);
const rect = range.getBoundingClientRect();
if (rect.width && rect.height) {
const style = window.getComputedStyle(parent);
context.font = [
style.fontStyle,
style.fontWeight,
style.fontSize,
style.fontFamily,
].join(' ');
context.fillStyle = style.color;
context.textBaseline = 'top';
context.fillText(
text,
rect.left - rootRect.left,
rect.top - rootRect.top,
);
}
}
node = walker.nextNode();
}
context.restore();
}
export function canvasToBlob(
canvas: HTMLCanvasElement,
): Promise<Blob> {
return new Promise((resolve, reject) => {
canvas.toBlob((blob) => {
if (blob) {
resolve(blob);
return;
}
reject(new Error('Failed to create chart image'));
}, 'image/png');
});
}
public copyImage = async (): Promise<void> => {
const canvas = this.lwcChart.takeScreenshot(true, false);
const chartElement = this.lwcChart.chartElement();
chartElement
.querySelectorAll<HTMLElement>(
`.${CHART_PANE_LEGEND_CONTAINER}`,
)
.forEach((legend) => {
if (
legend.hidden ||
window.getComputedStyle(legend).display === 'none'
) {
return;
}
drawTextLayer(
canvas,
legend,
chartElement,
);
});
const blob = await canvasToBlob(canvas);
await navigator.clipboard.write([
new ClipboardItem({
'image/png': blob,
}),
]);
};