@yanqirenshi/d3.deployment 0.9.0 → 0.10.0

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.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2018-2026 Satoshi Iwasaki (yanqirenshi@gmail.com)
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.markdown CHANGED
@@ -1,15 +1,110 @@
1
- # D3.Deployment
2
-
3
- See [Documents](https://yanqirenshi.github.io/D3.Deployment/)
4
-
5
- # Author
6
-
7
- yanqirenshi (yanqirenshie@gmail.com)
8
-
9
- # Copyright
10
-
11
- Copyright (c) 2019 yanqirenshi (yanqirenshie@gmail.com)
12
-
13
- # License
14
-
15
- Licensed under the LLGPL License.
1
+ # @yanqirenshi/d3.deployment
2
+
3
+ デプロイメント図(ノード・エッジ・ポート)を SVG で描画する React コンポーネントです。
4
+
5
+ - ノードは `children` で入れ子にできます。宣言サイズより子が大きい場合は親が自動で広がります。
6
+ - ノードはドラッグで移動でき、**親を動かすとサブツリーごと追従**します。
7
+ - エッジの取り付け位置はポートの角度で指定します(0=真下・時計回り。90=左 / 180=真上 / 270=右)。
8
+ - **このライブラリは描画のみを行います。** クリックと右クリックはコールバックで通知するだけで、
9
+ 編集 UI は利用側が用意します(ショーケースではインスペクタ `@yanqirenshi/colonoscope` を繋いでいます)。
10
+
11
+ ## インストール
12
+
13
+ ```bash
14
+ npm install @yanqirenshi/d3.deployment
15
+ ```
16
+
17
+ React 18 / 19 に対応しています(`peerDependencies`)。
18
+
19
+ ## 使い方
20
+
21
+ 描画の管理オブジェクト `Rectum` を作って React コンポーネント `D3Deployment` に渡し、
22
+ `data()` でデータを流し込みます。
23
+
24
+ ```jsx
25
+ import React from 'react';
26
+ import D3Deployment, { Rectum } from '@yanqirenshi/d3.deployment';
27
+
28
+ export default function Graph({ data }) {
29
+ const [rectum, setRectum] = React.useState(null);
30
+
31
+ React.useEffect(() => {
32
+ const r = new Rectum({
33
+ transform: { k: 0.6, x: 120, y: 120 }, // 初期のズーム / パン
34
+ callbacks: {
35
+ // 描画は行わず通知のみ。core は入力データそのもの
36
+ // contextmenu は右クリック。引数は click と同じで、最後に event(MouseEvent)。
37
+ // 渡したときだけブラウザ標準のメニューを止める。ドラッグ中は呼ばれない
38
+ node: { click: (core, node) => {}, contextmenu: (core, node, event) => {} },
39
+ edge: { click: (core, edge) => {}, contextmenu: (core, edge, event) => {} },
40
+ },
41
+ });
42
+ r.data(data);
43
+ setRectum(r);
44
+ }, [data]);
45
+
46
+ if (!rectum) return null;
47
+
48
+ return (
49
+ <div style={{ width: '100%', height: '100%' }}>
50
+ <D3Deployment rectum={rectum} />
51
+ </div>
52
+ );
53
+ }
54
+ ```
55
+
56
+ ### 描画後にポートの角度を変える
57
+
58
+ ```js
59
+ rectum.setEdgePorts(edge_id, { from: 0, to: 180 }); // 省略した側は変更しない
60
+ ```
61
+
62
+ 入力データ側(`_core`)の角度を書き換えてから再フィットするので、
63
+ 以後の再描画やコンポーネントの remount でも維持されます。
64
+
65
+ ## 入力データ
66
+
67
+ `{ nodes, edges }` の連想配列です。
68
+
69
+ ```js
70
+ {
71
+ nodes: [
72
+ {
73
+ type: 'NODE', id: 1,
74
+ label: { text: 'NODE 01', position: { x: 20, y: 20 }, font: { size: 16, color: '#333333' } },
75
+ description: 'ホバー時のツールチップに出る(任意)',
76
+ link: { url: 'https://example.com/' }, // 任意。ボックス左下に表示
77
+ padding: 40, // 任意。数値・全辺共通
78
+ size: { w: 150, h: 150 }, position: { x: 0, y: 0 },
79
+ children: [ /* 入れ子のノード */ ],
80
+ },
81
+ ],
82
+ edges: [
83
+ { id: 100, from: { id: 1, position: 0 }, to: { id: 2, position: 180 } },
84
+ ],
85
+ }
86
+ ```
87
+
88
+ `edges[].from.id` / `to.id` は `nodes[].id` を参照します(入れ子の内側のノードも指定できます)。
89
+
90
+ フィールドの詳細はショーケースの d3.deployment のページ(「データ」タブ)を参照してください。
91
+ サンプルの実データは `showcase/src/demos/data/deployment-sample.js` です。
92
+
93
+ ## 開発
94
+
95
+ ```bash
96
+ npm run transpile -w @yanqirenshi/d3.deployment # src -> dist(dist はコミット対象)
97
+ npm test -w @yanqirenshi/d3.deployment # jest
98
+ ```
99
+
100
+ ## Author
101
+
102
+ Satoshi Iwasaki (yanqirenshi@gmail.com)
103
+
104
+ ## Copyright
105
+
106
+ Copyright (c) 2018-2026 Satoshi Iwasaki (yanqirenshi@gmail.com)
107
+
108
+ ## License
109
+
110
+ Licensed under the MIT License.
@@ -1,18 +1,17 @@
1
1
  "use strict";
2
2
 
3
- function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
4
3
  Object.defineProperty(exports, "__esModule", {
5
4
  value: true
6
5
  });
7
6
  exports["default"] = D3Deployment;
8
- var _react = _interopRequireWildcard(require("react"));
7
+ var _react = _interopRequireDefault(require("react"));
9
8
  var _assh0le = _interopRequireDefault(require("@yanqirenshi/assh0le"));
10
9
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { "default": e }; }
11
- function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function _interopRequireWildcard(e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, "default": e }; if (null === e || "object" != _typeof(e) && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (var _t in e) "default" !== _t && {}.hasOwnProperty.call(e, _t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, _t)) && (i.get || i.set) ? o(f, _t, i) : f[_t] = e[_t]); return f; })(e, t); }
12
10
  function D3Deployment(props) {
13
11
  var rectum = props.rectum;
12
+ var id = props.id || "d3-deployment-graph";
14
13
  return /*#__PURE__*/_react["default"].createElement(_assh0le["default"], {
15
- id: "d3-deployment-graph",
14
+ id: id,
16
15
  rectum: rectum
17
16
  });
18
17
  }
package/dist/js/Rectum.js CHANGED
@@ -33,6 +33,26 @@ function _superPropBase(t, o) { for (; !{}.hasOwnProperty.call(t, o) && null !==
33
33
  function _getPrototypeOf(t) { return _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf.bind() : function (t) { return t.__proto__ || Object.getPrototypeOf(t); }, _getPrototypeOf(t); }
34
34
  function _inherits(t, e) { if ("function" != typeof e && null !== e) throw new TypeError("Super expression must either be null or a function"); t.prototype = Object.create(e && e.prototype, { constructor: { value: t, writable: !0, configurable: !0 } }), Object.defineProperty(t, "prototype", { writable: !1 }), e && _setPrototypeOf(t, e); }
35
35
  function _setPrototypeOf(t, e) { return _setPrototypeOf = Object.setPrototypeOf ? Object.setPrototypeOf.bind() : function (t, e) { return t.__proto__ = e, t; }, _setPrototypeOf(t, e); }
36
+ /**
37
+ * click / contextmenu のコールバックを呼ぶ。
38
+ *
39
+ * contextmenu(右クリック)のときだけ次のようにする。
40
+ * - 左ボタンを押したまま(ドラッグ中)の右クリックは通知しない
41
+ * - ブラウザ標準のコンテキストメニューを止める(コールバックがあるときだけ
42
+ * ここに来るので、渡していなければ標準のメニューが出る)
43
+ * - 最後の引数に event を渡す(clientX / clientY を使えるように)
44
+ */
45
+ var notify = function notify(callback, event, core, datum) {
46
+ if (event.type === 'contextmenu') {
47
+ if (event.buttons & 1) return;
48
+ event.preventDefault();
49
+ event.stopPropagation();
50
+ callback(core, datum, event);
51
+ return;
52
+ }
53
+ event.stopPropagation();
54
+ callback(core, datum);
55
+ };
36
56
  var Rectum = exports["default"] = /*#__PURE__*/function (_Colon) {
37
57
  function Rectum(params) {
38
58
  var _this;
@@ -67,10 +87,12 @@ var Rectum = exports["default"] = /*#__PURE__*/function (_Colon) {
67
87
  var edge = callbacks.edge || {};
68
88
  return {
69
89
  node: {
70
- click: node.click || null
90
+ click: node.click || null,
91
+ contextmenu: node.contextmenu || null
71
92
  },
72
93
  edge: {
73
- click: edge.click || null
94
+ click: edge.click || null,
95
+ contextmenu: edge.contextmenu || null
74
96
  }
75
97
  };
76
98
  }
@@ -414,56 +436,61 @@ var Rectum = exports["default"] = /*#__PURE__*/function (_Colon) {
414
436
  _iterator8.f();
415
437
  }
416
438
  this.attachNodeDrag(place, data);
417
- this.attachNodeClick(place);
418
- this.attachEdgeClick(place);
439
+ this.attachNodeEvent(place, 'click');
440
+ this.attachNodeEvent(place, 'contextmenu');
441
+ this.attachEdgeEvent(place, 'click');
442
+ this.attachEdgeEvent(place, 'contextmenu');
419
443
  }
420
444
  /**
421
- * ノードのクリック通知(callbacks.node.click)。
445
+ * ノードのクリック通知(callbacks.node.click)と
446
+ * 右クリック通知(callbacks.node.contextmenu)。
422
447
  * d3.drag は移動を伴ったクリックを抑止するため、静止クリックだけが届く。
423
448
  *
424
- * コールバックには (core, node) を渡す。
449
+ * コールバックには (core, node) を渡す。contextmenu は最後に event も渡す。
425
450
  * core: 入力データそのまま(ライブラリが解釈しないフィールドも落ちない)
426
451
  * node: 正規化済みデータ(位置・サイズ等が必要な場合に使う)
427
452
  *
428
453
  * リンク(a.link-alt)のクリックはリンク側を優先し、コールバックは発火しない。
454
+ *
455
+ * @param {string} type 'click' | 'contextmenu'
429
456
  */
430
457
  }, {
431
- key: "attachNodeClick",
432
- value: function attachNodeClick(place) {
433
- var callback = this._callbacks.node.click;
458
+ key: "attachNodeEvent",
459
+ value: function attachNodeEvent(place, type) {
460
+ var callback = this._callbacks.node[type];
434
461
  if (!callback) return;
435
- place.selectAll('g.node, g.component').on('click', function (event, d) {
462
+ place.selectAll('g.node, g.component').on(type, function (event, d) {
436
463
  var target = event.target;
437
464
  if (target && target.closest && target.closest('a.link-alt')) return; // リンク優先(既存の <a target="_blank"> と干渉しない)
438
465
 
439
- event.stopPropagation();
440
- callback(d._core, d);
466
+ notify(callback, event, d._core, d);
441
467
  });
442
468
  }
443
469
  /**
444
- * エッジのクリック通知(callbacks.edge.click)。
470
+ * エッジのクリック通知(callbacks.edge.click)と
471
+ * 右クリック通知(callbacks.edge.contextmenu)。
445
472
  * エッジ path のほか、両端のポート円からも同じエッジを通知する
446
473
  * (細い線より円のほうが掴みやすい)。(core, edge) を渡す契約は
447
- * node.click と同じ(core = 入力のエッジオブジェクトそのまま)。
474
+ * node.click / node.contextmenu と同じ(core = 入力のエッジオブジェクトそのまま)。
475
+ *
476
+ * @param {string} type 'click' | 'contextmenu'
448
477
  */
449
478
  }, {
450
- key: "attachEdgeClick",
451
- value: function attachEdgeClick(place) {
479
+ key: "attachEdgeEvent",
480
+ value: function attachEdgeEvent(place, type) {
452
481
  var _this5 = this;
453
- var callback = this._callbacks.edge.click;
482
+ var callback = this._callbacks.edge[type];
454
483
  if (!callback) return;
455
- place.selectAll('path.edge').style('cursor', 'pointer').on('click', function (event) {
484
+ place.selectAll('path.edge').style('cursor', 'pointer').on(type, function (event) {
456
485
  // path の datum は線分データのため data-edge-id からエッジを引く
457
486
  var el = event.currentTarget;
458
487
  var id = el && el.getAttribute && el.getAttribute('data-edge-id');
459
488
  var edge = _this5.findEdge(id);
460
489
  if (!edge) return;
461
- event.stopPropagation();
462
- callback(edge._core, edge);
490
+ notify(callback, event, edge._core, edge);
463
491
  });
464
- place.selectAll('circle.port').style('cursor', 'pointer').on('click', function (event, d) {
465
- event.stopPropagation();
466
- callback(d.edge._core, d.edge);
492
+ place.selectAll('circle.port').style('cursor', 'pointer').on(type, function (event, d) {
493
+ notify(callback, event, d.edge._core, d.edge);
467
494
  });
468
495
  }
469
496
  /** id(入力 id。DOM の data-edge-id は文字列)からエッジを引く。 */
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@yanqirenshi/d3.deployment",
3
- "version": "0.9.0",
4
- "description": "See [Documents](https://yanqirenshi.github.io/D3.Deployment/)",
3
+ "version": "0.10.0",
4
+ "description": "Deployment diagram renderer (nestable nodes / edges / ports) — dragging a parent moves its whole subtree",
5
5
  "main": "dist/index.js",
6
6
  "directories": {
7
7
  "doc": "docs"
@@ -26,19 +26,20 @@
26
26
  },
27
27
  "scripts": {
28
28
  "test": "jest",
29
- "transpile": "babel src -d dist --copy-files",
29
+ "transpile": "babel src -d dist --copy-files --delete-dir-on-start",
30
30
  "prepublishOnly": "npm run transpile"
31
31
  },
32
32
  "repository": {
33
33
  "type": "git",
34
- "url": "git+https://github.com/yanqirenshi/D3.Deployment.git"
34
+ "url": "git+https://github.com/Foolsgolds/Assholes.git",
35
+ "directory": "packages/d3.deployment"
35
36
  },
36
37
  "author": "yanqirenshi@gmail.com",
37
38
  "license": "MIT",
38
39
  "bugs": {
39
- "url": "https://github.com/yanqirenshi/D3.Deployment/issues"
40
+ "url": "https://github.com/Foolsgolds/Assholes/issues"
40
41
  },
41
- "homepage": "https://github.com/yanqirenshi/D3.Deployment#readme",
42
+ "homepage": "https://github.com/Foolsgolds/Assholes/tree/main/packages/d3.deployment#readme",
42
43
  "publishConfig": {
43
44
  "access": "public"
44
45
  }