diff --git a/CHANGELOG.md b/CHANGELOG.md index 4e30f732bd..87079e7af0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ _**Note:** Yet to be released breaking changes appear here._ **Breaking Changes**: - The `getTooltip` and `getTooltipForCell` methods have been moved from `AbstractGraph` to the `TooltipHandler` plugin. If you were overriding these methods in a `AbstractGraph` subclass, you should now extend `TooltipHandler` instead. +- `xmlUtils.getViewXml` moved to `xmlViewUtils.getViewXml`. The impact should be limited as this function was not widely used (only in the Editor class in the maxGraph code). ## 0.22.0 diff --git a/packages/core/src/editor/Editor.ts b/packages/core/src/editor/Editor.ts index 962162d844..b1f7b98690 100644 --- a/packages/core/src/editor/Editor.ts +++ b/packages/core/src/editor/Editor.ts @@ -45,7 +45,8 @@ import PrintPreview from '../view/other/PrintPreview.js'; import Clipboard from '../util/Clipboard.js'; import MaxLog from '../gui/MaxLog.js'; import { isNode } from '../util/domUtils.js'; -import { getViewXml, getXml } from '../util/xmlUtils.js'; +import { getXml } from '../util/xmlUtils.js'; +import { getViewXml } from '../util/xmlViewUtils.js'; import { load, post, submit } from '../util/requestUtils.js'; import type PopupMenuHandler from '../view/plugin/PopupMenuHandler.js'; import RubberBandHandler from '../view/plugin/RubberBandHandler.js'; diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index 327322c281..6daebbf386 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -180,6 +180,10 @@ export * as styleUtils from './util/styleUtils.js'; * @category Utils */ export * as xmlUtils from './util/xmlUtils.js'; +/** + * @category Utils + */ +export * as xmlViewUtils from './util/xmlViewUtils.js'; export * from './util/config.js'; export * from './util/logger.js'; diff --git a/packages/core/src/util/xmlUtils.ts b/packages/core/src/util/xmlUtils.ts index 8ac85a680a..abebe4fc8b 100644 --- a/packages/core/src/util/xmlUtils.ts +++ b/packages/core/src/util/xmlUtils.ts @@ -16,21 +16,16 @@ See the License for the specific language governing permissions and limitations under the License. */ -import { NODE_TYPE, NS_SVG } from './Constants.js'; -import Point from '../view/geometry/Point.js'; -import type Cell from '../view/cell/Cell.js'; -import type { AbstractGraph } from '../view/AbstractGraph.js'; +import { NODE_TYPE } from './Constants.js'; import { htmlEntities, trim } from './StringUtils.js'; -import TemporaryCellStates from '../view/cell/TemporaryCellStates.js'; -import type { StyleValue } from '../types.js'; import { getTextContent } from './domUtils.js'; -import Codec from '../serialization/Codec.js'; import { isElement } from '../internal/utils.js'; +import type { StyleValue } from '../types.js'; /** * Returns a new, empty XML document. */ -export const createXmlDocument = () => { +export const createXmlDocument = (): XMLDocument => { return document.implementation.createDocument('', '', null); }; @@ -38,69 +33,6 @@ export const parseXml = (xmlString: string): Document => { return new DOMParser().parseFromString(xmlString, 'text/xml'); }; -export const getViewXml = ( - graph: AbstractGraph, - scale = 1, - cells: Cell[] | null = null, - x0 = 0, - y0 = 0 -) => { - if (cells == null) { - const model = graph.getDataModel(); - cells = [model.getRoot()]; - } - - const view = graph.getView(); - let result = null; - - // Disables events on the view - const eventsEnabled = view.isEventsEnabled(); - view.setEventsEnabled(false); - - // Workaround for label bounds not taken into account for image export. - // Creates a temporary draw pane which is used for rendering the text. - // Text rendering is required for finding the bounds of the labels. - const { drawPane } = view; - const { overlayPane } = view; - - if (graph.dialect === 'svg') { - view.drawPane = document.createElementNS(NS_SVG, 'g'); - view.canvas.appendChild(view.drawPane); - - // Redirects cell overlays into temporary container - view.overlayPane = document.createElementNS(NS_SVG, 'g'); - view.canvas.appendChild(view.overlayPane); - } else { - view.drawPane = view.drawPane.cloneNode(false); - view.canvas.appendChild(view.drawPane); - - // Redirects cell overlays into temporary container - view.overlayPane = view.overlayPane.cloneNode(false); - view.canvas.appendChild(view.overlayPane); - } - - // Resets the translation - const translate = view.getTranslate(); - view.translate = new Point(x0, y0); - - // Creates the temporary cell states in the view - const temp = new TemporaryCellStates(graph.getView(), scale, cells); - - try { - const enc = new Codec(); - result = enc.encode(graph.getView()); - } finally { - temp.destroy(); - view.translate = translate; - view.canvas.removeChild(view.drawPane); - view.canvas.removeChild(view.overlayPane); - view.drawPane = drawPane; - view.overlayPane = overlayPane; - view.setEventsEnabled(eventsEnabled); - } - return result; -}; - /** * Returns the XML content of the specified node. * diff --git a/packages/core/src/util/xmlViewUtils.ts b/packages/core/src/util/xmlViewUtils.ts new file mode 100644 index 0000000000..24627d0eca --- /dev/null +++ b/packages/core/src/util/xmlViewUtils.ts @@ -0,0 +1,87 @@ +/* +Copyright 2026-present The maxGraph project Contributors +Copyright (c) 2006-2015, JGraph Ltd +Copyright (c) 2006-2015, Gaudenz Alder + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import { NS_SVG } from './Constants.js'; +import Point from '../view/geometry/Point.js'; +import type Cell from '../view/cell/Cell.js'; +import type { AbstractGraph } from '../view/AbstractGraph.js'; +import TemporaryCellStates from '../view/cell/TemporaryCellStates.js'; +import Codec from '../serialization/Codec.js'; + +export const getViewXml = ( + graph: AbstractGraph, + scale = 1, + cells: Cell[] | null = null, + x0 = 0, + y0 = 0 +): Element | null => { + if (cells == null) { + const model = graph.getDataModel(); + cells = [model.getRoot()!]; + } + + const view = graph.getView(); + let result = null; + + // Disables events on the view + const eventsEnabled = view.isEventsEnabled(); + view.setEventsEnabled(false); + + // Workaround for label bounds not taken into account for image export. + // Creates a temporary draw pane which is used for rendering the text. + // Text rendering is required for finding the bounds of the labels. + const { drawPane } = view; + const { overlayPane } = view; + + if (graph.dialect === 'svg') { + view.drawPane = document.createElementNS(NS_SVG, 'g'); + view.canvas.appendChild(view.drawPane); + + // Redirects cell overlays into a temporary container + view.overlayPane = document.createElementNS(NS_SVG, 'g'); + view.canvas.appendChild(view.overlayPane); + } else { + view.drawPane = view.drawPane.cloneNode(false); + view.canvas.appendChild(view.drawPane); + + // Redirects cell overlays into a temporary container + view.overlayPane = view.overlayPane.cloneNode(false); + view.canvas.appendChild(view.overlayPane); + } + + // Resets the translation + const translate = view.getTranslate(); + view.translate = new Point(x0, y0); + + // Creates the temporary cell states in the view + const temp = new TemporaryCellStates(graph.getView(), scale, cells); + + try { + const enc = new Codec(); + result = enc.encode(graph.getView()); + } finally { + temp.destroy(); + view.translate = translate; + view.canvas.removeChild(view.drawPane); + view.canvas.removeChild(view.overlayPane); + view.drawPane = drawPane; + view.overlayPane = overlayPane; + view.setEventsEnabled(eventsEnabled); + } + return result; +};