#Download map as a PNG file

1 messages · Page 1 of 1 (latest)

candid laurel
#

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?

https://reactflow.dev/docs/examples/misc/download-image/

This example shows how to download a flow as an image with html-to-image.

flint cloud
candid laurel
#

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;

flint cloud
#

ah, maybe you need to zoom out a bit

#

getRectOfNodes -> getTransformForBounds -> use the returned transform for the passed style.transform value

candid laurel
#

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;

flint cloud
#

Maybe you need to set minZoom to 0.1 instead of 0.5

#

getTransformForBounds(nodesBounds, imageWidth, imageHeight, 0.1, 1);

candid laurel
#

But with setting it to 0.1 the image will come out very blurry.

flint cloud
candid laurel
#

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.

flint cloud
#

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();

candid laurel
#

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;