@yanqirenshi/d3.deployment 0.10.0 → 0.11.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/README.markdown CHANGED
@@ -4,6 +4,9 @@
4
4
 
5
5
  - ノードは `children` で入れ子にできます。宣言サイズより子が大きい場合は親が自動で広がります。
6
6
  - ノードはドラッグで移動でき、**親を動かすとサブツリーごと追従**します。
7
+ 動かし終えたことは `callbacks.node.dragend(core, node, move)` で受け取れます(v0.11.0+)。
8
+ - 既定値(枠線・背景・線の stroke と矢印・端点の角度 90)は [`@yanqirenshi/model.deployment`](../model.deployment) から取ります。
9
+ インスペクタや保存は model.deployment と組み合わせます(ショーケースの `model.deployment` のデモ)。
7
10
  - エッジの取り付け位置はポートの角度で指定します(0=真下・時計回り。90=左 / 180=真上 / 270=右)。
8
11
  - **このライブラリは描画のみを行います。** クリックと右クリックはコールバックで通知するだけで、
9
12
  編集 UI は利用側が用意します(ショーケースではインスペクタ `@yanqirenshi/colonoscope` を繋いでいます)。
@@ -35,7 +38,9 @@ export default function Graph({ data }) {
35
38
  // 描画は行わず通知のみ。core は入力データそのもの
36
39
  // contextmenu は右クリック。引数は click と同じで、最後に event(MouseEvent)。
37
40
  // 渡したときだけブラウザ標準のメニューを止める。ドラッグ中は呼ばれない
38
- node: { click: (core, node) => {}, contextmenu: (core, node, event) => {} },
41
+ node: { click: (core, node) => {}, contextmenu: (core, node, event) => {},
42
+ // ドラッグの終わり(動いたときだけ)。move は移動量 { dx, dy }。model.deployment の movePatch(core, move) に渡せる
43
+ dragend: (core, node, move) => {} },
39
44
  edge: { click: (core, edge) => {}, contextmenu: (core, edge, event) => {} },
40
45
  },
41
46
  });
package/dist/js/Rectum.js CHANGED
@@ -7,6 +7,7 @@ Object.defineProperty(exports, "__esModule", {
7
7
  exports["default"] = void 0;
8
8
  var d3 = _interopRequireWildcard(require("d3"));
9
9
  var _assh0le = require("@yanqirenshi/assh0le");
10
+ var _model = require("@yanqirenshi/model.deployment");
10
11
  var _Node = _interopRequireDefault(require("./datamodels/Node.js"));
11
12
  var _Edge = _interopRequireDefault(require("./datamodels/Edge.js"));
12
13
  var _Port = _interopRequireDefault(require("./datamodels/Port.js"));
@@ -32,7 +33,7 @@ function _get() { return _get = "undefined" != typeof Reflect && Reflect.get ? R
32
33
  function _superPropBase(t, o) { for (; !{}.hasOwnProperty.call(t, o) && null !== (t = _getPrototypeOf(t));); return t; }
33
34
  function _getPrototypeOf(t) { return _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf.bind() : function (t) { return t.__proto__ || Object.getPrototypeOf(t); }, _getPrototypeOf(t); }
34
35
  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
- function _setPrototypeOf(t, e) { return _setPrototypeOf = Object.setPrototypeOf ? Object.setPrototypeOf.bind() : function (t, e) { return t.__proto__ = e, t; }, _setPrototypeOf(t, e); }
36
+ function _setPrototypeOf(t, e) { return _setPrototypeOf = Object.setPrototypeOf ? Object.setPrototypeOf.bind() : function (t, e) { return t.__proto__ = e, t; }, _setPrototypeOf(t, e); } // 端点の角度の既定(90=左)は図ごとの知識なので @yanqirenshi/model.deployment が持つ(Foolsgolds/Assholes#146)
36
37
  /**
37
38
  * click / contextmenu のコールバックを呼ぶ。
38
39
  *
@@ -88,7 +89,9 @@ var Rectum = exports["default"] = /*#__PURE__*/function (_Colon) {
88
89
  return {
89
90
  node: {
90
91
  click: node.click || null,
91
- contextmenu: node.contextmenu || null
92
+ contextmenu: node.contextmenu || null,
93
+ // ドラッグの終わり(動いたときだけ)。(core, node, move) を渡す
94
+ dragend: node.dragend || null
92
95
  },
93
96
  edge: {
94
97
  click: edge.click || null,
@@ -269,7 +272,9 @@ var Rectum = exports["default"] = /*#__PURE__*/function (_Colon) {
269
272
  value: function fittingPort(port) {
270
273
  var port_pos;
271
274
  if (port._type === 'FROM') port_pos = port.edge._core.from.position;else port_pos = port.edge._core.to.position;
272
- var position = this.positioningPort(port, port_pos, port.node);
275
+
276
+ // 角度が無ければモデルの既定(90=左)。Geometry.getPortLineTo も同じ値に倒すが、既定の出どころはモデル側
277
+ var position = this.positioningPort(port, (0, _model.degreeOf)(port_pos), port.node);
273
278
  port.position = position;
274
279
  }
275
280
  }, {
@@ -552,17 +557,46 @@ var Rectum = exports["default"] = /*#__PURE__*/function (_Colon) {
552
557
  // Next.js(Webpack/SWC)のトランスパイルで `this` が書き換わり得るため、
553
558
  // 掴んだ要素は sourceEvent から closest() で取り、クロージャで保持する。
554
559
  var grabbed = null;
555
- var drag = d3.drag().on('start', function (event) {
560
+
561
+ // dragend(callbacks.node.dragend)で移動量を出すために、掴んだときの位置を覚える
562
+ var origin = null;
563
+ var drag = d3.drag().on('start', function (event, node) {
556
564
  grabbed = event.sourceEvent.target.closest('g.node, g.component');
557
565
  if (grabbed) grabbed.style.cursor = 'grabbing';
566
+ origin = {
567
+ x: node._position.x,
568
+ y: node._position.y
569
+ };
558
570
  }).on('drag', function (event, node) {
559
571
  self.moveSubtree(place, data, node, event.dx, event.dy);
560
- }).on('end', function () {
572
+ }).on('end', function (event, node) {
561
573
  if (grabbed) grabbed.style.cursor = 'grab';
562
574
  grabbed = null;
575
+ self.notifyDragend(node, origin);
576
+ origin = null;
563
577
  });
564
578
  place.selectAll('g.node, g.component').style('cursor', 'grab').call(drag);
565
579
  }
580
+ /**
581
+ * ドラッグの終わり。動いたときだけ callbacks.node.dragend(core, node, move) を呼ぶ。
582
+ * core: 入力のレコード(node._core)
583
+ * node: 正規化済みのノード(_position は動かしたあとの位置)
584
+ * move: 移動量 { dx, dy }(世界座標)。model.deployment の movePatch(core, move) にそのまま渡せる
585
+ * 動かさずに離したとき(クリック)は呼ばない(保存が走らないように)。
586
+ * 掴んだノード(node / component)についてだけ呼ぶ(子孫はいっしょに動くが、position は親の中での位置なので変わらない)。
587
+ */
588
+ }, {
589
+ key: "notifyDragend",
590
+ value: function notifyDragend(node, origin) {
591
+ var callback = this._callbacks.node.dragend;
592
+ if (!callback || !origin) return;
593
+ var move = {
594
+ dx: node._position.x - origin.x,
595
+ dy: node._position.y - origin.y
596
+ };
597
+ if (move.dx === 0 && move.dy === 0) return;
598
+ callback(node._core, node, move);
599
+ }
566
600
  /** node を根とするサブツリーの node._id 集合を返す。 */
567
601
  }, {
568
602
  key: "collectSubtree",
@@ -4,12 +4,16 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports["default"] = void 0;
7
+ var _model = require("@yanqirenshi/model.deployment");
7
8
  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); }
9
+ function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
10
+ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
11
+ function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
8
12
  function _classCallCheck(a, n) { if (!(a instanceof n)) throw new TypeError("Cannot call a class as a function"); }
9
13
  function _defineProperties(e, r) { for (var t = 0; t < r.length; t++) { var o = r[t]; o.enumerable = o.enumerable || !1, o.configurable = !0, "value" in o && (o.writable = !0), Object.defineProperty(e, _toPropertyKey(o.key), o); } }
10
14
  function _createClass(e, r, t) { return r && _defineProperties(e.prototype, r), t && _defineProperties(e, t), Object.defineProperty(e, "prototype", { writable: !1 }), e; }
11
15
  function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : i + ""; }
12
- function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
16
+ function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); } // 線の既定(stroke と矢印)は図ごとの知識なので @yanqirenshi/model.deployment が持つ(Foolsgolds/Assholes#146)
13
17
  /**
14
18
  * Edge のデータクラス。入力データの正規化(既定値補完)を行う。
15
19
  * 描画は painters/Edges.js が担当する。
@@ -41,12 +45,9 @@ var Edge = exports["default"] = /*#__PURE__*/function () {
41
45
  }
42
46
  },
43
47
  stroke: {
44
- color: '#333',
45
- width: 1.5,
46
- marker: {
47
- start: false,
48
- end: true
49
- }
48
+ color: _model.EDGE_DEFAULTS.stroke.color,
49
+ width: _model.EDGE_DEFAULTS.stroke.width,
50
+ marker: _objectSpread({}, _model.EDGE_DEFAULTS.stroke.marker)
50
51
  },
51
52
  _id: null,
52
53
  _core: null,
@@ -5,12 +5,14 @@ Object.defineProperty(exports, "__esModule", {
5
5
  });
6
6
  exports["default"] = void 0;
7
7
  var _assh0le = require("@yanqirenshi/assh0le");
8
+ var _model = require("@yanqirenshi/model.deployment");
8
9
  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); }
9
10
  function _classCallCheck(a, n) { if (!(a instanceof n)) throw new TypeError("Cannot call a class as a function"); }
10
11
  function _defineProperties(e, r) { for (var t = 0; t < r.length; t++) { var o = r[t]; o.enumerable = o.enumerable || !1, o.configurable = !0, "value" in o && (o.writable = !0), Object.defineProperty(e, _toPropertyKey(o.key), o); } }
11
12
  function _createClass(e, r, t) { return r && _defineProperties(e.prototype, r), t && _defineProperties(e, t), Object.defineProperty(e, "prototype", { writable: !1 }), e; }
12
13
  function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : i + ""; }
13
- function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
14
+ function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); } // 枠線・背景の既定は図ごとの知識なので @yanqirenshi/model.deployment が持つ(Foolsgolds/Assholes#146)。
15
+ // 値は assh0le の Stroke.template / Background.template と同じ(model.deployment のテストが突き合わせる)。
14
16
  /**
15
17
  * Node のデータクラス。入力データの正規化(既定値補完)と幾何情報の提供を行う。
16
18
  * 描画は painters/Nodes.js が担当する。
@@ -21,8 +23,6 @@ var Node = exports["default"] = /*#__PURE__*/function () {
21
23
  this.label = new _assh0le.Label();
22
24
  this.rectangle = new _assh0le.Rectangle();
23
25
  this.position = new _assh0le.Position();
24
- this.stroke = new _assh0le.Stroke();
25
- this.background = new _assh0le.Background();
26
26
  this.padding = new _assh0le.Padding();
27
27
  }
28
28
  ///// ////////////////////////////////////////////////////////////////
@@ -124,9 +124,12 @@ var Node = exports["default"] = /*#__PURE__*/function () {
124
124
  new_data.label = this.label.build(new_data._core.label);
125
125
  new_data.size = this.rectangle.build(new_data._core.size);
126
126
  new_data.position = this.position.build(new_data._core.position);
127
- new_data.border = this.stroke.build(new_data._core.border) || this.stroke.template();
128
127
  new_data.padding = this.padding.build(new_data._core.padding);
129
- new_data.background = this.background.build(new_data._core.background);
128
+
129
+ // 枠線・背景(既定に入力の truthy な項目を重ねる)は model.deployment の nodeStyle
130
+ var style = (0, _model.nodeStyle)(new_data._core);
131
+ new_data.border = style.border;
132
+ new_data.background = style.background;
130
133
  data._node = new_data;
131
134
  return new_data;
132
135
  }
package/jest.config.js CHANGED
@@ -10,6 +10,10 @@ module.exports = {
10
10
  // d3 v7 は ESM-only で CJS ランタイムの jest では読めないため、スタブにマップする
11
11
  moduleNameMapper: {
12
12
  '^d3$': '<rootDir>/tests/d3-stub.js',
13
+ // model.deployment は ESM のみを main にしている。jest 25 は package.json の exports を見ないので、
14
+ // CommonJS 版(model.deployment の build が dist/cjs/ に出す)へ直接マップする。
15
+ // model.deployment を先にビルドしておくこと(npm run build -w @yanqirenshi/model.deployment)。
16
+ '^@yanqirenshi/model.deployment$': '<rootDir>/../model.deployment/dist/cjs/index.js',
13
17
  },
14
18
  collectCoverageFrom: [
15
19
  "**/src/**/*.js",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yanqirenshi/d3.deployment",
3
- "version": "0.10.0",
3
+ "version": "0.11.0",
4
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": {
@@ -12,7 +12,8 @@
12
12
  },
13
13
  "dependencies": {
14
14
  "d3": "^7.9.0",
15
- "@yanqirenshi/assh0le": "^0.5.0"
15
+ "@yanqirenshi/assh0le": "^0.5.0",
16
+ "@yanqirenshi/model.deployment": "^0.1.0"
16
17
  },
17
18
  "devDependencies": {
18
19
  "@babel/cli": "^7.12.17",