mxGraph usage in TypeScript projects
Thomas Bouffard
Posted on June 1, 2021
This article is the first one of a series about mxGraph, the Javascript diagramming library.
Over the last few months, my team has used it on a day-to-day basis as the rendering foundation of bpmn-visualization, an open source TypeScript library for visualizing process execution data on BPMN diagrams.
In this series, I will share integration challenges and solutions when using mxGraph in TypeScript projects, tooling developed to simplify mxGraph based developments, rendering extensions, usage tips and much more.
Most aspects described in the articles will also apply to JavaScript projects using mxGraph.
mxGraph and TypeScript: is it possible?
A few years ago, the mxGraph core development team stated that it would never port mxGraph to TypeScript, nor support it, and this was still applicable in 2020. (See issue #81 and related issues for more.)
If it is not supported, why would you even want to use mxGraph in a TypeScript project? Well, if your application integrates Angular or React, you probably already use TypeScript, so if you want to add mxGraph, a TypeScript integration would be nice.
You might also find it useful in vanilla TypeScript applications, or libraries like bpmn-visualization. When my team started our development, we wanted to build a TypeScript library that uses mxGraph for rendering.
In this article, I’ll explain how we handled this, the issues we faced, and how we have successfully integrated mxGraph.
“Cactus” by Steven Ritts
Plenty of disappointing examples and solutions
We started out as most developers do: when we saw that mxGraph has no native TypeScript support, we went to check how other people might have tried to do it.
However, we saw - almost always - the same kinds of custom, hacky, and disappointing solutions. Let’s look at some of them and why we thought they are a pain.
The ‘any’ way
No mxGraph native Typescript support? No problem, let’s use any everywhere!
declare var mxGraph: any;
const graph = new mxGraph(this.graphContainer.nativeElement);
Using any is fast, but be ready for no code assistance, no TypeScript compiler checks. In short, this is not the TypeScript way you expect. And remember, this is something the TypeScript documentation recommends not to do.
You may also use unknown which is better for the TypeScript compiler, but it won't help much more than any.
Examples:
- https://therichpost.com/angular-8-mxgraph-working-example/
- https://stackoverflow.com/questions/63495464/error-during-mxgraph-integration-with-angular-10
The ‘define your own mxGraph types’ way
Define your own mxGraph types for only the parts of the lib you are using.
This is only viable if you use a very small part of mxGraph. It is a large library, and as you use more and more features, the number of types you have to maintain increases.
The ‘copy unmaintained types’ way
Retrieve the work done by a single individual who has shared their attempt on mxGraph types, and copy everything directly in your project.
Be ready for a maintenance nightmare:
the types may be out of date, full of any instead of actual types, so you will find yourself modifying the types anyway
as mxGraph evolves, you will also have to update the types to reflect API changes
and...you will work alone on this tedious task.
This is a lot of extra work, and probably not what you expect from a true integration.
Examples:
- https://medium.com/habilelabs/how-to-integrate-mx-graph-with-angular-8-b4a8bb800694
- https://itnext.io/how-to-integrate-mxgraph-with-angular-6-18c3a2bb8566
“Road Between Pine Trees” by veeterzy
Searching for true mxgraph types
mxGraph is not the sole JavaScript library that hasn’t TypeScript native support.
In such situations, DefinitelyTyped is the way to go. It is a community-led open-source repository for TypeScript type
definitions.
Using types from DefinitelyTyped is very easy. Once you add the types package as a dependency of your project, TypeScript is automatically
able to read the types without any extra configuration. Unfortunately, although there is a request for adding mxGraph types to DefinitelyTyped, we found that there was no one working on it in 2020.
We also found some individual efforts to make mxGraph TypeScript usage easier. But everyone appeared to be working individually on their own solutions, leading to the following issues:
Most repository owners said that the type definition files in their project were not complete (or something similar). mxGraph provides a large API, so it is hard to keep types in sync as the lib evolves.
It is almost impossible to know which mxGraph version was targeted by the various type definition packages.
As we found several solutions and npm packages, so it was hard to find the best way to use mxGraph in a TypeScript project.
mxGraph is a very large library, which may frighten people about starting extracting and maintaining types.
If you are interested in more information, you can check this non-exhaustive list (last updated in mid-2020) that presents various solutions with
information about their activity status and implementation choices.
“Beautiful sunlight through clouds” by Yury Khristich
The 2021 solution
In 2020, a community effort emerged to make mxGraph types available in a consistent way, and a viable solution is now available.
This first started as mxgraph-type-definitions. Most parts of mxGraph were covered progressively, and types became more
accurate thanks to user feedback. Projects like grafana-flowcharting began using it.
Because it had issues integrating with the mxGraph npm package, it evolved into typed-mxgraph in Fall 2020, and mxgraph-type-definitions was finally deprecated in December 2020.
This effort is still led by @hungtcs, the original creator of the mxgraph-type-definitions repository.
Here is an example of what you can write with typed-mxgraph:
class Application {
constructor(container: HTMLElement) {
const graph: mxGraph = new mx.mxGraph(container);
const model: mxGraphModel = graph.getModel();
model.beginUpdate();
try {
graph.insertVertex(graph.getDefaultParent(), '', 'TEST', 0, 0, 100, 100);
} finally {
model.endUpdate();
}
}
}
Our bpmn-visualization project has followed a similar evolutionary path to the mxGraph usage in TypeScript projects.
We initially started with our own ts-mxgraph fork, and we were forced to manage the types by ourselves. We struggled with out-of-date types and had to manage updates for our sole usage.
When mxgraph-type-definitions was mature enough, we used it in our production code. We quickly benefited from fixes and started contributing to improve the types we used in our project.
We still needed ts-mxgraph for our tests due to the existing issue with the mxgraph npm package integration.
And now, we have recently fully switched to typed-mxgraph using examples like the mxgraph TypeScript example bundled with webpack.
So we have been able to remove our ts-mxgraph fork. We can focus all our mxgraph integration efforts to giving back to the community and getting further improvements from the community as well.
Take Away
The mxGraph TypeScript integration was difficult and painful in the past, but in 2021 we now have a solution with typed-mxgraph.
There is no more need for hacky solutions. mxGraph can be integrated into TypeScript projects as with any JavaScript library without native TypeScript support, and it's possible to get code assistance and TypeScript compiler checks.
typed-mxgraph is still a young solution and it will benefit from wider adoption. So, if you are using mxGraph and are using it or want to use it in TypeScript projects, feel free to contribute to typed-mxgraph.
There are a large number of areas that can be improved:
provide usage feedback (missing or incorrect types)
improve the types coverage
improve usage documentation
enrich existing examples (more mxGraph API usage) or provide new ones
help keeping types up to date as the mxGraph javascript library changes
We welcome your contribution to the typed-mxgraph team!
This article was originally published at Dzone
Posted on June 1, 2021
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.