@shijiu/jsview-vue 2.1.25 → 2.1.200

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 (80) hide show
  1. package/package.json +1 -1
  2. package/utils/JsViewEngineWidget/JsvFocusBlock.vue +1 -1
  3. package/utils/JsViewEngineWidget/JsvFocusHub.ts +123 -0
  4. package/utils/JsViewEngineWidget/JsvFocusManager.js +4 -3
  5. package/utils/JsViewEngineWidget/MetroWidget/AnimationManager.ts +145 -51
  6. package/utils/JsViewEngineWidget/MetroWidget/ListWidget.vue +51 -64
  7. package/utils/JsViewEngineWidget/MetroWidget/MetroWidget.vue +62 -71
  8. package/utils/JsViewEngineWidget/MetroWidget/MetroWidgetSetup.js +308 -613
  9. package/utils/JsViewEngineWidget/TemplateParser/CommonMetroTemplate.ts +127 -247
  10. package/utils/JsViewEngineWidget/TemplateParser/ListMetroTemplate.ts +1 -0
  11. package/utils/JsViewEngineWidget/TemplateParser/MetroTemplate.ts +36 -2
  12. package/utils/JsViewEngineWidget/WidgetCommon.ts +25 -6
  13. package/utils/JsViewPlugin/JsvAudio/{JsvAudioBrowser.vue → BrowserAudio/BrowserAudio.vue} +1 -1
  14. package/utils/JsViewPlugin/JsvAudio/index.js +1 -1
  15. package/utils/JsViewPlugin/JsvLatex/BrowserDomBuilder.js +37 -0
  16. package/utils/JsViewPlugin/JsvLatex/Color.ts +43 -0
  17. package/utils/JsViewPlugin/JsvLatex/JsvLatex.vue +159 -0
  18. package/utils/JsViewPlugin/JsvLatex/JsvLatexBridgeProxy.js +16 -0
  19. package/utils/JsViewPlugin/JsvLatex/JsvLatexBrowser.vue +59 -0
  20. package/utils/JsViewPlugin/JsvLatex/PluginLoader.js +171 -0
  21. package/utils/JsViewPlugin/JsvLatex/index.js +28 -0
  22. package/utils/JsViewPlugin/JsvLatex/mathjax-tex-svg.txt +1 -0
  23. package/utils/JsViewPlugin/JsvLatex/version.js +24 -0
  24. package/utils/JsViewPlugin/JsvLatex/version.mjs +24 -0
  25. package/utils/JsViewPlugin/index.js +2 -1
  26. package/utils/JsViewVueTools/JsvDynamicCssStyle.js +2 -52
  27. package/utils/JsViewVueTools/JsvPerformance.ts +11 -0
  28. package/utils/JsViewVueTools/JsvPreDownloader.ts +55 -11
  29. package/utils/JsViewVueTools/JsvStyleSheetsDeclarer.js +40 -0
  30. package/utils/JsViewVueTools/JsvTextureStore/CanvasTexture/CanvasTexture.ts +143 -0
  31. package/utils/JsViewVueTools/JsvTextureStore/CanvasTexture/CommandList.ts +24 -0
  32. package/utils/JsViewVueTools/JsvTextureStore/CanvasTexture/Path.ts +198 -0
  33. package/utils/JsViewVueTools/JsvTextureStore/JsvTextureStore.ts +31 -0
  34. package/utils/JsViewVueTools/JsvTextureStore/Store.ts +32 -0
  35. package/utils/JsViewVueTools/JsvTextureStore/Texture.ts +38 -0
  36. package/utils/JsViewVueTools/index.js +3 -0
  37. package/utils/JsViewVueWidget/JsvEnableRenderBreak.vue +17 -0
  38. package/utils/JsViewVueWidget/JsvFreeMoveActor/ActionRefObject.ts +6 -0
  39. package/utils/JsViewVueWidget/JsvFreeMoveActor/ActorControl.ts +144 -0
  40. package/utils/JsViewVueWidget/JsvFreeMoveActor/ActorState.ts +6 -0
  41. package/utils/JsViewVueWidget/JsvFreeMoveActor/{CallbackManager.js → CallbackManager.ts} +19 -10
  42. package/utils/JsViewVueWidget/JsvFreeMoveActor/ForgeTypeDefine.ts +45 -0
  43. package/utils/JsViewVueWidget/JsvFreeMoveActor/FreeMoveActor.vue +1 -1
  44. package/utils/JsViewVueWidget/JsvFreeMoveActor/JsvEnvBlocker.vue +124 -0
  45. package/utils/JsViewVueWidget/JsvFreeMoveActor/KeepFlags.ts +6 -0
  46. package/utils/JsViewVueWidget/JsvFreeMoveActor/SetAction.ts +553 -0
  47. package/utils/JsViewVueWidget/JsvFreeMoveActor/SetCondition.ts +138 -0
  48. package/utils/JsViewVueWidget/JsvFreeMoveActor/SetState.ts +53 -0
  49. package/utils/JsViewVueWidget/JsvFreeMoveActor/index.js +11 -1
  50. package/utils/JsViewVueWidget/JsvHole.js +1 -1
  51. package/utils/JsViewVueWidget/JsvLine/JsvLine.vue +101 -0
  52. package/utils/JsViewVueWidget/JsvLine/LineManager.js +62 -0
  53. package/utils/JsViewVueWidget/JsvLine/index.js +3 -0
  54. package/utils/JsViewVueWidget/JsvMarquee.vue +316 -139
  55. package/utils/JsViewVueWidget/JsvMindMap/CommonType.ts +1 -0
  56. package/utils/JsViewVueWidget/JsvMindMap/Constant.ts +20 -0
  57. package/utils/JsViewVueWidget/JsvMindMap/DataTree.ts +394 -0
  58. package/utils/JsViewVueWidget/JsvMindMap/Geometry.ts +277 -0
  59. package/utils/JsViewVueWidget/JsvMindMap/JsvMindMap.vue +653 -0
  60. package/utils/JsViewVueWidget/JsvMindMap/index.js +1 -0
  61. package/utils/JsViewVueWidget/JsvMindMap/rtree.js +628 -0
  62. package/utils/JsViewVueWidget/JsvNinePatch.vue +2 -2
  63. package/utils/JsViewVueWidget/JsvPieChart.vue +124 -0
  64. package/utils/JsViewVueWidget/JsvPosterImage.vue +32 -9
  65. package/utils/JsViewVueWidget/JsvPreload/BrowserPreload.vue +135 -133
  66. package/utils/JsViewVueWidget/JsvPreload/JsvPreload.vue +273 -270
  67. package/utils/JsViewVueWidget/JsvSector.vue +107 -0
  68. package/utils/JsViewVueWidget/JsvTextBox.vue +14 -1
  69. package/utils/JsViewVueWidget/JsvTextureAnim/JsvTextureAnim.vue +28 -2
  70. package/utils/JsViewVueWidget/JsvVisibleSensor/JsvVisibleSensor.vue +122 -93
  71. package/utils/JsViewVueWidget/index.js +15 -7
  72. package/utils/JsViewVueWidget/JsvFreeMoveActor/ActorControl.js +0 -112
  73. package/utils/JsViewVueWidget/JsvFreeMoveActor/CommonTools.js +0 -18
  74. package/utils/JsViewVueWidget/JsvFreeMoveActor/SetAction.js +0 -216
  75. package/utils/JsViewVueWidget/JsvFreeMoveActor/SetCondition.js +0 -66
  76. package/utils/JsViewVueWidget/JsvFreeMoveActor/SetState.js +0 -38
  77. package/utils/JsViewVueWidget/JsvFreeMoveActor/TypeDefine.js +0 -12
  78. package/utils/JsViewVueWidget/JsvTouchContainer.vue +0 -183
  79. package/utils/JsViewVueWidget/JsvTransparentDiv.vue +0 -87
  80. /package/utils/{JsViewVueWidget → JsViewPlugin/JsvAudio/BrowserAudio}/JsvSystemAudio.vue +0 -0
@@ -0,0 +1,653 @@
1
+ <!--
2
+ * @Author: ChenChanghua
3
+ * @Date: 2023-11-06 16:08:58
4
+ * @Description: file content
5
+ -->
6
+
7
+ <!--
8
+ [界面概述]
9
+ 思维导图控件
10
+
11
+ [控件介绍]
12
+ JsvMindMap:
13
+ props:
14
+ name: {string} 焦点name
15
+ provideData: {function} 提供数据的函数
16
+ width: {number} 组件宽
17
+ height: {number} 组件高
18
+ formatNode: {function} 接受数据, 返回标准格式节点信息的函数
19
+ {
20
+ left: number, left(必需)
21
+ top: number, top(必需)
22
+ width: number, width(必需)
23
+ height: number, height(必需)
24
+ id: string, 节点的唯一id(必需)
25
+ childrenList: Array<any>, 子数据列表
26
+ moveType: "star" | "layer" | "inherit", 节点布局类型(可选)
27
+ lineStyle: object 此节点线的style
28
+ {
29
+ lineWidth: number, 线宽
30
+ backgroundColor: string, 线的颜色(与backgroundImage互斥)
31
+ backgroundImage: string, 线的图片(与backgroundColor互斥)
32
+ borderRadius: string | number, 线的圆角设置
33
+ }
34
+ }
35
+ left: {number} 组件left
36
+ top: {number} 组件top
37
+ slideAnim: {object} 滚动动画设置, { duration: number, easing?: string }, duration为毫秒
38
+ onEdge: {function} 到达边缘回调
39
+ focusRectPadding: {number} 焦点区域内边距
40
+ renderRectMargin: {number} 描画区域外边距
41
+ methods:
42
+ getCurFocusNode
43
+ @description 获取当前焦点的数据
44
+ @return {object} 当前焦点节点的数据
45
+ getCurFocusId
46
+ @description 获取当前焦点的id
47
+ @return {string} 当前节点的id
48
+ getCurVisibleRect
49
+ @description 获取当前的可视区域
50
+ @return {object} 可视区域{x: number, y: number, width: number, height: number}
51
+ slideTo
52
+ @description 滚动到指定位置
53
+ @params {int} x x坐标
54
+ @params {int} y y坐标
55
+ @params {object} animInfo 动画设置, 为null时不做动画. {duration: number, easing: string, onEnd: function}
56
+ setFocusTo
57
+ @description 设置焦点
58
+ @params {string} id 目标节点的id
59
+ @params {boolean} needSlide 是否需要滚动
60
+ @params {object} animInfo 滚动动画设置
61
+ moveInItem
62
+ @description 把指定节点移入焦点区域
63
+ @params {string} id 目标节点的id
64
+ @params {object} animInfo 动画信息
65
+ moveFocus
66
+ @description 往指定方向移动焦点
67
+ @params {string} direction 移动方向 "left" | "top" | "right" | "bottom"
68
+ getEntireTreeBoundingSize
69
+ @description 获取整个树的包围框宽高
70
+ @return {object} 宽高 {width: number, height: number}
71
+ refreshData
72
+ @description 刷新数据
73
+
74
+ [额外说明]
75
+ 1. 焦点移动逻辑
76
+ 每个节点首先有个父方向, 若父节点是star模式, 则父方向由父节点相对位置决定, 若父节点是layer模式, 则父方向为父节点子方向的反向
77
+ layer模式的节点, 有一个子方向, 其子方向是所有子所在的一侧方向(只有上下左右四侧), 若无子, 则父方向的反向为子方向. 确定了父方向和子方向后, 剩余两个方向则寻找该方向最近的兄弟节点, 若无则寻找最近分支上最近的同级或者叶节点
78
+ star模式的节点, 除了父方向, 剩余三个方向均寻找相应方向的最近子节点, 若未找到则按layer寻找兄弟节点相同的逻辑寻找同级节点
79
+ -->
80
+ <script setup>
81
+ import { ref, shallowRef, reactive } from "vue";
82
+ import { DataNode } from "./DataTree";
83
+ import { Rect, opposite } from "./Geometry";
84
+ import RBush from "./rtree";
85
+ import { EdgeDirection } from "../../JsViewEngineWidget/WidgetCommon";
86
+ import JsvLine from "../JsvLine";
87
+
88
+ const TAG = "JsvMindMap";
89
+ const dirMap = {
90
+ 37: "left",
91
+ 38: "top",
92
+ 39: "right",
93
+ 40: "bottom",
94
+ };
95
+ const edgeDirectionMap = {
96
+ 37: EdgeDirection.left,
97
+ 38: EdgeDirection.top,
98
+ 39: EdgeDirection.right,
99
+ 40: EdgeDirection.bottom,
100
+ };
101
+ const dirToKeyCode = {
102
+ left: 37,
103
+ top: 38,
104
+ right: 39,
105
+ bottom: 40,
106
+ };
107
+ const defaultLineStyle = {
108
+ lineWidth: 5,
109
+ backgroundColor: "#000000",
110
+ };
111
+
112
+ const props = defineProps({
113
+ name: {
114
+ //组件的焦点名
115
+ type: String,
116
+ required: true,
117
+ },
118
+ provideData: {
119
+ //提供数据的回调
120
+ type: Function,
121
+ required: true,
122
+ },
123
+ width: {
124
+ //组件宽
125
+ type: Number,
126
+ required: true,
127
+ },
128
+ height: {
129
+ //组件高
130
+ type: Number,
131
+ required: true,
132
+ },
133
+ formatNode: {
134
+ /**
135
+ * 标准化节点数据的函数, (data, depth) => Object
136
+ * 节点数据格式
137
+ * {
138
+ * left: number, left(必需)
139
+ * top: number, top(必需)
140
+ * width: number, width(必需)
141
+ * height: number, height(必需)
142
+ * childrenList: Array<any>, 子数据列表
143
+ * id: string, 节点的唯一id(必需)
144
+ * moveType: "star" | "layer" | "inherit", 节点布局类型(可选)
145
+ * lineStyle: { 此节点线的style
146
+ * lineWidth: number, 线宽
147
+ * backgroundColor: string, 线的颜色(与backgroundImage互斥)
148
+ * backgroundImage: string, 线的图片(与backgroundColor互斥)
149
+ * borderRadius: string | number, 线的圆角设置
150
+ * }
151
+ * }
152
+ */
153
+ type: Function,
154
+ required: true,
155
+ },
156
+ left: {
157
+ //组件left
158
+ type: Number,
159
+ default: 0,
160
+ },
161
+ top: {
162
+ //组件top
163
+ type: Number,
164
+ default: 0,
165
+ },
166
+ slideAnim: {
167
+ type: Object,
168
+ },
169
+ onEdge: {
170
+ //组件到达边缘的回调
171
+ type: Function,
172
+ },
173
+ focusRectPadding: {
174
+ //组件区域向内收缩获得的焦点区域, 获焦的节点会移动到该区域内
175
+ type: Number,
176
+ default: 50,
177
+ },
178
+ renderRectMargin: {
179
+ //组件区域向外延展获得的描画区域, 区域内的节点会描画
180
+ type: Number,
181
+ default: 100,
182
+ },
183
+ });
184
+
185
+ let rootNode = null;
186
+ const currentFocusId = ref(0);
187
+ let preFocusNode = null;
188
+ let curFocusNode = null;
189
+ const locateDiv = shallowRef(null);
190
+ const renderNodeList = shallowRef([]);
191
+ const renderLineList = shallowRef([]);
192
+ const widgetWidth = 500;
193
+ const widgetHeight = 500;
194
+ let widgetFocused = false;
195
+ let rTree = null;
196
+ const slideAnimInfo = {
197
+ duration: props.slideAnim?.duration ?? 200,
198
+ easing: props.slideAnim?.easing ?? "",
199
+ onEnd: props.slideAnim?.easing ?? (() => {}),
200
+ };
201
+ const viewPortRect = new Rect(0, 0, widgetWidth, widgetHeight); // 组件的可视范围
202
+
203
+ // 描画范围
204
+ const getRenderRect = () => {
205
+ return new Rect(
206
+ viewPortRect.x - props.renderRectMargin,
207
+ viewPortRect.y - props.renderRectMargin,
208
+ viewPortRect.width + 2 * props.renderRectMargin,
209
+ viewPortRect.height + 2 * props.renderRectMargin
210
+ );
211
+ };
212
+
213
+ //item获焦时移入此范围
214
+ const getFocusRect = () => {
215
+ return new Rect(
216
+ viewPortRect.x + props.focusRectPadding,
217
+ viewPortRect.y + props.focusRectPadding,
218
+ viewPortRect.width - 2 * props.focusRectPadding,
219
+ viewPortRect.height - 2 * props.focusRectPadding
220
+ );
221
+ };
222
+
223
+ const buildNode = (root, data) => {
224
+ let depth = 0;
225
+ if (root != null) {
226
+ depth = root.depth + 1;
227
+ }
228
+ const formatedData = props.formatNode(data, root ? root.depth + 1 : 0);
229
+ const dataNode = new DataNode(
230
+ new Rect(
231
+ formatedData.left,
232
+ formatedData.top,
233
+ formatedData.width,
234
+ formatedData.height
235
+ ),
236
+ depth,
237
+ formatedData.id,
238
+ data,
239
+ formatedData.moveType ?? "layer"
240
+ );
241
+ dataNode.setLineStyle(formatedData.lineStyle ?? defaultLineStyle);
242
+ if (root == null) {
243
+ rootNode = dataNode;
244
+ } else {
245
+ root.insert(dataNode);
246
+ }
247
+
248
+ if (formatedData.childrenList?.length > 0) {
249
+ for (let child of formatedData.childrenList) {
250
+ buildNode(dataNode, child);
251
+ }
252
+ }
253
+ };
254
+
255
+ //构建树
256
+ const buildTree = () => {
257
+ //clean old tree
258
+ rootNode = null;
259
+ rTree = null;
260
+
261
+ //build new tree
262
+ buildNode(null, props.provideData());
263
+ const allNodeList = rootNode.all();
264
+ allNodeList.forEach((i) => i.calculateMoveInfo());
265
+ rTree = new RBush();
266
+ allNodeList.forEach((node) => rTree.insert(node));
267
+
268
+ //线的处理必须在moveInfo计算完成后处理
269
+ for (let i = 1; i < allNodeList.length; ++i) {
270
+ const node = allNodeList[i];
271
+ const parentDir = node.getParentDir();
272
+ const lineStyle = node.parent.getLineStyle();
273
+ const lineObj = {
274
+ startPos: node.parent.rect.getEdge(opposite(parentDir)).center,
275
+ endPos: node.rect.getEdge(parentDir).center,
276
+ idToken: node.parent.idToken + "_" + node.idToken,
277
+ ...lineStyle,
278
+ };
279
+ //node显示时, 其向父的连线和向子的连线均要显示, 因此同时往父子addLine
280
+ node.addLine(lineObj);
281
+ node.parent.addLine(lineObj);
282
+ }
283
+ curFocusNode = rootNode;
284
+ };
285
+
286
+ const visibleListStore = {
287
+ _tmpList: [],
288
+ _curList: [],
289
+ _merge(l1, l2) {
290
+ const pre = l1.concat();
291
+ const set = new Set(pre);
292
+ l2.forEach((i) => set.add(i));
293
+ return Array.from(set);
294
+ },
295
+ setCurList(list) {
296
+ const newTmp = this._merge(this._curList, list);
297
+ this._tmpList = this._merge(this._tmpList, newTmp);
298
+ this._curList = list;
299
+ },
300
+ getTmp() {
301
+ return this._tmpList;
302
+ },
303
+ getCur() {
304
+ this._tmpList = this._curList;
305
+ return this._curList;
306
+ },
307
+ };
308
+
309
+ const setFocusNode = (node) => {
310
+ if (!node) return;
311
+ preFocusNode = curFocusNode;
312
+ curFocusNode = node;
313
+ currentFocusId.value = curFocusNode.customerId;
314
+
315
+ //item的onFocus, onBlur
316
+ if (widgetFocused) {
317
+ preFocusNode?.onBlur();
318
+ curFocusNode?.onFocus();
319
+ }
320
+ };
321
+
322
+ //将node移入可视范围
323
+ const moveInNode = (node, animInfo) => {
324
+ if (node) {
325
+ const moveTarget = getMoveInfo(node);
326
+ if (moveTarget) {
327
+ moveTo(moveTarget, animInfo);
328
+ }
329
+ }
330
+ };
331
+
332
+ const focusToNext = (keyCode) => {
333
+ const dirStr = dirMap[keyCode];
334
+ const nextNode = curFocusNode.findNode(dirStr);
335
+ if (nextNode) {
336
+ //设置当前焦点node
337
+ setFocusNode(nextNode);
338
+
339
+ //移动动画
340
+ moveInNode(curFocusNode, {
341
+ duration: slideAnimInfo.duration,
342
+ });
343
+ } else {
344
+ //到达边缘
345
+ if (props.onEdge) {
346
+ props.onEdge({
347
+ direction: edgeDirectionMap[keyCode],
348
+ rect: {
349
+ x: curFocusNode?.rect.x ?? 0,
350
+ y: curFocusNode?.rect.y ?? 0,
351
+ width: curFocusNode?.rect.width ?? 0,
352
+ height: curFocusNode?.rect.height ?? 0,
353
+ },
354
+ });
355
+ }
356
+ }
357
+ };
358
+
359
+ const locateDivPos = reactive({
360
+ left: viewPortRect.x,
361
+ top: viewPortRect.y,
362
+ });
363
+
364
+ const moveTo = (info, animInfo) => {
365
+ if (!info) return;
366
+ //info: {left: number, top: number} 新的focusRect的x, y
367
+ if (info.x != viewPortRect.x || info.y != viewPortRect.y) {
368
+ viewPortRect.x = info.x;
369
+ viewPortRect.y = info.y;
370
+ const preLeft = locateDivPos.left,
371
+ preTop = locateDivPos.top;
372
+ locateDivPos.left = -viewPortRect.x;
373
+ locateDivPos.top = -viewPortRect.y;
374
+
375
+ visibleListStore.setCurList(rTree.search(getRenderRect()));
376
+
377
+ if (animInfo && !isNaN(animInfo.duration)) {
378
+ const forgeAnim = new Forge.TranslateAnimation(
379
+ preLeft - locateDivPos.left,
380
+ 0,
381
+ preTop - locateDivPos.top,
382
+ 0,
383
+ animInfo.duration,
384
+ animInfo.easing
385
+ );
386
+ forgeAnim.SetAnimationListener(
387
+ new Forge.AnimationListener(
388
+ null,
389
+ () => {
390
+ updateVisible(visibleListStore.getCur());
391
+ animInfo.onEnd?.();
392
+ },
393
+ null
394
+ )
395
+ );
396
+ locateDiv.value?.jsvGetProxyView(true).StartAnimation(forgeAnim);
397
+ updateVisible(visibleListStore.getTmp());
398
+ } else {
399
+ updateVisible(visibleListStore.getCur());
400
+ }
401
+ }
402
+ };
403
+
404
+ const getMoveInfo = (node) => {
405
+ const rect = node.rect;
406
+ const rectCenter = rect.center;
407
+ const focusRect = getFocusRect();
408
+ const centerTargetRect = new Rect(
409
+ focusRect.x + Math.round(rect.width / 2),
410
+ focusRect.y + Math.round(rect.height / 2),
411
+ focusRect.width - rect.width,
412
+ focusRect.height - rect.height
413
+ );
414
+ if (!centerTargetRect.containPoint(rectCenter)) {
415
+ //不在可视范围内
416
+ const point = centerTargetRect.getClosestPoint(rectCenter);
417
+ return {
418
+ x: viewPortRect.x + rectCenter.x - point.x,
419
+ y: viewPortRect.y + rectCenter.y - point.y,
420
+ };
421
+ }
422
+ return null;
423
+ };
424
+
425
+ const updateVisible = (list) => {
426
+ //根据显示区域获取可视item list
427
+ renderNodeList.value = list;
428
+ //更新线的列表
429
+ const lineSet = new Set();
430
+ for (let node of list) {
431
+ let list = node.getLineList();
432
+ for (let line of list) {
433
+ lineSet.add(line);
434
+ }
435
+ }
436
+ renderLineList.value = Array.from(lineSet);
437
+ };
438
+
439
+ const focusBlockOnFocus = () => {
440
+ widgetFocused = true;
441
+ curFocusNode?.onFocus();
442
+ };
443
+
444
+ const focusBlockOnBlur = () => {
445
+ widgetFocused = false;
446
+ curFocusNode?.onBlur();
447
+ };
448
+
449
+ const onKeyDown = (ev) => {
450
+ switch (ev.keyCode) {
451
+ case 37:
452
+ case 38:
453
+ case 39:
454
+ case 40:
455
+ {
456
+ focusToNext(ev.keyCode);
457
+ }
458
+ return true;
459
+ case 13:
460
+ curFocusNode?.onClick();
461
+ return true;
462
+ default:
463
+ return false;
464
+ }
465
+ };
466
+
467
+ //init
468
+ {
469
+ buildTree();
470
+ //初始焦点放置在屏幕中间
471
+ const center = curFocusNode.rect.center;
472
+ const viewPortPos = {
473
+ x: Math.round(center.x - viewPortRect.width / 2),
474
+ y: Math.round(center.y - viewPortRect.height / 2),
475
+ };
476
+ moveTo(viewPortPos);
477
+ }
478
+
479
+ // expose methos
480
+ /**
481
+ * 获取当前获焦的节点
482
+ */
483
+ const getCurFocusId = () => {
484
+ return currentFocusId.value;
485
+ };
486
+
487
+ const getCurFocusNode = () => {
488
+ return curFocusNode.customerData;
489
+ };
490
+
491
+ /**
492
+ * 获取当前的可视区域
493
+ */
494
+ const getCurVisibleRect = () => {
495
+ return viewPortRect;
496
+ };
497
+
498
+ /**
499
+ * 移动到指定位置
500
+ * @param {int} x
501
+ * @param {int} y
502
+ * @param {object} animInfo
503
+ */
504
+ const slideTo = (x, y, animInfo) => {
505
+ if (isNaN(x) || isNaN(y)) {
506
+ console.warn(TAG, "slideTo failed: x and y must be number.");
507
+ return;
508
+ }
509
+ moveTo({ x, y }, animInfo);
510
+ };
511
+
512
+ /**
513
+ * 设置焦点
514
+ * @param {string} id 节点id
515
+ * @param {boolean} needSlide 是否要将节点移入可视范围
516
+ * @param {object} animInfo 移动动画
517
+ */
518
+ const setFocusTo = (id, needSlide = true, animInfo) => {
519
+ const node = rootNode.find((n) => n.customerId == id);
520
+ if (!node) {
521
+ console.warn(TAG, `setFocusTo failed: node ${id} not found.`);
522
+ return;
523
+ }
524
+ setFocusNode(node);
525
+ if (needSlide) {
526
+ moveInNode(node, animInfo);
527
+ }
528
+ };
529
+
530
+ /**
531
+ * 将制定item移入可视范围, 若已在可视范围, 则不动
532
+ * @param {string} id 节点的id
533
+ * @param {object} animInfo 动画信息
534
+ */
535
+ const moveInItem = (id, animInfo) => {
536
+ const node = rootNode.find((n) => n.customerId == id);
537
+ if (!node) {
538
+ console.warn(TAG, `moveInItem failed: node ${id} not found.`);
539
+ return;
540
+ }
541
+ moveInNode(node, animInfo);
542
+ };
543
+
544
+ /**
545
+ * 获取全图的包围框大小
546
+ */
547
+ const getEntireTreeBoundingSize = () => {
548
+ const data = rTree.data;
549
+ return {
550
+ width: data.maxX - data.minX + 1,
551
+ height: data.maxY - data.minY + 1,
552
+ };
553
+ };
554
+
555
+ /**
556
+ * 移动焦点
557
+ * @param {string} direction "left" | "top" | "right" | "bottom"
558
+ */
559
+ const moveFocus = (direction) => {
560
+ if (!direction in dirToKeyCode) {
561
+ console.warn(TAG, "moveFocus failed: undefined direction " + direction);
562
+ }
563
+ focusToNext(dirToKeyCode[direction]);
564
+ };
565
+
566
+ /**
567
+ * 刷新数据
568
+ */
569
+ const refreshData = () => {
570
+ buildTree();
571
+ //TODO 刷新后的位置保持
572
+ const center = curFocusNode.rect.center;
573
+ const viewPortPos = {
574
+ x: Math.round(center.x - viewPortRect.width / 2),
575
+ y: Math.round(center.y - viewPortRect.height / 2),
576
+ };
577
+ moveTo(viewPortPos);
578
+ };
579
+
580
+ const exposeObj = {
581
+ getCurFocusNode,
582
+ getCurFocusId,
583
+ getCurVisibleRect,
584
+ slideTo,
585
+ setFocusTo,
586
+ moveInItem,
587
+ moveFocus,
588
+ getEntireTreeBoundingSize,
589
+ refreshData,
590
+ };
591
+ defineExpose(exposeObj);
592
+
593
+ //debug code
594
+ // window.rTree = rTree;
595
+ // window.dataTree = rootNode;
596
+ // window.mindMap = exposeObj;
597
+ </script>
598
+
599
+ <template>
600
+ <div
601
+ :style="{
602
+ left: props.left,
603
+ top: props.top,
604
+ width: viewPortRect.width,
605
+ height: viewPortRect.height,
606
+ overflow: 'hidden',
607
+ }"
608
+ >
609
+ <div
610
+ ref="locateDiv"
611
+ :style="{
612
+ left: locateDivPos.left,
613
+ top: locateDivPos.top,
614
+ width: viewPortRect.width,
615
+ height: viewPortRect.height,
616
+ }"
617
+ >
618
+ <slot name="background"></slot>
619
+ <jsv-focus-block
620
+ autoFocus
621
+ :onAction="{
622
+ onKeyDown,
623
+ onFocus: focusBlockOnFocus,
624
+ onBlur: focusBlockOnBlur,
625
+ }"
626
+ >
627
+ <jsv-line
628
+ v-for="item in renderLineList"
629
+ v-bind="item"
630
+ :key="item.idToken"
631
+ >
632
+ </jsv-line>
633
+ <div
634
+ v-for="item in renderNodeList"
635
+ :key="item.idToken"
636
+ :ref="item.onRef"
637
+ :style="{
638
+ left: item.rect.left,
639
+ top: item.rect.top,
640
+ width: item.rect.width,
641
+ height: item.rect.height,
642
+ }"
643
+ >
644
+ <slot
645
+ :data="item.customerData"
646
+ :handler="exposeObj"
647
+ :onAction="item.getRegister()"
648
+ ></slot>
649
+ </div>
650
+ </jsv-focus-block>
651
+ </div>
652
+ </div>
653
+ </template>
@@ -0,0 +1 @@
1
+ export { default as JsvMindMap } from "./JsvMindMap.vue"