@yanqirenshi/model.sitemap 0.0.0-stage → 0.1.1
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 +21 -0
- package/README.md +120 -2
- package/dist/check.d.ts +15 -0
- package/dist/check.d.ts.map +1 -0
- package/dist/check.js +27 -0
- package/dist/cjs/check.js +32 -0
- package/dist/cjs/defaults.js +101 -0
- package/dist/cjs/fields.js +40 -0
- package/dist/cjs/index.js +45 -0
- package/dist/cjs/package.json +3 -0
- package/dist/cjs/patch.js +120 -0
- package/dist/cjs/schema.js +97 -0
- package/dist/cjs/types.js +8 -0
- package/dist/defaults.d.ts +42 -0
- package/dist/defaults.d.ts.map +1 -0
- package/dist/defaults.js +93 -0
- package/dist/fields.d.ts +8 -0
- package/dist/fields.d.ts.map +1 -0
- package/dist/fields.js +36 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +16 -0
- package/dist/patch.d.ts +19 -0
- package/dist/patch.d.ts.map +1 -0
- package/dist/patch.js +109 -0
- package/dist/schema.d.ts +290 -0
- package/dist/schema.d.ts.map +1 -0
- package/dist/schema.js +94 -0
- package/dist/types.d.ts +83 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +7 -0
- package/package.json +55 -5
- package/src/check.ts +33 -0
- package/src/defaults.ts +112 -0
- package/src/fields.ts +41 -0
- package/src/index.ts +26 -0
- package/src/patch.ts +135 -0
- package/src/schema.ts +99 -0
- package/src/types.ts +99 -0
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.md
CHANGED
|
@@ -1,3 +1,121 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @yanqirenshi/model.sitemap
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
画面遷移図(サイトマップ図。view = `d3.sitemap`)の**図ごとの知識**を、描画から独立させたパッケージです。
|
|
4
|
+
react / d3 に依存しない、純粋なデータと関数だけを持ちます。
|
|
5
|
+
d3.sitemap は、このパッケージの既定値(ラベル・枠線・背景・余白・線の stroke・端点の角度)を読みます。
|
|
6
|
+
|
|
7
|
+
| 持つもの | 入口 |
|
|
8
|
+
|---|---|
|
|
9
|
+
| 入力データのスキーマ(JSON Schema 2020-12) | `SCHEMAS.nodes` / `SCHEMAS.edges` |
|
|
10
|
+
| コレクションをまたぐ整合性ルール(id の重複・参照先の存在) | `check(data)` |
|
|
11
|
+
| d3.sitemap が既定で描いている値 | `withDefaults(record)` / `nodeStyle` / `edgeStyle`、`NODE_STYLE_DEFAULTS` など |
|
|
12
|
+
| 編集できる項目の一覧(インスペクタ用) | `fieldsOf(record)` |
|
|
13
|
+
| UI の操作を保存する patch に変える変換 | `movePatch(node, move)` / `applyPatch(record, values)` |
|
|
14
|
+
|
|
15
|
+
利用側(iHub など)は、モデルが返す `{ collection, id, patch }` を保存するだけで、図の種類を知らずに書けます。
|
|
16
|
+
|
|
17
|
+
## 位置づけ
|
|
18
|
+
|
|
19
|
+
```
|
|
20
|
+
利用側 ──▶ d3.sitemap (view) ──▶ model.sitemap (既定値を読む)
|
|
21
|
+
──▶ colonoscope (ModelInspector)
|
|
22
|
+
──▶ model.sitemap
|
|
23
|
+
──▶ 自前の永続化
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
model.sitemap・colonoscope の間に横の依存はありません。組み合わせるのは利用側だけです。
|
|
27
|
+
これは [Foolsgolds/Assholes#138](https://github.com/Foolsgolds/Assholes/issues/138) の派生([#145](https://github.com/Foolsgolds/Assholes/issues/145))です。
|
|
28
|
+
ノードと線の図なので [model.unchi](../model.unchi) と形が近く、`check` / `movePatch` / `mergePatch` と入力の読み取り部品は
|
|
29
|
+
共通部品 [model.core](../model.core) のものに model.sitemap の型を付けて公開しています([#151](https://github.com/Foolsgolds/Assholes/issues/151))。
|
|
30
|
+
|
|
31
|
+
## レコードの形
|
|
32
|
+
|
|
33
|
+
d3.sitemap の `data()` に渡す入力そのもの(`nodes` / `edges` の 1 要素)です。
|
|
34
|
+
|
|
35
|
+
```js
|
|
36
|
+
{
|
|
37
|
+
nodes: [{ id, type, label: { contents, position, font, link }, size: { w, h }, position: { x, y },
|
|
38
|
+
padding, border, background, link: { url, icon, position }, path, node_type,
|
|
39
|
+
children: [ /* 同じ形 */ ] }],
|
|
40
|
+
edges: [{ id, from: { id, position }, to: { id, position }, stroke: { color, width } }],
|
|
41
|
+
}
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
model.unchi(ポンチ絵)との違い: ラベルは `label.contents`(unchi は `label.text`)、ノードにリンク(`link.url`)・URL パス(`path`)・画面の種類(`node_type`)があり、線にマーカーとラベルはありません。
|
|
45
|
+
|
|
46
|
+
## 使い方
|
|
47
|
+
|
|
48
|
+
```js
|
|
49
|
+
import D3Sitemap, { Rectum } from '@yanqirenshi/d3.sitemap';
|
|
50
|
+
import { ModelInspector } from '@yanqirenshi/colonoscope';
|
|
51
|
+
import {
|
|
52
|
+
check, fieldsOf, titleOf, withDefaults, movePatch, applyPatch, mergePatch, findById, ModelError,
|
|
53
|
+
} from '@yanqirenshi/model.sitemap';
|
|
54
|
+
|
|
55
|
+
const errors = check({ nodes, edges }); // [] なら問題なし
|
|
56
|
+
|
|
57
|
+
const rectum = new Rectum({
|
|
58
|
+
callbacks: {
|
|
59
|
+
node: {
|
|
60
|
+
// ドラッグの終わり → 位置の patch(core は入力のレコード)
|
|
61
|
+
dragend: (core, node, move) => save(movePatch(core, move)),
|
|
62
|
+
// → { collection: 'nodes', id: 1000031, patch: { position: { x: 120, y: 40 } } }
|
|
63
|
+
contextmenu: (core) => setTarget(core.id),
|
|
64
|
+
},
|
|
65
|
+
},
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
const record = findById(nodes, target); // 子も探す
|
|
69
|
+
<ModelInspector
|
|
70
|
+
target={record && withDefaults(record)}
|
|
71
|
+
fields={fieldsOf}
|
|
72
|
+
title={titleOf}
|
|
73
|
+
onApply={(values) => {
|
|
74
|
+
try {
|
|
75
|
+
save(applyPatch(record, values)); // 変えた項目だけが patch に入る
|
|
76
|
+
} catch (e) {
|
|
77
|
+
if (e instanceof ModelError) alert(e.message); // 利用者向けの日本語
|
|
78
|
+
}
|
|
79
|
+
}}
|
|
80
|
+
/>
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### `applyPatch` の検証
|
|
84
|
+
|
|
85
|
+
| 項目 | 規則 |
|
|
86
|
+
|---|---|
|
|
87
|
+
| 名称(`label.contents`) | 空にできない |
|
|
88
|
+
| 種類(`node_type`) | 空にすると項目を除く |
|
|
89
|
+
| URL(`link.url`) | 空にすると `link` ごと除く(d3.sitemap は url の無い link を描かない) |
|
|
90
|
+
| 幅・高さ | 0 以上。整数に丸める(0 で子に合わせる) |
|
|
91
|
+
| 色(背景・枠線・線) | ブラウザでは `CSS.supports('color', v)`。CSS の無い環境では `#hex` / 関数表記 / 英字の色名を通す緩い判定 |
|
|
92
|
+
| 枠線・線の太さ | 0 以上の数 |
|
|
93
|
+
| 接続位置(角度) | 数。0 以上 360 未満の整数に正規化 |
|
|
94
|
+
|
|
95
|
+
図に描いている値(`withDefaults` の結果)から**変えた項目だけ**を patch に入れます。
|
|
96
|
+
|
|
97
|
+
### 編集できる項目(`fieldsOf`)
|
|
98
|
+
|
|
99
|
+
- ノード: 名称・種類・URL・ID・幅・高さ・背景色・枠線の色 / 太さ
|
|
100
|
+
- 線: ID・遷移元 / 遷移先のノードと位置(角度)・線の色 / 太さ
|
|
101
|
+
|
|
102
|
+
`path`(文字列か `{ contents, link, font }` の 2 つの形がある)と `label.link` は当面スコープ外です。
|
|
103
|
+
`border.type` は d3.sitemap が描かないので項目にしません。
|
|
104
|
+
|
|
105
|
+
## スコープ外(いまは持たない)
|
|
106
|
+
|
|
107
|
+
- `path` / `label.link` / `link.icon` の編集、ノード・線の追加削除
|
|
108
|
+
- ファイル・HTTP などの永続化(利用側の実装)
|
|
109
|
+
|
|
110
|
+
## 配布形式
|
|
111
|
+
|
|
112
|
+
ESM(`dist/`)に加えて CommonJS 版(`dist/cjs/`)も出します。
|
|
113
|
+
Babel 系の `d3.sitemap` を jest(CommonJS)でテストするためで、d3.sitemap の jest が ESM を読めるようになったら外せます。
|
|
114
|
+
|
|
115
|
+
## コマンド
|
|
116
|
+
|
|
117
|
+
```bash
|
|
118
|
+
npm run build -w @yanqirenshi/model.sitemap # tsc で dist/(ESM + d.ts)と dist/cjs/(CommonJS)へビルド
|
|
119
|
+
npm run typecheck -w @yanqirenshi/model.sitemap
|
|
120
|
+
npm test -w @yanqirenshi/model.sitemap # vitest(d3.sitemap の Drawer との突き合わせを含む)
|
|
121
|
+
```
|
package/dist/check.d.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { SitemapGraph, SitemapId, SitemapNodeRecord, SitemapRecord } from './types.js';
|
|
2
|
+
/** 入れ子のノード(children)を平らにする(親 → 子 の順) */
|
|
3
|
+
export declare function flatten(nodes: SitemapNodeRecord[]): SitemapNodeRecord[];
|
|
4
|
+
/**
|
|
5
|
+
* 図全体を検査する。
|
|
6
|
+
* - nodes(子を含む)の id が重複していない
|
|
7
|
+
* - edges の id が重複していない
|
|
8
|
+
* - edges の from.id / to.id がノードに存在する
|
|
9
|
+
*
|
|
10
|
+
* @param prefix メッセージのコレクション名の前に付ける文字列(例: 'sitemap/')
|
|
11
|
+
*/
|
|
12
|
+
export declare function check(data: SitemapGraph, prefix?: string): string[];
|
|
13
|
+
/** ノード(子を含む)か線を id で探す(無ければ null) */
|
|
14
|
+
export declare function findById<T extends SitemapRecord>(list: readonly T[] | undefined, id: SitemapId): T | null;
|
|
15
|
+
//# sourceMappingURL=check.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"check.d.ts","sourceRoot":"","sources":["../src/check.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,YAAY,EAAE,SAAS,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAE5F,wCAAwC;AACxC,wBAAgB,OAAO,CAAC,KAAK,EAAE,iBAAiB,EAAE,GAAG,iBAAiB,EAAE,CAEvE;AAED;;;;;;;GAOG;AACH,wBAAgB,KAAK,CAAC,IAAI,EAAE,YAAY,EAAE,MAAM,SAAK,GAAG,MAAM,EAAE,CAE/D;AAED,qCAAqC;AACrC,wBAAgB,QAAQ,CAAC,CAAC,SAAS,aAAa,EAAE,IAAI,EAAE,SAAS,CAAC,EAAE,GAAG,SAAS,EAAE,EAAE,EAAE,SAAS,GAAG,CAAC,GAAG,IAAI,CAEzG"}
|
package/dist/check.js
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
// コレクションをまたぐ整合性の検査(id の重複・参照先の存在)。
|
|
2
|
+
// スキーマ(schema.ts)に合っているデータを渡す。戻り値はエラーのメッセージの配列(空なら問題なし)。
|
|
3
|
+
//
|
|
4
|
+
// iHub の server/validation/rules.mjs の checkGraph('sitemap', data) と同じ検査・同じ文言。
|
|
5
|
+
// 検査そのものは graph 系(unchi / sitemap / deployment)で共通なので model.core の checkGraph にあり、
|
|
6
|
+
// ここでは model.sitemap の型を付けて公開する(#151)。
|
|
7
|
+
// メッセージの先頭はコレクション名で、prefix を渡すと 'sitemap/nodes: ...' のように付けられる。
|
|
8
|
+
import { checkGraph, flattenNodes, findById as findInList } from '@yanqirenshi/model.core';
|
|
9
|
+
/** 入れ子のノード(children)を平らにする(親 → 子 の順) */
|
|
10
|
+
export function flatten(nodes) {
|
|
11
|
+
return flattenNodes(nodes);
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* 図全体を検査する。
|
|
15
|
+
* - nodes(子を含む)の id が重複していない
|
|
16
|
+
* - edges の id が重複していない
|
|
17
|
+
* - edges の from.id / to.id がノードに存在する
|
|
18
|
+
*
|
|
19
|
+
* @param prefix メッセージのコレクション名の前に付ける文字列(例: 'sitemap/')
|
|
20
|
+
*/
|
|
21
|
+
export function check(data, prefix = '') {
|
|
22
|
+
return checkGraph(data, prefix);
|
|
23
|
+
}
|
|
24
|
+
/** ノード(子を含む)か線を id で探す(無ければ null) */
|
|
25
|
+
export function findById(list, id) {
|
|
26
|
+
return findInList(list, id);
|
|
27
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// コレクションをまたぐ整合性の検査(id の重複・参照先の存在)。
|
|
3
|
+
// スキーマ(schema.ts)に合っているデータを渡す。戻り値はエラーのメッセージの配列(空なら問題なし)。
|
|
4
|
+
//
|
|
5
|
+
// iHub の server/validation/rules.mjs の checkGraph('sitemap', data) と同じ検査・同じ文言。
|
|
6
|
+
// 検査そのものは graph 系(unchi / sitemap / deployment)で共通なので model.core の checkGraph にあり、
|
|
7
|
+
// ここでは model.sitemap の型を付けて公開する(#151)。
|
|
8
|
+
// メッセージの先頭はコレクション名で、prefix を渡すと 'sitemap/nodes: ...' のように付けられる。
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.flatten = flatten;
|
|
11
|
+
exports.check = check;
|
|
12
|
+
exports.findById = findById;
|
|
13
|
+
const model_core_1 = require("@yanqirenshi/model.core");
|
|
14
|
+
/** 入れ子のノード(children)を平らにする(親 → 子 の順) */
|
|
15
|
+
function flatten(nodes) {
|
|
16
|
+
return (0, model_core_1.flattenNodes)(nodes);
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* 図全体を検査する。
|
|
20
|
+
* - nodes(子を含む)の id が重複していない
|
|
21
|
+
* - edges の id が重複していない
|
|
22
|
+
* - edges の from.id / to.id がノードに存在する
|
|
23
|
+
*
|
|
24
|
+
* @param prefix メッセージのコレクション名の前に付ける文字列(例: 'sitemap/')
|
|
25
|
+
*/
|
|
26
|
+
function check(data, prefix = '') {
|
|
27
|
+
return (0, model_core_1.checkGraph)(data, prefix);
|
|
28
|
+
}
|
|
29
|
+
/** ノード(子を含む)か線を id で探す(無ければ null) */
|
|
30
|
+
function findById(list, id) {
|
|
31
|
+
return (0, model_core_1.findById)(list, id);
|
|
32
|
+
}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// d3.sitemap が「書いていない項目」に既定で描く値。
|
|
3
|
+
//
|
|
4
|
+
// 値の出どころは d3.sitemap の src/js/Drawer.js(normalizeLabel / normalizeBorder / normalizeBackground /
|
|
5
|
+
// normalizePadding)、Edges.js の dataTemplate(stroke)、Rectum.getPortLineTo(角度の既定 90)。
|
|
6
|
+
// d3.sitemap はこのファイルを読む(#145)ので、ここが正。
|
|
7
|
+
//
|
|
8
|
+
// d3.sitemap は border.type を正規化するが描画には使わない(dasharray を付けない)ので、モデルも項目にしない。
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.EDGE_DEFAULTS = exports.NODE_DEFAULTS = exports.LABEL_DEFAULTS = exports.NODE_STYLE_DEFAULTS = void 0;
|
|
11
|
+
exports.isEdge = isEdge;
|
|
12
|
+
exports.nodeStyle = nodeStyle;
|
|
13
|
+
exports.edgeStyle = edgeStyle;
|
|
14
|
+
exports.degreeOf = degreeOf;
|
|
15
|
+
exports.withDefaults = withDefaults;
|
|
16
|
+
/** ノードの枠線・背景の既定(Drawer.normalizeBorder / normalizeBackground) */
|
|
17
|
+
exports.NODE_STYLE_DEFAULTS = {
|
|
18
|
+
border: { color: '#666666', width: 1, type: 'solid' },
|
|
19
|
+
background: { color: '#ffffff' },
|
|
20
|
+
};
|
|
21
|
+
/** ラベルの既定(Drawer.normalizeLabel) */
|
|
22
|
+
exports.LABEL_DEFAULTS = {
|
|
23
|
+
position: { x: 20, y: 20 },
|
|
24
|
+
font: { size: 16, color: '#333333' },
|
|
25
|
+
};
|
|
26
|
+
/** ノードの既定(Drawer.normalizePadding / normalizePosition / normalizeSize)。size の 0 は「子に合わせる」 */
|
|
27
|
+
exports.NODE_DEFAULTS = {
|
|
28
|
+
type: 'NODE',
|
|
29
|
+
padding: 0,
|
|
30
|
+
position: { x: 0, y: 0 },
|
|
31
|
+
};
|
|
32
|
+
/** 線の既定(Edges.dataTemplate の stroke、端点の角度は Rectum.getPortLineTo の 90=左) */
|
|
33
|
+
exports.EDGE_DEFAULTS = {
|
|
34
|
+
stroke: { color: '#333', width: 1.5 },
|
|
35
|
+
position: 90,
|
|
36
|
+
};
|
|
37
|
+
/** 線か(from と to を持つ)。ノードは持たない */
|
|
38
|
+
function isEdge(record) {
|
|
39
|
+
return !!(record && record.from && record.to);
|
|
40
|
+
}
|
|
41
|
+
/** 既定に入力の指定(truthy な項目だけ。Drawer.normalize* と同じ判定)を重ねる。width は 0 も通す */
|
|
42
|
+
function mergeStyle(defaults, given) {
|
|
43
|
+
const out = { ...defaults };
|
|
44
|
+
for (const key of Object.keys(given || {})) {
|
|
45
|
+
const v = given[key];
|
|
46
|
+
if (v || (key === 'width' && v === 0))
|
|
47
|
+
out[key] = v;
|
|
48
|
+
}
|
|
49
|
+
return out;
|
|
50
|
+
}
|
|
51
|
+
/** ノードが描かれる枠線・背景(既定に入力を重ねた、実際に描かれる値) */
|
|
52
|
+
function nodeStyle(node) {
|
|
53
|
+
return {
|
|
54
|
+
border: mergeStyle(exports.NODE_STYLE_DEFAULTS.border, node.border),
|
|
55
|
+
background: mergeStyle(exports.NODE_STYLE_DEFAULTS.background, node.background),
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
/** 線が描かれる値。stroke は d3.sitemap の Edges.normalize と同じく、stroke があればそれ(無ければ既定) */
|
|
59
|
+
function edgeStyle(edge) {
|
|
60
|
+
return {
|
|
61
|
+
stroke: {
|
|
62
|
+
color: edge.stroke?.color || exports.EDGE_DEFAULTS.stroke.color,
|
|
63
|
+
width: edge.stroke?.width || exports.EDGE_DEFAULTS.stroke.width,
|
|
64
|
+
},
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
/** 端点の角度(無ければ 90。Rectum.getPortLineTo と同じ: 0 は 0、それ以外の falsy は 90) */
|
|
68
|
+
function degreeOf(position) {
|
|
69
|
+
if (position === 0)
|
|
70
|
+
return 0;
|
|
71
|
+
return position ? position : exports.EDGE_DEFAULTS.position;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* レコードに、d3.sitemap が既定で描いている値を重ねて返す(入力は書き換えない)。
|
|
75
|
+
* インスペクタの初期値に使う。children は重ねない(子は右クリックしたときに自分で通す)。
|
|
76
|
+
*
|
|
77
|
+
* 重ねる項目: ノードは label.contents(無ければ '')・border・background・type・padding・position、
|
|
78
|
+
* 線は stroke・from.position・to.position。size は view が子に合わせて埋めるので触らない。
|
|
79
|
+
*/
|
|
80
|
+
function withDefaults(record) {
|
|
81
|
+
if (isEdge(record)) {
|
|
82
|
+
return {
|
|
83
|
+
...record,
|
|
84
|
+
...edgeStyle(record),
|
|
85
|
+
from: { ...record.from, position: degreeOf(record.from.position) },
|
|
86
|
+
to: { ...record.to, position: degreeOf(record.to.position) },
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
const node = record;
|
|
90
|
+
const style = nodeStyle(node);
|
|
91
|
+
const label = node.label && typeof node.label === 'object' ? node.label : {};
|
|
92
|
+
return {
|
|
93
|
+
...node,
|
|
94
|
+
type: node.type || exports.NODE_DEFAULTS.type,
|
|
95
|
+
label: { ...label, contents: typeof label.contents === 'string' ? label.contents : '' },
|
|
96
|
+
padding: node.padding || node.padding === 0 ? node.padding : exports.NODE_DEFAULTS.padding,
|
|
97
|
+
position: { ...exports.NODE_DEFAULTS.position, ...(node.position || {}) },
|
|
98
|
+
border: style.border,
|
|
99
|
+
background: style.background,
|
|
100
|
+
};
|
|
101
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// 編集できる項目の一覧。インスペクタ(colonoscope の ModelInspector)に渡す。
|
|
3
|
+
//
|
|
4
|
+
// path はレコードの実際の項目を指す。既定値は withDefaults() で重ねてから渡すので、
|
|
5
|
+
// 書いていない項目(枠線の色など)も、図に描かれている値が初期値として出る。
|
|
6
|
+
// type: 'readonly' は表示だけ。
|
|
7
|
+
//
|
|
8
|
+
// iHub の ScreenTransitionDiagram.js の fields(label.contents / node_type / link.url / id)から始め、
|
|
9
|
+
// d3.sitemap が描く枠線・背景・幅・高さを足した。path(文字列か { contents, link, font })は形が 2 つあるので
|
|
10
|
+
// 当面スコープ外(#145)。border.type は d3.sitemap が描かないので出さない。
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.EDGE_FIELDS = exports.NODE_FIELDS = void 0;
|
|
13
|
+
exports.fieldsOf = fieldsOf;
|
|
14
|
+
const defaults_js_1 = require("./defaults.js");
|
|
15
|
+
/** ノードの項目 */
|
|
16
|
+
exports.NODE_FIELDS = [
|
|
17
|
+
{ path: 'label.contents', label: '名称', type: 'text' },
|
|
18
|
+
{ path: 'node_type', label: '種類', type: 'text' },
|
|
19
|
+
{ path: 'link.url', label: 'URL', type: 'text' },
|
|
20
|
+
{ path: 'id', label: 'ID', type: 'readonly' },
|
|
21
|
+
{ path: 'size.w', label: '幅', type: 'number' },
|
|
22
|
+
{ path: 'size.h', label: '高さ', type: 'number' },
|
|
23
|
+
{ path: 'background.color', label: '背景色', type: 'text' },
|
|
24
|
+
{ path: 'border.color', label: '枠線の色', type: 'text' },
|
|
25
|
+
{ path: 'border.width', label: '枠線の太さ', type: 'number' },
|
|
26
|
+
];
|
|
27
|
+
/** 線の項目。接続位置はノードの中心から見た角度(0=真下・時計回り。90=左 / 180=真上 / 270=右) */
|
|
28
|
+
exports.EDGE_FIELDS = [
|
|
29
|
+
{ path: 'id', label: 'ID', type: 'readonly' },
|
|
30
|
+
{ path: 'from.id', label: '遷移元のノード', type: 'readonly' },
|
|
31
|
+
{ path: 'from.position', label: '遷移元の位置 (角度)', type: 'number' },
|
|
32
|
+
{ path: 'to.id', label: '遷移先のノード', type: 'readonly' },
|
|
33
|
+
{ path: 'to.position', label: '遷移先の位置 (角度)', type: 'number' },
|
|
34
|
+
{ path: 'stroke.color', label: '線の色', type: 'text' },
|
|
35
|
+
{ path: 'stroke.width', label: '線の太さ', type: 'number' },
|
|
36
|
+
];
|
|
37
|
+
/** レコードに応じた項目の一覧(線 / ノード) */
|
|
38
|
+
function fieldsOf(record) {
|
|
39
|
+
return (0, defaults_js_1.isEdge)(record) ? [...exports.EDGE_FIELDS] : [...exports.NODE_FIELDS];
|
|
40
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// model.sitemap — 画面遷移図(d3.sitemap)の「図ごとの知識」。描画はしない(react / d3 に依存しない)。
|
|
3
|
+
//
|
|
4
|
+
// スキーマ: SCHEMAS / NODES_SCHEMA / EDGES_SCHEMA(JSON Schema 2020-12)
|
|
5
|
+
// 整合性ルール: check(data)(id の重複・参照先の存在)/ flatten / findById
|
|
6
|
+
// 既定値の補完: withDefaults(record) / nodeStyle / edgeStyle / degreeOf
|
|
7
|
+
// NODE_STYLE_DEFAULTS / LABEL_DEFAULTS / NODE_DEFAULTS / EDGE_DEFAULTS(d3.sitemap が読む)
|
|
8
|
+
// 編集できる項目: fieldsOf(record) / NODE_FIELDS / EDGE_FIELDS
|
|
9
|
+
// patch への変換: movePatch(node, move) / applyPatch(record, values) / mergePatch(record, patch)
|
|
10
|
+
//
|
|
11
|
+
// graph 系(unchi / sitemap / deployment)で共通の check / flatten / findById / movePatch / mergePatch / getByPath / isColor と
|
|
12
|
+
// 入力の読み取り部品は model.core(#151)のもので、ここでは model.sitemap の型を付けて公開している。
|
|
13
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
14
|
+
exports.isColor = exports.applyPatch = exports.movePatch = exports.mergePatch = exports.getByPath = exports.titleOf = exports.collectionOf = exports.ModelError = exports.fieldsOf = exports.EDGE_FIELDS = exports.NODE_FIELDS = exports.findById = exports.flatten = exports.check = exports.SCHEMAS = exports.EDGES_SCHEMA = exports.NODES_SCHEMA = exports.withDefaults = exports.degreeOf = exports.edgeStyle = exports.nodeStyle = exports.isEdge = exports.EDGE_DEFAULTS = exports.NODE_DEFAULTS = exports.LABEL_DEFAULTS = exports.NODE_STYLE_DEFAULTS = void 0;
|
|
15
|
+
var defaults_js_1 = require("./defaults.js");
|
|
16
|
+
Object.defineProperty(exports, "NODE_STYLE_DEFAULTS", { enumerable: true, get: function () { return defaults_js_1.NODE_STYLE_DEFAULTS; } });
|
|
17
|
+
Object.defineProperty(exports, "LABEL_DEFAULTS", { enumerable: true, get: function () { return defaults_js_1.LABEL_DEFAULTS; } });
|
|
18
|
+
Object.defineProperty(exports, "NODE_DEFAULTS", { enumerable: true, get: function () { return defaults_js_1.NODE_DEFAULTS; } });
|
|
19
|
+
Object.defineProperty(exports, "EDGE_DEFAULTS", { enumerable: true, get: function () { return defaults_js_1.EDGE_DEFAULTS; } });
|
|
20
|
+
Object.defineProperty(exports, "isEdge", { enumerable: true, get: function () { return defaults_js_1.isEdge; } });
|
|
21
|
+
Object.defineProperty(exports, "nodeStyle", { enumerable: true, get: function () { return defaults_js_1.nodeStyle; } });
|
|
22
|
+
Object.defineProperty(exports, "edgeStyle", { enumerable: true, get: function () { return defaults_js_1.edgeStyle; } });
|
|
23
|
+
Object.defineProperty(exports, "degreeOf", { enumerable: true, get: function () { return defaults_js_1.degreeOf; } });
|
|
24
|
+
Object.defineProperty(exports, "withDefaults", { enumerable: true, get: function () { return defaults_js_1.withDefaults; } });
|
|
25
|
+
var schema_js_1 = require("./schema.js");
|
|
26
|
+
Object.defineProperty(exports, "NODES_SCHEMA", { enumerable: true, get: function () { return schema_js_1.NODES_SCHEMA; } });
|
|
27
|
+
Object.defineProperty(exports, "EDGES_SCHEMA", { enumerable: true, get: function () { return schema_js_1.EDGES_SCHEMA; } });
|
|
28
|
+
Object.defineProperty(exports, "SCHEMAS", { enumerable: true, get: function () { return schema_js_1.SCHEMAS; } });
|
|
29
|
+
var check_js_1 = require("./check.js");
|
|
30
|
+
Object.defineProperty(exports, "check", { enumerable: true, get: function () { return check_js_1.check; } });
|
|
31
|
+
Object.defineProperty(exports, "flatten", { enumerable: true, get: function () { return check_js_1.flatten; } });
|
|
32
|
+
Object.defineProperty(exports, "findById", { enumerable: true, get: function () { return check_js_1.findById; } });
|
|
33
|
+
var fields_js_1 = require("./fields.js");
|
|
34
|
+
Object.defineProperty(exports, "NODE_FIELDS", { enumerable: true, get: function () { return fields_js_1.NODE_FIELDS; } });
|
|
35
|
+
Object.defineProperty(exports, "EDGE_FIELDS", { enumerable: true, get: function () { return fields_js_1.EDGE_FIELDS; } });
|
|
36
|
+
Object.defineProperty(exports, "fieldsOf", { enumerable: true, get: function () { return fields_js_1.fieldsOf; } });
|
|
37
|
+
var patch_js_1 = require("./patch.js");
|
|
38
|
+
Object.defineProperty(exports, "ModelError", { enumerable: true, get: function () { return patch_js_1.ModelError; } });
|
|
39
|
+
Object.defineProperty(exports, "collectionOf", { enumerable: true, get: function () { return patch_js_1.collectionOf; } });
|
|
40
|
+
Object.defineProperty(exports, "titleOf", { enumerable: true, get: function () { return patch_js_1.titleOf; } });
|
|
41
|
+
Object.defineProperty(exports, "getByPath", { enumerable: true, get: function () { return patch_js_1.getByPath; } });
|
|
42
|
+
Object.defineProperty(exports, "mergePatch", { enumerable: true, get: function () { return patch_js_1.mergePatch; } });
|
|
43
|
+
Object.defineProperty(exports, "movePatch", { enumerable: true, get: function () { return patch_js_1.movePatch; } });
|
|
44
|
+
Object.defineProperty(exports, "applyPatch", { enumerable: true, get: function () { return patch_js_1.applyPatch; } });
|
|
45
|
+
Object.defineProperty(exports, "isColor", { enumerable: true, get: function () { return patch_js_1.isColor; } });
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// UI の操作(ドラッグ・インスペクタの適用)を、保存する patch(JSON Merge Patch)に変換する。
|
|
3
|
+
//
|
|
4
|
+
// 戻り値は { collection, id, patch }。利用側(iHub など)は図の種類を知らずにこれを保存すればよい。
|
|
5
|
+
// 入力の検証に失敗したときは ModelError を投げる(メッセージは利用者にそのまま見せられる日本語)。
|
|
6
|
+
// model.unchi の patch.ts を元にしている(ラベルは label.contents、リンクは link.url、マーカーと border.type は無い)。
|
|
7
|
+
// 読み取り部品(toColor など)と patch の道具は model.core にある(#151)。
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.isColor = exports.mergePatch = exports.getByPath = exports.ModelError = void 0;
|
|
10
|
+
exports.collectionOf = collectionOf;
|
|
11
|
+
exports.titleOf = titleOf;
|
|
12
|
+
exports.movePatch = movePatch;
|
|
13
|
+
exports.applyPatch = applyPatch;
|
|
14
|
+
const model_core_1 = require("@yanqirenshi/model.core");
|
|
15
|
+
const defaults_js_1 = require("./defaults.js");
|
|
16
|
+
const fields_js_1 = require("./fields.js");
|
|
17
|
+
// model.core のものをそのまま公開する(利用側が model.sitemap だけを読めばよいように)
|
|
18
|
+
var model_core_2 = require("@yanqirenshi/model.core");
|
|
19
|
+
Object.defineProperty(exports, "ModelError", { enumerable: true, get: function () { return model_core_2.ModelError; } });
|
|
20
|
+
Object.defineProperty(exports, "getByPath", { enumerable: true, get: function () { return model_core_2.getByPath; } });
|
|
21
|
+
Object.defineProperty(exports, "mergePatch", { enumerable: true, get: function () { return model_core_2.mergePatch; } });
|
|
22
|
+
Object.defineProperty(exports, "isColor", { enumerable: true, get: function () { return model_core_2.isColor; } });
|
|
23
|
+
/** レコードを置くコレクション */
|
|
24
|
+
function collectionOf(record) {
|
|
25
|
+
return (0, defaults_js_1.isEdge)(record) ? 'edges' : 'nodes';
|
|
26
|
+
}
|
|
27
|
+
/** インスペクタの見出し。ラベルの文字、無ければ id(線は「遷移元 → 遷移先」) */
|
|
28
|
+
function titleOf(record) {
|
|
29
|
+
if ((0, defaults_js_1.isEdge)(record))
|
|
30
|
+
return `${String(record.from.id)} → ${String(record.to.id)}`;
|
|
31
|
+
const contents = record.label && typeof record.label === 'object' ? record.label.contents : null;
|
|
32
|
+
return typeof contents === 'string' && contents !== '' ? contents : String(record.id);
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* ドラッグで動かしたノードの位置を保存する patch。
|
|
36
|
+
* 保存してある position に移動量を足し、整数に丸める(position が無いときは 0, 0 から)。
|
|
37
|
+
* 子のノードの position は親の中での位置なので、親を動かしても子の patch は要らない。
|
|
38
|
+
*/
|
|
39
|
+
function movePatch(node, move) {
|
|
40
|
+
return (0, model_core_1.movePatch)(node, move, 'nodes');
|
|
41
|
+
}
|
|
42
|
+
// インスペクタの入力のうち、図に描いている値(withDefaults)から変わった項目だけ
|
|
43
|
+
function changedValues(record, values) {
|
|
44
|
+
return (0, model_core_1.changedValues)((0, defaults_js_1.withDefaults)(record), values, (0, fields_js_1.fieldsOf)(record));
|
|
45
|
+
}
|
|
46
|
+
// 幅・高さは 0 以上(0 は「子に合わせる」)。枠線・線の太さは 0 以上(0 は線なし)
|
|
47
|
+
const LENGTH = { hint: '(0 で子に合わせる)' };
|
|
48
|
+
const WIDTH = { allowZero: true };
|
|
49
|
+
// ノードの入力 → patch(label.contents / node_type / link.url / size / background / border)
|
|
50
|
+
function nodePatch(node, values) {
|
|
51
|
+
const patch = {};
|
|
52
|
+
for (const [path, value] of changedValues(node, values)) {
|
|
53
|
+
switch (path) {
|
|
54
|
+
case 'label.contents':
|
|
55
|
+
// 名称は空にできない(画面の箱に文字が無くなる)
|
|
56
|
+
if (value === '')
|
|
57
|
+
throw new model_core_1.ModelError('名称を入力してください。');
|
|
58
|
+
(0, model_core_1.put)(patch, path, value);
|
|
59
|
+
break;
|
|
60
|
+
case 'node_type':
|
|
61
|
+
(0, model_core_1.put)(patch, path, (0, model_core_1.toOptionalText)(value));
|
|
62
|
+
break;
|
|
63
|
+
case 'link.url':
|
|
64
|
+
// URL を空にするとリンクごと除く(d3.sitemap は url の無い link を描かない)
|
|
65
|
+
if (value === '')
|
|
66
|
+
patch.link = null;
|
|
67
|
+
else
|
|
68
|
+
(0, model_core_1.put)(patch, path, value);
|
|
69
|
+
break;
|
|
70
|
+
case 'size.w':
|
|
71
|
+
(0, model_core_1.put)(patch, path, (0, model_core_1.toLength)(value, '幅', LENGTH));
|
|
72
|
+
break;
|
|
73
|
+
case 'size.h':
|
|
74
|
+
(0, model_core_1.put)(patch, path, (0, model_core_1.toLength)(value, '高さ', LENGTH));
|
|
75
|
+
break;
|
|
76
|
+
case 'background.color':
|
|
77
|
+
(0, model_core_1.put)(patch, path, (0, model_core_1.toColor)(value, '背景色'));
|
|
78
|
+
break;
|
|
79
|
+
case 'border.color':
|
|
80
|
+
(0, model_core_1.put)(patch, path, (0, model_core_1.toColor)(value, '枠線の色'));
|
|
81
|
+
break;
|
|
82
|
+
case 'border.width':
|
|
83
|
+
(0, model_core_1.put)(patch, path, (0, model_core_1.toWidth)(value, '枠線の太さ', WIDTH));
|
|
84
|
+
break;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
return patch;
|
|
88
|
+
}
|
|
89
|
+
const END_LABELS = { from: '遷移元', to: '遷移先' };
|
|
90
|
+
// 線の入力 → patch(from / to の角度・stroke)
|
|
91
|
+
function edgePatch(edge, values) {
|
|
92
|
+
const patch = {};
|
|
93
|
+
for (const [path, value] of changedValues(edge, values)) {
|
|
94
|
+
switch (path) {
|
|
95
|
+
case 'from.position':
|
|
96
|
+
case 'to.position':
|
|
97
|
+
(0, model_core_1.put)(patch, path, (0, model_core_1.toDegree)(value, `${END_LABELS[path.split('.')[0]]}の位置`));
|
|
98
|
+
break;
|
|
99
|
+
case 'stroke.color':
|
|
100
|
+
(0, model_core_1.put)(patch, path, (0, model_core_1.toColor)(value, '線の色'));
|
|
101
|
+
break;
|
|
102
|
+
case 'stroke.width':
|
|
103
|
+
(0, model_core_1.put)(patch, path, (0, model_core_1.toWidth)(value, '線の太さ', WIDTH));
|
|
104
|
+
break;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
return patch;
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* インスペクタの「適用」の値を、保存する patch に変換する。
|
|
111
|
+
* 図に描いている値から変えた項目だけを patch に入れる(変えていない既定の値まで書き込まないため)。
|
|
112
|
+
* 変更が無ければ patch は {}。
|
|
113
|
+
*/
|
|
114
|
+
function applyPatch(record, values) {
|
|
115
|
+
return {
|
|
116
|
+
collection: collectionOf(record),
|
|
117
|
+
id: record.id,
|
|
118
|
+
patch: (0, defaults_js_1.isEdge)(record) ? edgePatch(record, values) : nodePatch(record, values),
|
|
119
|
+
};
|
|
120
|
+
}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// d3.sitemap の入力データの JSON Schema(2020-12)。
|
|
3
|
+
//
|
|
4
|
+
// iHub の server/schemas/sitemap/{nodes,edges}.schema.json を移したもの。
|
|
5
|
+
// 検査するのは、図の構造にかかわる項目(id・type・size・position・children・link・node_type、
|
|
6
|
+
// 線の from / to)だけで、見た目の項目(label・border・background・padding・path)は
|
|
7
|
+
// d3.sitemap の入力の形のまま書けるよう additionalProperties を閉じていない(iHub 版は閉じていた)。
|
|
8
|
+
//
|
|
9
|
+
// x-id-start はスキーマの検証には使わない注釈(コレクションが空のときに最初に振る id)。
|
|
10
|
+
// Ajv で使うときは addKeyword({ keyword: 'x-id-start', schemaType: 'number' }) を足す。
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.SCHEMAS = exports.EDGES_SCHEMA = exports.NODES_SCHEMA = void 0;
|
|
13
|
+
const ID = { type: ['integer', 'string'] };
|
|
14
|
+
const POINT = {
|
|
15
|
+
type: 'object',
|
|
16
|
+
properties: { x: { type: 'number' }, y: { type: 'number' } },
|
|
17
|
+
required: ['x', 'y'],
|
|
18
|
+
};
|
|
19
|
+
exports.NODES_SCHEMA = {
|
|
20
|
+
$schema: 'https://json-schema.org/draft/2020-12/schema',
|
|
21
|
+
title: '画面遷移図のノード',
|
|
22
|
+
description: 'd3.sitemap に渡す画面のノード。children に子のノードを入れ子で持つ。id は子のノードも含めて一意にする。position は親の中での位置で、ドラッグで動かすと書き換わる。見た目の項目 (label・padding・border・background・path) は d3.sitemap の入力の形のまま書ける。',
|
|
23
|
+
'x-id-start': 1000000,
|
|
24
|
+
type: 'array',
|
|
25
|
+
items: { $ref: '#/$defs/node' },
|
|
26
|
+
$defs: {
|
|
27
|
+
node: {
|
|
28
|
+
type: 'object',
|
|
29
|
+
properties: {
|
|
30
|
+
id: ID,
|
|
31
|
+
type: { type: 'string' },
|
|
32
|
+
label: {
|
|
33
|
+
type: 'object',
|
|
34
|
+
properties: { contents: { type: ['string', 'null'] } },
|
|
35
|
+
},
|
|
36
|
+
size: {
|
|
37
|
+
type: 'object',
|
|
38
|
+
properties: { w: { type: 'number', minimum: 0 }, h: { type: 'number', minimum: 0 } },
|
|
39
|
+
required: ['w', 'h'],
|
|
40
|
+
},
|
|
41
|
+
position: POINT,
|
|
42
|
+
link: {
|
|
43
|
+
type: ['object', 'null'],
|
|
44
|
+
properties: {
|
|
45
|
+
url: { type: ['string', 'null'] },
|
|
46
|
+
icon: { type: ['string', 'null'] },
|
|
47
|
+
position: POINT,
|
|
48
|
+
},
|
|
49
|
+
},
|
|
50
|
+
node_type: { type: ['string', 'null'], description: 'window など (利用側の項目)' },
|
|
51
|
+
children: { type: 'array', items: { $ref: '#/$defs/node' } },
|
|
52
|
+
},
|
|
53
|
+
required: ['id'],
|
|
54
|
+
additionalProperties: true,
|
|
55
|
+
},
|
|
56
|
+
},
|
|
57
|
+
};
|
|
58
|
+
exports.EDGES_SCHEMA = {
|
|
59
|
+
$schema: 'https://json-schema.org/draft/2020-12/schema',
|
|
60
|
+
title: '画面遷移図の遷移',
|
|
61
|
+
description: '画面のノードの間の遷移。from.id / to.id はノード (子を含む) の id。position は接続位置の角度 (0=真下・時計回り。省略すると 90=左)。',
|
|
62
|
+
'x-id-start': 2000001,
|
|
63
|
+
type: 'array',
|
|
64
|
+
items: {
|
|
65
|
+
type: 'object',
|
|
66
|
+
properties: {
|
|
67
|
+
id: ID,
|
|
68
|
+
from: { $ref: '#/$defs/end' },
|
|
69
|
+
to: { $ref: '#/$defs/end' },
|
|
70
|
+
stroke: {
|
|
71
|
+
type: 'object',
|
|
72
|
+
properties: {
|
|
73
|
+
color: { type: 'string' },
|
|
74
|
+
width: { type: 'number' },
|
|
75
|
+
type: { type: 'string' },
|
|
76
|
+
},
|
|
77
|
+
},
|
|
78
|
+
},
|
|
79
|
+
required: ['id', 'from', 'to'],
|
|
80
|
+
additionalProperties: true,
|
|
81
|
+
},
|
|
82
|
+
$defs: {
|
|
83
|
+
end: {
|
|
84
|
+
type: 'object',
|
|
85
|
+
properties: {
|
|
86
|
+
id: ID,
|
|
87
|
+
position: { type: 'number' },
|
|
88
|
+
},
|
|
89
|
+
required: ['id'],
|
|
90
|
+
},
|
|
91
|
+
},
|
|
92
|
+
};
|
|
93
|
+
/** コレクション名 → スキーマ */
|
|
94
|
+
exports.SCHEMAS = {
|
|
95
|
+
nodes: exports.NODES_SCHEMA,
|
|
96
|
+
edges: exports.EDGES_SCHEMA,
|
|
97
|
+
};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// model.sitemap の公開型。
|
|
3
|
+
//
|
|
4
|
+
// ここで言う「レコード」は、d3.sitemap の data() に渡す入力そのもの({ nodes, edges })の 1 要素。
|
|
5
|
+
// iHub では data/sitemap/{nodes,edges}.json の 1 要素。d3.sitemap が正規化したあとの datum(_id / _core を持つもの)ではない。
|
|
6
|
+
// ノードと線の図なので model.unchi と形が近いが、ラベルは label.contents(unchi は label.text)で、
|
|
7
|
+
// ノードにリンク(link.url)と URL パス(path)、画面の種類(node_type)がある。
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|