Hello everyone, I'm using an example from the documentation that describes downloading a map as a PNG image. My problem is that the map sizes will dynamically expand based on user actions. The map will also grow to very large dimensions, causing not all nodes on the map to fit within it. Is there a way to modify the example in the documentation to make it more scalable?
#Download map as a PNG file
1 messages · Page 1 of 1 (latest)
you can make a screenshot of ".react-flow__viewport" and use the style option https://github.com/bubkoo/html-to-image#style to reset the transform (style: transform: "translate(0,0) scale(1)")
Not sure if I've got that one right but with this code: ``` import { toPng } from 'html-to-image';
import { ReactComponent as PrinterIcon } from '@/assets/icons/print.svg';
import styles from '@/components/Header/PrintButton/PrintButton.module.scss';
const downloadImage = (dataUrl: string) => {
const a = document.createElement('a');
a.setAttribute('download', 'relationship-map.png');
a.setAttribute('href', dataUrl);
a.click();
};
const PrintButton = () => {
const handleOnClick = () => {
toPng(document.querySelector('.react-flow__viewport') as HTMLElement, {
backgroundColor: '#ebedf1',
style: {
transform: 'translate(0,0) scale(1)',
},
}).then(downloadImage);
};
return (
<button onClick={handleOnClick} className={styles.button}>
<PrinterIcon className={styles.icon} />
</button>
);
};
export default PrintButton;
ah, maybe you need to zoom out a bit
getRectOfNodes -> getTransformForBounds -> use the returned transform for the passed style.transform value
It seems to me that you did the same thing as in the example in the documentation? Did I miss any differences? When implementing the code from the documentation, the situation was very similar, and it also trimmed some of the nodes.
So I did something like this: ``` import { toPng } from 'html-to-image';
import { getRectOfNodes, getTransformForBounds, useReactFlow } from 'reactflow';
import { ReactComponent as PrinterIcon } from '@/assets/icons/print.svg';
import styles from '@/components/Header/PrintButton/PrintButton.module.scss';
const downloadImage = (dataUrl: string) => {
const a = document.createElement('a');
a.setAttribute('download', 'relationship-map.png');
a.setAttribute('href', dataUrl);
a.click();
};
const PrintButton = () => {
const { getNodes } = useReactFlow();
const handleOnClick = () => {
const imageWidth = window.innerWidth;
const imageHeight = window.innerHeight;
const nodesBounds = getRectOfNodes(getNodes());
const transform = getTransformForBounds(nodesBounds, imageWidth, imageHeight, 0.5, 1);
toPng(document.querySelector('.react-flow__viewport') as HTMLElement, {
backgroundColor: '#ebedf1',
style: {
transform: `translate(${transform[0]}px, ${transform[1]}px) scale(${transform[2]})`,
},
}).then(downloadImage);
};
return (
<button onClick={handleOnClick} className={styles.button}>
<PrinterIcon className={styles.icon} />
</button>
);
};
export default PrintButton;
Maybe you need to set minZoom to 0.1 instead of 0.5
getTransformForBounds(nodesBounds, imageWidth, imageHeight, 0.1, 1);
But with setting it to 0.1 the image will come out very blurry.
then you need to increase width and height https://github.com/bubkoo/html-to-image#width-height
Is there a way to increase it by the value which is dependent on flow viewport dimensions?
So basically, the image width and image height would scale based on the dimensions of the map itself.
you can get the dimensions from the viewport and multiply it with 2, 4 ,8 whatever works for you
const domRect = document.querySelector('.react-flow').getBoundingClientRect();
We are getting somewhere with this. 😄
import { getRectOfNodes, getTransformForBounds, useReactFlow } from 'reactflow';
import { ReactComponent as PrinterIcon } from '@/assets/icons/print.svg';
import styles from '@/components/Header/PrintButton/PrintButton.module.scss';
const downloadImage = (dataUrl: string) => {
const a = document.createElement('a');
a.setAttribute('download', 'relationship-map.png');
a.setAttribute('href', dataUrl);
a.click();
};
const multipler = 4;
const PrintButton = () => {
const { getNodes } = useReactFlow();
const handleOnClick = () => {
const domRect = document.querySelector('.react-flow')!.getBoundingClientRect();
const nodesBounds = getRectOfNodes(getNodes());
const imageWidth = domRect.width * multipler;
const imageHeight = domRect.height * multipler;
const transform = getTransformForBounds(nodesBounds, imageWidth, imageHeight, 0.2, 1);
toPng(document.querySelector('.react-flow__viewport') as HTMLElement, {
backgroundColor: '#ebedf1',
width: domRect.width * multipler,
height: domRect.height * multipler,
style: {
transform: `translate(${transform[0]}px, ${transform[1]}px) scale(${transform[2]})`,
},
}).then(downloadImage);
};
return (
<button onClick={handleOnClick} className={styles.button}>
<PrinterIcon className={styles.icon} />
</button>
);
};
export default PrintButton;