Releases: maxGraph/maxGraph
0.21.0
Version 0.21.0 released on 2025-07-23.
⚡ This release improves Webpack and Node.js compatibility, removes legacy code, and slightly reduces bundle size. ⚡
Resources
- npm package: @maxgraph/core 0.21.0
- Fixed issues: milestone 0.21.0
- Documentation: maxgraph_0.21.0_website.zip
- Examples: maxgraph_0.21.0_examples.zip
- Changelog (only includes a summary and breaking changes): changelog
Breaking changes
Important
These changes might require updates in your codebase if you relied on internal behaviors or legacy APIs.
See the issues and pull requests referenced below for migration help.
fit
method moved to FitPlugin
The AbstractGraph.fit
method and the minFitScale
and maxFitScale
properties have been moved to the FitPlugin
.
This helps reduce the size of the base graph when the plugin is not used.
Tip
The fit
method now accepts a single options parameter to reduce boilerplate. See #734.
Removal of Dictionary
class
The Dictionary
class has been removed. You can now use the native JavaScript Map
object, which is available in all environments supported by maxGraph.
This class was originally introduced in mxGraph to support old browsers lacking Map
.
If your code used Dictionary
, replace it with Map
.
Note
This change slightly reduces the bundle size. See #857.
Rounded shapes: consistent arcSize
rendering
The way arcSize
is computed for rounded shapes is now consistent across all shape types and matches the behavior of mxGraph.
Important
If you were relying on the previous behavior (especially for edges), you may need to multiply your arcSize
value by 2
to keep the same rendering.
TypeScript-specific changes
-
AbstractGraph.getPlugin()
now explicitly returnsundefined
if the plugin is not found.
You must handle theundefined
case in your code. -
Improved return types for
EditorToolbar
methods:addPrototype()
now returnsHTMLImageElement
(wasHTMLImageElement | HTMLButtonElement
)addCombo()
now returnsHTMLSelectElement
(wasHTMLElement
)
Highlights
🔍 Search bar on the documentation website
You can now quickly search the documentation!
The new search bar uses a local lunr-search
index for fast results.
website_search_20250722.mp4
Note
For more details, see #853
🛠️ Webpack configuration simplified + Node.js ESM support
maxGraph can now be used with Webpack and Node.js ESM without extra config 🎉
Before this update, using maxGraph with Webpack required a workaround like this:
module.exports = {
module: {
rules: [
{
test: /\.m?js/,
resolve: {
fullySpecified: false,
},
},
],
},
};
This was needed because import paths in maxGraph were missing the .js
extension.
This also caused issues when importing maxGraph in ESM contexts with Node.js — no workaround was possible in that case.
These issues are now fixed ✅
📦 Bundle size reduction
Small but measurable size gains:
-0.7 kB
: removal of theDictionary
class and internal refactoring (#857)-1.0 kB
: when not using theFitPlugin
, due tofit
logic moving out ofBaseGraph
(#734)
What's Changed
🎉 New Features
- feat: let choose the implementation of
ConstraintHandler
by @tbouffard in #838 - feat(type): allow optional for parameters of AbstractGraph.addCells by @tbouffard in #847
- feat: add search to website by @tbouffard in #853
- feat: ease webpack configuration and add support Node ESM by @tbouffard in #867
🐛 Bug Fixes
- fix(FitPlugin): handle edge cases in fitCenter calculation by @tbouffard in #831
- fix: correct Editor cycleAttribute and swapStyles methods by @tbouffard in #871
- fix!: improve the robustness of codecs by @tbouffard in #872
- fix: consistently compute the arcSize for edges and vertices by @tbouffard in #884
📝 Documentation
- docs(release): fix the name of the zip files to archive by @tbouffard in #833
- docs: fix CHANGELOG for 0.20.0 by @tbouffard in #845
- docs: improve jsdoc of CellOverlay by @tbouffard in #846
- docs: fix some typedoc warnings by @tbouffard in #870
⚙️ Refactor
- refactor!: move
AbstractGraph.fit
toFitPlugin
by @tbouffard in #734 - refactor: migrate the Orthogonal story to TypeScript by @tbouffard in #835
- refactor: migrate the FixedPoints story to TypeScript by @tbouffard in #839
- refactor(type)!: make AbstractGraph.getPlugin return
T | undefined
by @tbouffard in #842 - refactor: increase usage of the MouseListenerSet interface by @tbouffard in #848
- refactor(stories): remove reference to Graph handler by @tbouffard in #849
- refactor!: remove
Dictionary
and useMap
instead by @tbouffard in #857 - refactor: migrate the DragSource story to TypeScript by @tbouffard in #860
- refactor: remove reference to legacy insert cells methods by @tbouffard in #876
- refactor: migrate the Thread story to TypeScript by @tbouffard in #877
- refactor: migrate the Stylesheet story to TypeScript by @tbouffard in #878
🛠 Chore
- test: add more tests to FitPlugin by @tbouffard in #834
- test: add tests for Cell.hasAttribute by @tbouffard in #850
- chore(eslint): use flat configuration by @tbouffard in #851
- ci: run with ubuntu-24.04 by @tbouffard in #861
- ci: display the date of the release in the release notes by @tbouffard in #885
Full Changelog: v0.20.0...v0.21.0
0.20.0
Version 0.20.0 released on 2025-05-16.
⚡ This new version improves registry consistency, removes legacy enums, supports CommonJS, and enables tree-shaking optimizations. ⚡
Resources
- npm package: @maxgraph/core 0.20.0
- Fixed issues: milestone 0.20.0
- Documentation: maxgraph_0.20.0_website.zip
- Examples: maxgraph_0.20.0_examples.zip
- Changelog (only includes a summary and breaking changes): changelog
Breaking changes
Important
Several breaking changes are introduced to align internal APIs, improve tree-shaking, and reduce complexity. These changes mostly affect users customizing the graph.
Unified Registry API for Style Elements
All style-related registries now implement the same Registry
interface. This ensures a consistent developer experience and makes it easier to use or extend them. 🛠️
- All registries now expose the same methods:
add
,get
,getName
, andclear
. - Their internal storage is no longer directly accessible.
Note
If you were using custom style registration, you'll likely need to update your code.
Renamed / Replaced Registries
MarkerShape
→EdgeMarkerRegistry
- Shapes are now registered via
ShapeRegistry
(notCellRenderer
anymore) StyleRegistry
has been removed. UseEdgeStyleRegistry
andPerimeterRegistry
instead.
Code migration examples
// Edge Marker
- MarkerShape.addMarker('oval', EdgeMarker.oval);
+ EdgeMarkerRegistry.add('oval', EdgeMarker.oval);
// Perimeter
- StyleRegistry.putValue('hexagonPerimeter', Perimeter.HexagonPerimeter);
+ PerimeterRegistry.add('hexagonPerimeter', Perimeter.HexagonPerimeter);
// Shape
- CellRenderer.registerShape('rhombus', RhombusShape);
+ ShapeRegistry.add('rhombus', RhombusShape);
// Stencil Shape
- StencilShapeRegistry.addStencil('my-stencil', new StencilShape(shape));
+ StencilShapeRegistry.add('my-stencil', new StencilShape(shape));
Special case: EdgeStyleRegistry
In addition to method renaming, EdgeStyleRegistry.add()
now takes an extra options
object to categorize the style. This avoids hardcoded behavior and improves flexibility. 🧩
- StyleRegistry.putValue('elbowEdgeStyle', EdgeStyle.ElbowConnector);
+ EdgeStyleRegistry.add('elbowEdgeStyle', EdgeStyle.ElbowConnector, { handlerKind: 'elbow', isOrthogonal: true });
This change supports internal refactors (see Highlights) and better extension patterns.
Element retrieval
For most users, no impact is expected. Retrieval methods are typically used in custom extensions only.
// Edge Marker
- MarkerShape.markers['oval'];
+ EdgeMarkerRegistry.get('oval');
// Edge Style
- StyleRegistry.getValue('elbowEdgeStyle');
+ EdgeStyleRegistry.get('elbowEdgeStyle');
// Perimeter
- StyleRegistry.getValue('hexagonPerimeter');
+ PerimeterRegistry.get('hexagonPerimeter');
// Shape
- CellRenderer.defaultShapes['rhombus'];
+ ShapeRegistry.get('rhombus');
// Stencil Shape
- StencilShapeRegistry.getStencil('my-stencil')
+ StencilShapeRegistry.get('my-stencil')
Note
EdgeMarkerRegistry
still exposes its specific createMarker
method unchanged. 🎯
Enum Removal and Renaming
All remaining enums have been removed. They caused unnecessary complexity and weren’t actually used to list values. 🧹
Use the corresponding string-based types instead:
Removed Enum | Use this instead |
---|---|
constants.ALIGN |
AlignValue , VAlignValue |
constants.DIALECT |
DialectValue |
constants.ARROW |
ArrowValue |
constants.DIRECTION |
DirectionValue |
constants.EDGESTYLE |
EdgeStyleValue |
constants.ELBOW |
ElbowValue |
constants.PERIMETER |
PerimeterValue |
constants.SHAPE |
ShapeValue |
constants.TEXT_DIRECTION |
TextDirectionValue |
constants.RENDERING_HINT |
No replacement |
Other specific changes:
-
constants.NODETYPE
→ replaced by value objectconstants.NODE_TYPE
DOCUMENTTYPE
→DOCUMENT_TYPE
-
constants.FONT
→ replaced byconstants.FONT_STYLE_FLAG
-
constants.CURSOR
→ values moved to:ConnectionHandler
EdgeHandlerConfig
HandleConfig
VertexHandlerConfig
Also, constants.DIRECTION_MASK
is now read-only. 🔒
Highlights
CommonJS Support for Node & Test Environments
maxGraph now ships with dual ESM and CommonJS builds. 🎉
Historically, only ESM was supported, as maxGraph was mainly used in browser-based applications with bundlers. But some new use cases made CJS support necessary:
Why it's useful
-
Testing (e.g. with Jest): CJS is default in many test setups. Previously, you had to:
- Add extra config just to run tests.
- Migrate whole test suites to ESM - a massive task in large apps.
- Replace CJS-only dependencies.
Now, maxGraph works in Jest without forcing ESM migration. ✅
- Node-based (headless) apps: Like SVG export use cases (see #761). Some apps still use CommonJS, and maxGraph was previously unusable in those.
Now it just works. 😎
Tip
Two new examples were added to show CommonJS usage:
- TypeScript: Use with Jest +
ts-jest
- JavaScript: Run headless in Node.js using
jsdom
, export XML and SVG
Tree-shaking Improvements
Tree-shaking is now much more effective thanks to multiple internal refactors. 🧼
Main improvement
EdgeStyle
implementations are no longer hardcoded throughout the codebase. Instead, the code only relies on what is dynamically registered with configuration (see Breaking changes).
This allows bundlers to remove unused styles - big win on size! 📦
Example size comparison
Examples from maxGraph
repo
Even with no changes in your app, enum removal already saves 3–5 kB. If your app avoids most EdgeStyles, savings can go up to 17 kB. 📉
Example | v0.19.0 | enums removal | EdgeStyles tree-shaking | v0.20.0 |
---|---|---|---|---|
js-example | 475.30 kB | 469.80 kB | 470.56 kB | 467.59 kB |
js-example-selected-features | 415.10 kB | 410.18 kB | 393.27 kB | 390.40 kB |
js-example-without-default | 347.33 kB | 342.69 kB | 325.79 kB | 325.44 kB |
ts-example | 438.64 kB | 434.80 kB | 435.46 kB | 435.23 kB |
ts-example-selected-features | 380.70 kB | 377.11 kB | 369.30 kB | 369.09 kB |
ts-example-without-default | 329.90 kB | 326.43 kB | 309.40 kB | 309.18 kB |
Warning
The 3 kB drop in js-example*
is from button simplification in the examples, not related to maxGraph itself (see #822).
Examples from maxgraph-integration-examples
repo
All share common Graph config and use EdgeStyle.OrthConnector
. ⚙️
Example | 0.19.0 | 0.20.0 |
---|---|---|
farm | 406.09 kB (2 chunks) | 404.25 kB (5 chunks) |
lit (vite) | 402.19 kB | 389.92 kB |
parcel | 506.70 kB | 500.98 kB |
rollup | 380.44 kB | 369.02 kB |
rsbuild | 361.94 kB | 347.19 kB |
vite | 383.50 kB | 371.86 kB |
What's Changed
🎉 New Features
- feat!: make various cursors configurable by @tbouffard in #806
- feat!: improve tree-shaking of EdgeStyle by @tbouffard in #809
- feat: improve plugin ID guidance and type safety by @tbouffard in #818
- feat: add CommonJS support to npm package by @tbouffard in #826
🐛 Bug Fixes
- fix: correctly set italic in
styleUtils.getSizeForString
by @tbouffard in #805 - fix: ensure mdx pages can be displayed by storybook by @tbouffard in #814
📝 Documentation
- docs: fix changelog 0.19.0 by @tbouffard in #794
- docs: introduce and use more categories in JSDoc by @tbouffard in #807
- docs: display documentation with some stories by @tbouffard in #816
- docs: enhance demo homepage with emojis and better organization by @tbouffard in #820
⚙️ Refactor
- refactor!: remove the SHAPE enum by @tbouffard in #795
- refactor!: remove ARROW, EDGESTYLE, PERIMETER enums by @tbouffard in #796
- refactor!: remove the ALIGN and RENDERING_HINT enums by @tbouffard in #798
- refactor!: remove the DIALECT enum by @tbouffard in #800
- refactor!: remove DIRECTION and TEXT_DIRECTION enums by @tbouffard in https://github...
0.19.0
⚡ This new version improves tree-shaking for EdgeStyle
and Perimeter
, updates the documentation, and fixes bugs. ⚡
Resources
- npm package: @maxgraph/core 0.19.0
- Fixed issues: milestone 0.19.0
- Documentation: maxgraph_0.19.0_website.zip
- Examples: maxgraph_0.19.0_examples.zip
- Changelog (only includes a summary and breaking changes): changelog
Breaking changes
Warning
These changes only impact advanced use cases where edge styles or perimeters are customized directly.
-
EdgeStyle
is now a namespace
It used to be a class with static properties. You could technically mutate it to add or override values — but that’s no longer possible.
If you were doing this, you now need to define your ownEdgeStyle
implementation and register it explicitly. -
Perimeter
is now a namespace
Previously a plain object,Perimeter
could be mutated too. Not anymore.
Like withEdgeStyle
, create your own perimeter implementation and register it if needed.
Highlights
📦 Tree-shaking improvements for EdgeStyle
and Perimeter
Until now, all edge styles and perimeters were bundled into your app even if you only used a few of them. Why? Because EdgeStyle
and Perimeter
were objects that referenced everything, which prevented bundlers from optimizing properly.
Here’s what changed:
EdgeStyle
is now a namespace. This allows bundlers to drop unused edge styles and only keep what’s actually registered and used viaStyleRegistry
.Perimeter
is now also a namespace, instead of a value object. This improves bundling behavior, especially for bundlers that couldn’t previously optimize it (Webpack, Vite when misconfigured, etc.).
Note
Bundlers like Rollup already did a great job here. But now all bundlers should behave nicely 🎉
📉 Impact on bundle size
Depending on what edge styles and perimeters your app uses, and the bundler you're using, bundle size can shrink by 1 to 5 kB.
🔍 A few things to keep in mind
- The
EdgeStyle
change currently has limited effect, since many built-in styles are still referenced directly in the codebase. This will improve in the future (see #767). - The
Perimeter
change doesn’t impact apps built with Rollup or Vite (which uses Rollup internally), since they already optimized this before. But it’s now cleaner and safer across the board.
Here’s a concrete example of what Rollup was doing with the old object-based Perimeter
(with minification disabled):
const RectanglePerimeter = ...
const EllipsePerimeter = ...
const Perimeter = {
RectanglePerimeter,
EllipsePerimeter
};
Only the perimeters actually used are bundled in.
🔬 Real-world examples from the maxGraph
repo
Note
JS examples use Webpack, TS examples use Vite (Rollup)
📦 In JS examples: the size = full app
📦 In TS examples: the size = maxGraph
chunk only
Example | v0.18.0 | After #785 | After #791 |
---|---|---|---|
js-example | 476.10 kB | 475.92 kB | 475.30 kB |
js-example-selected-features | 423.45 kB | 415.59 kB | 415.10 kB |
js-example-without-default | 347.86 kB | 347.83 kB | 347.33 kB |
ts-example | 439.30 kB | 439.15 kB | 438.64 kB |
ts-example-selected-features | 381.15 kB | 381.14 kB | 380.70 kB |
ts-example-without-default | 330.38 kB | 330.38 kB | 329.90 kB |
Analysis:
- In the
*-without-default
examples, there's no change — becausePerimeter
wasn't used. - In TS examples, the gains are minor (Rollup already tree-shaked well).
- The best gains are seen in JS/Webpack examples where tree-shaking was previously limited.
🔬 Examples from the maxgraph-integration-examples
repository
Example | 0.18.0 | 0.19.0 |
---|---|---|
farm | 407.8 kB (in 5 chunks) | 406.1 kB (in 2 chunks) |
lit (vite) | 402.7 kB | 402.2 kB |
parcel | 506.5 kB | 506.7 kB |
rollup | 381.0 kB | 380.4 kB |
rsbuild | 358.0 kB | 361.9 kB |
vite | 384.0 kB | 383.5 kB |
- Related PR: #220
What's Changed
🎉 New Features
- feat!: improve tree-shaking of
Perimeter
by @tbouffard in #785 - feat: improve IDE guidance for style element registration by @tbouffard in #787
- feat!: improve tree-shaking of
EdgeStyle
by @tbouffard in #791
🐛 Bug Fixes
- fix: correctly convert "arc" attributes to boolean in StencilShape by @tbouffard in #788
📝 Documentation
- docs: add structure section and improve npm package details by @tbouffard in #792
Full Changelog: v0.18.0...v0.19.0
0.18.0
⚡ This new version introduces BaseGraph
for better control over loaded features, adds new utilities to register default style elements, and significantly reduces bundle size! ⚡
Resources
- npm package: @maxgraph/core 0.18.0
- Fixed issues: milestone 0.18.0
- Documentation: maxgraph_0.18.0_website.zip
- Examples: maxgraph_0.18.0_examples.zip
- Changelog (only includes a summary and breaking changes): changelog
Highlights
🚀 Introducing BaseGraph
Historically, the Graph
class has been the main entry point in maxGraph
, just like it was in mxGraph
.
It automatically loads default plugins and style elements, making it convenient for prototyping but less ideal for production use - it increases the bundle size by including features you might not even use.
With v0.18.0
, you now have a better option:
BaseGraph
: an alternative toGraph
that loads nothing by default. You choose what to include.AbstractGraph
: a new abstract class with all the common logic, shared by bothGraph
andBaseGraph
.Graph
remains fully functional, but it's now built on top ofAbstractGraph
.
This is a big step toward full tree-shaking support!
More improvements are coming soon. Stay tuned! 📻
Note
See issue #665 for the full roadmap on tree-shaking improvements.
- Related PR: Introduce
BaseGraph
in #776
🛠 Usage of BaseGraph
BaseGraph
also simplifies constructor usage:
Instead of many parameters (and sometimes lots of null
), you now pass a single configuration object.
Example - Basic setup:
const graph = new BaseGraph({
container: document.getElementById('graphContainer')!,
});
Example - Full configuration:
const graph = new BaseGraph({
container: document.getElementById('graphContainer')!,
model: new MyGraphDataModel(),
stylesheet: new MyStylesheet(),
plugins: [Plugin1, Plugin2],
cellRenderer: new MyCellRenderer(),
view: (graph: AbstractGraph) => new MyGraphView(graph),
selectionModel: (graph: AbstractGraph) => new MyGraphSelectionModel(graph),
});
Compared to Graph
, it's much cleaner - no need to extend classes just to customize internals!
⚡ Comparison: Graph
Usage
When using the traditional Graph
class, customization often requires class extension and overriding internal methods (createXXX
) which makes the code heavier and less readable.
Example - Basic setup:
const graph = new Graph(document.getElementById('graphContainer')!);
Example - Full customization:
class MyCustomGraph extends Graph {
override createCellRenderer(): CellRenderer {
return new MyCellRenderer();
}
override createGraphView(): GraphView {
return new MyGraphView(this);
}
override createSelectionModel(): GraphSelectionModel {
return new MyGraphSelectionModel(this);
}
}
const graph = new MyCustomGraph(
document.getElementById('graphContainer')!,
new MyGraphDataModel(),
new MyStylesheet(),
[Plugin1, Plugin2],
);
// If you want to override only some elements and not others, you might end up passing `undefined` explicitly:
// In case of the GraphDataModel and Stylesheet are managed by overriding `createGraphDataModel` and `createStylesheet` respectively
const graph = new MyCustomGraph(
document.getElementById('graphContainer')!,
undefined,
undefined,
[Plugin1, Plugin2],
);
Warning
This approach leads to less readable code and harder maintenance, especially when you don't want to override everything!
🎨 Easier Ways to Register Style Elements
Want to manually register default styles? New helper functions are available:
registerDefaultEdgeMarkers();
registerDefaultEdgeStyles();
registerDefaultPerimeters();
registerDefaultShapes();
Use them to selectively register only what your app actually needs!
If you need all built-in elements for a category, these helpers make it super easy.
Note
"Edge Marker" factories (for arrow shapes and such) are now public too. Flexibility unlocked! 🔓
- Related PR: #757
📦 Impact of BaseGraph
on Bundle Size
Using BaseGraph
with only the styles and plugins you need can drastically shrink your app's bundle size.
Tree-shaking now works better and smarter!
In our examples, switching to BaseGraph
with a minimal setup gave measurable improvements, even with default bundler configs!
The "without-defaults" examples showed a decrease 105 kB!
🔬 Examples from the maxGraph
repository
Tip
JS examples use Webpack, TS examples use Vite (Vite/Rollup does better tree-shaking!)
- the JS and TS examples doesn't cover the same use case
- the size mentioned here is the one of the whole application in the JS examples and the one of the maxGraph chunk in the TS examples
Example | 0.17.0 | before BaseGraph (main branch, commit 94a1609) | 0.18.0 |
---|---|---|---|
js-example | 475.7 kB | 475.8 kB | 476.1 kB |
js-example-selected-features | - | 476.1 kB | 423.5 kB |
js-example-without-default | 452.1 kB | 454.2 kB | 347.8 kB |
ts-example | 439.1 kB | 439.0 kB | 439.3 kB |
ts-example-selected-features | - | 439.1 kB | 381.2 kB |
ts-example-without-default | 435.1 kB | 434.9 kB | 330.4 kB |
📖 See documentation for full example details.
🔬 Examples from the maxgraph-integration-examples
repository
Integration projects also switched to BaseGraph
, showing similar gains:
Example | Previously with Graph |
Now with BaseGraph |
---|---|---|
farm | 454.2 kB (in 2 chunks) | 407.8 kB (in 5 chunks) |
lit (vite) | 462.4 kB | 402.7 kB |
parcel | 529.3 kB | 506.5 kB |
rollup | 439.2 kB | 381.0 kB |
rsbuild | 416.9 kB | 358.0 kB |
vite | 443.1 kB | 384.0 kB |
Fun fact:
-
Removing the optional
CellEditorHandler
plugin invite
drops another ~12.5 kB!
What's Changed
🎉 New Features
- feat: simplify types used to register shapes by @tbouffard in #768
- feat(core): explicitly support undefined container in Graph constructor by @tbouffard in #769
- feat: let register and unregister default style elements by @tbouffard in #757
- feat: introduce examples that not rely on default plugins and styles by @tbouffard in #774
- feat: let efficiently not load default plugins and style builtins by @tbouffard in #776
- feat: let serialize
BaseGraph
with Codecs by @tbouffard in #778
🐛 Bug Fixes
- fix: use the right list of excluded fields in GraphCodec by @tbouffard in #777
📝 Documentation
- docs: explain that the mxGraph migration guide is no longer updated by @tbouffard in #783
⚙️ Refactor
- refactor(type): explicitly declare the MouseListenerSet interface by @tbouffard in #770
- refactor: reorganize builtin style elements by @tbouffard in #775
- refactor: use CellEditorHandler plugin in selected-features examples by @tbouffard in #779
Full Changelog: v0.17.0...v0.18.0
0.17.0
⚡ This new version improves graph fitting, makes i18n fully configurable, and reduces bundle size significantly. ⚡
Resources
- npm package: @maxgraph/core 0.17.0
- Fixed issues: milestone 0.17.0
- Documentation: maxgraph_0.17.0_website.zip
- Examples: maxgraph_0.17.0_examples.zip
- Changelog (only includes a summary and breaking changes): changelog
Breaking changes
Important
These changes may impact existing usages. Please review them carefully and check the related pull requests for migration guidance.
🔐 Eval usage is now disabled by default
To prevent potential security issues, StylesheetCodec.allowEval
is now false
by default.
Note
See #736 for details.
🌐 Configurable i18n
The built-in Translations
class is no longer used by default. If you want to keep using it, you must now explicitly enable it:
GlobalConfig.i18n = new TranslationsAsI18n();
Note
See #737
🧰 Utility functions access changes
Several utils have been reorganized for better clarity and maintainability:
- These functions are now accessed through specific namespaces:
get
,getAll
,load
,post
,submit
→requestUtils
error
,popup
→guiUtils
- The old
utils
namespace has been removed. - Remaining relevant properties were moved to
guiUtils
.
Note
See #740
💥 Removed internal functions
Some functions that were mistakenly exposed as public have been removed:
-
Utils.copyTextToClipboard
is no longer available.See #738
-
cellArrayUtils.filterCells
was removed - just use the nativeArray.filter()
instead!See #752
Highlights
🎯 New: Fit Center
You can now center and fit your graph into the container with the new FitPlugin
.
The method is inspired by the former example provided in the JSDoc of Graph.fit()
but improved to:
- handle margins better,
- reduce visual shifts when called multiple times.
The storybook and TypeScript example have been updated to showcase how it works in various contexts.
PR_733_story_fit_center.mp4
Note
See #733
🌍 Configurable i18n support
Until now, the Translations
class was always used internally. Now you can:
- Disable i18n completely for smaller bundles,
- Plug in your own i18n solution.
This makes maxGraph more flexible and lighter by default.
Note
See #737
📦 Smaller bundle size
Thanks to the new i18n configuration, tree-shaking now works better.
Depending on your setup, you could reduce the size of your app by 5-10kB - and probably more with tuned bundler configs!
Tip
Examples use default bundler configs and still show measurable gains.
🔬 Examples in the maxGraph
repo
Example | 0.16.0 | 0.17.0 |
---|---|---|
js-example | 484.1 kB | 475.71 kB |
js-example-without-defaults | 462.4 kB | 452.13 kB |
ts-example | 444.4 kB | 439.15 kB |
ts-example-without-defaults | 440.4 kB | 435.12 kB |
📖 See documentation for what each example includes.
🔬 Examples in maxgraph-integration-examples
All integration projects reuse a shared core similar to ts-example
. Here's the app size:
Example | 0.16.0 | 0.17.0 |
---|---|---|
farm | 461.0 kB | 453.9 kB |
lit with vite | 471.7 kB | 466.5 kB |
parcel[1] | 521.2 KB | 528.1 kB |
rollup | 443.7 kB | 438.3 kB |
rsbuild | 429.4 kB | 417.3 kB |
vite | 447.5 kB | 442.2 kB |
[1] parcel is the sole bundler that increases the size of the application. Parcel was bump from 2.13.3 to 2.14.4 which may have introduced changes.
➰ New story: curved edges
We've added a story to show the difference between:
- default edges
- curved edges
- rounded edges
PR_731_story_edges_curved_and_rounded.mp4
Note
See #731
What's Changed
🎉 New Features
- feat: refine the type of
CellStateStyle.elbow
by @tbouffard in #701 - feat: CellStateStyle port constraints accept multiple DirectionValue by @tbouffard in #721
- feat: let "fit center" with the new
FitPlugin
by @tbouffard in #733 - feat!: limit usage of the
eval
function by @tbouffard in #736 - feat!: introduce a way to configure the I18n provider by @tbouffard in #737
🐛 Bug Fixes
- fix: consider
ManhattanConnector
as orthogonal by @tbouffard in #707 - fix(type): let Graph fitScale properties allow null by @tbouffard in #715
- fix(story): add buttons to container, not to the document by @tbouffard in #750
- fix(story): ensure that the Model Codecs are always registered by @tbouffard in #749
- fix: make
Graph.options
truly per-instance by @tbouffard in #751
📝 Documentation
- docs: add more JSDoc categories by @tbouffard in #714
- docs: improve jsdoc for custom implementation of EdgeStyle by @tbouffard in #724
- docs: improve JSDoc of
styleUtils
by @tbouffard in #727 - docs: improve JSDoc of
allowEval
properties by @tbouffard in #729 - docs: update reference to functions moved to dedicated namespaces by @tbouffard in #746
⚙️ Refactor
- refactor: migrate the Events story to TypeScript by @tbouffard in #702
- refactor: introduce shared code to manage description of story by @tbouffard in #703
- refactor: migrate the Wrapping story to TypeScript by @tbouffard in #720
- refactor: simplify type management in Codecs by @tbouffard in #723
- refactor: apply internal improvements to editor classes by @tbouffard in #726
- refactor: improve the management of
CellStateStyle.curved
by @tbouffard in #731 - refactor: remove
isNotNullish
internal function by @tbouffard in #732 - refactor: move plugins to a dedicated folder by @tbouffard in #735
- refactor!: move internal utils functions to a dedicated directory by @tbouffard in #738
- refactor!: expose all exported functions in namespaces by @tbouffard in #740
- refactor!: move properties of
utils
toguiUtils
by @tbouffard in #741 - refactor(types): simplify imports of the
Graph
types by @tbouffard in #743 - refactor!: remove
cellArrayUtils.filterCells
by @tbouffard in #752
🛠 Chore
- chore: add more checks in
ts-support
by @tbouffard in #728 - chore(types): enforce usage of explicit override keyword in examples by @tbouffard in #739
Full Changelog: v0.16.0...v0.17.0
0.16.0
⚡ This new version enhances internationalization (i18n), improves connector configurations, and prepares for future updates with tree shaking optimizations. ⚡
Resources
- npm package: @maxgraph/core 0.16.0
- Fixed issues: milestone 0.16.0
- Documentation: maxgraph_0.16.0_website.zip
- Examples: maxgraph_0.16.0_examples.zip
- Changelog (only includes a summary and breaking changes): changelog
Breaking changes
Note
Some changes are introduced to prepare for tree shaking improvements as part of issue #665.
-
Private utility functions:
The functionsutils.isNullish
andutils.isNotNullish
are now marked as private. They were mistakenly made public and have always been intended for internal use. -
Removed utility functions:
Several utility functions, originally designed for internal use to retrieve default values forCellStateStyle
andCellStyle
, have been removed:utils.getValue
stringUtils.getColor
stringUtils.getNumber
stringUtils.getStringValue
You should now use the nullish coalescing operator (??) and Optional chaining (?.) instead.
-
Removed
Client.isBrowserSupported
:
TheClient.isBrowserSupported
method has been removed. It was not correctly validating all the prerequisites for determining whether the browser supports maxGraph. This method is now deprecated with no direct replacement. -
Moved
Client.VERSION
toconstants.VERSION
:
TheVERSION
constant, previously stored inClient
, is now stored in theconstants
module to ensure its immutability, as it represents the actual version of maxGraph. -
Relocated Translations configuration:
Configuration elements for translations have been moved fromClient
toTranslationsConfig
. The following properties have been migrated:Client.defaultLanguage
→TranslationsConfig.getDefaultLanguage
Client.setDefaultLanguage
→TranslationsConfig.setDefaultLanguage
Client.language
→TranslationsConfig.getLanguage
Client.setLanguage
→TranslationsConfig.setLanguage
Client.languages
→TranslationsConfig.getLanguages
Client.setLanguages
→TranslationsConfig.setLanguages
-
Connector Configuration changes:
- ManhattanConnector: Now configured via the global
ManhattanConnectorConfig
object. Several properties that were previously part ofEdgeStyle
have moved to this configuration object:MANHATTAN_END_DIRECTIONS
→endDirections
MANHATTAN_MAX_ALLOWED_DIRECTION_CHANGE
→maxAllowedDirectionChange
MANHATTAN_MAXIMUM_LOOPS
→maxLoops
MANHATTAN_START_DIRECTIONS
→startDirections
MANHATTAN_STEP
→step
- OrthConnector: Now configured via the global
OrthogonalConnectorConfig
object. The following properties have been moved:orthBuffer
→buffer
orthPointsFallback
→pointsFallback
- ManhattanConnector: Now configured via the global
-
Internal utility methods:
Several properties and utility methods previously exposed byEdgeStyle
are now internal. For example:- The
getRoutePattern
method has been removed entirely, as it was not being used anywhere within the codebase.
- The
Highlights
🌍 Custom Shape Support for Overlays
You can now use custom shapes for overlays instead of just images. The CellRenderer
provides extension points for configuring custom shapes and their associated DOM nodes.
Here is an example of custom Overlays taken from the Overlays story 👇🏿
PR_696_custom_overlays.webm
Note
For more details, see #696.
🌐 Improved i18n Support
This release enhances i18n support with the restoration of original mxGraph resource files (Chinese, English, and German) and adds French and Spanish resources. Additionally, a new configuration object, TranslationsConfig
, is introduced to simplify and extend internationalization functionality in future releases.
This update is part of ongoing efforts to allow for custom i18n mechanisms in future versions (see issue #688).
🔗 Enhanced Manhattan and Orthogonal Connector Configuration
The configuration for both the Manhattan and Orthogonal connectors is now centralized in dedicated global configuration objects: ManhattanConnectorConfig
and OrthogonalConnectorConfig
. This change helps clarify responsibilities and makes future tree shaking optimizations easier. Additionally, related reset functions are now available.
What's Changed
🎉 New Features
- feat!: introduce global config for the Orthogonal connector by @tbouffard in #678
- feat!: introduce global config for the Manhattan connector by @tbouffard in #681
- feat: provide i18n default resources by @tbouffard in #689
- feat: provide i18n resources for French and Spanish by @tbouffard in #690
- feat!: introduce
TranslationsConfig
by @tbouffard in #691 - feat: allow to use custom shape for overlays by @tbouffard in #696
🐛 Bug Fixes
- fix: Graph.isValidAncestor manages null Cell parameter by @tbouffard in #699
📝 Documentation
- docs: apply improvements to the navbar by @tbouffard in #675
- docs: improve css and images page by @tbouffard in #677
⚙️ Refactor
- refactor!: mark
isNullish
andisNotNullish
as private by @tbouffard in #661 - refactor!: remove extra getDefault functions and related functions by @tbouffard in #662
- refactor!: remove
Client.isBrowserSupported
by @tbouffard in #679 - refactor!: move
VERSION
toconstants
by @tbouffard in #680 - refactor!: extract Orthogonal and Manhattan connectors by @tbouffard in #684
- refactor: rename
OrthConnectorConfig
toOrthogonalConnectorConfig
by @tbouffard in #685 - refactor: do not redeclare ImageShape properties already in Shape by @tbouffard in #694
- refactor: reset more global configurations in stories by @tbouffard in #646
- refactor: use external CSS file MenuStyle and ShowRegion stories by @tbouffard in #698
Full Changelog: v0.15.1...v0.16.0
0.15.1
⚡ This new version includes bug fixes and documentation improvements. ⚡
Resources
- npm package: @maxgraph/core 0.15.1
- Fixed issues: milestone 0.15.1
- Documentation: maxgraph_0.15.1_website.zip
- Examples: maxgraph_0.15.1_examples.zip
- Changelog (only includes a summary and breaking changes): changelog
What's Changed
🐛 Bug Fixes
- fix: remove some circular dependencies by @tbouffard in #663
- fix(VertexHandler): display overlay when resizing a vertex by @tbouffard in #673
📝 Documentation
- docs: fix typo in CHANGELOG by @tbouffard in #653
- docs: apply quick fixes to the "getting started" and "demos" page by @tbouffard in #654
- docs(release): better explain how to choose the new version by @tbouffard in #655
- docs: add more information about perimeters by @tbouffard in #656
- docs: add missing Logging category to the Logger interface by @tbouffard in #667
- docs: add a first blog post in the website by @tbouffard in #672
⚙️ Refactor
- refactor: improve
StencilShapeRegistry
method signatures by @tbouffard in #660 - refactor: simplify CellRenderer by @tbouffard in #659
🛠 Chore
- ci(release): fix api call to get milestone number by @tbouffard in #651
- ci: include js-example-without-defaults during the build by @tbouffard in #669
Full Changelog: v0.15.0...v0.15.1
0.15.0
⚡ A step forward! This new version brings major improvements, especially in documentation and edge handling, while also addressing long-standing issues. ⚡
Many thanks to @HalilFocic for all the fixes and the great work on improving the documentation! 🙌
Resources
- npm package: @maxgraph/core 0.15.0
- Fixed issues: milestone 0.15.0
- Documentation: maxgraph_0.15.0_website.zip
- Examples: maxgraph_0.15.0_examples.zip
- Changelog (summary and breaking changes only): changelog
Breaking Changes 🚨
The impact of breaking changes in this release is minimal. They mainly affect unused or non-functional parts of the API.
EdgeHandler Property Removal
Some properties have been removed from EdgeHandler
because they couldn't be modified correctly. They are now replaced by global configuration options in EdgeHandlerConfig
:
addEnabled
→addBendOnShiftClickEnabled
removeEnabled
→removeBendOnShiftClickEnabled
virtualBendOpacity
virtualBendsEnabled
Note
For more details, see #633.
domUtils.importNodeImplementation
Removed
- This function was only used internally in
mxGraph
to support old versions of Internet Explorer. - It was never intended to be part of the public API.
- No migration is needed, as the function was unused.
Note
For more details, see #648.
Highlights ✨
🚀 Major Documentation Improvements
The entire mxGraph manuals and tutorials have been integrated and adapted for maxGraph! 🎉
This is a huge milestone that ensures we have comprehensive and structured documentation, benefiting from the experience and maturity of mxGraph.
We also listened to your feedback and have placed a stronger emphasis on examples and demos in the documentation, making it easier to find relevant code snippets for specific features directly from most pages.
What’s next? Better organization of manuals and tutorials:
- Creating a clear learning path for newcomers.
- Ensuring consistency with the existing usage documentation of all specific features that were already documented before integrating the manuals and tutorials.
Note
Documentation is a hot topic! Join the discussion on the roadmap: GitHub Discussion #595.
🔧 New EdgeHandler Configuration
Managing edge bend points is now much easier!
Previously in mxGraph, modifying EdgeHandler
properties required updating the class prototype, which no longer worked in `maxGraph`. Now, you can configure everything via EdgeHandlerConfig
. This allows:
- Virtual bends: Add bends at the midpoint of all edge segments.
- Adding bends: Shift-click anywhere on an edge.
- Removing bends: Shift-click an existing point.
Note
For more details, see #633.
PR_633_new_properties_in_story.mp4
🔄 Fix: Vertex Rotation
A major issue from the first release of maxGraph has been fixed!
The rotation handle was misplaced, and the initial rotation angle was incorrect. The handle always appeared to the right of the vertex, even after rotation, making subsequent rotations behave incorrectly.
This made the feature impossible to use—but not anymore! ✅
Note
For more details, see issue #482.
Before
story_stencils.mp4
Now
stencils.mov
What's Changed
🎉 New Features
- feat: introduce global config for the Entity Relation connector by @tbouffard in #620
- feat: make the stencils XML schema available in the npm package by @tbouffard in #626
- feat!: make edge bend points easier to manage by @tbouffard in #633
🐛 Bug Fixes
- fix: correct rotation handle positioning during vertex rotation by @HalilFocic in #592
- fix(VertexHandler): do not create label handle for swimlane by @tbouffard in #607
- fix: popup menu story caused has more submenus open by @HalilFocic in #572
- fix(TooltipHandler): initialize the div when tooltip is shown by @HalilFocic in #591
- fix: ensure that codecs for base JS elements are registered by @tbouffard in #610
- fix(story): correctly set the perimeter on labels at page load by @HalilFocic in #589
📝 Documentation
- docs: add a page to highlight demo and examples by @tbouffard in #602
- docs: add links to specific examples and demos in various pages by @tbouffard in #603
- docs: add content to getting started page by @HalilFocic in #598
- docs: fix link to getting-started page by @tbouffard in #606
- docs: add a Codecs page by @tbouffard in #524
- docs: migrate the mxGraph tutorial by @tbouffard in #618
- docs: remove mxGraph resources that are no longer used by @tbouffard in #621
- docs: reorganize and improve the manual pages by @tbouffard in #622
- docs: integrate contents from the mxGraph Java manual by @tbouffard in #624
- docs: highlight the getting started page by @tbouffard in #625
- docs: fix a broken link in the migrate from mxGraph guide by @tbouffard in #627
- docs: update references to GraphDataModel by @tbouffard in #641
- docs: integrate remaining mxGraph resources by @tbouffard in #642
- docs: apply minor improvements by @tbouffard in #647
⚙️ Refactor
- refactor(VertexHandler): simplify management of
style.rotation
by @tbouffard in #634 - refactor: migrate the "Animation" story to TypeScript by @tbouffard in #635
- refactor: migrate the "AutoLayout" story to TypeScript by @tbouffard in #638
- refactor: remove clipboard fallback for old browsers by @tbouffard in #645
- refactor!: remove unused domUtils.importNodeImplementation by @tbouffard in #648
🛠 Chore
- ci: build and deploy the website when the storybook resources change by @tbouffard in #609
- ci: configure dependabot to update JavaScript dependencies by @tbouffard in #629
- ci: fix dependabot configuration by @tbouffard in #630
- ci: improve the template of the GitHub release by @tbouffard in #593
- chore: add a script to simplify version update on release by @tbouffard in #650
Full Changelog: v0.14.0...v0.15.0
0.14.0
⚡ This new version offers more configuration options for vertex and edge handles, and allows certain default style configurations to be globally replaced. ⚡
🎉 We've made it easier to shape your graphs the way you want!
Labels are now editable out of the box ✍️, handles can be customized with ease 🎨, and shadows have new global style options 🌌.
Many thanks to @HalilFocic for all the fixes provided and those to come! 🙌
Resources
- npm package: 0.14.0
- Fixed issues: milestone 0.14.0
- Changelog: Changelog
Highlights
Editable Labels and Correct Editing Position
Labels are now editable by default for both vertices and edges, restoring the expected behavior seen in mxGraph
.
Previously, due to a bug, making the label editable required configuring the Cell style with:
style.editable = true;
This is no longer necessary.
In addition, when editing a label, the editing area now appears exactly where the label is in "view" mode. Previously, a bug caused it to appear at the bottom of the page, which was... less than ideal. 😅
PR_567_label_edition.webm
Tip
If you want to restore the previous behavior (cells not editable), use one of the following:
const graph = new Graph(container);
// forbid cell label edition
graph.setCellsEditable(false);
// make vertex labels not editable by default (use the getDefaultEdgeStyle to apply the same to the edge labels)
graph.getStylesheet().getDefaultVertexStyle().editable = false;
// and if you want to make the label of a specific vertex editable
vertex.style.editable = true;
More Configuration Options for EdgeHandler and VertexHandler
Edge handles, which represent the edge points when an edge is selected, can now be a "circle" ⚪ instead of just a "square" ⬛.
Configuration for EdgeHandler
and VertexHandler
is now more straightforward. Previously, changing default values like the color or size of handles required extending the original implementation.
Now, you can use simple configuration value objects to change default settings, such as:
EdgeHandlerConfig.handleShape = 'circle';
EdgeHandlerConfig.selectionColor = 'blue';
EdgeHandlerConfig.selectionDashed = false;
// configure the label handle of both edge and vertex
HandleConfig.size = 8;
HandleConfig.strokeColor = '#0088cf';
VertexHandlerConfig.selectionColor = 'orange';
Check it out in the story:
- Code: CustomHandlesConfiguration.stories.ts
- Live demo: CustomHandlesConfiguration story
rn_0.14.0_custom_handles_config.webm
Important
Not all default values are configurable for now. This is a first step, stay tuned for future updates. For more details, see issue #192.
Override the Default Shadow Style Values
Global style defaults are defined in the constants
namespace, and up until now, changing them globally wasn't possible. You could only change them for an instance of Graph
with custom configurations for edge and vertex default styles.
Starting with version 0.14.0, you can now change the default shadow styles globally for all instances of Graph
:
StyleDefaultsConfig.shadowColor = 'chartreuse';
StyleDefaultsConfig.shadowOpacity = 0.5;
Check out the new CustomStyleDefaults
story to see it in action:
- Code: CustomStyleDefaults.stories.ts
- Live demo: CustomStyleDefaults story
PR_577_custom_default_shadow_styles.webm
Note
For more details, see issue #577.
Important
Overriding more default style values will be possible in the future. This is just the beginning—stay tuned for more updates! For details, see issue #192.
What's Changed
🎉 New Features
- feat: allow usage of functions in
CellStateStyle.edgeStyle
by @tbouffard in #563 - feat: ease configuration of handles in
VertexHandler
by @tbouffard in #569 - feat: let configure the defaults value of the shadow styles by @tbouffard in #577
- feat: ease configuration of handles in
EdgeHandler
by @tbouffard in #576 - feat: allow the use of circles for edge handles by @tbouffard in #586
🐛 Bug Fixes
- fix: correctly use the default value of
CellStateStyle.editable
by @tbouffard in #570 - fix: improve the panning on iOS/iPadOS by @HalilFocic in #566
- fix(label): improve editing position and 'label changed" event by @HalilFocic in #567
- fix(VertexHandle): add missing setPosition call in processEvent by @HalilFocic in #583
📝 Documentation
- docs: explain what is included in the changelog file by @tbouffard in #561
- docs: improve JSDoc of elements in the
constants
namespace by @tbouffard in #568 - docs: improve JSDoc of handlers and constants by @tbouffard in #575
- docs: mention examples in the documentation introduction by @tbouffard in #585
⚙️ Refactor
- refactor(CellMixin): simplify
isCell*able
methods by @tbouffard in #571 - refactor: use constants.NS_SVG instead of hard coded values by @tbouffard in #578
- refactor: simplify the reset config functions by @tbouffard in #582
🛠 Chore
- chore: build with node 20 by @tbouffard in #560
New Contributors
- @HalilFocic made their first contribution in #566
Full Changelog: v0.13.1...v0.14.0
0.13.1
⚡ This release contains documentation improvements and bug fixes (mainly for MaxPopupMenu
and PrintPreview
). ⚡
npm package: 0.13.1
Fixed issues: milestone 0.13.1
See also the Changelog file.
What's Changed
🐛 Bug Fixes
- fix(story): convert page-breaks story to typescript and add missing imports by @reuse-ay in #537
- fix: add missing
printUtils
export by @tbouffard in #538 - fix(PrintPreview): Execute writeHead even if css is null by @reuse-ay in #541
- fix: correctly call methods in TemporaryCellStates and PrintPreview by @tbouffard in #546
- fix: display submenu image in MenuStyle story by @tbouffard in #551
- fix: make ShowRegion story correctly create the preview page by @tbouffard in #553
- fix: improve type of the handler parameter in
factoryMethod
by @tbouffard in #554 - fix: allow to insert vertex without setting position and size by @tbouffard in #555
📝 Documentation
- docs: update CHANGELOG for 0.13.0 by @tbouffard in #514
- docs: improve CHANGELOG for 0.13.0 by @tbouffard in #516
- docs(README): improve the mxGraph documentation migration status by @tbouffard in #522
- docs: fix "edit this page" URL by @tbouffard in #525
- docs: shorten the title of the "migrate from mxGraph" page by @tbouffard in #528
- docs: simplify PR size requirement in the PR template by @tbouffard in #542
- docs: improve JSDoc of
PrintPreview
by @tbouffard in #549 - docs(migrate): improve
mxGraphModel
paragraph by @tbouffard in #550 - docs: provide more information about global configuration by @tbouffard in #557
- docs: improve the "migrate from mxGraph" guide by @tbouffard in #556
⚙️ Refactor
- refactor: improve signature of some
PrintPreview
methods by @tbouffard in #548
🛠 Chore
- chore(test): switch from ts-jest to @swc/jest by @tbouffard in #540
- chore(package): store application resources in the
lib
folder by @tbouffard in #543
New Contributors
Full Changelog: v0.13.0...v0.13.1