From 9a7b2b463d2346710ec843fea2375f5a7e547e63 Mon Sep 17 00:00:00 2001 From: Thomas Bouffard <27200110+tbouffard@users.noreply.github.com> Date: Mon, 8 Jan 2024 18:49:27 +0100 Subject: [PATCH] fix: make the DynamicLoading story work again (#296) Fix Story by using `ModelXmlSerializer` to ensure that codecs are correctly registered. Also move the code of the story to TypeScript to better detect the errors. In addition: - update `DynamicStyle.stories.js` to improve comments and the code. - change the `moduleResolution` to `node` in tsconfig to work in all IDE. This is a temporary change. --- ...g.stories.js => DynamicLoading.stories.ts} | 60 ++++++++++--------- packages/html/stories/DynamicStyle.stories.js | 6 +- packages/html/tsconfig.json | 3 +- 3 files changed, 36 insertions(+), 33 deletions(-) rename packages/html/stories/{DynamicLoading.stories.js => DynamicLoading.stories.ts} (80%) diff --git a/packages/html/stories/DynamicLoading.stories.js b/packages/html/stories/DynamicLoading.stories.ts similarity index 80% rename from packages/html/stories/DynamicLoading.stories.js rename to packages/html/stories/DynamicLoading.stories.ts index db8d1a2dd..c74339cc0 100644 --- a/packages/html/stories/DynamicLoading.stories.js +++ b/packages/html/stories/DynamicLoading.stories.ts @@ -16,15 +16,16 @@ limitations under the License. */ import { - Graph, - TextShape, Effects, + EventObject, + Graph, + GraphDataModel, InternalEvent, - constants, + ModelXmlSerializer, Perimeter, - Codec, - xmlUtils, + TextShape, } from '@maxgraph/core'; +import type { Cell } from '@maxgraph/core'; import { globalTypes, globalValues } from './shared/args.js'; export default { @@ -37,7 +38,7 @@ export default { }, }; -const Template = ({ label, ...args }) => { +const Template = ({ label, ...args }: Record) => { const container = document.createElement('div'); container.style.position = 'relative'; container.style.overflow = 'hidden'; @@ -48,7 +49,7 @@ const Template = ({ label, ...args }) => { let requestId = 0; // Speedup the animation - TextShape.prototype.enableBoundingBox = false; + TextShape.prototype.useSvgBoundingBox = false; // Creates the graph inside the given container const graph = new Graph(container); @@ -57,7 +58,7 @@ const Template = ({ label, ...args }) => { graph.setEnabled(false); // Handles clicks on cells - graph.addListener(InternalEvent.CLICK, function (sender, evt) { + graph.addListener(InternalEvent.CLICK, function (_sender: any, evt: EventObject) { const cell = evt.getProperty('cell'); if (cell != null) { @@ -67,7 +68,7 @@ const Template = ({ label, ...args }) => { // Changes the default vertex style in-place const style = graph.getStylesheet().getDefaultVertexStyle(); - style.shape = constants.SHAPE.ELLIPSE; + style.shape = 'ellipse'; style.perimeter = Perimeter.EllipsePerimeter; style.gradientColor = 'white'; @@ -81,15 +82,17 @@ const Template = ({ label, ...args }) => { const cell = graph.insertVertex(parent, '0-0', '0-0', cx - 20, cy - 15, 60, 40); // Animates the changes in the graph model - graph.getDataModel().addListener(InternalEvent.CHANGE, function (sender, evt) { - const { changes } = evt.getProperty('edit'); - Effects.animateChanges(graph, changes); - }); + graph + .getDataModel() + .addListener(InternalEvent.CHANGE, function (_sender: any, evt: EventObject) { + const { changes } = evt.getProperty('edit'); + Effects.animateChanges(graph, changes); + }); // Loads the links for the given cell into the given graph // by requesting the respective data in the server-side // (implemented for this demo using the server-function) - function load(graph, cell) { + function load(graph: Graph, cell: Cell) { if (cell.isVertex()) { const cx = args.width / 2; const cy = args.height / 2; @@ -101,22 +104,24 @@ const Template = ({ label, ...args }) => { // Adds cells to the model in a single step graph.batchUpdate(() => { const xml = server(cell.id); - const doc = xmlUtils.parseXml(xml); - const dec = new Codec(doc); - const model = dec.decode(doc.documentElement); + const model = new GraphDataModel(); + new ModelXmlSerializer(model).import(xml); // Removes all cells which are not in the response for (const key in graph.getDataModel().cells) { const tmp = graph.getDataModel().getCell(key); - if (tmp != cell && tmp.isVertex()) { + if (tmp != null && tmp != cell && tmp.isVertex()) { graph.removeCells([tmp]); } } // Merges the response model with the client model - graph.getDataModel().mergeChildren(model.getRoot().getChildAt(0), parent); + // Here we know that the root is not null + graph + .getDataModel() + .mergeChildren((model.getRoot() as Cell).getChildAt(0), parent); // Moves the given cell to the center let geo = cell.getGeometry(); @@ -138,7 +143,7 @@ const Template = ({ label, ...args }) => { for (const key in graph.getDataModel().cells) { const tmp = graph.getDataModel().getCell(key); - if (tmp != cell && tmp.isVertex()) { + if (tmp != null && tmp != cell && tmp.isVertex()) { vertices.push(tmp); // Changes the initial location "in-place" @@ -176,12 +181,12 @@ const Template = ({ label, ...args }) => { // Simulates the existence of a server that can crawl the // big graph with a certain depth and create a graph model // for the traversed cells, which is then sent to the client - function server(cellId) { + function server(cellId: string | null) { // Increments the request ID as a prefix for the cell IDs requestId++; - // Creates a local graph with no display - const graph = new Graph(); + // Creates a local graph with no display (pass null as container) + const graph = new Graph(null!); // Gets the default parent for inserting new cells. This // is normally the first child of the root (ie. layer 0). @@ -190,20 +195,17 @@ const Template = ({ label, ...args }) => { // Adds cells to the model in a single step graph.batchUpdate(() => { const v0 = graph.insertVertex(parent, cellId, 'Dummy', 0, 0, 60, 40); - const cellCount = parseInt(Math.random() * 16) + 4; + const cellCount = Math.floor(Math.random() * 16) + 4; // Creates the random links and cells for the response for (let i = 0; i < cellCount; i++) { const id = `${requestId}-${i}`; const v = graph.insertVertex(parent, id, id, 0, 0, 60, 40); - const e = graph.insertEdge(parent, null, `Link ${i}`, v0, v); + graph.insertEdge(parent, null, `Link ${i}`, v0, v); } }); - const enc = new Codec(); - const node = enc.encode(graph.getDataModel()); - - return xmlUtils.getXml(node); + return new ModelXmlSerializer(graph.getDataModel()).export(); } load(graph, cell); diff --git a/packages/html/stories/DynamicStyle.stories.js b/packages/html/stories/DynamicStyle.stories.js index 6eeba41b2..d808b3b68 100644 --- a/packages/html/stories/DynamicStyle.stories.js +++ b/packages/html/stories/DynamicStyle.stories.js @@ -15,7 +15,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -import { Graph, utils, RubberBandHandler } from '@maxgraph/core'; +import { Graph, RubberBandHandler } from '@maxgraph/core'; import { globalTypes, globalValues, @@ -57,7 +57,7 @@ const Template = ({ label, ...args }) => { // Needs to set a flag to check for dynamic style changes, // that is, changes to styles on cells where the style was - // not explicitely changed using mxStyleChange + // not explicitly changed using mxStyleChange graph.getView().updateStyle = true; // Overrides Cell.getStyle to return a specific style @@ -74,7 +74,7 @@ const Template = ({ label, ...args }) => { if (target != null) { const targetStyle = graph.getCurrentCellStyle(target); - const fill = utils.getValue(targetStyle, 'fillColor'); + const fill = targetStyle.fillColor; if (fill != null) { style.strokeColor = fill; diff --git a/packages/html/tsconfig.json b/packages/html/tsconfig.json index a2a56eaf8..61ec4ac29 100644 --- a/packages/html/tsconfig.json +++ b/packages/html/tsconfig.json @@ -9,7 +9,8 @@ /* Bundler mode */ "allowJs": true, - "moduleResolution": "bundler", + // TODO restore bundler - require exports in the package.json of @maxgraph/core + "moduleResolution": "Node", "allowImportingTsExtensions": true, "resolveJsonModule": true, "isolatedModules": true,