markmap-view 0.14.2-alpha.0 → 0.14.2

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/dist/index.cjs.js CHANGED
@@ -1,6 +1,7 @@
1
- /*! markmap-view v0.14.2-alpha.0+518591b | MIT License */
1
+ /*! markmap-view v0.14.2 | MIT License */
2
2
  'use strict';
3
3
 
4
+ var markmapCommon = require('markmap-common');
4
5
  var d3 = require('d3');
5
6
 
6
7
  function _interopNamespace(e) {
@@ -17,219 +18,6 @@ return Object.freeze(n);
17
18
 
18
19
  var d3__namespace = /*#__PURE__*/_interopNamespace(d3);
19
20
 
20
- /*! markmap-common v0.14.2-alpha.0+518591b | MIT License */
21
- class Hook {
22
- constructor() {
23
- this.listeners = [];
24
- }
25
-
26
- tap(fn) {
27
- this.listeners.push(fn);
28
- return () => this.revoke(fn);
29
- }
30
-
31
- revoke(fn) {
32
- const i = this.listeners.indexOf(fn);
33
- if (i >= 0) this.listeners.splice(i, 1);
34
- }
35
-
36
- revokeAll() {
37
- this.listeners.splice(0);
38
- }
39
-
40
- call(...args) {
41
- for (const fn of this.listeners) {
42
- fn(...args);
43
- }
44
- }
45
-
46
- }
47
-
48
- function _extends$1() {
49
- _extends$1 = Object.assign || function (target) {
50
- for (var i = 1; i < arguments.length; i++) {
51
- var source = arguments[i];
52
-
53
- for (var key in source) {
54
- if (Object.prototype.hasOwnProperty.call(source, key)) {
55
- target[key] = source[key];
56
- }
57
- }
58
- }
59
-
60
- return target;
61
- };
62
-
63
- return _extends$1.apply(this, arguments);
64
- }
65
-
66
- const uniqId = Math.random().toString(36).slice(2, 8);
67
- let globalIndex = 0;
68
-
69
- function getId() {
70
- globalIndex += 1;
71
- return `mm-${uniqId}-${globalIndex}`;
72
- }
73
-
74
- function noop() {// noop
75
- }
76
-
77
- function walkTree(tree, callback, key = 'children') {
78
- const walk = (item, parent) => callback(item, () => {
79
- var _item$key;
80
-
81
- (_item$key = item[key]) == null ? void 0 : _item$key.forEach(child => {
82
- walk(child, item);
83
- });
84
- }, parent);
85
-
86
- walk(tree);
87
- }
88
-
89
- function arrayFrom(arrayLike) {
90
- if (Array.from) return Array.from(arrayLike);
91
- const array = [];
92
-
93
- for (let i = 0; i < arrayLike.length; i += 1) {
94
- array.push(arrayLike[i]);
95
- }
96
-
97
- return array;
98
- }
99
-
100
- function addClass(className, ...rest) {
101
- const classList = (className || '').split(' ').filter(Boolean);
102
- rest.forEach(item => {
103
- if (item && classList.indexOf(item) < 0) classList.push(item);
104
- });
105
- return classList.join(' ');
106
- }
107
-
108
- function childSelector(filter) {
109
- if (typeof filter === 'string') {
110
- const tagName = filter;
111
-
112
- filter = el => el.tagName === tagName;
113
- }
114
-
115
- const filterFn = filter;
116
- return function selector() {
117
- let nodes = arrayFrom(this.childNodes);
118
- if (filterFn) nodes = nodes.filter(node => filterFn(node));
119
- return nodes;
120
- };
121
- }
122
-
123
- function memoize(fn) {
124
- const cache = {};
125
- return function memoized(...args) {
126
- const key = `${args[0]}`;
127
- let data = cache[key];
128
-
129
- if (!data) {
130
- data = {
131
- value: fn(...args)
132
- };
133
- cache[key] = data;
134
- }
135
-
136
- return data.value;
137
- };
138
- }
139
-
140
- function createElement(tagName, props, attrs) {
141
- const el = document.createElement(tagName);
142
-
143
- if (props) {
144
- Object.entries(props).forEach(([key, value]) => {
145
- el[key] = value;
146
- });
147
- }
148
-
149
- if (attrs) {
150
- Object.entries(attrs).forEach(([key, value]) => {
151
- el.setAttribute(key, value);
152
- });
153
- }
154
-
155
- return el;
156
- }
157
-
158
- const memoizedPreloadJS = memoize(url => {
159
- document.head.append(createElement('link', {
160
- rel: 'preload',
161
- as: 'script',
162
- href: url
163
- }));
164
- });
165
-
166
- async function loadJSItem(item, context) {
167
- if (!item.loaded) {
168
- if (item.type === 'script') {
169
- item.loaded = new Promise((resolve, reject) => {
170
- var _item$data;
171
-
172
- document.head.append(createElement('script', _extends$1({}, item.data, {
173
- onload: resolve,
174
- onerror: reject
175
- }))); // Run inline script synchronously
176
-
177
- if (!((_item$data = item.data) != null && _item$data.src)) resolve(undefined);
178
- }).then(() => {
179
- item.loaded = true;
180
- });
181
- }
182
-
183
- if (item.type === 'iife') {
184
- const {
185
- fn,
186
- getParams
187
- } = item.data;
188
- fn(...((getParams == null ? void 0 : getParams(context)) || []));
189
- item.loaded = true;
190
- }
191
- }
192
-
193
- await item.loaded;
194
- }
195
-
196
- function loadCSSItem(item) {
197
- if (item.loaded) return;
198
- item.loaded = true;
199
-
200
- if (item.type === 'style') {
201
- document.head.append(createElement('style', {
202
- textContent: item.data
203
- }));
204
- } else if (item.type === 'stylesheet') {
205
- document.head.append(createElement('link', _extends$1({
206
- rel: 'stylesheet'
207
- }, item.data)));
208
- }
209
- }
210
-
211
- async function loadJS(items, context) {
212
- const needPreload = items.filter(item => {
213
- var _item$data2;
214
-
215
- return item.type === 'script' && ((_item$data2 = item.data) == null ? void 0 : _item$data2.src);
216
- });
217
- if (needPreload.length > 1) needPreload.forEach(item => memoizedPreloadJS(item.data.src));
218
- context = _extends$1({
219
- getMarkmap: () => window.markmap
220
- }, context);
221
-
222
- for (const item of items) {
223
- await loadJSItem(item, context);
224
- }
225
- }
226
-
227
- function loadCSS(items) {
228
- for (const item of items) {
229
- loadCSSItem(item);
230
- }
231
- }
232
-
233
21
  function _extends() {
234
22
  _extends = Object.assign || function (target) {
235
23
  for (var i = 1; i < arguments.length; i++) {
@@ -1240,7 +1028,7 @@ function linkWidth(nodeData) {
1240
1028
  }
1241
1029
 
1242
1030
  function adjustSpacing(tree, spacing) {
1243
- walkTree(tree, (d, next) => {
1031
+ markmapCommon.walkTree(tree, (d, next) => {
1244
1032
  d.ySizeInner = d.ySize - spacing;
1245
1033
  d.y += spacing;
1246
1034
  next();
@@ -1258,7 +1046,7 @@ function stopPropagation(e) {
1258
1046
 
1259
1047
  function createViewHooks() {
1260
1048
  return {
1261
- transformHtml: new Hook()
1049
+ transformHtml: new markmapCommon.Hook()
1262
1050
  };
1263
1051
  }
1264
1052
  /**
@@ -1266,7 +1054,7 @@ function createViewHooks() {
1266
1054
  */
1267
1055
 
1268
1056
 
1269
- const refreshHook = new Hook();
1057
+ const refreshHook = new markmapCommon.Hook();
1270
1058
  const defaultColorFn = d3__namespace.scaleOrdinal(d3__namespace.schemeCategory10);
1271
1059
  const isMacintosh = typeof navigator !== 'undefined' && navigator.userAgent.includes('Macintosh');
1272
1060
  class Markmap {
@@ -1288,11 +1076,10 @@ class Markmap {
1288
1076
  }).on('zoom', this.handleZoom);
1289
1077
  this.setOptions(opts);
1290
1078
  this.state = {
1291
- id: this.options.id || this.svg.attr('id') || getId()
1079
+ id: this.options.id || this.svg.attr('id') || markmapCommon.getId()
1292
1080
  };
1293
1081
  this.g = this.svg.append('g');
1294
1082
  this.updateStyle();
1295
- this.svg.call(this.zoom).on('wheel', this.handlePan);
1296
1083
  this.revokers.push(refreshHook.tap(() => {
1297
1084
  this.setData();
1298
1085
  }));
@@ -1310,7 +1097,7 @@ class Markmap {
1310
1097
  }
1311
1098
 
1312
1099
  updateStyle() {
1313
- this.svg.attr('class', addClass(this.svg.attr('class'), 'markmap', this.state.id));
1100
+ this.svg.attr('class', markmapCommon.addClass(this.svg.attr('class'), 'markmap', this.state.id));
1314
1101
  const style = this.getStyleContent();
1315
1102
  this.styleNode.text(style);
1316
1103
  }
@@ -1361,8 +1148,8 @@ class Markmap {
1361
1148
  document.body.append(container, style);
1362
1149
  const groupStyle = maxWidth ? `max-width: ${maxWidth}px` : '';
1363
1150
  let foldRecursively = 0;
1364
- walkTree(node, (item, next) => {
1365
- var _item$children, _item$payload;
1151
+ markmapCommon.walkTree(node, (item, next, parent) => {
1152
+ var _item$children, _parent$state, _item$payload;
1366
1153
 
1367
1154
  item.children = (_item$children = item.children) == null ? void 0 : _item$children.map(child => _extends({}, child));
1368
1155
  nodeId += 1;
@@ -1380,6 +1167,7 @@ class Markmap {
1380
1167
  id: nodeId,
1381
1168
  el: group.firstChild
1382
1169
  });
1170
+ item.state.path = [parent == null ? void 0 : (_parent$state = parent.state) == null ? void 0 : _parent$state.path, item.state.id].filter(Boolean).join('.');
1383
1171
  color(item); // preload colors
1384
1172
 
1385
1173
  const isFoldRecursively = ((_item$payload = item.payload) == null ? void 0 : _item$payload.fold) === 2;
@@ -1395,7 +1183,7 @@ class Markmap {
1395
1183
  next();
1396
1184
  if (isFoldRecursively) foldRecursively -= 1;
1397
1185
  });
1398
- const nodes = arrayFrom(container.childNodes).map(group => group.firstChild);
1186
+ const nodes = markmapCommon.arrayFrom(container.childNodes).map(group => group.firstChild);
1399
1187
  this.viewHooks.transformHtml.call(this, nodes); // Clone the rendered HTML and set `white-space: nowrap` to it to detect its max-width.
1400
1188
  // The parent node will have a width of the max-width and the original content without
1401
1189
  // `white-space: nowrap` gets re-layouted, then we will get the expected layout, with
@@ -1404,13 +1192,12 @@ class Markmap {
1404
1192
  nodes.forEach(node => {
1405
1193
  node.parentNode.append(node.cloneNode(true));
1406
1194
  });
1407
- walkTree(node, (item, next, parent) => {
1408
- var _parent$state, _parent$state2;
1195
+ markmapCommon.walkTree(node, (item, next, parent) => {
1196
+ var _parent$state2;
1409
1197
 
1410
1198
  const rect = item.state.el.getBoundingClientRect();
1411
1199
  item.content = item.state.el.innerHTML;
1412
1200
  item.state.size = [Math.ceil(rect.width) + 1, Math.max(Math.ceil(rect.height), nodeMinHeight)];
1413
- item.state.path = [parent == null ? void 0 : (_parent$state = parent.state) == null ? void 0 : _parent$state.path, item.state.id].filter(Boolean).join('.');
1414
1201
  item.state.key = [parent == null ? void 0 : (_parent$state2 = parent.state) == null ? void 0 : _parent$state2.id, item.state.id].filter(Boolean).join('.') + // FIXME: find a way to check content hash
1415
1202
  item.content;
1416
1203
  next();
@@ -1421,6 +1208,14 @@ class Markmap {
1421
1208
 
1422
1209
  setOptions(opts) {
1423
1210
  this.options = _extends({}, Markmap.defaultOptions, opts);
1211
+
1212
+ if (this.options.zoom) {
1213
+ this.svg.call(this.zoom);
1214
+ } else {
1215
+ this.svg.on('.zoom', null);
1216
+ }
1217
+
1218
+ this.svg.on('wheel', this.options.pan ? this.handlePan : null);
1424
1219
  }
1425
1220
 
1426
1221
  setData(data, opts) {
@@ -1472,7 +1267,7 @@ class Markmap {
1472
1267
  const x0 = (_origin$data$state$x = origin.data.state.x0) != null ? _origin$data$state$x : origin.x;
1473
1268
  const y0 = (_origin$data$state$y = origin.data.state.y0) != null ? _origin$data$state$y : origin.y; // Update the nodes
1474
1269
 
1475
- const node = this.g.selectAll(childSelector('g')).data(descendants, d => d.data.state.key);
1270
+ const node = this.g.selectAll(markmapCommon.childSelector('g')).data(descendants, d => d.data.state.key);
1476
1271
  const nodeEnter = node.enter().append('g').attr('data-depth', d => d.data.depth).attr('data-path', d => d.data.state.path).attr('transform', d => `translate(${y0 + origin.ySizeInner - d.ySizeInner},${x0 + origin.xSize / 2 - d.xSize})`);
1477
1272
  const nodeExit = this.transition(node.exit());
1478
1273
  nodeExit.select('line').attr('x1', d => d.ySizeInner).attr('x2', d => d.ySizeInner);
@@ -1485,12 +1280,12 @@ class Markmap {
1485
1280
  });
1486
1281
  this.transition(nodeMerge).attr('transform', d => `translate(${d.y},${d.x - d.xSize / 2})`); // Update lines under the content
1487
1282
 
1488
- const line = nodeMerge.selectAll(childSelector('line')).data(d => [d], d => d.data.state.key).join(enter => {
1283
+ const line = nodeMerge.selectAll(markmapCommon.childSelector('line')).data(d => [d], d => d.data.state.key).join(enter => {
1489
1284
  return enter.append('line').attr('x1', d => d.ySizeInner).attr('x2', d => d.ySizeInner);
1490
1285
  }, update => update, exit => exit.remove());
1491
1286
  this.transition(line).attr('x1', -1).attr('x2', d => d.ySizeInner + 2).attr('y1', d => d.xSize).attr('y2', d => d.xSize).attr('stroke', d => color(d.data)).attr('stroke-width', linkWidth); // Circle to link to children of the node
1492
1287
 
1493
- const circle = nodeMerge.selectAll(childSelector('circle')).data(d => d.data.children ? [d] : [], d => d.data.state.key).join(enter => {
1288
+ const circle = nodeMerge.selectAll(markmapCommon.childSelector('circle')).data(d => d.data.children ? [d] : [], d => d.data.state.key).join(enter => {
1494
1289
  return enter.append('circle').attr('stroke-width', '1.5').attr('cx', d => d.ySizeInner).attr('cy', d => d.xSize).attr('r', 0).on('click', (e, d) => this.handleClick(e, d));
1495
1290
  }, update => update, exit => exit.remove());
1496
1291
  this.transition(circle).attr('r', 6).attr('cx', d => d.ySizeInner).attr('cy', d => d.xSize).attr('stroke', d => color(d.data)).attr('fill', d => {
@@ -1498,7 +1293,7 @@ class Markmap {
1498
1293
 
1499
1294
  return (_d$data$payload2 = d.data.payload) != null && _d$data$payload2.fold && d.data.children ? color(d.data) : '#fff';
1500
1295
  });
1501
- const foreignObject = nodeMerge.selectAll(childSelector('foreignObject')).data(d => [d], d => d.data.state.key).join(enter => {
1296
+ const foreignObject = nodeMerge.selectAll(markmapCommon.childSelector('foreignObject')).data(d => [d], d => d.data.state.key).join(enter => {
1502
1297
  const fo = enter.append('foreignObject').attr('class', 'markmap-foreign').attr('x', paddingX).attr('y', 0).style('opacity', 0).on('mousedown', stopPropagation).on('dblclick', stopPropagation);
1503
1298
  fo.append('xhtml:div').select(function select(d) {
1504
1299
  const clone = d.data.state.el.cloneNode(true);
@@ -1509,7 +1304,7 @@ class Markmap {
1509
1304
  }, update => update, exit => exit.remove()).attr('width', d => Math.max(0, d.ySizeInner - paddingX * 2)).attr('height', d => d.xSize);
1510
1305
  this.transition(foreignObject).style('opacity', 1); // Update the links
1511
1306
 
1512
- const path = this.g.selectAll(childSelector('path')).data(links, d => d.target.data.state.key).join(enter => {
1307
+ const path = this.g.selectAll(markmapCommon.childSelector('path')).data(links, d => d.target.data.state.key).join(enter => {
1513
1308
  const source = [y0 + origin.ySizeInner, x0 + origin.xSize / 2];
1514
1309
  return enter.insert('path', 'g').attr('class', 'markmap-link').attr('data-depth', d => d.target.data.depth).attr('data-path', d => d.target.data.state.path).attr('d', linkShape({
1515
1310
  source,
@@ -1566,7 +1361,7 @@ class Markmap {
1566
1361
  const naturalHeight = maxX - minX;
1567
1362
  const scale = Math.min(offsetWidth / naturalWidth * fitRatio, offsetHeight / naturalHeight * fitRatio, 2);
1568
1363
  const initialZoom = d3__namespace.zoomIdentity.translate((offsetWidth - naturalWidth * scale) / 2 - minY * scale, (offsetHeight - naturalHeight * scale) / 2 - minX * scale).scale(scale);
1569
- return this.transition(this.svg).call(this.zoom.transform, initialZoom).end().catch(noop);
1364
+ return this.transition(this.svg).call(this.zoom.transform, initialZoom).end().catch(markmapCommon.noop);
1570
1365
  }
1571
1366
  /**
1572
1367
  * Pan the content to make the provided node visible in the viewport.
@@ -1576,7 +1371,7 @@ class Markmap {
1576
1371
  async ensureView(node, padding) {
1577
1372
  let g;
1578
1373
  let itemData;
1579
- this.g.selectAll(childSelector('g')).each(function walk(d) {
1374
+ this.g.selectAll(markmapCommon.childSelector('g')).each(function walk(d) {
1580
1375
  if (d.data === node) {
1581
1376
  g = this;
1582
1377
  itemData = d;
@@ -1603,7 +1398,7 @@ class Markmap {
1603
1398
 
1604
1399
  if (dx || dy) {
1605
1400
  const newTransform = transform.translate(dx, dy);
1606
- return this.transition(this.svg).call(this.zoom.transform, newTransform).end().catch(noop);
1401
+ return this.transition(this.svg).call(this.zoom.transform, newTransform).end().catch(markmapCommon.noop);
1607
1402
  }
1608
1403
  }
1609
1404
  /**
@@ -1621,7 +1416,7 @@ class Markmap {
1621
1416
  const halfHeight = offsetHeight / 2;
1622
1417
  const transform = d3__namespace.zoomTransform(svgNode);
1623
1418
  const newTransform = transform.translate((halfWidth - transform.x) * (1 - scale) / transform.k, (halfHeight - transform.y) * (1 - scale) / transform.k).scale(scale);
1624
- return this.transition(this.svg).call(this.zoom.transform, newTransform).end().catch(noop);
1419
+ return this.transition(this.svg).call(this.zoom.transform, newTransform).end().catch(markmapCommon.noop);
1625
1420
  }
1626
1421
 
1627
1422
  destroy() {
@@ -1646,7 +1441,7 @@ class Markmap {
1646
1441
  }
1647
1442
  Markmap.defaultOptions = {
1648
1443
  autoFit: false,
1649
- color: node => defaultColorFn(`${node.state.id}`),
1444
+ color: node => defaultColorFn(`${node.state.path}`),
1650
1445
  duration: 500,
1651
1446
  embedGlobalCSS: true,
1652
1447
  fitRatio: 0.95,
@@ -1656,13 +1451,16 @@ Markmap.defaultOptions = {
1656
1451
  scrollForPan: isMacintosh,
1657
1452
  spacingHorizontal: 80,
1658
1453
  spacingVertical: 5,
1659
- initialExpandLevel: -1
1454
+ initialExpandLevel: -1,
1455
+ zoom: true,
1456
+ pan: true
1660
1457
  };
1661
1458
  function deriveOptions(jsonOptions) {
1662
1459
  const opts = {};
1663
1460
  jsonOptions || (jsonOptions = {});
1664
1461
  const {
1665
- color
1462
+ color,
1463
+ colorFreezeLevel
1666
1464
  } = jsonOptions;
1667
1465
 
1668
1466
  if ((color == null ? void 0 : color.length) === 1) {
@@ -1672,7 +1470,20 @@ function deriveOptions(jsonOptions) {
1672
1470
  } else if (color != null && color.length) {
1673
1471
  const colorFn = d3__namespace.scaleOrdinal(color);
1674
1472
 
1675
- opts.color = node => colorFn(`${node.state.id}`);
1473
+ opts.color = node => colorFn(`${node.state.path}`);
1474
+ }
1475
+
1476
+ if (colorFreezeLevel) {
1477
+ const color = opts.color || Markmap.defaultOptions.color;
1478
+
1479
+ opts.color = node => {
1480
+ node = _extends({}, node, {
1481
+ state: _extends({}, node.state, {
1482
+ path: node.state.path.split('.').slice(0, colorFreezeLevel).join('.')
1483
+ })
1484
+ });
1485
+ return color(node);
1486
+ };
1676
1487
  }
1677
1488
 
1678
1489
  const numberKeys = ['duration', 'maxWidth', 'initialExpandLevel'];
@@ -1680,13 +1491,18 @@ function deriveOptions(jsonOptions) {
1680
1491
  const value = jsonOptions[key];
1681
1492
  if (typeof value === 'number') opts[key] = value;
1682
1493
  });
1494
+ const booleanKeys = ['zoom', 'pan'];
1495
+ booleanKeys.forEach(key => {
1496
+ const value = jsonOptions[key];
1497
+ if (value != null) opts[key] = !!value;
1498
+ });
1683
1499
  return opts;
1684
1500
  }
1685
1501
 
1502
+ exports.loadCSS = markmapCommon.loadCSS;
1503
+ exports.loadJS = markmapCommon.loadJS;
1686
1504
  exports.Markmap = Markmap;
1687
1505
  exports.defaultColorFn = defaultColorFn;
1688
1506
  exports.deriveOptions = deriveOptions;
1689
1507
  exports.globalCSS = globalCSS;
1690
- exports.loadCSS = loadCSS;
1691
- exports.loadJS = loadJS;
1692
1508
  exports.refreshHook = refreshHook;