power-link 0.0.6 → 0.0.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +238 -31
  2. package/dist/index.js +2 -2
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -1,16 +1,16 @@
1
1
  # power-link
2
2
 
3
- [![npm version](https://img.shields.io/npm/v/node-link-utils.svg)](https://www.npmjs.com/package/node-link-utils)
4
- [![license](https://img.shields.io/npm/l/node-link-utils.svg)](https://github.com/your-username/node-link-utils/blob/main/LICENSE)
3
+ [![npm version](https://img.shields.io/npm/v/power-link.svg)](https://www.npmjs.com/package/power-link)
4
+ [![license](https://img.shields.io/npm/l/power-link.svg)](https://github.com/Tem-man/power-link/blob/main)
5
5
 
6
6
  A pure JavaScript visual node connector for creating draggable connections between nodes. Framework-agnostic and easy to use.
7
7
 
8
- ![Node Link Connector Demo](https://github.com/Tem-man/node-link-utils/blob/main/packages/images/screen-shot.png)
8
+ ![Node Link Connector Demo](https://github.com/Tem-man/power-link/blob/main/public/images/screen-shot.png)
9
9
 
10
10
  ### 📹 Demo Video
11
11
 
12
12
  <video width="100%" controls>
13
- <source src="https://github.com/Tem-man/node-link-utils/raw/main/packages/images/video.mp4" type="video/mp4">
13
+ <source src="https://github.com/Tem-man/power-link/blob/main/public/images/video.mp4" type="video/mp4">
14
14
  Your browser does not support the video tag.
15
15
  </video>
16
16
 
@@ -74,7 +74,7 @@ const connector = new Connector({
74
74
 
75
75
  onDisconnect: (connection) => {
76
76
  console.log("Connection removed:", connection);
77
- },
77
+ }
78
78
  });
79
79
 
80
80
  // 3. Register nodes
@@ -82,20 +82,33 @@ const node1 = document.getElementById("node1");
82
82
  const node2 = document.getElementById("node2");
83
83
 
84
84
  connector.registerNode("node1", node1, {
85
- dotPositions: ["right"], // Only right connection dot
85
+ dotPositions: ["right"] // Only right connection dot
86
86
  });
87
87
 
88
88
  connector.registerNode("node2", node2, {
89
- dotPositions: ["left", "right"], // Both left and right dots
89
+ dotPositions: ["left", "right"] // Both left and right dots
90
90
  });
91
91
  ```
92
92
 
93
93
  ### HTML Structure
94
94
 
95
95
  ```html
96
- <div id="connector-container" style="position: relative; height: 600px;">
97
- <div id="node1" style="position: absolute; left: 100px; top: 100px;">Node 1</div>
98
- <div id="node2" style="position: absolute; left: 400px; top: 100px;">Node 2</div>
96
+ <div
97
+ id="connector-container"
98
+ style="position: relative; height: 600px;"
99
+ >
100
+ <div
101
+ id="node1"
102
+ style="position: absolute; left: 100px; top: 100px;"
103
+ >
104
+ Node 1
105
+ </div>
106
+ <div
107
+ id="node2"
108
+ style="position: absolute; left: 400px; top: 100px;"
109
+ >
110
+ Node 2
111
+ </div>
99
112
  </div>
100
113
  ```
101
114
 
@@ -114,6 +127,11 @@ connector.registerNode("node2", node2, {
114
127
  | `enableNodeDrag` | Boolean | `true` | Enable node dragging |
115
128
  | `enableSnap` | Boolean | `true` | Enable connection snapping |
116
129
  | `snapDistance` | Number | `20` | Snap distance in pixels |
130
+ | `enableZoom` | Boolean | `true` | Enable zoom functionality |
131
+ | `enablePan` | Boolean | `true` | Enable pan functionality |
132
+ | `minZoom` | Number | `0.1` | Minimum zoom level (10%) |
133
+ | `maxZoom` | Number | `4` | Maximum zoom level (400%) |
134
+ | `zoomStep` | Number | `0.1` | Zoom step size (10%) |
117
135
  | `onConnect` | Function | `() => {}` | Callback when connection is created |
118
136
  | `onDisconnect` | Function | `() => {}` | Callback when connection is removed |
119
137
 
@@ -133,6 +151,7 @@ Register a node for connection.
133
151
  - `['left', 'right']`: Array format, both sides
134
152
  - `['left']`: Only left dot
135
153
  - `['right']`: Only right dot
154
+ - `info` (Object): Node extraneous information
136
155
 
137
156
  **Returns:** Node object
138
157
 
@@ -141,10 +160,15 @@ Register a node for connection.
141
160
  ```javascript
142
161
  connector.registerNode("myNode", element, {
143
162
  dotPositions: ["right"],
163
+ info: {
164
+ id: "123",
165
+ name: "apple",
166
+ desc: "this is a red apple"
167
+ }
144
168
  });
145
169
  ```
146
170
 
147
- #### `createConnection(fromNode, toNode, fromDot, toDot)`
171
+ #### `createConnection(fromNode, toNode, fromDot, toDot,options)`
148
172
 
149
173
  Programmatically create a connection between nodes.
150
174
 
@@ -154,6 +178,8 @@ Programmatically create a connection between nodes.
154
178
  - `toNode` (Object): Target node object
155
179
  - `fromDot` (Object): Source connection dot (optional)
156
180
  - `toDot` (Object): Target connection dot (optional)
181
+ - `options` (Object): Configuration options (optional)
182
+ - `silent` (boolean): Whether to create silently (without triggering callbacks)
157
183
 
158
184
  **Returns:** Connection object
159
185
 
@@ -162,22 +188,26 @@ Programmatically create a connection between nodes.
162
188
  ```javascript
163
189
  const node1 = connector.nodes[0];
164
190
  const node2 = connector.nodes[1];
165
- connector.createConnection(node1, node2);
191
+ connector.createConnection(node1, node2); // Create connection with callbacks
192
+ connector.createConnection(node1, node2, null, null, { silent: true }); // Create connection silently without triggering callbacks
166
193
  ```
167
194
 
168
- #### `disconnect(connectionId)`
195
+ #### `disconnect(connectionId,options)`
169
196
 
170
197
  Remove a connection.
171
198
 
172
199
  **Parameters:**
173
200
 
174
201
  - `connectionId` (String): Connection ID (optional, if not provided, removes all connections)
202
+ - `options` (Object): Configuration options (optional)
203
+ - `silent` (boolean): Whether to disconnect silently (without triggering callbacks)
175
204
 
176
205
  **Example:**
177
206
 
178
207
  ```javascript
179
208
  connector.disconnect(); // Remove all connections
180
209
  connector.disconnect("connection-id"); // Remove specific connection
210
+ connector.disconnect("connection-id", { silent: true }); // Remove connection silently without triggering callbacks
181
211
  ```
182
212
 
183
213
  #### `getConnections()`
@@ -211,25 +241,65 @@ Update node position (called when node is moved).
211
241
 
212
242
  - `nodeId` (String): Node ID
213
243
 
214
- #### `destroy()`
244
+ #### `destroy(options)`
215
245
 
216
246
  Destroy the connector and clean up all resources.
217
247
 
248
+ **Parameters:**
249
+
250
+ - `options` (Object): Configuration options (optional)
251
+ - `silent` (boolean): Whether to destroy silently (without triggering callbacks)
252
+
218
253
  **Example:**
219
254
 
220
255
  ```javascript
221
- connector.destroy();
256
+ connector.destroy(); // Destroy silently by default (without triggering callbacks)
257
+ connector.destroy({ silent: false }); // Destroy non-silently (triggering callbacks)
258
+ ```
259
+
260
+ #### `setViewState(scale,translateX,translateY)`
261
+
262
+ Set the initial view state
263
+
264
+ **Parameters:**
265
+
266
+ - `scale` (Number): set initial view scale
267
+ - `translateX` (Number): set initial view x-axis translation
268
+ - `translateY` (Number): set initial view y-axis translation
269
+
270
+ **Example:**
271
+
272
+ ````javascript
273
+ connector.setViewState({
274
+ scale: 0.8,
275
+ translateX: 50,
276
+ translateY: 30
277
+ })
222
278
  ```
223
279
 
280
+
224
281
  ## 🎨 Usage Examples
225
282
 
226
283
  ### Vue 3
227
284
 
228
285
  ```vue
229
286
  <template>
230
- <div class="container" ref="containerRef">
231
- <div class="node" ref="node1Ref">Node 1</div>
232
- <div class="node" ref="node2Ref">Node 2</div>
287
+ <div
288
+ class="container"
289
+ ref="containerRef"
290
+ >
291
+ <div
292
+ class="node"
293
+ ref="node1Ref"
294
+ >
295
+ Node 1
296
+ </div>
297
+ <div
298
+ class="node"
299
+ ref="node2Ref"
300
+ >
301
+ Node 2
302
+ </div>
233
303
  </div>
234
304
  </template>
235
305
 
@@ -251,15 +321,25 @@ connector.destroy();
251
321
  },
252
322
  onDisconnect: (connection) => {
253
323
  console.log("Connection removed:", connection);
254
- },
324
+ }
255
325
  });
256
326
 
257
327
  connector.registerNode("node1", node1Ref.value, {
258
328
  dotPositions: ["right"],
329
+ info: {
330
+ id: "123",
331
+ name: "apple",
332
+ desc: "this is a red apple"
333
+ }
259
334
  });
260
335
 
261
336
  connector.registerNode("node2", node2Ref.value, {
262
337
  dotPositions: ["left"],
338
+ info: {
339
+ id: "456",
340
+ name: "pear",
341
+ desc: "this is a yellow pear"
342
+ }
263
343
  });
264
344
  });
265
345
 
@@ -286,7 +366,7 @@ connector.destroy();
286
366
  cursor: move;
287
367
  }
288
368
  </style>
289
- ```
369
+ ````
290
370
 
291
371
  ### React
292
372
 
@@ -310,15 +390,25 @@ function App() {
310
390
  },
311
391
  onDisconnect: (connection) => {
312
392
  console.log("Connection removed:", connection);
313
- },
393
+ }
314
394
  });
315
395
 
316
396
  connectorRef.current.registerNode("node1", node1Ref.current, {
317
397
  dotPositions: ["right"],
398
+ info: {
399
+ id: "123",
400
+ name: "apple",
401
+ desc: "this is a red apple"
402
+ }
318
403
  });
319
404
 
320
405
  connectorRef.current.registerNode("node2", node2Ref.current, {
321
406
  dotPositions: ["left"],
407
+ info: {
408
+ id: "456",
409
+ name: "pear",
410
+ desc: "this is a yellow pear"
411
+ }
322
412
  });
323
413
 
324
414
  return () => {
@@ -329,11 +419,20 @@ function App() {
329
419
  }, []);
330
420
 
331
421
  return (
332
- <div ref={containerRef} style={{ position: "relative", height: "600px" }}>
333
- <div ref={node1Ref} style={{ position: "absolute", left: "100px", top: "100px" }}>
422
+ <div
423
+ ref={containerRef}
424
+ style={{ position: "relative", height: "600px" }}
425
+ >
426
+ <div
427
+ ref={node1Ref}
428
+ style={{ position: "absolute", left: "100px", top: "100px" }}
429
+ >
334
430
  Node 1
335
431
  </div>
336
- <div ref={node2Ref} style={{ position: "absolute", left: "400px", top: "100px" }}>
432
+ <div
433
+ ref={node2Ref}
434
+ style={{ position: "absolute", left: "400px", top: "100px" }}
435
+ >
337
436
  Node 2
338
437
  </div>
339
438
  </div>
@@ -365,8 +464,20 @@ function App() {
365
464
  </head>
366
465
  <body>
367
466
  <div id="container">
368
- <div id="node1" class="node" style="left: 100px; top: 100px;">Node 1</div>
369
- <div id="node2" class="node" style="left: 400px; top: 100px;">Node 2</div>
467
+ <div
468
+ id="node1"
469
+ class="node"
470
+ style="left: 100px; top: 100px;"
471
+ >
472
+ Node 1
473
+ </div>
474
+ <div
475
+ id="node2"
476
+ class="node"
477
+ style="left: 400px; top: 100px;"
478
+ >
479
+ Node 2
480
+ </div>
370
481
  </div>
371
482
 
372
483
  <script type="module">
@@ -376,15 +487,25 @@ function App() {
376
487
  container: document.getElementById("container"),
377
488
  onConnect: (connection) => {
378
489
  console.log("Connection created:", connection);
379
- },
490
+ }
380
491
  });
381
492
 
382
493
  connector.registerNode("node1", document.getElementById("node1"), {
383
494
  dotPositions: ["right"],
495
+ info: {
496
+ id: "123",
497
+ name: "apple",
498
+ desc: "this is a red apple"
499
+ }
384
500
  });
385
501
 
386
502
  connector.registerNode("node2", document.getElementById("node2"), {
387
503
  dotPositions: ["left"],
504
+ info: {
505
+ id: "456",
506
+ name: "pear",
507
+ desc: "this is a yellow pear"
508
+ }
388
509
  });
389
510
  </script>
390
511
  </body>
@@ -398,17 +519,103 @@ function App() {
398
519
  ```javascript
399
520
  // Node with both left and right connection points
400
521
  connector.registerNode("centerNode", element, {
401
- dotPositions: ["left", "right"],
522
+ dotPositions: ["left", "right"]
402
523
  });
403
524
 
404
525
  // Node with only left connection point
405
526
  connector.registerNode("endNode", element, {
406
527
  dotPositions: ["left"],
528
+ info: {
529
+ id: "456",
530
+ name: "pear",
531
+ desc: "this is a yellow pear"
532
+ }
407
533
  });
408
534
 
409
535
  // Node with only right connection point
410
536
  connector.registerNode("startNode", element, {
411
- dotPositions: ["right"],
537
+ dotPositions: ["right"]
538
+ });
539
+ ```
540
+
541
+ ### Silent Operations (No Callbacks)
542
+
543
+ Sometimes you may want to perform operations without triggering callbacks, such as when initializing connections from saved data or bulk operations.
544
+
545
+ ```javascript
546
+ // Silent connection creation (won't trigger onConnect callback)
547
+ const node1 = connector.nodes[0];
548
+ const node2 = connector.nodes[1];
549
+ connector.createConnection(node1, node2, null, null, { silent: true });
550
+
551
+ // Silent disconnection (won't trigger onDisconnect callback)
552
+ connector.disconnect("connection-id", { silent: true });
553
+
554
+ // Silent destroy (won't trigger callbacks, default behavior)
555
+ connector.destroy(); // Default is silent
556
+ connector.destroy({ silent: false }); // Non-silent destroy (triggers callbacks)
557
+
558
+ // Example: Restore connections from saved data without triggering callbacks
559
+ const savedConnections = [
560
+ { from: "node1", to: "node2", fromDot: "right", toDot: "left" },
561
+ { from: "node2", to: "node3", fromDot: "right", toDot: "left" }
562
+ ];
563
+
564
+ savedConnections.forEach((conn) => {
565
+ const fromNode = connector.nodes.find((n) => n.id === conn.from);
566
+ const toNode = connector.nodes.find((n) => n.id === conn.to);
567
+ const fromDot = fromNode?.dots[conn.fromDot];
568
+ const toDot = toNode?.dots[conn.toDot];
569
+
570
+ if (fromNode && toNode && fromDot && toDot) {
571
+ connector.createConnection(fromNode, toNode, fromDot, toDot, { silent: true });
572
+ }
573
+ });
574
+ ```
575
+
576
+ ### Node Info and Connection Data
577
+
578
+ You can attach custom information to nodes using the `info` parameter, which will be available in connection callbacks.
579
+
580
+ ```javascript
581
+ // Register node with custom info
582
+ const items = [
583
+ { id: "node1", name: "Apple", desc: "This is a red apple", type: "fruit" },
584
+ { id: "node2", name: "Pear", desc: "This is a yellow pear", type: "fruit" }
585
+ ];
586
+
587
+ items.forEach((item) => {
588
+ const nodeElement = document.getElementById(item.id);
589
+ connector.registerNode(item.id, nodeElement, {
590
+ dotPositions: ["left"],
591
+ info: item // Attach custom info to the node
592
+ });
593
+ });
594
+
595
+ // Access node info in connection callbacks
596
+ const connector = new Connector({
597
+ container: container,
598
+ onConnect: async (connection) => {
599
+ console.log("Connection created:", connection);
600
+ console.log("From node info:", connection.fromInfo);
601
+ // { id: "node1", name: "Apple", desc: "This is a red apple", type: "fruit" }
602
+ console.log("To node info:", connection.toInfo);
603
+ // { id: "node2", name: "Pear", desc: "This is a yellow pear", type: "fruit" }
604
+
605
+ // You can use the info for saving to database, validation, etc.
606
+ await saveConnection({
607
+ from: connection.from,
608
+ to: connection.to,
609
+ fromInfo: connection.fromInfo,
610
+ toInfo: connection.toInfo
611
+ });
612
+ },
613
+
614
+ onDisconnect: (connection) => {
615
+ console.log("Connection removed:", connection);
616
+ console.log("From node info:", connection.fromInfo);
617
+ console.log("To node info:", connection.toInfo);
618
+ }
412
619
  });
413
620
  ```
414
621
 
@@ -421,7 +628,7 @@ const connector = new Connector({
421
628
  lineWidth: 3, // Thicker lines
422
629
  dotSize: 16, // Larger dots
423
630
  dotColor: "#4ECDC4", // Teal dots
424
- deleteButtonSize: 24, // Larger delete button
631
+ deleteButtonSize: 24 // Larger delete button
425
632
  });
426
633
  ```
427
634
 
@@ -444,7 +651,7 @@ const connector = new Connector({
444
651
 
445
652
  // Update database, state, etc.
446
653
  removeConnection(connection);
447
- },
654
+ }
448
655
  });
449
656
  ```
450
657
 
package/dist/index.js CHANGED
@@ -1,2 +1,2 @@
1
- /*! node-link v0.0.4 | MIT License */
2
- function t(t,e){(null==e||e>t.length)&&(e=t.length);for(var n=0,o=Array(e);n<e;n++)o[n]=t[n];return o}function e(t,e,n){return e&&function(t,e){for(var n=0;n<e.length;n++){var o=e[n];o.enumerable=o.enumerable||!1,o.configurable=!0,"value"in o&&(o.writable=!0),Object.defineProperty(t,a(o.key),o)}}(t.prototype,e),Object.defineProperty(t,"prototype",{writable:!1}),t}function n(t,e){var n="undefined"!=typeof Symbol&&t[Symbol.iterator]||t["@@iterator"];if(!n){if(Array.isArray(t)||(n=l(t))||e){n&&(t=n);var o=0,i=function(){};return{s:i,n:function(){return o>=t.length?{done:!0}:{done:!1,value:t[o++]}},e:function(t){throw t},f:i}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var s,r=!0,a=!1;return{s:function(){n=n.call(t)},n:function(){var t=n.next();return r=t.done,t},e:function(t){a=!0,s=t},f:function(){try{r||null==n.return||n.return()}finally{if(a)throw s}}}}function o(t,e,n){return(e=a(e))in t?Object.defineProperty(t,e,{value:n,enumerable:!0,configurable:!0,writable:!0}):t[e]=n,t}function i(t,e){var n=Object.keys(t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(t);e&&(o=o.filter(function(e){return Object.getOwnPropertyDescriptor(t,e).enumerable})),n.push.apply(n,o)}return n}function s(t){for(var e=1;e<arguments.length;e++){var n=null!=arguments[e]?arguments[e]:{};e%2?i(Object(n),!0).forEach(function(e){o(t,e,n[e])}):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(n)):i(Object(n)).forEach(function(e){Object.defineProperty(t,e,Object.getOwnPropertyDescriptor(n,e))})}return t}function r(e){return function(e){if(Array.isArray(e))return t(e)}(e)||function(t){if("undefined"!=typeof Symbol&&null!=t[Symbol.iterator]||null!=t["@@iterator"])return Array.from(t)}(e)||l(e)||function(){throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function a(t){var e=function(t,e){if("object"!=typeof t||!t)return t;var n=t[Symbol.toPrimitive];if(void 0!==n){var o=n.call(t,e);if("object"!=typeof o)return o;throw new TypeError("@@toPrimitive must return a primitive value.")}return String(t)}(t,"string");return"symbol"==typeof e?e:e+""}function l(e,n){if(e){if("string"==typeof e)return t(e,n);var o={}.toString.call(e).slice(8,-1);return"Object"===o&&e.constructor&&(o=e.constructor.name),"Map"===o||"Set"===o?Array.from(e):"Arguments"===o||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(o)?t(e,n):void 0}}var c=function(){return e(function t(){var e=this,n=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};!function(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}(this,t),o(this,"handleNodeDragMove",function(t){if(e.isDraggingNode&&e.draggedNode){var n=e.contentWrapper.getBoundingClientRect(),o=t.clientX-n.left-e.dragOffset.x,i=t.clientY-n.top-e.dragOffset.y;e.draggedNode.element.style.left="".concat(o,"px"),e.draggedNode.element.style.top="".concat(i,"px"),e.updateNodeConnections(e.draggedNode.id)}}),o(this,"handleNodeDragEnd",function(){e.isDraggingNode=!1,e.draggedNode=null,document.removeEventListener("mousemove",e.handleNodeDragMove),document.removeEventListener("mouseup",e.handleNodeDragEnd)}),o(this,"handleMouseMove",function(t){e.isDragging&&e.updateTempLine(t)}),o(this,"handleMouseUp",function(t){if(e.isDragging){e.isDragging=!1;var n=e.isSnapped?e.snapTarget:e.getNodeAtPosition(t.clientX,t.clientY),o=e.isSnapped?e.snapTargetDot:null;n&&n.id!==e.startNode.id&&e.createConnection(e.startNode,n,e.startDot,o),e.clearSnapHighlight(),e.snapTarget=null,e.snapTargetDot=null,e.isSnapped=!1,e.startDot=null,e.tempLine&&(e.svg.removeChild(e.tempLine),e.tempLine=null),document.removeEventListener("mousemove",e.handleMouseMove),document.removeEventListener("mouseup",e.handleMouseUp)}}),this.container=n.container,this.nodes=[],this.connections=[],this.isDragging=!1,this.isDraggingNode=!1,this.tempLine=null,this.draggedNode=null,this.dragOffset={x:0,y:0},this.onConnect=n.onConnect||function(){},this.onDisconnect=n.onDisconnect||function(){},this.onViewChange=n.onViewChange||function(){},this.config=s({lineColor:n.lineColor||"#155BD4",lineWidth:n.lineWidth||2,dotSize:n.dotSize||12,dotColor:n.dotColor||"#155BD4",deleteButtonSize:n.deleteButtonSize||20,enableNodeDrag:!1!==n.enableNodeDrag,snapDistance:n.snapDistance||20,enableSnap:!1!==n.enableSnap,enableZoom:!1!==n.enableZoom,enablePan:!1!==n.enablePan,minZoom:n.minZoom||.1,maxZoom:n.maxZoom||4,zoomStep:n.zoomStep||.1},n.config),this.snapTarget=null,this.isSnapped=!1,this.viewState={scale:1,translateX:0,translateY:0},this.isPanning=!1,this.panStart={x:0,y:0},this.spacePressed=!1,this.contentWrapper=null,this.init()},[{key:"init",value:function(){var t=this;if(!this.container)throw new Error("Container element is required");"static"===window.getComputedStyle(this.container).position&&(this.container.style.position="relative"),this.container.style.overflow="hidden",this.contentWrapper=document.createElement("div"),this.contentWrapper.className="connector-content-wrapper",this.contentWrapper.style.cssText="\n position: absolute;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n transform-origin: 0 0;\n transition: none;\n ",Array.from(this.container.children).forEach(function(e){t.contentWrapper.appendChild(e)}),this.container.appendChild(this.contentWrapper),this.svg=document.createElementNS("http://www.w3.org/2000/svg","svg"),this.svg.style.position="absolute",this.svg.style.top="0",this.svg.style.left="0",this.svg.style.width="100%",this.svg.style.height="100%",this.svg.style.pointerEvents="none",this.svg.style.zIndex="1",this.contentWrapper.appendChild(this.svg),this.config.enableZoom&&this.bindZoomEvents(),this.config.enablePan&&this.bindPanEvents(),this.bindResizeEvents(),this.updateTransform()}},{key:"updateTransform",value:function(){if(this.contentWrapper){var t=this.viewState,e=t.scale,n=t.translateX,o=t.translateY;this.contentWrapper.style.transform="translate(".concat(n,"px, ").concat(o,"px) scale(").concat(e,")"),this.onViewChange({scale:e,translateX:n,translateY:o})}}},{key:"bindZoomEvents",value:function(){var t=this;this.handleWheel=function(e){if(e.ctrlKey||e.metaKey){e.preventDefault();var n=t.container.getBoundingClientRect(),o=e.clientX-n.left,i=e.clientY-n.top,s=e.deltaY<0?t.config.zoomStep:-t.config.zoomStep,r=Math.max(t.config.minZoom,Math.min(t.config.maxZoom,t.viewState.scale+s));t.zoomAtPoint(r,o,i)}},this.container.addEventListener("wheel",this.handleWheel,{passive:!1})}},{key:"bindPanEvents",value:function(){var t=this;this.handleKeyDown=function(e){"Space"!==e.code||t.spacePressed||t.isDragging||t.isDraggingNode||(e.preventDefault(),t.spacePressed=!0,t.container.style.cursor="grab")},this.handleKeyUp=function(e){"Space"===e.code&&(t.spacePressed=!1,t.container.style.cursor="",t.isPanning&&t.stopPan())},this.handlePanStart=function(e){!t.spacePressed||t.isDragging||t.isDraggingNode||(e.preventDefault(),e.stopPropagation(),t.isPanning=!0,t.panStart={x:e.clientX-t.viewState.translateX,y:e.clientY-t.viewState.translateY},t.container.style.cursor="grabbing")},this.handlePanMove=function(e){t.isPanning&&(e.preventDefault(),t.viewState.translateX=e.clientX-t.panStart.x,t.viewState.translateY=e.clientY-t.panStart.y,t.updateTransform())},this.handlePanEnd=function(){t.isPanning&&t.stopPan()},document.addEventListener("keydown",this.handleKeyDown),document.addEventListener("keyup",this.handleKeyUp),this.container.addEventListener("mousedown",this.handlePanStart),document.addEventListener("mousemove",this.handlePanMove),document.addEventListener("mouseup",this.handlePanEnd)}},{key:"stopPan",value:function(){this.isPanning=!1,this.container.style.cursor=this.spacePressed?"grab":""}},{key:"bindResizeEvents",value:function(){var t=this,e=null;this.handleResize=function(){e&&clearTimeout(e),e=setTimeout(function(){t.updateAllConnections()},100)},window.addEventListener("resize",this.handleResize),"undefined"!=typeof ResizeObserver&&(this.resizeObserver=new ResizeObserver(function(){e&&clearTimeout(e),e=setTimeout(function(){t.updateAllConnections()},100)}),this.resizeObserver.observe(this.container))}},{key:"zoomAtPoint",value:function(t,e,n){var o=this.viewState.scale,i=(e-this.viewState.translateX)/o,s=(n-this.viewState.translateY)/o;this.viewState.scale=t,this.viewState.translateX=e-i*t,this.viewState.translateY=n-s*t,this.updateTransform()}},{key:"setZoom",value:function(t){var e=this.container.getBoundingClientRect(),n=e.width/2,o=e.height/2;this.zoomAtPoint(t,n,o)}},{key:"getZoom",value:function(){return this.viewState.scale}},{key:"resetView",value:function(){this.viewState.scale=1,this.viewState.translateX=0,this.viewState.translateY=0,this.updateTransform()}},{key:"zoomIn",value:function(){var t=Math.min(this.config.maxZoom,this.viewState.scale+this.config.zoomStep);this.setZoom(t)}},{key:"zoomOut",value:function(){var t=Math.max(this.config.minZoom,this.viewState.scale-this.config.zoomStep);this.setZoom(t)}},{key:"getViewState",value:function(){return s({},this.viewState)}},{key:"registerNode",value:function(t,e){var n=this,o=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{};if(!this.nodes.find(function(e){return e.id===t})){var i=[];i="both"===o.dotPositions?["left","right"]:Array.isArray(o.dotPositions)?o.dotPositions.filter(function(t){return"left"===t||"right"===t}):[0===this.nodes.length?"right":"left"],i=r(new Set(i)).slice(0,2);var s={};i.forEach(function(t){var o=n.createDot(t);e.appendChild(o),s[t]={element:o,position:t}});var a={id:t,element:e,info:null==o?void 0:o.info,dots:s,dotPositions:i,connections:[]};return this.nodes.push(a),Object.values(s).forEach(function(t){n.bindDotEvents(a,t)}),this.config.enableNodeDrag&&this.bindNodeDragEvents(a),a}console.warn("节点 ".concat(t," 已存在"))}},{key:"createDot",value:function(t){var e=document.createElement("div");e.className="connector-dot";var n="right"===t?"right: -".concat(this.config.dotSize/2,"px;"):"left: -".concat(this.config.dotSize/2,"px;");return e.style.cssText="\n position: absolute;\n width: ".concat(this.config.dotSize,"px;\n height: ").concat(this.config.dotSize,"px;\n background-color: ").concat(this.config.dotColor,";\n border: 2px solid white;\n border-radius: 50%;\n cursor: pointer;\n ").concat(n,"\n top: 50%;\n transform: translateY(-50%);\n z-index: 10;\n transition: transform 0.2s;\n "),e.dataset.baseTransform="translateY(-50%)",e.addEventListener("mouseenter",function(){e.style.transform="translateY(-50%) scale(1.2)"}),e.addEventListener("mouseleave",function(){e.style.transform="translateY(-50%) scale(1)"}),e}},{key:"bindDotEvents",value:function(t,e){var n=this;e.element.addEventListener("mousedown",function(o){o.preventDefault(),o.stopPropagation(),n.isDragging=!0,n.startNode=t,n.startDot=e,n.tempLine=n.createLine(),n.svg.appendChild(n.tempLine),n.updateTempLine(o),document.addEventListener("mousemove",n.handleMouseMove),document.addEventListener("mouseup",n.handleMouseUp)})}},{key:"bindNodeDragEvents",value:function(t){var e=this,n=t.element;n.addEventListener("mousedown",function(o){if(!o.target.classList.contains("connector-dot")&&!e.spacePressed){o.preventDefault(),o.stopPropagation(),e.isDraggingNode=!0,e.draggedNode=t;var i=n.getBoundingClientRect(),s=e.contentWrapper.getBoundingClientRect();e.dragOffset={x:o.clientX-i.left,y:o.clientY-i.top};var r=i.left-s.left,a=i.top-s.top;n.style.left="".concat(r,"px"),n.style.top="".concat(a,"px"),n.style.right="",n.style.bottom="",document.addEventListener("mousemove",e.handleNodeDragMove),document.addEventListener("mouseup",e.handleNodeDragEnd)}})}},{key:"updateTempLine",value:function(t){if(this.tempLine&&this.startNode&&this.startDot){var e=this.getDotPosition(this.startNode.element,this.startDot.position),n=this.container.getBoundingClientRect(),o=t.clientX-n.left,i=t.clientY-n.top,s=this.viewState,r=s.scale,a={x:(o-s.translateX)/r,y:(i-s.translateY)/r};if(this.config.enableSnap){var l=this.checkSnap(a,this.startNode);l?(a=l.position,this.snapTarget=l.node,this.snapTargetDot=l.dot,this.isSnapped=!0,this.highlightSnapTarget(l.node,l.dot)):(this.isSnapped=!1,this.clearSnapHighlight(),this.snapTarget=null,this.snapTargetDot=null)}this.updateLine(this.tempLine,e,a,this.startDot.position)}}},{key:"createConnection",value:function(t,e){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:null,o=arguments.length>3&&void 0!==arguments[3]?arguments[3]:null,i=arguments.length>4&&void 0!==arguments[4]?arguments[4]:{};if(!n&&t.dots&&(n=t.dots.right||t.dots.left||Object.values(t.dots)[0]),!o&&e.dots&&(o=e.dots.left||e.dots.right||Object.values(e.dots)[0]),!this.connections.find(function(i){return i.fromNode.id===t.id&&i.toNode.id===e.id&&i.fromDot.position===n.position&&i.toDot.position===o.position||i.fromNode.id===e.id&&i.toNode.id===t.id&&i.fromDot.position===o.position&&i.toDot.position===n.position})){var s=this.createLine();this.svg.appendChild(s);var r=this.createDeleteButton(),a={id:"".concat(t.id,"-").concat(e.id,"-").concat(n.position,"-").concat(o.position,"-").concat(Date.now()),fromNode:t,toNode:e,fromDot:n,toDot:o,line:s,deleteButton:r};return this.connections.push(a),t.connections.push(a),e.connections.push(a),this.updateConnection(a),this.bindConnectionEvents(a),i.silent||this.onConnect({from:t.id,fromInfo:t.info,to:e.id,toInfo:e.info,fromDot:n.position,toDot:o.position}),a}console.warn("该连接已存在")}},{key:"updateConnection",value:function(t){if(t&&t.line){var e=this.getDotPosition(t.fromNode.element,t.fromDot.position),n=this.getDotPosition(t.toNode.element,t.toDot.position);if(this.updateLine(t.line,e,n,t.fromDot.position,t.toDot.position),t.hoverPath&&this.updateLine(t.hoverPath,e,n,t.fromDot.position,t.toDot.position),t.deleteButton){var o=this.getBezierMidPoint(e,n,t.fromDot.position,t.toDot.position);t.deleteButton.style.left="".concat(o.x-this.config.deleteButtonSize/2,"px"),t.deleteButton.style.top="".concat(o.y-this.config.deleteButtonSize/2,"px")}}}},{key:"updateNodeConnections",value:function(t){var e=this;this.connections.filter(function(e){return e.fromNode.id===t||e.toNode.id===t}).forEach(function(t){return e.updateConnection(t)})}},{key:"updateAllConnections",value:function(){var t=this;this.connections.forEach(function(e){return t.updateConnection(e)})}},{key:"createLine",value:function(){var t=document.createElementNS("http://www.w3.org/2000/svg","path");return t.setAttribute("stroke",this.config.lineColor),t.setAttribute("stroke-width",this.config.lineWidth),t.setAttribute("fill","none"),t}},{key:"updateLine",value:function(t,e,n){var o=arguments.length>3&&void 0!==arguments[3]?arguments[3]:"right",i=arguments.length>4&&void 0!==arguments[4]?arguments[4]:"left",s=n.x-e.x,r=n.y-e.y,a=Math.sqrt(s*s+r*r),l=Math.min(.5*a,150),c="right"===o?e.x+l:e.x-l,d="right"===i?n.x+l:n.x-l,h="M ".concat(e.x," ").concat(e.y," C ").concat(c," ").concat(e.y,", ").concat(d," ").concat(n.y,", ").concat(n.x," ").concat(n.y);t.setAttribute("d",h)}},{key:"getBezierMidPoint",value:function(t,e){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:"right",o=arguments.length>3&&void 0!==arguments[3]?arguments[3]:"left",i=e.x-t.x,s=e.y-t.y,r=Math.sqrt(i*i+s*s),a=Math.min(.5*r,150),l="right"===n?t.x+a:t.x-a,c=t.y,d="right"===o?e.x+a:e.x-a,h=e.y,u=.5,f=u*u,p=f*u;return{x:.125*t.x+.375*l+.375*d+p*e.x,y:.125*t.y+.375*c+.375*h+p*e.y}}},{key:"createDeleteButton",value:function(){var t=document.createElement("div");return t.className="connector-delete-btn",t.innerHTML="×",t.style.cssText="\n position: absolute;\n width: ".concat(this.config.deleteButtonSize,"px;\n height: ").concat(this.config.deleteButtonSize,"px;\n background-color: #ff4d4f;\n color: white;\n border-radius: 50%;\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: pointer;\n font-size: 16px;\n font-weight: bold;\n z-index: 100;\n opacity: 0;\n transition: opacity 0.2s, transform 0.2s;\n pointer-events: none;\n "),this.contentWrapper.appendChild(t),t.addEventListener("mouseenter",function(){t.style.transform="scale(1.2)"}),t.addEventListener("mouseleave",function(){t.style.transform="scale(1)",t.style.opacity="0",t.style.pointerEvents="none"}),t}},{key:"bindConnectionEvents",value:function(t){var e=this,n=t.line,o=t.deleteButton;n.style.pointerEvents="stroke",n.style.cursor="pointer";var i=document.createElementNS("http://www.w3.org/2000/svg","path");i.setAttribute("stroke","transparent"),i.setAttribute("stroke-width","20"),i.setAttribute("fill","none"),i.style.pointerEvents="stroke",i.style.cursor="pointer",i.setAttribute("d",n.getAttribute("d")),this.svg.insertBefore(i,n),t.hoverPath=i;var s=function(){o.style.opacity="1",o.style.pointerEvents="auto"},r=function(){setTimeout(function(){o.matches(":hover")||(o.style.opacity="0",o.style.pointerEvents="none")},100)};i.addEventListener("mouseenter",s),i.addEventListener("mouseleave",r),n.addEventListener("mouseenter",s),n.addEventListener("mouseleave",r),o.addEventListener("click",function(){e.disconnect(t.id)})}},{key:"disconnect",value:function(t){var e=this,n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};if(t){var o=this.connections.findIndex(function(e){return e.id===t});if(-1===o)return;var i=this.connections[o],s={from:i.fromNode.id,fromInfo:i.fromNode.info,to:i.toNode.id,toInfo:i.toNode.info,fromDot:i.fromDot.position,toDot:i.toDot.position};i.line&&i.line.parentNode&&this.svg.removeChild(i.line),i.hoverPath&&i.hoverPath.parentNode&&this.svg.removeChild(i.hoverPath),i.deleteButton&&i.deleteButton.parentNode&&i.deleteButton.parentNode.removeChild(i.deleteButton),i.fromNode.connections=i.fromNode.connections.filter(function(e){return e.id!==t}),i.toNode.connections=i.toNode.connections.filter(function(e){return e.id!==t}),this.connections.splice(o,1),n.silent||this.onDisconnect(s)}else{r(this.connections).forEach(function(t){return e.disconnect(t.id,n)})}}},{key:"getElementCenter",value:function(t){var e=t.getBoundingClientRect(),n=this.container.getBoundingClientRect(),o=e.left+e.width/2-n.left,i=e.top+e.height/2-n.top,s=this.viewState,r=s.scale;return{x:(o-s.translateX)/r,y:(i-s.translateY)/r}}},{key:"getDotPosition",value:function(t,e){var n=t.getBoundingClientRect(),o=this.container.getBoundingClientRect(),i="right"===e?n.right-o.left:n.left-o.left,s=n.top+n.height/2-o.top,r=this.viewState,a=r.scale;return{x:(i-r.translateX)/a,y:(s-r.translateY)/a}}},{key:"getNodeAtPosition",value:function(t,e){var o,i=n(this.nodes);try{for(i.s();!(o=i.n()).done;){var s=o.value,r=s.element.getBoundingClientRect();if(t>=r.left&&t<=r.right&&e>=r.top&&e<=r.bottom)return s}}catch(t){i.e(t)}finally{i.f()}return null}},{key:"checkSnap",value:function(t,e){var o=this;if(!this.config.enableSnap)return null;var i,s=null,r=null,a=1/0,l=n(this.nodes);try{var c=function(){var n=i.value;if(n.id===e.id)return 1;n.dots&&Object.values(n.dots).forEach(function(e){var i=o.getDotPosition(n.element,e.position),l=t.x-i.x,c=t.y-i.y,d=Math.sqrt(l*l+c*c);d<o.config.snapDistance&&d<a&&(a=d,s=n,r=e)})};for(l.s();!(i=l.n()).done;)c()}catch(t){l.e(t)}finally{l.f()}return s&&r?{node:s,dot:r,position:this.getDotPosition(s.element,r.position)}:null}},{key:"highlightSnapTarget",value:function(t){var e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:null;if(t&&t.element&&(this.clearSnapHighlight(),t.element.style.boxShadow="0 0 0 3px rgba(21, 91, 212, 0.3)",t.element.style.transform="scale(1.05)",t.element.dataset.snapped="true",e&&e.element)){var n=e.element.dataset.baseTransform||"translateY(-50%)";e.element.style.transform="".concat(n," scale(1.5)"),e.element.style.boxShadow="0 0 10px rgba(21, 91, 212, 0.6)",e.element.dataset.highlighted="true"}}},{key:"clearSnapHighlight",value:function(){this.nodes.forEach(function(t){"true"===t.element.dataset.snapped&&(t.element.style.boxShadow="",t.element.style.transform="",delete t.element.dataset.snapped,t.dots&&Object.values(t.dots).forEach(function(t){if("true"===t.element.dataset.highlighted){var e=t.element.dataset.baseTransform||"translateY(-50%)";t.element.style.transform=e,t.element.style.boxShadow="",delete t.element.dataset.highlighted}}))})}},{key:"updateNodePosition",value:function(t){var e=this,n=this.nodes.find(function(e){return e.id===t});n&&(n.dots&&Object.values(n.dots).forEach(function(t){t.coords=e.getDotPosition(n.element,t.position)}),this.updateNodeConnections(t))}},{key:"destroy",value:function(){this.disconnect(null,{silent:!0}),this.nodes.forEach(function(t){t.dots&&Object.values(t.dots).forEach(function(t){t.element&&t.element.parentNode&&t.element.parentNode.removeChild(t.element)})}),this.svg&&this.svg.parentNode&&this.svg.parentNode.removeChild(this.svg),document.removeEventListener("mousemove",this.handleMouseMove),document.removeEventListener("mouseup",this.handleMouseUp),document.removeEventListener("mousemove",this.handleNodeDragMove),document.removeEventListener("mouseup",this.handleNodeDragEnd),this.handleWheel&&this.container.removeEventListener("wheel",this.handleWheel),this.handleKeyDown&&document.removeEventListener("keydown",this.handleKeyDown),this.handleKeyUp&&document.removeEventListener("keyup",this.handleKeyUp),this.handlePanStart&&this.container.removeEventListener("mousedown",this.handlePanStart),this.handlePanMove&&document.removeEventListener("mousemove",this.handlePanMove),this.handlePanEnd&&document.removeEventListener("mouseup",this.handlePanEnd),this.handleResize&&window.removeEventListener("resize",this.handleResize),this.resizeObserver&&(this.resizeObserver.disconnect(),this.resizeObserver=null),this.nodes=[],this.connections=[]}},{key:"getConnections",value:function(){return this.connections.map(function(t){return{id:t.id,from:t.fromNode.id,to:t.toNode.id,fromDot:t.fromDot.position,toDot:t.toDot.position}})}},{key:"getNodeConnections",value:function(t){return this.connections.filter(function(e){return e.fromNode.id===t||e.toNode.id===t}).map(function(t){return{id:t.id,from:t.fromNode.id,to:t.toNode.id,fromDot:t.fromDot.position,toDot:t.toDot.position}})}}])}();export{c as Connector,c as default};
1
+ /*! node-link v0.0.8 | MIT License */
2
+ function t(t,e){(null==e||e>t.length)&&(e=t.length);for(var n=0,o=Array(e);n<e;n++)o[n]=t[n];return o}function e(t,e,n){return e&&function(t,e){for(var n=0;n<e.length;n++){var o=e[n];o.enumerable=o.enumerable||!1,o.configurable=!0,"value"in o&&(o.writable=!0),Object.defineProperty(t,a(o.key),o)}}(t.prototype,e),Object.defineProperty(t,"prototype",{writable:!1}),t}function n(t,e){var n="undefined"!=typeof Symbol&&t[Symbol.iterator]||t["@@iterator"];if(!n){if(Array.isArray(t)||(n=l(t))||e){n&&(t=n);var o=0,i=function(){};return{s:i,n:function(){return o>=t.length?{done:!0}:{done:!1,value:t[o++]}},e:function(t){throw t},f:i}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var r,s=!0,a=!1;return{s:function(){n=n.call(t)},n:function(){var t=n.next();return s=t.done,t},e:function(t){a=!0,r=t},f:function(){try{s||null==n.return||n.return()}finally{if(a)throw r}}}}function o(t,e,n){return(e=a(e))in t?Object.defineProperty(t,e,{value:n,enumerable:!0,configurable:!0,writable:!0}):t[e]=n,t}function i(t,e){var n=Object.keys(t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(t);e&&(o=o.filter(function(e){return Object.getOwnPropertyDescriptor(t,e).enumerable})),n.push.apply(n,o)}return n}function r(t){for(var e=1;e<arguments.length;e++){var n=null!=arguments[e]?arguments[e]:{};e%2?i(Object(n),!0).forEach(function(e){o(t,e,n[e])}):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(n)):i(Object(n)).forEach(function(e){Object.defineProperty(t,e,Object.getOwnPropertyDescriptor(n,e))})}return t}function s(e){return function(e){if(Array.isArray(e))return t(e)}(e)||function(t){if("undefined"!=typeof Symbol&&null!=t[Symbol.iterator]||null!=t["@@iterator"])return Array.from(t)}(e)||l(e)||function(){throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function a(t){var e=function(t,e){if("object"!=typeof t||!t)return t;var n=t[Symbol.toPrimitive];if(void 0!==n){var o=n.call(t,e);if("object"!=typeof o)return o;throw new TypeError("@@toPrimitive must return a primitive value.")}return String(t)}(t,"string");return"symbol"==typeof e?e:e+""}function l(e,n){if(e){if("string"==typeof e)return t(e,n);var o={}.toString.call(e).slice(8,-1);return"Object"===o&&e.constructor&&(o=e.constructor.name),"Map"===o||"Set"===o?Array.from(e):"Arguments"===o||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(o)?t(e,n):void 0}}var c=function(){return e(function t(){var e=this,n=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};!function(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}(this,t),o(this,"handleNodeDragMove",function(t){if(e.isDraggingNode&&e.draggedNode){var n=e.contentWrapper.getBoundingClientRect(),o=e.viewState.scale,i=(t.clientX-n.left)/o-e.dragOffset.x,r=(t.clientY-n.top)/o-e.dragOffset.y;e.draggedNode.element.style.left="".concat(i,"px"),e.draggedNode.element.style.top="".concat(r,"px"),e.updateNodeConnections(e.draggedNode.id)}}),o(this,"handleNodeDragEnd",function(){e.isDraggingNode=!1,e.draggedNode=null,document.removeEventListener("mousemove",e.handleNodeDragMove),document.removeEventListener("mouseup",e.handleNodeDragEnd)}),o(this,"handleMouseMove",function(t){e.isDragging&&e.updateTempLine(t)}),o(this,"handleMouseUp",function(t){if(e.isDragging){e.isDragging=!1;var n=e.isSnapped?e.snapTarget:e.getNodeAtPosition(t.clientX,t.clientY),o=e.isSnapped?e.snapTargetDot:null;n&&n.id!==e.startNode.id&&e.createConnection(e.startNode,n,e.startDot,o),e.clearSnapHighlight(),e.snapTarget=null,e.snapTargetDot=null,e.isSnapped=!1,e.startDot=null,e.tempLine&&(e.svg.removeChild(e.tempLine),e.tempLine=null),document.removeEventListener("mousemove",e.handleMouseMove),document.removeEventListener("mouseup",e.handleMouseUp)}}),this.container=n.container,this.nodes=[],this.connections=[],this.isDragging=!1,this.isDraggingNode=!1,this.tempLine=null,this.draggedNode=null,this.dragOffset={x:0,y:0},this.onConnect=n.onConnect||function(){},this.onDisconnect=n.onDisconnect||function(){},this.onViewChange=n.onViewChange||function(){},this.config=r({lineColor:n.lineColor||"#155BD4",lineWidth:n.lineWidth||2,dotSize:n.dotSize||12,dotColor:n.dotColor||"#155BD4",deleteButtonSize:n.deleteButtonSize||20,enableNodeDrag:!1!==n.enableNodeDrag,snapDistance:n.snapDistance||20,enableSnap:!1!==n.enableSnap,enableZoom:!1!==n.enableZoom,enablePan:!1!==n.enablePan,minZoom:n.minZoom||.1,maxZoom:n.maxZoom||4,zoomStep:n.zoomStep||.1},n.config),this.snapTarget=null,this.isSnapped=!1,this.viewState={scale:1,translateX:0,translateY:0},this.isPanning=!1,this.panStart={x:0,y:0},this.contentWrapper=null,this.init()},[{key:"init",value:function(){var t=this;if(!this.container)throw new Error("Container element is required");"static"===window.getComputedStyle(this.container).position&&(this.container.style.position="relative"),this.container.style.overflow="hidden",this.contentWrapper=document.createElement("div"),this.contentWrapper.className="connector-content-wrapper",this.contentWrapper.style.cssText="\n position: absolute;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n transform-origin: 0 0;\n transition: none;\n ",Array.from(this.container.children).forEach(function(e){t.contentWrapper.appendChild(e)}),this.container.appendChild(this.contentWrapper),this.svg=document.createElementNS("http://www.w3.org/2000/svg","svg"),this.svg.style.position="absolute",this.svg.style.top="0",this.svg.style.left="0",this.svg.style.width="100%",this.svg.style.height="100%",this.svg.style.pointerEvents="none",this.svg.style.zIndex="1",this.contentWrapper.appendChild(this.svg),this.config.enableZoom&&this.bindZoomEvents(),this.config.enablePan&&this.bindPanEvents(),this.bindResizeEvents(),this.updateTransform()}},{key:"updateTransform",value:function(){if(this.contentWrapper){var t=this.viewState,e=t.scale,n=t.translateX,o=t.translateY;this.contentWrapper.style.transform="translate(".concat(n,"px, ").concat(o,"px) scale(").concat(e,")"),this.onViewChange({scale:e,translateX:n,translateY:o})}}},{key:"bindZoomEvents",value:function(){var t=this;this.handleWheel=function(e){e.preventDefault();var n=t.container.getBoundingClientRect(),o=e.clientX-n.left,i=e.clientY-n.top,r=e.deltaY<0?t.config.zoomStep:-t.config.zoomStep,s=Math.max(t.config.minZoom,Math.min(t.config.maxZoom,t.viewState.scale+r));t.zoomAtPoint(s,o,i)},this.container.addEventListener("wheel",this.handleWheel,{passive:!1})}},{key:"bindPanEvents",value:function(){var t=this;this.container.style.cursor="grab",this.handlePanStart=function(e){e.target.classList.contains("connector-dot")||t.isDragging||t.isDraggingNode||(t.getNodeAtPosition(e.clientX,e.clientY)&&t.config.enableNodeDrag||(e.preventDefault(),e.stopPropagation(),t.isPanning=!0,t.panStart={x:e.clientX-t.viewState.translateX,y:e.clientY-t.viewState.translateY},t.container.style.cursor="grabbing"))},this.handlePanMove=function(e){t.isPanning&&(e.preventDefault(),t.viewState.translateX=e.clientX-t.panStart.x,t.viewState.translateY=e.clientY-t.panStart.y,t.updateTransform())},this.handlePanEnd=function(){t.isPanning&&t.stopPan()},this.container.addEventListener("mousedown",this.handlePanStart),document.addEventListener("mousemove",this.handlePanMove),document.addEventListener("mouseup",this.handlePanEnd)}},{key:"stopPan",value:function(){this.isPanning=!1,this.container.style.cursor="grab"}},{key:"bindResizeEvents",value:function(){var t=this,e=null;this.handleResize=function(){e&&clearTimeout(e),e=setTimeout(function(){t.updateAllConnections()},100)},window.addEventListener("resize",this.handleResize),"undefined"!=typeof ResizeObserver&&(this.resizeObserver=new ResizeObserver(function(){e&&clearTimeout(e),e=setTimeout(function(){t.updateAllConnections()},100)}),this.resizeObserver.observe(this.container))}},{key:"zoomAtPoint",value:function(t,e,n){var o=this.viewState.scale,i=(e-this.viewState.translateX)/o,r=(n-this.viewState.translateY)/o;this.viewState.scale=t,this.viewState.translateX=e-i*t,this.viewState.translateY=n-r*t,this.updateTransform()}},{key:"setZoom",value:function(t){var e=this.container.getBoundingClientRect(),n=e.width/2,o=e.height/2;this.zoomAtPoint(t,n,o)}},{key:"getZoom",value:function(){return this.viewState.scale}},{key:"resetView",value:function(){this.viewState.scale=1,this.viewState.translateX=0,this.viewState.translateY=0,this.updateTransform()}},{key:"zoomIn",value:function(){var t=Math.min(this.config.maxZoom,this.viewState.scale+this.config.zoomStep);this.setZoom(t)}},{key:"zoomOut",value:function(){var t=Math.max(this.config.minZoom,this.viewState.scale-this.config.zoomStep);this.setZoom(t)}},{key:"getViewState",value:function(){return r({},this.viewState)}},{key:"setViewState",value:function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};"number"==typeof t.scale&&(this.viewState.scale=Math.max(this.config.minZoom,Math.min(this.config.maxZoom,t.scale))),"number"==typeof t.translateX&&(this.viewState.translateX=t.translateX),"number"==typeof t.translateY&&(this.viewState.translateY=t.translateY),this.updateTransform()}},{key:"registerNode",value:function(t,e){var n=this,o=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{};if(!this.nodes.find(function(e){return e.id===t})){var i=[];i="both"===o.dotPositions?["left","right"]:Array.isArray(o.dotPositions)?o.dotPositions.filter(function(t){return"left"===t||"right"===t}):[0===this.nodes.length?"right":"left"],i=s(new Set(i)).slice(0,2);var r={};i.forEach(function(t){var o=n.createDot(t);e.appendChild(o),r[t]={element:o,position:t}});var a={id:t,element:e,info:null==o?void 0:o.info,dots:r,dotPositions:i,connections:[]};return this.nodes.push(a),Object.values(r).forEach(function(t){n.bindDotEvents(a,t)}),this.config.enableNodeDrag&&this.bindNodeDragEvents(a),a}console.warn("节点 ".concat(t," 已存在"))}},{key:"createDot",value:function(t){var e=document.createElement("div");e.className="connector-dot";var n="right"===t?"right: -".concat(this.config.dotSize/2,"px;"):"left: -".concat(this.config.dotSize/2,"px;");return e.style.cssText="\n position: absolute;\n width: ".concat(this.config.dotSize,"px;\n height: ").concat(this.config.dotSize,"px;\n background-color: ").concat(this.config.dotColor,";\n border: 2px solid white;\n border-radius: 50%;\n cursor: pointer;\n ").concat(n,"\n top: 50%;\n transform: translateY(-50%);\n z-index: 10;\n transition: transform 0.2s;\n "),e.dataset.baseTransform="translateY(-50%)",e.addEventListener("mouseenter",function(){e.style.transform="translateY(-50%) scale(1.2)"}),e.addEventListener("mouseleave",function(){e.style.transform="translateY(-50%) scale(1)"}),e}},{key:"bindDotEvents",value:function(t,e){var n=this;e.element.addEventListener("mousedown",function(o){o.preventDefault(),o.stopPropagation(),n.isDragging=!0,n.startNode=t,n.startDot=e,n.tempLine=n.createLine(),n.svg.appendChild(n.tempLine),n.updateTempLine(o),document.addEventListener("mousemove",n.handleMouseMove),document.addEventListener("mouseup",n.handleMouseUp)})}},{key:"bindNodeDragEvents",value:function(t){var e=this,n=t.element;n.addEventListener("mousedown",function(o){if(!o.target.classList.contains("connector-dot")){o.preventDefault(),o.stopPropagation(),e.isDraggingNode=!0,e.draggedNode=t;var i=n.getBoundingClientRect(),r=e.contentWrapper.getBoundingClientRect(),s=e.viewState.scale;e.dragOffset={x:(o.clientX-i.left)/s,y:(o.clientY-i.top)/s};var a=(i.left-r.left)/s,l=(i.top-r.top)/s;n.style.left="".concat(a,"px"),n.style.top="".concat(l,"px"),n.style.right="",n.style.bottom="",document.addEventListener("mousemove",e.handleNodeDragMove),document.addEventListener("mouseup",e.handleNodeDragEnd)}})}},{key:"updateTempLine",value:function(t){if(this.tempLine&&this.startNode&&this.startDot){var e=this.getDotPosition(this.startNode.element,this.startDot.position),n=this.container.getBoundingClientRect(),o=t.clientX-n.left,i=t.clientY-n.top,r=this.viewState,s=r.scale,a={x:(o-r.translateX)/s,y:(i-r.translateY)/s};if(this.config.enableSnap){var l=this.checkSnap(a,this.startNode);l?(a=l.position,this.snapTarget=l.node,this.snapTargetDot=l.dot,this.isSnapped=!0,this.highlightSnapTarget(l.node,l.dot)):(this.isSnapped=!1,this.clearSnapHighlight(),this.snapTarget=null,this.snapTargetDot=null)}this.updateLine(this.tempLine,e,a,this.startDot.position)}}},{key:"createConnection",value:function(t,e){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:null,o=arguments.length>3&&void 0!==arguments[3]?arguments[3]:null,i=arguments.length>4&&void 0!==arguments[4]?arguments[4]:{};if(!n&&t.dots&&(n=t.dots.right||t.dots.left||Object.values(t.dots)[0]),!o&&e.dots&&(o=e.dots.left||e.dots.right||Object.values(e.dots)[0]),!this.connections.find(function(i){return i.fromNode.id===t.id&&i.toNode.id===e.id&&i.fromDot.position===n.position&&i.toDot.position===o.position||i.fromNode.id===e.id&&i.toNode.id===t.id&&i.fromDot.position===o.position&&i.toDot.position===n.position})){var r=this.createLine();this.svg.appendChild(r);var s=this.createDeleteButton(),a={id:"".concat(t.id,"-").concat(e.id,"-").concat(n.position,"-").concat(o.position,"-").concat(Date.now()),fromNode:t,toNode:e,fromDot:n,toDot:o,line:r,deleteButton:s};return this.connections.push(a),t.connections.push(a),e.connections.push(a),this.updateConnection(a),this.bindConnectionEvents(a),i.silent||this.onConnect({from:t.id,fromInfo:t.info,to:e.id,toInfo:e.info,fromDot:n.position,toDot:o.position}),a}console.warn("该连接已存在")}},{key:"updateConnection",value:function(t){if(t&&t.line){var e=this.getDotPosition(t.fromNode.element,t.fromDot.position),n=this.getDotPosition(t.toNode.element,t.toDot.position);if(this.updateLine(t.line,e,n,t.fromDot.position,t.toDot.position),t.hoverPath&&this.updateLine(t.hoverPath,e,n,t.fromDot.position,t.toDot.position),t.deleteButton){var o=this.getBezierMidPoint(e,n,t.fromDot.position,t.toDot.position);t.deleteButton.style.left="".concat(o.x-this.config.deleteButtonSize/2,"px"),t.deleteButton.style.top="".concat(o.y-this.config.deleteButtonSize/2,"px")}}}},{key:"updateNodeConnections",value:function(t){var e=this;this.connections.filter(function(e){return e.fromNode.id===t||e.toNode.id===t}).forEach(function(t){return e.updateConnection(t)})}},{key:"updateAllConnections",value:function(){var t=this;this.connections.forEach(function(e){return t.updateConnection(e)})}},{key:"createLine",value:function(){var t=document.createElementNS("http://www.w3.org/2000/svg","path");return t.setAttribute("stroke",this.config.lineColor),t.setAttribute("stroke-width",this.config.lineWidth),t.setAttribute("fill","none"),t}},{key:"updateLine",value:function(t,e,n){var o=arguments.length>3&&void 0!==arguments[3]?arguments[3]:"right",i=arguments.length>4&&void 0!==arguments[4]?arguments[4]:"left",r=n.x-e.x,s=n.y-e.y,a=Math.sqrt(r*r+s*s),l=Math.min(.5*a,150),c="right"===o?e.x+l:e.x-l,d="right"===i?n.x+l:n.x-l,u="M ".concat(e.x," ").concat(e.y," C ").concat(c," ").concat(e.y,", ").concat(d," ").concat(n.y,", ").concat(n.x," ").concat(n.y);t.setAttribute("d",u)}},{key:"getBezierMidPoint",value:function(t,e){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:"right",o=arguments.length>3&&void 0!==arguments[3]?arguments[3]:"left",i=e.x-t.x,r=e.y-t.y,s=Math.sqrt(i*i+r*r),a=Math.min(.5*s,150),l="right"===n?t.x+a:t.x-a,c=t.y,d="right"===o?e.x+a:e.x-a,u=e.y,h=.5,f=h*h,v=f*h;return{x:.125*t.x+.375*l+.375*d+v*e.x,y:.125*t.y+.375*c+.375*u+v*e.y}}},{key:"createDeleteButton",value:function(){var t=document.createElement("div");return t.className="connector-delete-btn",t.innerHTML="×",t.style.cssText="\n position: absolute;\n width: ".concat(this.config.deleteButtonSize,"px;\n height: ").concat(this.config.deleteButtonSize,"px;\n background-color: #ff4d4f;\n color: white;\n border-radius: 50%;\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: pointer;\n font-size: 16px;\n font-weight: bold;\n z-index: 100;\n opacity: 0;\n transition: opacity 0.2s, transform 0.2s;\n pointer-events: none;\n "),this.contentWrapper.appendChild(t),t.addEventListener("mouseenter",function(){t.style.transform="scale(1.2)"}),t.addEventListener("mouseleave",function(){t.style.transform="scale(1)",t.style.opacity="0",t.style.pointerEvents="none"}),t}},{key:"bindConnectionEvents",value:function(t){var e=this,n=t.line,o=t.deleteButton;n.style.pointerEvents="stroke",n.style.cursor="pointer";var i=document.createElementNS("http://www.w3.org/2000/svg","path");i.setAttribute("stroke","transparent"),i.setAttribute("stroke-width","20"),i.setAttribute("fill","none"),i.style.pointerEvents="stroke",i.style.cursor="pointer",i.setAttribute("d",n.getAttribute("d")),this.svg.insertBefore(i,n),t.hoverPath=i;var r=function(){o.style.opacity="1",o.style.pointerEvents="auto"},s=function(){setTimeout(function(){o.matches(":hover")||(o.style.opacity="0",o.style.pointerEvents="none")},100)};i.addEventListener("mouseenter",r),i.addEventListener("mouseleave",s),n.addEventListener("mouseenter",r),n.addEventListener("mouseleave",s),o.addEventListener("click",function(){e.disconnect(t.id)})}},{key:"disconnect",value:function(t){var e=this,n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};if(t){var o=this.connections.findIndex(function(e){return e.id===t});if(-1===o)return;var i=this.connections[o],r={from:i.fromNode.id,fromInfo:i.fromNode.info,to:i.toNode.id,toInfo:i.toNode.info,fromDot:i.fromDot.position,toDot:i.toDot.position};i.line&&i.line.parentNode&&this.svg.removeChild(i.line),i.hoverPath&&i.hoverPath.parentNode&&this.svg.removeChild(i.hoverPath),i.deleteButton&&i.deleteButton.parentNode&&i.deleteButton.parentNode.removeChild(i.deleteButton),i.fromNode.connections=i.fromNode.connections.filter(function(e){return e.id!==t}),i.toNode.connections=i.toNode.connections.filter(function(e){return e.id!==t}),this.connections.splice(o,1),n.silent||this.onDisconnect(r)}else{s(this.connections).forEach(function(t){return e.disconnect(t.id,n)})}}},{key:"getElementCenter",value:function(t){var e=t.getBoundingClientRect(),n=this.container.getBoundingClientRect(),o=e.left+e.width/2-n.left,i=e.top+e.height/2-n.top,r=this.viewState,s=r.scale;return{x:(o-r.translateX)/s,y:(i-r.translateY)/s}}},{key:"getDotPosition",value:function(t,e){var n=t.getBoundingClientRect(),o=this.container.getBoundingClientRect(),i="right"===e?n.right-o.left:n.left-o.left,r=n.top+n.height/2-o.top,s=this.viewState,a=s.scale;return{x:(i-s.translateX)/a,y:(r-s.translateY)/a}}},{key:"getNodeAtPosition",value:function(t,e){var o,i=n(this.nodes);try{for(i.s();!(o=i.n()).done;){var r=o.value,s=r.element.getBoundingClientRect();if(t>=s.left&&t<=s.right&&e>=s.top&&e<=s.bottom)return r}}catch(t){i.e(t)}finally{i.f()}return null}},{key:"checkSnap",value:function(t,e){var o=this;if(!this.config.enableSnap)return null;var i,r=null,s=null,a=1/0,l=n(this.nodes);try{var c=function(){var n=i.value;if(n.id===e.id)return 1;n.dots&&Object.values(n.dots).forEach(function(e){var i=o.getDotPosition(n.element,e.position),l=t.x-i.x,c=t.y-i.y,d=Math.sqrt(l*l+c*c);d<o.config.snapDistance&&d<a&&(a=d,r=n,s=e)})};for(l.s();!(i=l.n()).done;)c()}catch(t){l.e(t)}finally{l.f()}return r&&s?{node:r,dot:s,position:this.getDotPosition(r.element,s.position)}:null}},{key:"highlightSnapTarget",value:function(t){var e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:null;if(t&&t.element&&(this.clearSnapHighlight(),t.element.style.boxShadow="0 0 0 3px rgba(21, 91, 212, 0.3)",t.element.style.transform="scale(1.05)",t.element.dataset.snapped="true",e&&e.element)){var n=e.element.dataset.baseTransform||"translateY(-50%)";e.element.style.transform="".concat(n," scale(1.5)"),e.element.style.boxShadow="0 0 10px rgba(21, 91, 212, 0.6)",e.element.dataset.highlighted="true"}}},{key:"clearSnapHighlight",value:function(){this.nodes.forEach(function(t){"true"===t.element.dataset.snapped&&(t.element.style.boxShadow="",t.element.style.transform="",delete t.element.dataset.snapped,t.dots&&Object.values(t.dots).forEach(function(t){if("true"===t.element.dataset.highlighted){var e=t.element.dataset.baseTransform||"translateY(-50%)";t.element.style.transform=e,t.element.style.boxShadow="",delete t.element.dataset.highlighted}}))})}},{key:"updateNodePosition",value:function(t){var e=this,n=this.nodes.find(function(e){return e.id===t});n&&(n.dots&&Object.values(n.dots).forEach(function(t){t.coords=e.getDotPosition(n.element,t.position)}),this.updateNodeConnections(t))}},{key:"destroy",value:function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};this.disconnect(null,{silent:t.silent||!0}),this.nodes.forEach(function(t){t.dots&&Object.values(t.dots).forEach(function(t){t.element&&t.element.parentNode&&t.element.parentNode.removeChild(t.element)})}),this.svg&&this.svg.parentNode&&this.svg.parentNode.removeChild(this.svg),document.removeEventListener("mousemove",this.handleMouseMove),document.removeEventListener("mouseup",this.handleMouseUp),document.removeEventListener("mousemove",this.handleNodeDragMove),document.removeEventListener("mouseup",this.handleNodeDragEnd),this.handleWheel&&this.container.removeEventListener("wheel",this.handleWheel),this.handlePanStart&&this.container.removeEventListener("mousedown",this.handlePanStart),this.handlePanMove&&document.removeEventListener("mousemove",this.handlePanMove),this.handlePanEnd&&document.removeEventListener("mouseup",this.handlePanEnd),this.handleResize&&window.removeEventListener("resize",this.handleResize),this.resizeObserver&&(this.resizeObserver.disconnect(),this.resizeObserver=null),this.nodes=[],this.connections=[]}},{key:"getConnections",value:function(){return this.connections.map(function(t){return{id:t.id,from:t.fromNode.id,to:t.toNode.id,fromDot:t.fromDot.position,toDot:t.toDot.position}})}},{key:"getNodeConnections",value:function(t){return this.connections.filter(function(e){return e.fromNode.id===t||e.toNode.id===t}).map(function(t){return{id:t.id,from:t.fromNode.id,to:t.toNode.id,fromDot:t.fromDot.position,toDot:t.toDot.position}})}}])}();export{c as Connector,c as default};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "power-link",
3
- "version": "0.0.6",
3
+ "version": "0.0.8",
4
4
  "description": "A pure JavaScript visual node connector for creating draggable connections between nodes. Framework-agnostic and easy to use",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",