@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.
- package/package.json +1 -1
- package/utils/JsViewEngineWidget/JsvFocusBlock.vue +1 -1
- package/utils/JsViewEngineWidget/JsvFocusHub.ts +123 -0
- package/utils/JsViewEngineWidget/JsvFocusManager.js +4 -3
- package/utils/JsViewEngineWidget/MetroWidget/AnimationManager.ts +145 -51
- package/utils/JsViewEngineWidget/MetroWidget/ListWidget.vue +51 -64
- package/utils/JsViewEngineWidget/MetroWidget/MetroWidget.vue +62 -71
- package/utils/JsViewEngineWidget/MetroWidget/MetroWidgetSetup.js +308 -613
- package/utils/JsViewEngineWidget/TemplateParser/CommonMetroTemplate.ts +127 -247
- package/utils/JsViewEngineWidget/TemplateParser/ListMetroTemplate.ts +1 -0
- package/utils/JsViewEngineWidget/TemplateParser/MetroTemplate.ts +36 -2
- package/utils/JsViewEngineWidget/WidgetCommon.ts +25 -6
- package/utils/JsViewPlugin/JsvAudio/{JsvAudioBrowser.vue → BrowserAudio/BrowserAudio.vue} +1 -1
- package/utils/JsViewPlugin/JsvAudio/index.js +1 -1
- package/utils/JsViewPlugin/JsvLatex/BrowserDomBuilder.js +37 -0
- package/utils/JsViewPlugin/JsvLatex/Color.ts +43 -0
- package/utils/JsViewPlugin/JsvLatex/JsvLatex.vue +159 -0
- package/utils/JsViewPlugin/JsvLatex/JsvLatexBridgeProxy.js +16 -0
- package/utils/JsViewPlugin/JsvLatex/JsvLatexBrowser.vue +59 -0
- package/utils/JsViewPlugin/JsvLatex/PluginLoader.js +171 -0
- package/utils/JsViewPlugin/JsvLatex/index.js +28 -0
- package/utils/JsViewPlugin/JsvLatex/mathjax-tex-svg.txt +1 -0
- package/utils/JsViewPlugin/JsvLatex/version.js +24 -0
- package/utils/JsViewPlugin/JsvLatex/version.mjs +24 -0
- package/utils/JsViewPlugin/index.js +2 -1
- package/utils/JsViewVueTools/JsvDynamicCssStyle.js +2 -52
- package/utils/JsViewVueTools/JsvPerformance.ts +11 -0
- package/utils/JsViewVueTools/JsvPreDownloader.ts +55 -11
- package/utils/JsViewVueTools/JsvStyleSheetsDeclarer.js +40 -0
- package/utils/JsViewVueTools/JsvTextureStore/CanvasTexture/CanvasTexture.ts +143 -0
- package/utils/JsViewVueTools/JsvTextureStore/CanvasTexture/CommandList.ts +24 -0
- package/utils/JsViewVueTools/JsvTextureStore/CanvasTexture/Path.ts +198 -0
- package/utils/JsViewVueTools/JsvTextureStore/JsvTextureStore.ts +31 -0
- package/utils/JsViewVueTools/JsvTextureStore/Store.ts +32 -0
- package/utils/JsViewVueTools/JsvTextureStore/Texture.ts +38 -0
- package/utils/JsViewVueTools/index.js +3 -0
- package/utils/JsViewVueWidget/JsvEnableRenderBreak.vue +17 -0
- package/utils/JsViewVueWidget/JsvFreeMoveActor/ActionRefObject.ts +6 -0
- package/utils/JsViewVueWidget/JsvFreeMoveActor/ActorControl.ts +144 -0
- package/utils/JsViewVueWidget/JsvFreeMoveActor/ActorState.ts +6 -0
- package/utils/JsViewVueWidget/JsvFreeMoveActor/{CallbackManager.js → CallbackManager.ts} +19 -10
- package/utils/JsViewVueWidget/JsvFreeMoveActor/ForgeTypeDefine.ts +45 -0
- package/utils/JsViewVueWidget/JsvFreeMoveActor/FreeMoveActor.vue +1 -1
- package/utils/JsViewVueWidget/JsvFreeMoveActor/JsvEnvBlocker.vue +124 -0
- package/utils/JsViewVueWidget/JsvFreeMoveActor/KeepFlags.ts +6 -0
- package/utils/JsViewVueWidget/JsvFreeMoveActor/SetAction.ts +553 -0
- package/utils/JsViewVueWidget/JsvFreeMoveActor/SetCondition.ts +138 -0
- package/utils/JsViewVueWidget/JsvFreeMoveActor/SetState.ts +53 -0
- package/utils/JsViewVueWidget/JsvFreeMoveActor/index.js +11 -1
- package/utils/JsViewVueWidget/JsvHole.js +1 -1
- package/utils/JsViewVueWidget/JsvLine/JsvLine.vue +101 -0
- package/utils/JsViewVueWidget/JsvLine/LineManager.js +62 -0
- package/utils/JsViewVueWidget/JsvLine/index.js +3 -0
- package/utils/JsViewVueWidget/JsvMarquee.vue +316 -139
- package/utils/JsViewVueWidget/JsvMindMap/CommonType.ts +1 -0
- package/utils/JsViewVueWidget/JsvMindMap/Constant.ts +20 -0
- package/utils/JsViewVueWidget/JsvMindMap/DataTree.ts +394 -0
- package/utils/JsViewVueWidget/JsvMindMap/Geometry.ts +277 -0
- package/utils/JsViewVueWidget/JsvMindMap/JsvMindMap.vue +653 -0
- package/utils/JsViewVueWidget/JsvMindMap/index.js +1 -0
- package/utils/JsViewVueWidget/JsvMindMap/rtree.js +628 -0
- package/utils/JsViewVueWidget/JsvNinePatch.vue +2 -2
- package/utils/JsViewVueWidget/JsvPieChart.vue +124 -0
- package/utils/JsViewVueWidget/JsvPosterImage.vue +32 -9
- package/utils/JsViewVueWidget/JsvPreload/BrowserPreload.vue +135 -133
- package/utils/JsViewVueWidget/JsvPreload/JsvPreload.vue +273 -270
- package/utils/JsViewVueWidget/JsvSector.vue +107 -0
- package/utils/JsViewVueWidget/JsvTextBox.vue +14 -1
- package/utils/JsViewVueWidget/JsvTextureAnim/JsvTextureAnim.vue +28 -2
- package/utils/JsViewVueWidget/JsvVisibleSensor/JsvVisibleSensor.vue +122 -93
- package/utils/JsViewVueWidget/index.js +15 -7
- package/utils/JsViewVueWidget/JsvFreeMoveActor/ActorControl.js +0 -112
- package/utils/JsViewVueWidget/JsvFreeMoveActor/CommonTools.js +0 -18
- package/utils/JsViewVueWidget/JsvFreeMoveActor/SetAction.js +0 -216
- package/utils/JsViewVueWidget/JsvFreeMoveActor/SetCondition.js +0 -66
- package/utils/JsViewVueWidget/JsvFreeMoveActor/SetState.js +0 -38
- package/utils/JsViewVueWidget/JsvFreeMoveActor/TypeDefine.js +0 -12
- package/utils/JsViewVueWidget/JsvTouchContainer.vue +0 -183
- package/utils/JsViewVueWidget/JsvTransparentDiv.vue +0 -87
- /package/utils/{JsViewVueWidget → JsViewPlugin/JsvAudio/BrowserAudio}/JsvSystemAudio.vue +0 -0
|
@@ -0,0 +1,394 @@
|
|
|
1
|
+
import { Rect, Line } from "./Geometry";
|
|
2
|
+
import * as CONST from "./Constant"
|
|
3
|
+
import { Direction } from "./CommonType";
|
|
4
|
+
import { opposite } from "./Geometry";
|
|
5
|
+
|
|
6
|
+
type MoveType = "star" | "layer" | "inherit"
|
|
7
|
+
const NO_NEIGHBOR = Symbol("noNeighbor");
|
|
8
|
+
|
|
9
|
+
interface MoveInfoCache {
|
|
10
|
+
moveType: MoveType | null;
|
|
11
|
+
parentDir: Direction | null;
|
|
12
|
+
childDir: Direction | null;
|
|
13
|
+
left: DataNode | null | symbol,
|
|
14
|
+
top: DataNode | null | symbol,
|
|
15
|
+
right: DataNode | null | symbol,
|
|
16
|
+
bottom: DataNode | null | symbol,
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
let token = 0;
|
|
20
|
+
export class DataNode {
|
|
21
|
+
public idToken = token++;
|
|
22
|
+
private static readonly DEFAULT_MOVE_TYPE = "star"
|
|
23
|
+
public parent: DataNode | null = null;
|
|
24
|
+
public children: Array<DataNode> = [];
|
|
25
|
+
public rect: Rect;
|
|
26
|
+
public depth: number;
|
|
27
|
+
public customerData: any;
|
|
28
|
+
public customerId: string;
|
|
29
|
+
public moveType: MoveType = "inherit";
|
|
30
|
+
private lineList: Array<any> = [];
|
|
31
|
+
|
|
32
|
+
//焦点移动相关
|
|
33
|
+
private moveInfoCache: MoveInfoCache = {
|
|
34
|
+
moveType: null,
|
|
35
|
+
parentDir: null,
|
|
36
|
+
childDir: null,
|
|
37
|
+
left: null,
|
|
38
|
+
top: null,
|
|
39
|
+
right: null,
|
|
40
|
+
bottom: null,
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
constructor(rect: Rect, depth: number, id: string, data: any, moveType: MoveType = "inherit") {
|
|
44
|
+
this.rect = rect;
|
|
45
|
+
this.depth = depth;
|
|
46
|
+
this.customerData = data;
|
|
47
|
+
this.moveType = moveType;
|
|
48
|
+
this.customerId = id;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
//>>>>为了对接rtree库>>>>
|
|
52
|
+
get minX() { return this.rect.minX; }
|
|
53
|
+
|
|
54
|
+
get maxX() { return this.rect.maxX; }
|
|
55
|
+
|
|
56
|
+
get minY() { return this.rect.minY; }
|
|
57
|
+
|
|
58
|
+
get maxY() { return this.rect.maxY; }
|
|
59
|
+
//<<<<<<<<
|
|
60
|
+
|
|
61
|
+
public addLine(lineObj: any) {
|
|
62
|
+
this.lineList.push(lineObj);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
public getLineList() {
|
|
66
|
+
return this.lineList;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
public getParentDir() {
|
|
70
|
+
return this.moveInfoCache.parentDir;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
public insert(r: DataNode) {
|
|
74
|
+
this.children.push(r);
|
|
75
|
+
r.parent = this;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
public find(equalFunc: Function): DataNode | null {
|
|
79
|
+
if (equalFunc(this)) {
|
|
80
|
+
return this;
|
|
81
|
+
} else if (this.children.length > 0) {
|
|
82
|
+
for (let i of this.children) {
|
|
83
|
+
const result = i.find(equalFunc);
|
|
84
|
+
if (result) {
|
|
85
|
+
return result;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
return null;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* 获取子tree的所有节点的列表(包含此节点)
|
|
94
|
+
*/
|
|
95
|
+
public all() {
|
|
96
|
+
const nodeList: Array<DataNode> = [];
|
|
97
|
+
const queue: Array<DataNode> = [];
|
|
98
|
+
queue.push(this);
|
|
99
|
+
while (queue.length > 0) {
|
|
100
|
+
const n = queue.pop();
|
|
101
|
+
if (n) {
|
|
102
|
+
nodeList.push(n);
|
|
103
|
+
if (n.children.length > 0) {
|
|
104
|
+
queue.push(...n.children);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
return nodeList
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* 寻找指定方向的node
|
|
113
|
+
* 移动逻辑说明:
|
|
114
|
+
* moveType代表本节点和其子节点之间的移动方式
|
|
115
|
+
* star:
|
|
116
|
+
*/
|
|
117
|
+
public findNode(direction: Direction) {
|
|
118
|
+
if (this.moveInfoCache[direction] == null) {
|
|
119
|
+
this.calculateMoveInfo();
|
|
120
|
+
}
|
|
121
|
+
return this.moveInfoCache[direction] == NO_NEIGHBOR ? null : this.moveInfoCache[direction];
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
private calculateMoveInfo() {
|
|
125
|
+
const directions: Set<Direction> = new Set([CONST.LEFT, CONST.TOP, CONST.RIGHT, CONST.BOTTOM])
|
|
126
|
+
//确认parent方向
|
|
127
|
+
if (this.moveInfoCache.parentDir == null) {
|
|
128
|
+
if (this.parent) {
|
|
129
|
+
const pMoveType = this.parent.getMoveType();
|
|
130
|
+
if (pMoveType == "layer") {
|
|
131
|
+
const dir = opposite(this.parent.getLayoutChildDir());
|
|
132
|
+
this.parent.children.forEach((i: DataNode) => {
|
|
133
|
+
i.moveInfoCache.parentDir = dir;
|
|
134
|
+
i.moveInfoCache[dir] = this.parent;
|
|
135
|
+
});
|
|
136
|
+
} else {
|
|
137
|
+
//星图模式, 只支持四个方向
|
|
138
|
+
const dir = this.parent.rect.relativeTo(this.rect);
|
|
139
|
+
this.moveInfoCache.parentDir = dir;
|
|
140
|
+
this.moveInfoCache[dir] = this.parent;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
if (this.moveInfoCache.parentDir) {
|
|
145
|
+
directions.delete(this.moveInfoCache.parentDir as Direction);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
//确认child方向
|
|
149
|
+
const moveType = this.getMoveType();
|
|
150
|
+
if (this.children.length == 0) {
|
|
151
|
+
//无子时, 以parentDir反向为childDir
|
|
152
|
+
if (this.moveInfoCache.parentDir) {
|
|
153
|
+
const dir = opposite(this.moveInfoCache.parentDir as Direction) //parentDir必然存在
|
|
154
|
+
this.moveInfoCache[dir] = NO_NEIGHBOR;
|
|
155
|
+
directions.delete(dir);
|
|
156
|
+
} else {
|
|
157
|
+
//无父无子
|
|
158
|
+
}
|
|
159
|
+
} else {
|
|
160
|
+
if (moveType == "layer") {
|
|
161
|
+
//layer模式只有一个子方向,
|
|
162
|
+
const dir = this.getLayoutChildDir();
|
|
163
|
+
const nearest = this.findNearest(this.children) as DataNode; // 必然不为null, 强转类型
|
|
164
|
+
this.moveInfoCache[dir] = nearest;
|
|
165
|
+
const oppositeDir = opposite(dir);
|
|
166
|
+
this.children.forEach(i => {
|
|
167
|
+
i.moveInfoCache.parentDir = oppositeDir;
|
|
168
|
+
i.moveInfoCache[oppositeDir] = this;
|
|
169
|
+
})
|
|
170
|
+
directions.delete(dir);
|
|
171
|
+
} else {
|
|
172
|
+
//start模式, 规定只有四个方向
|
|
173
|
+
const minDistance: any = {};
|
|
174
|
+
for (let item of this.children) {
|
|
175
|
+
const dir = item.rect.relativeTo(this.rect);
|
|
176
|
+
const distance = item.rect.distance(this.rect, true);
|
|
177
|
+
if (typeof minDistance[dir] == "undefined" || minDistance[dir] > distance) {
|
|
178
|
+
minDistance[dir] = distance;
|
|
179
|
+
this.moveInfoCache[dir] = item;
|
|
180
|
+
}
|
|
181
|
+
directions.delete(dir);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
//剩下的方向在同级节点中寻找
|
|
187
|
+
for (let d of directions) {
|
|
188
|
+
if (this.moveInfoCache[d] == null) {
|
|
189
|
+
const node = this.findNearestBrother(d);
|
|
190
|
+
this.moveInfoCache[d] = node == null ? NO_NEIGHBOR : node;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
private getLayoutChildDir() {
|
|
196
|
+
//layer模式, 所有子的共同方向
|
|
197
|
+
const commonDir = this.findListCommonDir(this.children);
|
|
198
|
+
let dir: Direction;
|
|
199
|
+
if (commonDir != null) {
|
|
200
|
+
dir = commonDir;
|
|
201
|
+
} else {
|
|
202
|
+
//layer模式, 子却没有一个统一的方向, 改为寻找最近
|
|
203
|
+
console.warn("layer mode while children node are not at same side of parent.");
|
|
204
|
+
const nearest = this.findNearest(this.children) as DataNode; // 必然不为null, 强转类型
|
|
205
|
+
//矩形的位置判断逻辑没有交换等价性, 因此需要子相对父的位置再取反
|
|
206
|
+
dir = nearest.rect.relativeTo(this.rect);
|
|
207
|
+
}
|
|
208
|
+
return dir;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
private findListCommonDir(list: Array<DataNode>): Direction | null {
|
|
212
|
+
let result = 0b1111;
|
|
213
|
+
let detail = { value: 0 }
|
|
214
|
+
list.forEach(node => {
|
|
215
|
+
detail.value = 0;
|
|
216
|
+
node.rect.relativeTo(this.rect, detail);
|
|
217
|
+
result &= detail.value
|
|
218
|
+
});
|
|
219
|
+
if (result & CONST.LEFT_BIT) {
|
|
220
|
+
return CONST.LEFT;
|
|
221
|
+
} else if (result & CONST.TOP_BIT) {
|
|
222
|
+
return CONST.TOP;
|
|
223
|
+
} else if (result & CONST.RIGHT_BIT) {
|
|
224
|
+
return CONST.RIGHT;
|
|
225
|
+
} else if (result & CONST.BOTTOM_BIT) {
|
|
226
|
+
return CONST.BOTTOM;
|
|
227
|
+
} else {
|
|
228
|
+
return null;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* 寻找指定方向的同级节点, 寻找逻辑:
|
|
234
|
+
* 1. 寻找该方向的最近兄弟节点, 否则就寻找父的最近兄弟节点, 直到找到节点或者到达根节点
|
|
235
|
+
* 2. 若找到的是其他子树的节点, 则往叶方向寻找与本分支同级节点最近的节点, 直到无子或者找到与本节点同级的节点为止
|
|
236
|
+
* @param direction
|
|
237
|
+
*/
|
|
238
|
+
private findNearestBrother(direction: Direction) {
|
|
239
|
+
let result: DataNode | null = null;
|
|
240
|
+
let stack: Array<DataNode> = [this];
|
|
241
|
+
while (stack.length > 0) {
|
|
242
|
+
const target = stack[stack.length - 1];
|
|
243
|
+
if (target.parent) {
|
|
244
|
+
if (target.parent.children.length > 0) {
|
|
245
|
+
//寻找target的最近的兄弟节点
|
|
246
|
+
const nearestNode = target.findDirNearest(target.parent.children, direction);
|
|
247
|
+
if (nearestNode != null) {
|
|
248
|
+
//向上找到相邻分支的根节点, 开始延该分支往下找
|
|
249
|
+
result = nearestNode;
|
|
250
|
+
stack.pop();
|
|
251
|
+
while (stack.length > 0 && result.children.length > 0) {
|
|
252
|
+
const t = stack.pop() as DataNode;
|
|
253
|
+
const n = t.findDirNearest(result.children, direction);
|
|
254
|
+
if (n) {
|
|
255
|
+
result = n;
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
break;
|
|
259
|
+
} else {
|
|
260
|
+
//指定方向无兄弟节点, 继续往上
|
|
261
|
+
stack.push(target.parent);
|
|
262
|
+
}
|
|
263
|
+
} else {
|
|
264
|
+
//父节点无child, 继续往上找
|
|
265
|
+
stack.push(target.parent);
|
|
266
|
+
}
|
|
267
|
+
} else {
|
|
268
|
+
//未找到
|
|
269
|
+
break;
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
return result;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
private cleanMoveInfoCache() {
|
|
276
|
+
this.moveInfoCache.left = null;
|
|
277
|
+
this.moveInfoCache.top = null;
|
|
278
|
+
this.moveInfoCache.right = null;
|
|
279
|
+
this.moveInfoCache.bottom = null;
|
|
280
|
+
this.moveInfoCache.moveType = null;
|
|
281
|
+
this.moveInfoCache.parentDir = null;
|
|
282
|
+
|
|
283
|
+
if (this.children) {
|
|
284
|
+
this.children.forEach(i => i.cleanMoveInfoCache())
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
private getMoveType() {
|
|
289
|
+
if (this.moveInfoCache.moveType) return this.moveInfoCache.moveType;
|
|
290
|
+
let type = this.moveType;
|
|
291
|
+
if (type == "inherit") {
|
|
292
|
+
type = DataNode.DEFAULT_MOVE_TYPE;
|
|
293
|
+
let node = this.parent;
|
|
294
|
+
while (node) {
|
|
295
|
+
if (node.moveType != "inherit") {
|
|
296
|
+
type = node.moveType;
|
|
297
|
+
break;
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
this.moveInfoCache.moveType = type;
|
|
302
|
+
return type;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
/**
|
|
306
|
+
* 寻找最近的node
|
|
307
|
+
*/
|
|
308
|
+
private findNearest(list: Array<DataNode>, minDistance: number = Infinity) {
|
|
309
|
+
if (this.children.length == 0) return null;
|
|
310
|
+
let targetChild: DataNode | null = null;
|
|
311
|
+
for (let i of list) {
|
|
312
|
+
if (i != this) {
|
|
313
|
+
const d = this.rect.distance(i.rect);
|
|
314
|
+
if (d < minDistance) {
|
|
315
|
+
minDistance = d;
|
|
316
|
+
targetChild = i;
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
return targetChild;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
//寻找指定方向最近item
|
|
324
|
+
private findDirNearest(list: Array<DataNode>, direction: Direction) {
|
|
325
|
+
if (!list || list.length == 0) return null;
|
|
326
|
+
let targetChild: DataNode | null = null;
|
|
327
|
+
let dirDetail = { value: 0 }
|
|
328
|
+
let minDistance = Infinity;
|
|
329
|
+
const dirBit = CONST.dirStrToBit(direction);
|
|
330
|
+
for (let i of list) {
|
|
331
|
+
if (i != this) {
|
|
332
|
+
dirDetail.value = 0
|
|
333
|
+
i.rect.relativeTo(this.rect, dirDetail);
|
|
334
|
+
if (dirDetail.value & dirBit) {
|
|
335
|
+
const d = i.rect.distance(this.rect, true);
|
|
336
|
+
if (d < minDistance) {
|
|
337
|
+
minDistance = d;
|
|
338
|
+
targetChild = i;
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
return targetChild;
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
//描画相关代码
|
|
347
|
+
private customerListener: any = {};
|
|
348
|
+
private mounted: boolean = false;
|
|
349
|
+
private focused: boolean = false;
|
|
350
|
+
private divRef: any = null;
|
|
351
|
+
private lineStyle: any = null;
|
|
352
|
+
|
|
353
|
+
public setLineStyle(style: any) {
|
|
354
|
+
this.lineStyle = style;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
public getLineStyle() { return this.lineStyle; }
|
|
358
|
+
|
|
359
|
+
public onFocus() {
|
|
360
|
+
this.focused = true;
|
|
361
|
+
this.customerListener.onFocus?.()
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
public onBlur() {
|
|
365
|
+
this.focused = false;
|
|
366
|
+
this.customerListener.onBlur?.()
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
public onClick() { this.customerListener.onClick?.() }
|
|
370
|
+
|
|
371
|
+
public getRegister() {
|
|
372
|
+
return {
|
|
373
|
+
register: (name: string, func: Function) => {
|
|
374
|
+
this.customerListener[name] = func;
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
public onRef = (divRef: any) => {
|
|
380
|
+
if (this.divRef == null && !!divRef) {
|
|
381
|
+
// mounted
|
|
382
|
+
this.mounted = true;
|
|
383
|
+
this.divRef = divRef;
|
|
384
|
+
if (this.focused) {
|
|
385
|
+
this.customerListener.onFocus?.();
|
|
386
|
+
}
|
|
387
|
+
} else if (this.divRef != null && !divRef) {
|
|
388
|
+
// unmounted
|
|
389
|
+
this.divRef = null;
|
|
390
|
+
this.mounted = false;
|
|
391
|
+
this.customerListener = {};
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
}
|
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
import * as CONST from "./Constant";
|
|
2
|
+
import { Direction } from "./CommonType";
|
|
3
|
+
|
|
4
|
+
export function opposite(dir: Direction): Direction {
|
|
5
|
+
switch (dir) {
|
|
6
|
+
case "left": return "right"
|
|
7
|
+
case "top": return "bottom"
|
|
8
|
+
case "right": return "left"
|
|
9
|
+
case "bottom": return "top"
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export class Point {
|
|
14
|
+
public x: number = 0;
|
|
15
|
+
public y: number = 0;
|
|
16
|
+
constructor(x: number, y: number) {
|
|
17
|
+
this.x = x;
|
|
18
|
+
this.y = y;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
public distance(p: Point, quad: boolean = false) {
|
|
22
|
+
const qd = (p.x - this.x) ** 2 + (p.y - this.y) ** 2;
|
|
23
|
+
if (quad) {
|
|
24
|
+
return qd;
|
|
25
|
+
} else {
|
|
26
|
+
return Math.sqrt(qd);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* 获取两点指点的相对位置(四向划分, 以45度线为界)
|
|
32
|
+
* @param p
|
|
33
|
+
* @returns
|
|
34
|
+
*/
|
|
35
|
+
public relativeTo(p: Point) {
|
|
36
|
+
const dx = this.x - p.x;
|
|
37
|
+
const dy = this.y - p.y;
|
|
38
|
+
const absDx = Math.abs(dx);
|
|
39
|
+
const absDy = Math.abs(dy)
|
|
40
|
+
if (absDx < absDy) {
|
|
41
|
+
return dy > 0 ? CONST.BOTTOM : CONST.TOP;
|
|
42
|
+
} else {
|
|
43
|
+
return dx > 0 ? CONST.RIGHT : CONST.LEFT;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
public clone() {
|
|
48
|
+
return new Point(this.x, this.y);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export class Line {
|
|
53
|
+
public p0: Point;
|
|
54
|
+
public p1: Point;
|
|
55
|
+
|
|
56
|
+
constructor(p0: Point, p1: Point) {
|
|
57
|
+
this.p0 = p0;
|
|
58
|
+
this.p1 = p1;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
get center() {
|
|
62
|
+
return new Point(Math.round((this.p0.x + this.p1.x) / 2), Math.round((this.p0.y + this.p1.y) / 2))
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export class Rect {
|
|
67
|
+
public x: number;
|
|
68
|
+
public y: number;
|
|
69
|
+
public width: number;
|
|
70
|
+
public height: number;
|
|
71
|
+
|
|
72
|
+
constructor(x: number, y: number, width: number, height: number) {
|
|
73
|
+
this.x = x;
|
|
74
|
+
this.y = y;
|
|
75
|
+
this.width = width;
|
|
76
|
+
this.height = height;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* 计算两个矩形之间的最小距离
|
|
81
|
+
* @param rect
|
|
82
|
+
* @param quad
|
|
83
|
+
* @returns
|
|
84
|
+
*/
|
|
85
|
+
public distance(rect: Rect, quad: boolean = false) {
|
|
86
|
+
// 计算两个矩形的中心点坐标
|
|
87
|
+
const center1 = this.center;
|
|
88
|
+
const center2 = rect.center
|
|
89
|
+
|
|
90
|
+
// 计算中心点之间的水平和垂直距离
|
|
91
|
+
const deltaX = Math.abs(center1.x - center2.x);
|
|
92
|
+
const deltaY = Math.abs(center1.y - center2.y);
|
|
93
|
+
|
|
94
|
+
// 计算最近距离
|
|
95
|
+
const halfWidth1 = this.width / 2;
|
|
96
|
+
const halfHeight1 = this.height / 2;
|
|
97
|
+
const halfWidth2 = rect.width / 2;
|
|
98
|
+
const halfHeight2 = rect.height / 2;
|
|
99
|
+
|
|
100
|
+
const closestX = Math.max(0, deltaX - halfWidth1 - halfWidth2);
|
|
101
|
+
const closestY = Math.max(0, deltaY - halfHeight1 - halfHeight2);
|
|
102
|
+
|
|
103
|
+
if (quad) {
|
|
104
|
+
return closestX * closestX + closestY * closestY;
|
|
105
|
+
} else {
|
|
106
|
+
return Math.sqrt(closestX * closestX + closestY * closestY);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* 获取两个矩形的相对位置
|
|
112
|
+
* @param rect 自身相对于rect的位置
|
|
113
|
+
* @returns
|
|
114
|
+
*/
|
|
115
|
+
public relativeTo(rect: Rect, eightDirInfo: { value: number } | null = null) {
|
|
116
|
+
if (this.distance(rect, true) == 0) {
|
|
117
|
+
//相交的判断中心点的相对位置
|
|
118
|
+
const c1 = this.center;
|
|
119
|
+
const c2 = rect.center;
|
|
120
|
+
if (eightDirInfo) {
|
|
121
|
+
eightDirInfo.value = 0;
|
|
122
|
+
if (c1.x < c2.x) {
|
|
123
|
+
eightDirInfo.value |= CONST.LEFT_BIT
|
|
124
|
+
} else {
|
|
125
|
+
eightDirInfo.value |= CONST.RIGHT_BIT
|
|
126
|
+
}
|
|
127
|
+
if (c1.y < c2.y) {
|
|
128
|
+
eightDirInfo.value |= CONST.TOP_BIT
|
|
129
|
+
} else {
|
|
130
|
+
eightDirInfo.value |= CONST.BOTTOM_BIT
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
return c1.relativeTo(c2);
|
|
134
|
+
} else {
|
|
135
|
+
//处在正向区域中
|
|
136
|
+
if (this.y < rect.y + rect.height - 1 && rect.y < this.y + this.height - 1) {
|
|
137
|
+
if (eightDirInfo) {
|
|
138
|
+
eightDirInfo.value = this.x < rect.x ? CONST.LEFT_BIT : CONST.RIGHT_BIT;
|
|
139
|
+
}
|
|
140
|
+
return this.x < rect.x ? CONST.LEFT : CONST.RIGHT
|
|
141
|
+
} else if (this.x < rect.x + rect.width - 1 && rect.x < this.x + this.width - 1) {
|
|
142
|
+
if (eightDirInfo) {
|
|
143
|
+
eightDirInfo.value = this.y < rect.y ? CONST.TOP_BIT : CONST.BOTTOM_BIT;
|
|
144
|
+
}
|
|
145
|
+
return this.y < rect.y ? CONST.TOP : CONST.BOTTOM
|
|
146
|
+
} else {
|
|
147
|
+
//处在角区域中, 以对应角点的45度区分方位
|
|
148
|
+
if (this.x < rect.x) {
|
|
149
|
+
if (this.y > rect.y) {
|
|
150
|
+
//左下
|
|
151
|
+
if (eightDirInfo) {
|
|
152
|
+
eightDirInfo.value = CONST.LEFT_BIT | CONST.BOTTOM_BIT;
|
|
153
|
+
}
|
|
154
|
+
return this.center.relativeTo(rect.bottomLeft);
|
|
155
|
+
} else {
|
|
156
|
+
//左上
|
|
157
|
+
if (eightDirInfo) {
|
|
158
|
+
eightDirInfo.value = CONST.TOP_BIT | CONST.LEFT_BIT;
|
|
159
|
+
}
|
|
160
|
+
return this.center.relativeTo(rect.topLeft);
|
|
161
|
+
}
|
|
162
|
+
} else {
|
|
163
|
+
if (this.y > rect.y) {
|
|
164
|
+
//右下
|
|
165
|
+
if (eightDirInfo) {
|
|
166
|
+
eightDirInfo.value = CONST.BOTTOM_BIT | CONST.RIGHT_BIT;
|
|
167
|
+
}
|
|
168
|
+
return this.center.relativeTo(rect.bottomRight);
|
|
169
|
+
} else {
|
|
170
|
+
//右上
|
|
171
|
+
if (eightDirInfo) {
|
|
172
|
+
eightDirInfo.value = CONST.TOP_BIT | CONST.RIGHT_BIT;
|
|
173
|
+
}
|
|
174
|
+
return this.center.relativeTo(rect.topRight);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
public getEdge(dir: Direction): Line {
|
|
182
|
+
switch (dir) {
|
|
183
|
+
case "left": return this.leftEdge;
|
|
184
|
+
case "top": return this.topEdge;
|
|
185
|
+
case "right": return this.rightEdge;
|
|
186
|
+
case "bottom": return this.bottomEdge;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
public containPoint(point: Point): boolean {
|
|
191
|
+
return this.x <= point.x
|
|
192
|
+
&& this.x + this.width - 1 >= point.x
|
|
193
|
+
&& this.y <= point.y
|
|
194
|
+
&& this.y + this.height - 1 >= point.y
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
public containRect(rect: Rect): boolean {
|
|
198
|
+
return this.x <= rect.x
|
|
199
|
+
&& this.y <= rect.y
|
|
200
|
+
&& this.x + this.width - 1 >= rect.x + rect.width - 1
|
|
201
|
+
&& this.y + this.height - 1 >= rect.y + rect.height - 1
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* 获取矩形中离点最近的点
|
|
206
|
+
* @param point
|
|
207
|
+
*/
|
|
208
|
+
public getClosestPoint(point: Point): Point {
|
|
209
|
+
if (this.containPoint(point)) {
|
|
210
|
+
return point.clone();
|
|
211
|
+
} else if (this.x <= point.x && this.x + this.width - 1 >= point.x) {
|
|
212
|
+
return new Point(point.x, point.y < this.y ? this.y : this.y + this.width - 1);
|
|
213
|
+
} else if (this.y <= point.y && this.y + this.height - 1 >= point.y) {
|
|
214
|
+
return new Point(point.x < this.x ? this.x : this.x + this.width - 1, point.y);
|
|
215
|
+
} else {
|
|
216
|
+
//角部
|
|
217
|
+
if (point.x < this.x) {
|
|
218
|
+
return point.y < this.y ? this.topLeft : this.bottomLeft;
|
|
219
|
+
} else {
|
|
220
|
+
return point.y < this.y ? this.topRight : this.bottomRight;
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
get topLeft() {
|
|
226
|
+
return new Point(this.x, this.y);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
get topRight() {
|
|
230
|
+
return new Point(this.x + this.width - 1, this.y);
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
get bottomLeft() {
|
|
234
|
+
return new Point(this.x, this.y + this.height - 1);
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
get bottomRight() {
|
|
238
|
+
return new Point(this.x + this.width - 1, this.y + this.height - 1);
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
get center() {
|
|
242
|
+
return new Point(Math.round(this.x + this.width / 2), Math.round(this.y + this.height / 2))
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
get leftEdge() {
|
|
246
|
+
return new Line(this.topLeft, this.bottomLeft);
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
get topEdge() {
|
|
250
|
+
return new Line(this.topLeft, this.topRight);
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
get rightEdge() {
|
|
254
|
+
return new Line(this.topRight, this.bottomRight);
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
get bottomEdge() {
|
|
258
|
+
return new Line(this.bottomLeft, this.bottomRight);
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
get left() { return this.x; }
|
|
262
|
+
|
|
263
|
+
get top() { return this.y; }
|
|
264
|
+
|
|
265
|
+
get right() { return this.x + this.width - 1; }
|
|
266
|
+
|
|
267
|
+
get bottom() { return this.y + this.height - 1; }
|
|
268
|
+
|
|
269
|
+
|
|
270
|
+
get minX() { return this.x; }
|
|
271
|
+
|
|
272
|
+
get maxX() { return this.x + this.width - 1; }
|
|
273
|
+
|
|
274
|
+
get minY() { return this.y; }
|
|
275
|
+
|
|
276
|
+
get maxY() { return this.y + this.height - 1; }
|
|
277
|
+
}
|