11import {
2+ type AbstractCanvas2D ,
3+ CellRenderer ,
24 constants ,
3- getDefaultPlugins ,
5+ EdgeStyle ,
6+ EllipseShape ,
47 Graph ,
5- GraphDataModel ,
68 InternalEvent ,
9+ MarkerShape ,
10+ PanningHandler ,
711 Perimeter ,
12+ type Point ,
813 RubberBandHandler ,
14+ SelectionCellsHandler ,
15+ SelectionHandler ,
16+ type Shape ,
17+ type StyleArrowValue ,
18+ StyleRegistry ,
919} from '@maxgraph/core' ;
1020import { registerCustomShapes } from "./custom-shapes" ;
1121
22+
23+ // TODO remove this function when maxGraph 0.18.0 is released and import it from maxGraph instead using EdgeMarker.createArrow
24+ // It is currently duplicated from maxGraph as it is not exported in version 0.17.0
25+ const createArrow =
26+ ( widthFactor : number ) =>
27+ (
28+ canvas : AbstractCanvas2D ,
29+ _shape : Shape ,
30+ type : StyleArrowValue ,
31+ pe : Point ,
32+ unitX : number ,
33+ unitY : number ,
34+ size : number ,
35+ _source : boolean ,
36+ sw : number ,
37+ filled : boolean
38+ ) => {
39+ // The angle of the forward facing arrow sides against the x axis is
40+ // 26.565 degrees, 1/sin(26.565) = 2.236 / 2 = 1.118 ( / 2 allows for
41+ // only half the strokewidth is processed ).
42+ const endOffsetX = unitX * sw * 1.118 ;
43+ const endOffsetY = unitY * sw * 1.118 ;
44+
45+ unitX *= size + sw ;
46+ unitY *= size + sw ;
47+
48+ const pt = pe . clone ( ) ;
49+ pt . x -= endOffsetX ;
50+ pt . y -= endOffsetY ;
51+
52+ const f = type !== constants . ARROW . CLASSIC && type !== constants . ARROW . CLASSIC_THIN ? 1 : 3 / 4 ;
53+ pe . x += - unitX * f - endOffsetX ;
54+ pe . y += - unitY * f - endOffsetY ;
55+
56+ return ( ) => {
57+ canvas . begin ( ) ;
58+ canvas . moveTo ( pt . x , pt . y ) ;
59+ canvas . lineTo (
60+ pt . x - unitX - unitY / widthFactor ,
61+ pt . y - unitY + unitX / widthFactor
62+ ) ;
63+
64+ if ( type === constants . ARROW . CLASSIC || type === constants . ARROW . CLASSIC_THIN ) {
65+ canvas . lineTo ( pt . x - ( unitX * 3 ) / 4 , pt . y - ( unitY * 3 ) / 4 ) ;
66+ }
67+
68+ canvas . lineTo (
69+ pt . x + unitY / widthFactor - unitX ,
70+ pt . y - unitY - unitX / widthFactor
71+ ) ;
72+ canvas . close ( ) ;
73+
74+ if ( filled ) {
75+ canvas . fillAndStroke ( ) ;
76+ } else {
77+ canvas . stroke ( ) ;
78+ }
79+ } ;
80+ } ;
81+
82+ /**
83+ * Create a custom implementation to not load all default built-in styles. This is because Graph registers them.
84+ *
85+ * In the future, we expect to have an implementation of Graph that does not do it.
86+ * See https://github.com/maxGraph/maxGraph/issues/760
87+ */
88+ class CustomGraph extends Graph {
89+ /**
90+ * Only registers the elements required for this example. Do not let Graph load all default built-in styles.
91+ */
92+ protected override registerDefaults ( ) {
93+ // Register builtin shapes
94+ // RectangleShape is not registered here because it is always available. It is the fallback shape for vertices when no shape is returned by the registry
95+ // TODO remove ts-ignore when maxGraph 0.18.0 is released
96+ // @ts -ignore
97+ CellRenderer . registerShape ( 'ellipse' , EllipseShape ) ;
98+
99+ // Register builtin styles
100+ StyleRegistry . putValue ( 'ellipsePerimeter' , Perimeter . EllipsePerimeter ) ;
101+ StyleRegistry . putValue ( 'rectanglePerimeter' , Perimeter . RectanglePerimeter ) ; // declared in the default vertex style, so must be registered to be used
102+ StyleRegistry . putValue ( 'orthogonalEdgeStyle' , EdgeStyle . OrthConnector ) ;
103+
104+ const arrowFunction = createArrow ( 2 ) ;
105+ MarkerShape . addMarker ( 'classic' , arrowFunction ) ;
106+ MarkerShape . addMarker ( 'block' , arrowFunction ) ;
107+
108+ // Register custom shapes
109+ registerCustomShapes ( ) ;
110+ }
111+ }
112+
12113/**
13114 * Initializes the graph inside the given container.
14115 * @param container if not set, use the element matching the selector '#graph-container'
@@ -19,71 +120,60 @@ export const initializeGraph = (container?: HTMLElement) => {
19120 // Disables the built-in context menu
20121 InternalEvent . disableContextMenu ( container ) ;
21122
22- const graph = new Graph ( container , new GraphDataModel ( ) , [
23- ... getDefaultPlugins ( ) ,
123+ const graph = new CustomGraph ( container , undefined , [
124+ PanningHandler , // Enables panning with the mouse
24125 RubberBandHandler , // Enables rubber band selection
126+ SelectionCellsHandler , // Enables management of selected cells
127+ SelectionHandler , // Enables selection with the mouse
25128 ] ) ;
26129 graph . setPanning ( true ) ; // Use mouse right button for panning
27130
28131 // Customize the rubber band selection
29132 graph . getPlugin < RubberBandHandler > ( 'RubberBandHandler' ) . fadeOut = true ;
30133
31- // shapes and styles
32- registerCustomShapes ( ) ;
33134 // create a dedicated style for "ellipse" to share properties
34135 graph . getStylesheet ( ) . putCellStyle ( 'myEllipse' , {
35- perimeter : Perimeter . EllipsePerimeter ,
136+ perimeter : 'ellipsePerimeter' ,
36137 shape : 'ellipse' ,
37138 verticalAlign : 'top' ,
38139 verticalLabelPosition : 'bottom' ,
39140 } ) ;
40141
41- // Gets the default parent for inserting new cells. This
42- // is normally the first child of the root (ie. layer 0).
43- const parent = graph . getDefaultParent ( ) ;
44-
45142 // Adds cells to the model in a single step
46143 graph . batchUpdate ( ( ) => {
47- // use the legacy insertVertex method
48- const vertex01 = graph . insertVertex (
49- parent ,
50- null ,
51- 'a regular rectangle' ,
52- 10 ,
53- 10 ,
54- 100 ,
55- 100
144+ const vertex01 = graph . insertVertex ( {
145+ value : 'a regular rectangle' ,
146+ position : [ 10 , 10 ] ,
147+ size : [ 100 , 100 ] ,
148+ }
56149 ) ;
57- const vertex02 = graph . insertVertex (
58- parent ,
59- null ,
60- 'a regular ellipse' ,
61- 350 ,
62- 90 ,
63- 50 ,
64- 50 ,
65- {
66- baseStyleNames : [ 'myEllipse' ] ,
67- fillColor : 'orange' ,
150+ const vertex02 = graph . insertVertex ( {
151+ value : 'a regular ellipse' ,
152+ position : [ 350 , 90 ] ,
153+ size : [ 50 , 50 ] ,
154+ style : {
155+ baseStyleNames : [ 'myEllipse' ] ,
156+ fillColor : 'orange' ,
157+ }
68158 }
69159 ) ;
70- // use the legacy insertEdge method
71- graph . insertEdge ( parent , null , 'an orthogonal style edge' , vertex01 , vertex02 , {
72- edgeStyle : constants . EDGESTYLE . ORTHOGONAL ,
73- rounded : true ,
160+ graph . insertEdge ( {
161+ value : 'an orthogonal style edge' ,
162+ source : vertex01 ,
163+ target : vertex02 ,
164+ style : {
165+ edgeStyle : 'orthogonalEdgeStyle' ,
166+ rounded : true ,
167+ }
74168 } ) ;
75169
76- // insert vertex using custom shapes using the new insertVertex method
77170 const vertex11 = graph . insertVertex ( {
78- parent,
79171 value : 'a custom rectangle' ,
80172 position : [ 20 , 200 ] ,
81173 size : [ 100 , 100 ] ,
82174 style : { shape : 'customRectangle' } ,
83175 } ) ;
84- // use the new insertVertex method using position and size parameters
85176 const vertex12 = graph . insertVertex ( {
86- parent,
87177 value : 'a custom ellipse' ,
88178 x : 150 ,
89179 y : 350 ,
@@ -94,9 +184,7 @@ export const initializeGraph = (container?: HTMLElement) => {
94184 shape : 'customEllipse' ,
95185 } ,
96186 } ) ;
97- // use the new insertEdge method
98187 graph . insertEdge ( {
99- parent,
100188 value : 'another edge' ,
101189 source : vertex11 ,
102190 target : vertex12 ,
0 commit comments