Skip to content

Commit

Permalink
[2296] Create a dedicated hook for the export to image action
Browse files Browse the repository at this point in the history
Also move the code for diagram panel in a dedicated folder

Bug: #2296
Signed-off-by: Axel RICHARD <axel.richard@obeo.fr>
  • Loading branch information
AxelRICHARD committed Aug 24, 2023
1 parent 853ecd9 commit feaed4e
Show file tree
Hide file tree
Showing 9 changed files with 84 additions and 38 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.adoc
Expand Up @@ -27,6 +27,7 @@ It is not available for applications anymore, and thus, applications that need a
All of its remaining content was only relevant inside of Sirius Web and it has thus been migrated to this location
- [releng] Stop minifying the code of Sirius Components packages.
As a result the development of applications consuming Sirius Components packages will be easier and it will be the responsability of the application to minify everything (which they should already be doing).
- https://github.com/eclipse-sirius/sirius-web/issues/2296[#2296] [diagram] `sirius-components-diagrams-reactflow` now depends on `html-to-image` node package.

=== Dependency update

Expand All @@ -40,6 +41,8 @@ As a result the development of applications consuming Sirius Components packages
- [releng] Switch to `reactflow` 11.8.1
- [releng] Switch to Spring Boot 3.1.2
- [releng] Switch to Sirius Desktop 7.2.0
- [frontend] The frontend now depends on `html-to-image` to support the "export to SVG" action in the diagram panel of the react-flow prototype (see https://github.com/eclipse-sirius/sirius-web/issues/2296[#2296]).


=== Bug fixes

Expand Down
9 changes: 5 additions & 4 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Expand Up @@ -34,6 +34,7 @@
"@material-ui/core": "4.12.4",
"@material-ui/icons": "4.11.3",
"graphql": "16.8.0",
"html-to-image": "1.11.11",
"react": "17.0.2",
"react-dom": "17.0.2",
"reactflow": "11.8.1"
Expand Down
Expand Up @@ -28,7 +28,6 @@ import {
useNodesState,
useStoreApi,
} from 'reactflow';
import { DiagramPanel } from './DiagramPanel';
import { DiagramRendererProps, DiagramRendererState, NodeData } from './DiagramRenderer.types';
import { ImageNode } from './ImageNode';
import { ListNode } from './ListNode';
Expand All @@ -42,6 +41,7 @@ import { CustomEdgeData } from './edge/CustomEdge.types';
import { useLayout } from './layout/useLayout';
import { DiagramPalette } from './palette/DiagramPalette';
import { useDiagramPalette } from './palette/useDiagramPalette';
import { DiagramPanel } from './panel/DiagramPanel';
import { useReconnectEdge } from './reconnect-edge/useReconnectEdge';

import 'reactflow/dist/style.css';
Expand Down
Expand Up @@ -26,20 +26,13 @@ import VisibilityOffIcon from '@material-ui/icons/VisibilityOff';
import ZoomInIcon from '@material-ui/icons/ZoomIn';
import ZoomOutIcon from '@material-ui/icons/ZoomOut';

import { toSvg } from 'html-to-image';
import { useState } from 'react';
import { Panel, Rect, Transform, getRectOfNodes, getTransformForBounds, useReactFlow } from 'reactflow';
import { Panel, useReactFlow } from 'reactflow';
import { ShareDiagramDialog } from '../ShareDiagramDialog';
import { useFadeDiagramElements } from '../fade/useFadeDiagramElements';
import { useHideDiagramElements } from '../hide/useHideDiagramElements';
import { DiagramPanelProps, DiagramPanelState } from './DiagramPanel.types';
import { ShareDiagramDialog } from './ShareDiagramDialog';
import { useFadeDiagramElements } from './fade/useFadeDiagramElements';
import { useHideDiagramElements } from './hide/useHideDiagramElements';

const downloadImage = (dataUrl: string) => {
const a: HTMLAnchorElement = document.createElement('a');
a.setAttribute('download', 'diagram.svg');
a.setAttribute('href', dataUrl);
a.click();
};
import { useExportToImage } from './useExportToImage';

export const DiagramPanel = ({
fullscreen,
Expand All @@ -65,26 +58,7 @@ export const DiagramPanel = ({
const onUnfadeAll = () => fadeDiagramElements([...getAllElementsIds()], false);
const onUnhideAll = () => hideDiagramElements([...getAllElementsIds()], false);

const handleExport = () => {
const nodesBounds: Rect = getRectOfNodes(reactFlow.getNodes());
const imageWidth: number = nodesBounds.width;
const imageHeight: number = nodesBounds.height;
const transform: Transform = getTransformForBounds(nodesBounds, imageWidth, imageHeight, 0.5, 2, 0.2);

const viewport: HTMLElement | null = document.querySelector<HTMLElement>('.react-flow__viewport');
if (viewport) {
toSvg(viewport, {
backgroundColor: '#ffffff',
width: imageWidth,
height: imageHeight,
style: {
width: imageWidth.toString(),
height: imageHeight.toString(),
transform: `translate(${transform[0]}px, ${transform[1]}px) scale(${transform[2]})`,
},
}).then(downloadImage);
}
};
const { exportToImage } = useExportToImage();

const getAllElementsIds = () => {
return [...reactFlow.getNodes().map((elem) => elem.id), ...reactFlow.getEdges().map((elem) => elem.id)];
Expand Down Expand Up @@ -119,7 +93,7 @@ export const DiagramPanel = ({
size="small"
aria-label="export to svg"
title="Export to SVG"
onClick={handleExport}
onClick={exportToImage}
data-testid="export-diagram-to-svg">
<ImageIcon />
</IconButton>
Expand Down
@@ -0,0 +1,50 @@
/*******************************************************************************
* Copyright (c) 2023 Obeo and others.
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Obeo - initial API and implementation
*******************************************************************************/

import { toSvg } from 'html-to-image';
import { useCallback } from 'react';
import { Rect, Transform, getRectOfNodes, getTransformForBounds, useReactFlow } from 'reactflow';
import { UseExportToImage } from './useExportToImage.types';

const downloadImage = (dataUrl: string) => {
const a: HTMLAnchorElement = document.createElement('a');
a.setAttribute('download', 'diagram.svg');
a.setAttribute('href', dataUrl);
a.click();
};

export const useExportToImage = (): UseExportToImage => {
const reactFlow = useReactFlow();

const exportToImage = useCallback(() => {
const nodesBounds: Rect = getRectOfNodes(reactFlow.getNodes());
const imageWidth: number = nodesBounds.width;
const imageHeight: number = nodesBounds.height;
const transform: Transform = getTransformForBounds(nodesBounds, imageWidth, imageHeight, 0.5, 2, 0.2);

const viewport: HTMLElement | null = document.querySelector<HTMLElement>('.react-flow__viewport');
if (viewport) {
toSvg(viewport, {
backgroundColor: '#ffffff',
width: imageWidth,
height: imageHeight,
style: {
width: imageWidth.toString(),
height: imageHeight.toString(),
transform: `translate(${transform[0]}px, ${transform[1]}px) scale(${transform[2]})`,
},
}).then(downloadImage);
}
}, []);
return { exportToImage };
};
@@ -0,0 +1,16 @@
/*******************************************************************************
* Copyright (c) 2023 Obeo and others.
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Obeo - initial API and implementation
*******************************************************************************/

export interface UseExportToImage {
exportToImage: () => void;
}
1 change: 1 addition & 0 deletions packages/sirius-web/frontend/sirius-web/package.json
Expand Up @@ -33,6 +33,7 @@
"d3": "7.0.0",
"fontsource-roboto": "4.0.0",
"graphql": "16.8.0",
"html-to-image": "1.11.11",
"notistack": "3.0.1",
"prop-types": "15.8.1",
"react": "17.0.2",
Expand Down

0 comments on commit feaed4e

Please sign in to comment.