From a9981b17c047c917c57b238e9feb5779ae18ab42 Mon Sep 17 00:00:00 2001 From: Axel RICHARD Date: Wed, 23 Aug 2023 17:24:35 +0200 Subject: [PATCH] [2296] Create a dedicated hook for the export to image action Also move the code for diagram panel in a dedicated folder Bug: https://github.com/eclipse-sirius/sirius-web/issues/2296 Signed-off-by: Axel RICHARD --- CHANGELOG.adoc | 3 ++ package-lock.json | 9 ++-- .../package.json | 1 + .../src/renderer/DiagramRenderer.tsx | 2 +- .../src/renderer/{ => panel}/DiagramPanel.tsx | 40 +++------------ .../{ => panel}/DiagramPanel.types.ts | 0 .../src/renderer/panel/useExportToImage.tsx | 50 +++++++++++++++++++ .../renderer/panel/useExportToImage.types.ts | 16 ++++++ .../frontend/sirius-web/package.json | 1 + 9 files changed, 84 insertions(+), 38 deletions(-) rename packages/diagrams/frontend/sirius-components-diagrams-reactflow/src/renderer/{ => panel}/DiagramPanel.tsx (77%) rename packages/diagrams/frontend/sirius-components-diagrams-reactflow/src/renderer/{ => panel}/DiagramPanel.types.ts (100%) create mode 100644 packages/diagrams/frontend/sirius-components-diagrams-reactflow/src/renderer/panel/useExportToImage.tsx create mode 100644 packages/diagrams/frontend/sirius-components-diagrams-reactflow/src/renderer/panel/useExportToImage.types.ts diff --git a/CHANGELOG.adoc b/CHANGELOG.adoc index 2e77ed594c..0e214d7298 100644 --- a/CHANGELOG.adoc +++ b/CHANGELOG.adoc @@ -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 @@ -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 diff --git a/package-lock.json b/package-lock.json index 4aae75df89..70f5e0c8ea 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13863,9 +13863,6 @@ "name": "@eclipse-sirius/sirius-components-diagrams-reactflow", "version": "2023.8.0", "license": "EPL-2.0", - "dependencies": { - "html-to-image": "^1.11.11" - }, "devDependencies": { "@apollo/client": "3.8.1", "@eclipse-sirius/sirius-components-core": "~2023.8.0", @@ -13878,6 +13875,7 @@ "@vitest/coverage-v8": "0.34.2", "elkjs": "0.8.2", "graphql": "16.8.0", + "html-to-image": "1.11.11", "jsdom": "16.7.0", "prettier": "2.7.1", "react": "17.0.2", @@ -13894,6 +13892,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" @@ -14698,6 +14697,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", @@ -16053,7 +16053,7 @@ "@vitest/coverage-v8": "0.34.2", "elkjs": "0.8.2", "graphql": "16.8.0", - "html-to-image": "*", + "html-to-image": "1.11.11", "jsdom": "16.7.0", "prettier": "2.7.1", "react": "17.0.2", @@ -16722,6 +16722,7 @@ "d3": "7.0.0", "fontsource-roboto": "4.0.0", "graphql": "16.8.0", + "html-to-image": "1.11.11", "jest-junit-reporter": "1.1.0", "notistack": "3.0.1", "prettier": "2.7.1", diff --git a/packages/diagrams/frontend/sirius-components-diagrams-reactflow/package.json b/packages/diagrams/frontend/sirius-components-diagrams-reactflow/package.json index c04fdfd4cf..bd3a7e4106 100644 --- a/packages/diagrams/frontend/sirius-components-diagrams-reactflow/package.json +++ b/packages/diagrams/frontend/sirius-components-diagrams-reactflow/package.json @@ -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" diff --git a/packages/diagrams/frontend/sirius-components-diagrams-reactflow/src/renderer/DiagramRenderer.tsx b/packages/diagrams/frontend/sirius-components-diagrams-reactflow/src/renderer/DiagramRenderer.tsx index e3078a5608..871bb2e994 100644 --- a/packages/diagrams/frontend/sirius-components-diagrams-reactflow/src/renderer/DiagramRenderer.tsx +++ b/packages/diagrams/frontend/sirius-components-diagrams-reactflow/src/renderer/DiagramRenderer.tsx @@ -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'; @@ -43,6 +42,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'; diff --git a/packages/diagrams/frontend/sirius-components-diagrams-reactflow/src/renderer/DiagramPanel.tsx b/packages/diagrams/frontend/sirius-components-diagrams-reactflow/src/renderer/panel/DiagramPanel.tsx similarity index 77% rename from packages/diagrams/frontend/sirius-components-diagrams-reactflow/src/renderer/DiagramPanel.tsx rename to packages/diagrams/frontend/sirius-components-diagrams-reactflow/src/renderer/panel/DiagramPanel.tsx index b83b24ad09..8a268382d2 100644 --- a/packages/diagrams/frontend/sirius-components-diagrams-reactflow/src/renderer/DiagramPanel.tsx +++ b/packages/diagrams/frontend/sirius-components-diagrams-reactflow/src/renderer/panel/DiagramPanel.tsx @@ -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, @@ -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('.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)]; @@ -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"> diff --git a/packages/diagrams/frontend/sirius-components-diagrams-reactflow/src/renderer/DiagramPanel.types.ts b/packages/diagrams/frontend/sirius-components-diagrams-reactflow/src/renderer/panel/DiagramPanel.types.ts similarity index 100% rename from packages/diagrams/frontend/sirius-components-diagrams-reactflow/src/renderer/DiagramPanel.types.ts rename to packages/diagrams/frontend/sirius-components-diagrams-reactflow/src/renderer/panel/DiagramPanel.types.ts diff --git a/packages/diagrams/frontend/sirius-components-diagrams-reactflow/src/renderer/panel/useExportToImage.tsx b/packages/diagrams/frontend/sirius-components-diagrams-reactflow/src/renderer/panel/useExportToImage.tsx new file mode 100644 index 0000000000..e0c2592070 --- /dev/null +++ b/packages/diagrams/frontend/sirius-components-diagrams-reactflow/src/renderer/panel/useExportToImage.tsx @@ -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('.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 }; +}; diff --git a/packages/diagrams/frontend/sirius-components-diagrams-reactflow/src/renderer/panel/useExportToImage.types.ts b/packages/diagrams/frontend/sirius-components-diagrams-reactflow/src/renderer/panel/useExportToImage.types.ts new file mode 100644 index 0000000000..03d9b9044f --- /dev/null +++ b/packages/diagrams/frontend/sirius-components-diagrams-reactflow/src/renderer/panel/useExportToImage.types.ts @@ -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; +} diff --git a/packages/sirius-web/frontend/sirius-web/package.json b/packages/sirius-web/frontend/sirius-web/package.json index 952580e07d..af4291c751 100644 --- a/packages/sirius-web/frontend/sirius-web/package.json +++ b/packages/sirius-web/frontend/sirius-web/package.json @@ -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",