A web-based diagramming tool for Event Modeling built on top of diagram-js
.
-
Prerequisites
- Node.js 18+ (recommended: 20 LTS)
- npm 9+
-
Install
npm install
-
Start dev server
npm run dev
- Open the URL shown in your terminal (default:
http://localhost:5173/
)
-
Build for production
npm run build
- Output in
dist/
-
Optional tooling
- Format:
npm run format
- Lint:
npm run lint
- Format:
-
Directory layout
src/Editor.js
: Editor bootstrap and module compositionsrc/main.js
: App entry (creates the editor)src/modeling/*
: Domain element factory, modeling commandssrc/providers/*
: Palette provider(s)src/render/*
: Custom renderer, text rendering, path mapsrc/spec/*
: Domain specs (business objects)src/utils/*
: Utility helperspublic/
: Static assetsindex.html
: App shell
References:
- diagram-js: https://github.com/bpmn-io/diagram-js
- Sliceify composes custom modules (providers, modeling, renderer) with diagram-js’ core features (palette, selection, move, connect, etc.).
- It separates domain data (businessObject) from presentation (geometry, color, label styles) on the diagram element.
- Modules are wired through diagram-js’ dependency injection (DI) container.
src/Editor.js
extendsDiagram
(from diagram-js) and composes:- Custom modules:
providers
,render
,modeling
- Built-in modules: palette, selection, move, connect, snapping, grid, etc.
- Custom modules:
src/main.js
instantiatesEditor
, passing the canvas container and optionaladditionalModules
(to inject config or overrides).
- Each module exports a plain object with:
__depends__
: other modules it requires__init__
: services to instantiate eagerly- service providers:
name: ['type'|'value'|'factory', Provider]
- Services declare dependencies via
Service.$inject = [...]
. - You can pass config via “value services” in
additionalModules
, e.g.:{ 'config.Renderer': ['value', { defaultFillColor: 'white' }] }
-
Modeling (
src/modeling/index.js
)- Registers:
elementFactory
: custom factory for diagram elementsmodeling
: extends diagram-js modeling to add commandsEMFactory
: creates domain business objects (Specs) + defaults
- Depends on core diagram-js modeling, rules, selection, command stack.
- Registers:
-
Providers (
src/providers/index.js
)- Registers the palette provider (
paletteProvider
) which populates the left-hand palette.
- Registers the palette provider (
-
Rendering (
src/render/index.js
)- Registers:
renderer
: customBaseRenderer
override for shapestextRenderer
: wraps diagram-jsText
util with defaultspathMap
: optional vector path utilities for icons/markers
- Registers:
- Located in
src/spec/*
. - Examples:
Event
,Element
,Field
. - Each spec uses normalized, lower-cased domain fields like:
type
,name
,description
,metadata
. - Defaults useful to the UI are attached to the prototype for palette/renderer usage:
Event.prototype.THUMBNAIL_CLASS
Event.prototype.DEFAULT_SIZE
Event.prototype.DEFAULT_COLOR
Event.prototype.type = 'Event'
src/modeling/EMFactory.js
- Maps a
type
to a Spec class and instantiates it:create(type) => new Spec()
. - Provides default accessors:
getDefaultSize(semantic)
andgetDefaultColor(semantic)
src/modeling/ElementFactory.js
- Overrides
create(elementType, attrs)
to:- Ensure
attrs.businessObject
(creates viaEMFactory
if missing) - Apply defaults:
- width/height from
EMFactory.getDefaultSize()
- color on the element (presentation), not on the business object
- width/height from
- Delegate to base factory to produce the actual shape
- Ensure
Example (from the palette):
const shape = elementFactory.createShape({ type: 'Event' });
src/modeling/Modeling.js
extends diagram-jsBaseModeling
.- Adds custom command
element.updateProperties
that mutates the business object via a handler (undo/redo through the command stack). - Provides a
connect
helper that consultsrules
when connecting elements.
-
src/render/Renderer.js
extends diagram-jsBaseRenderer
:- Declares handlers per element type (e.g.,
Event
) to draw shapes. - Uses
renderEmbeddedLabel
to create styled SVG text viatextRenderer
. - Reads color from the element first (
element.color || bo.color
). - Label styling can be customized per call via an options object (
align
,fontSize
,fontWeight
,style
).
- Declares handlers per element type (e.g.,
-
src/render/TextRenderer.js
wraps diagram-jsText
util with default font settings (configurable viaconfig.textRenderer
). -
src/render/PathMap.js
provides optional vector path utilities (for icons/markers). It is not required for simple rectangles/labels; use it if you add richer pictograms.
src/providers/PaletteProvider.js
- Registers palette entries (tools + create actions).
- On click/drag, calls
elementFactory.createShape({ type })
and starts thecreate
interaction. - Uses each Spec’s prototype constants for the entry (e.g.,
THUMBNAIL_CLASS
).
- Domain (businessObject): holds domain fields only (
type
,name
,source
, etc.). - Presentation (element): holds visual attributes (
x
,y
,width
,height
,color
, label styles). - Renderer reads presentation attributes from the element.
- Create a Spec in
src/spec/
:
export default class Command extends Element {}
Command.prototype.type = 'Command';
Command.prototype.DEFAULT_SIZE = { width: 120, height: 60 };
Command.prototype.DEFAULT_COLOR = '#4f46e5';
Command.prototype.THUMBNAIL_CLASS = 'palette-icon-create-command';
- Register in
EMFactory
:
typeToSpec.set('Command', Command);
- Add a palette entry:
entries['create-Command'] = createAction(
'Command',
'state',
Command.prototype.THUMBNAIL_CLASS,
'Create Command'
);
- Render it in
Renderer
:
handlers.Command = (parentGfx, element) => {
const rect = drawRect(parentGfx, element.width, element.height, 0, {
fill: getFillColor(element, defaultFillColor),
stroke: getStrokeColor(element, defaultStrokeColor)
});
renderEmbeddedLabel(parentGfx, element, { align: 'left-top', fontWeight: 'bold' });
return rect;
};
- (Optional) Define rules if creation or connections must be restricted.
- Create a custom
RuleProvider
module to control creation, connection, and move behavior. This keeps the editor predictable as types and features grow.
- Export/import a JSON schema with:
- Elements:
id
,type
,x
,y
,width
,height
, and presentation attrs - Business objects: domain fields needed for your model
- Elements:
- Keep domain and presentation separated in your schema.
- Provide defaults at startup using
additionalModules
:
new Editor({
container: document.querySelector('#canvas'),
additionalModules: [
{ 'config.Renderer': ['value', { defaultFillColor: 'white', defaultStrokeColor: '#111' }] },
{ 'config.textRenderer': ['value', { defaultStyle: { fontSize: 14 } }] }
]
});
- diagram-js: https://github.com/bpmn-io/diagram-js