leafer-x-tooltip-canvas 1.0.0 → 1.0.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/README.en.md +39 -11
- package/README.md +48 -18
- package/dev/bundle.js +191 -12192
- package/dist/index.cjs +181 -10677
- package/dist/index.esm.js +181 -10677
- package/dist/index.esm.min.js +1 -1
- package/dist/index.js +183 -10677
- package/dist/index.min.cjs +1 -1
- package/dist/index.min.js +1 -1
- package/package.json +62 -51
- package/src/Tooltip.ts +12 -10
- package/src/TooltipPlugin.ts +156 -56
- package/src/constants.ts +21 -0
- package/src/defaultConfig.ts +2 -0
- package/src/interface/config.ts +2 -0
- package/src/utils.ts +86 -25
- package/types/index.d.ts +8 -0
package/package.json
CHANGED
|
@@ -1,52 +1,63 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
"
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
"
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
"
|
|
52
|
-
|
|
2
|
+
"name": "leafer-x-tooltip-canvas",
|
|
3
|
+
"description": "A tooltip plugin for Leafer-ui.",
|
|
4
|
+
"version": "1.0.2",
|
|
5
|
+
"author": "214L",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"type": "module",
|
|
8
|
+
"main": "dist/index.esm.js",
|
|
9
|
+
"exports": {
|
|
10
|
+
"import": "./dist/index.esm.js",
|
|
11
|
+
"require": "./dist/index.cjs"
|
|
12
|
+
},
|
|
13
|
+
"types": "types/index.d.ts",
|
|
14
|
+
"files": [
|
|
15
|
+
"src",
|
|
16
|
+
"types",
|
|
17
|
+
"dev",
|
|
18
|
+
"dist"
|
|
19
|
+
],
|
|
20
|
+
"repository": {
|
|
21
|
+
"type": "git",
|
|
22
|
+
"url": "https://github.com/214L/leafer-x-tooltip-canvas"
|
|
23
|
+
},
|
|
24
|
+
"homepage": "https://github.com/214L/leafer-x-tooltip-canvas",
|
|
25
|
+
"bugs": "https://github.com/214L/leafer-x-tooltip-canvas/issues",
|
|
26
|
+
"scripts": {
|
|
27
|
+
"start": "cross-env NODE_ENV=development rollup -c -w",
|
|
28
|
+
"build": "cross-env PLATFORM=all rollup -c",
|
|
29
|
+
"test": "vitest"
|
|
30
|
+
},
|
|
31
|
+
"devDependencies": {
|
|
32
|
+
"@rollup/plugin-commonjs": "^28.0.9",
|
|
33
|
+
"@rollup/plugin-html": "^2.0.0",
|
|
34
|
+
"@rollup/plugin-multi-entry": "^6.0.0",
|
|
35
|
+
"@rollup/plugin-node-resolve": "^16.0.3",
|
|
36
|
+
"@rollup/plugin-terser": "^0.4.4",
|
|
37
|
+
"@rollup/plugin-typescript": "^12.3.0",
|
|
38
|
+
"@typescript-eslint/eslint-plugin": "^5.54.1",
|
|
39
|
+
"@typescript-eslint/parser": "^5.54.1",
|
|
40
|
+
"cross-env": "^7.0.3",
|
|
41
|
+
"eslint": "^8.49.0",
|
|
42
|
+
"jsdom": "^22.0.0",
|
|
43
|
+
"leafer-ui": "^1.12.2",
|
|
44
|
+
"rollup": "^4.54.0",
|
|
45
|
+
"rollup-plugin-copy": "^3.5.0",
|
|
46
|
+
"rollup-plugin-dts": "^6.3.0",
|
|
47
|
+
"rollup-plugin-livereload": "^2.0.5",
|
|
48
|
+
"rollup-plugin-serve": "^2.0.2",
|
|
49
|
+
"rollup-plugin-string": "^3.0.0",
|
|
50
|
+
"tslib": "^2.6.2",
|
|
51
|
+
"typescript": "^5.2.2",
|
|
52
|
+
"vite": "^4.4.9",
|
|
53
|
+
"vitest": "^0.34.4"
|
|
54
|
+
},
|
|
55
|
+
"dependencies": {
|
|
56
|
+
"@leafer-in/flow": "^1.12.2",
|
|
57
|
+
"@leafer-ui/core": "^1.12.2",
|
|
58
|
+
"leafer-ui": "^1.12.2"
|
|
59
|
+
},
|
|
60
|
+
"publishConfig": {
|
|
61
|
+
"registry": "https://registry.npmjs.org"
|
|
62
|
+
}
|
|
63
|
+
}
|
package/src/Tooltip.ts
CHANGED
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
} from 'leafer-ui'
|
|
10
10
|
import { IPos, IUserConfig } from './interface'
|
|
11
11
|
import { handleTextStyle } from './utils'
|
|
12
|
+
import { TOOLTIP_TAG, TOOLTIP_CLASS_NAME } from './constants'
|
|
12
13
|
|
|
13
14
|
interface ITooltip extends IPen {
|
|
14
15
|
target?: ILeaf
|
|
@@ -40,9 +41,9 @@ export class TooltipData extends PenData implements ITooltipData {
|
|
|
40
41
|
@registerUI()
|
|
41
42
|
export class Tooltip extends Pen implements ITooltip {
|
|
42
43
|
public get __tag() {
|
|
43
|
-
return
|
|
44
|
+
return TOOLTIP_TAG
|
|
44
45
|
}
|
|
45
|
-
public className:
|
|
46
|
+
public className: typeof TOOLTIP_CLASS_NAME
|
|
46
47
|
@dataProcessor(TooltipData)
|
|
47
48
|
public declare __: ITooltipData
|
|
48
49
|
|
|
@@ -93,7 +94,7 @@ export class Tooltip extends Pen implements ITooltip {
|
|
|
93
94
|
})
|
|
94
95
|
this.add(
|
|
95
96
|
new Text({
|
|
96
|
-
className:
|
|
97
|
+
className: TOOLTIP_CLASS_NAME,
|
|
97
98
|
fill: color,
|
|
98
99
|
fontSize,
|
|
99
100
|
fontWeight,
|
|
@@ -130,8 +131,7 @@ export class Tooltip extends Pen implements ITooltip {
|
|
|
130
131
|
this.clearShowHideTimers()
|
|
131
132
|
this.showTimerId = setTimeout(() => {
|
|
132
133
|
this.createShapes(pos)
|
|
133
|
-
|
|
134
|
-
this.showTimerId = null
|
|
134
|
+
this.showTimerId = null // 定时器执行完毕,清空引用
|
|
135
135
|
}, this.config.showDelay)
|
|
136
136
|
}
|
|
137
137
|
|
|
@@ -140,19 +140,21 @@ export class Tooltip extends Pen implements ITooltip {
|
|
|
140
140
|
if (immediate) {
|
|
141
141
|
this.destroy()
|
|
142
142
|
} else {
|
|
143
|
-
if (
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
}
|
|
143
|
+
// 移除 if 判断,确保每次 hide() 都能正确设置定时器
|
|
144
|
+
this.hideTimerId = setTimeout(() => {
|
|
145
|
+
this.destroy()
|
|
146
|
+
this.hideTimerId = null
|
|
147
|
+
}, this.config.hideDelay)
|
|
148
148
|
}
|
|
149
149
|
}
|
|
150
150
|
|
|
151
151
|
public update(pos: IPos) {
|
|
152
152
|
this.clearShowHideTimers()
|
|
153
153
|
if (this.isShow) {
|
|
154
|
+
// 已显示,立即更新位置
|
|
154
155
|
this.createShapes(pos)
|
|
155
156
|
} else {
|
|
157
|
+
// 未显示,启动 show 定时器
|
|
156
158
|
this.show(pos)
|
|
157
159
|
}
|
|
158
160
|
}
|
package/src/TooltipPlugin.ts
CHANGED
|
@@ -1,13 +1,10 @@
|
|
|
1
1
|
import { App, PointerEvent } from '@leafer-ui/core'
|
|
2
|
-
import type {
|
|
3
|
-
IEventListenerId,
|
|
4
|
-
ILeaf,
|
|
5
|
-
ILeafer,
|
|
6
|
-
} from '@leafer-ui/interface'
|
|
2
|
+
import type { IEventListenerId, ILeaf, ILeafer } from '@leafer-ui/interface'
|
|
7
3
|
import { IUserConfig } from './interface'
|
|
8
4
|
import { Tooltip } from './Tooltip'
|
|
9
5
|
import { getTooltipId } from './utils'
|
|
10
6
|
import { defaultConfig } from './defaultConfig'
|
|
7
|
+
import { TOOLTIP_TAG, TOOLTIP_CLASS_NAME } from './constants'
|
|
11
8
|
|
|
12
9
|
export class TooltipPlugin {
|
|
13
10
|
/**
|
|
@@ -28,39 +25,100 @@ export class TooltipPlugin {
|
|
|
28
25
|
*/
|
|
29
26
|
private readonly pointEventId: IEventListenerId
|
|
30
27
|
|
|
28
|
+
/**
|
|
29
|
+
* @param tooltipCache - Tooltip 实例缓存,避免重复 DOM 查询
|
|
30
|
+
* @private
|
|
31
|
+
*/
|
|
32
|
+
private tooltipCache: Map<string, Tooltip> = new Map()
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* @param 类型过滤 Set 缓存,将数组转为 Set 提升查询性能 O(n) -> O(1)
|
|
36
|
+
* @private
|
|
37
|
+
*/
|
|
38
|
+
private includesTypeSet: Set<string> = new Set()
|
|
39
|
+
private excludesTypeSet: Set<string> = new Set()
|
|
40
|
+
private ignoreTypeSet: Set<string> = new Set()
|
|
41
|
+
|
|
31
42
|
constructor(instance: ILeafer | App, config?: IUserConfig) {
|
|
32
43
|
this.instance = instance
|
|
33
|
-
this.config =
|
|
44
|
+
this.config = this.mergeConfig(defaultConfig, config)
|
|
34
45
|
this.handleConfig()
|
|
35
46
|
this.initState()
|
|
36
47
|
this.pointEventId = this.initEvent()
|
|
37
48
|
}
|
|
38
49
|
|
|
50
|
+
/**
|
|
51
|
+
* @description 深度合并配置,避免实例间相互影响
|
|
52
|
+
* @private
|
|
53
|
+
*/
|
|
54
|
+
private mergeConfig(base: IUserConfig, override?: IUserConfig): IUserConfig {
|
|
55
|
+
if (!override) {
|
|
56
|
+
// 深拷贝默认配置
|
|
57
|
+
return {
|
|
58
|
+
...base,
|
|
59
|
+
style: { ...base.style },
|
|
60
|
+
includesType: [...(base.includesType || [])],
|
|
61
|
+
excludesType: [...(base.excludesType || [])],
|
|
62
|
+
ignoreType: [...(base.ignoreType || [])],
|
|
63
|
+
info: [...(base.info || [])],
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// 深度合并用户配置
|
|
68
|
+
return {
|
|
69
|
+
...base,
|
|
70
|
+
...override,
|
|
71
|
+
style: {
|
|
72
|
+
...base.style,
|
|
73
|
+
...override.style,
|
|
74
|
+
},
|
|
75
|
+
includesType: override.includesType || base.includesType,
|
|
76
|
+
excludesType: override.excludesType || base.excludesType,
|
|
77
|
+
ignoreType: override.ignoreType || base.ignoreType,
|
|
78
|
+
info: override.info || base.info,
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* @description 类型守卫: 判断实例是否为 App
|
|
84
|
+
* @private
|
|
85
|
+
*/
|
|
86
|
+
private isAppInstance(instance: ILeafer | App): instance is App {
|
|
87
|
+
return instance.isApp === true
|
|
88
|
+
}
|
|
89
|
+
|
|
39
90
|
/**
|
|
40
91
|
* @description 初始化状态
|
|
41
92
|
*/
|
|
42
93
|
private initState() {
|
|
43
|
-
if (this.instance
|
|
44
|
-
|
|
45
|
-
if (
|
|
46
|
-
|
|
94
|
+
if (this.isAppInstance(this.instance)) {
|
|
95
|
+
// TypeScript 自动推断 this.instance 为 App 类型
|
|
96
|
+
if (this.instance.sky === undefined) {
|
|
97
|
+
this.instance.sky = this.instance.addLeafer({
|
|
47
98
|
type: 'draw',
|
|
48
99
|
usePartRender: false,
|
|
49
100
|
})
|
|
50
101
|
}
|
|
51
|
-
this.aimLeafer =
|
|
102
|
+
this.aimLeafer = this.instance.sky
|
|
52
103
|
} else if (this.instance.isLeafer) {
|
|
53
104
|
this.aimLeafer = this.instance
|
|
105
|
+
} else {
|
|
106
|
+
throw new Error('TooltipPlugin: Instance must be either App or Leafer')
|
|
54
107
|
}
|
|
55
108
|
}
|
|
56
109
|
|
|
57
|
-
private handleConfig(){
|
|
58
|
-
if(this.config.theme==='dark'){
|
|
59
|
-
this.config.style.backgroundColor =
|
|
60
|
-
this.config.style.color =
|
|
61
|
-
}
|
|
110
|
+
private handleConfig() {
|
|
111
|
+
if (this.config.theme === 'dark') {
|
|
112
|
+
this.config.style.backgroundColor = 'black'
|
|
113
|
+
this.config.style.color = 'white'
|
|
62
114
|
}
|
|
63
|
-
|
|
115
|
+
|
|
116
|
+
// 初始化类型过滤 Set,提升查询性能
|
|
117
|
+
this.includesTypeSet = new Set(this.config.includesType || [])
|
|
118
|
+
this.excludesTypeSet = new Set(this.config.excludesType || [])
|
|
119
|
+
this.ignoreTypeSet = new Set(this.config.ignoreType || [])
|
|
120
|
+
}
|
|
121
|
+
|
|
64
122
|
/**
|
|
65
123
|
* @description 初始化事件处理
|
|
66
124
|
* @private
|
|
@@ -95,14 +153,19 @@ export class TooltipPlugin {
|
|
|
95
153
|
}
|
|
96
154
|
this.handleTooltip(event, target)
|
|
97
155
|
}
|
|
98
|
-
|
|
99
156
|
private filterTarget(list: ILeaf[]): ILeaf | null {
|
|
100
|
-
const
|
|
157
|
+
const { throughExcludes } = this.config
|
|
158
|
+
|
|
101
159
|
const pureResult = list.filter((item) => {
|
|
160
|
+
// 使用 Set.has() 代替 Array.includes(),性能提升
|
|
161
|
+
const shouldIgnore = this.ignoreTypeSet.has(item?.tag)
|
|
162
|
+
const shouldExclude = throughExcludes && this.excludesTypeSet.has(item?.tag)
|
|
163
|
+
|
|
102
164
|
if (
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
item?.
|
|
165
|
+
shouldIgnore ||
|
|
166
|
+
shouldExclude ||
|
|
167
|
+
item?.parent?.tag === TOOLTIP_TAG ||
|
|
168
|
+
item?.className === TOOLTIP_CLASS_NAME
|
|
106
169
|
) {
|
|
107
170
|
return false
|
|
108
171
|
}
|
|
@@ -117,28 +180,48 @@ export class TooltipPlugin {
|
|
|
117
180
|
* @param target 目标节点
|
|
118
181
|
* @returns
|
|
119
182
|
*/
|
|
120
|
-
private handleAllowed(target: ILeaf) {
|
|
121
|
-
const
|
|
122
|
-
const { includesType, excludesType } = this.config
|
|
183
|
+
private handleAllowed(target: ILeaf): boolean {
|
|
184
|
+
const targetIdentifiers = ['#' + target.id, '.' + target.className, target.tag]
|
|
123
185
|
|
|
124
|
-
|
|
186
|
+
const hasIncludesRule = this.includesTypeSet.size > 0
|
|
187
|
+
const hasExcludesRule = this.excludesTypeSet.size > 0
|
|
188
|
+
|
|
189
|
+
// 如果没有配置任何过滤规则,默认允许
|
|
190
|
+
if (!hasIncludesRule && !hasExcludesRule) {
|
|
191
|
+
return true
|
|
192
|
+
}
|
|
125
193
|
|
|
126
|
-
const
|
|
127
|
-
const
|
|
194
|
+
const matchesInclude = targetIdentifiers.some((id) => this.includesTypeSet.has(id))
|
|
195
|
+
const matchesExclude = targetIdentifiers.some((id) => this.excludesTypeSet.has(id))
|
|
128
196
|
|
|
129
|
-
|
|
130
|
-
if (
|
|
131
|
-
return
|
|
197
|
+
// includes 优先级高于 excludes
|
|
198
|
+
if (matchesInclude) return true // 匹配白名单,直接允许(即使也在黑名单中)
|
|
199
|
+
if (matchesExclude) return false // 不在白名单但在黑名单,拒绝
|
|
200
|
+
|
|
201
|
+
// 两者都不匹配的情况
|
|
202
|
+
if (hasIncludesRule) return false // 有白名单规则但不匹配 → 拒绝
|
|
203
|
+
return true // 只有黑名单规则且不匹配 → 允许
|
|
132
204
|
}
|
|
133
205
|
|
|
134
206
|
/**
|
|
135
207
|
* @description 隐藏 tooltip
|
|
136
208
|
*/
|
|
137
209
|
private hideTooltip() {
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
210
|
+
// 使用缓存而不是 DOM 查询,提升性能
|
|
211
|
+
// 同时清理已销毁的实例
|
|
212
|
+
const invalidIds: string[] = []
|
|
213
|
+
|
|
214
|
+
this.tooltipCache.forEach((tooltip, id) => {
|
|
215
|
+
if (tooltip.parent) {
|
|
216
|
+
tooltip.hide()
|
|
217
|
+
} else {
|
|
218
|
+
// 标记无效的缓存条目
|
|
219
|
+
invalidIds.push(id)
|
|
220
|
+
}
|
|
141
221
|
})
|
|
222
|
+
|
|
223
|
+
// 清理无效缓存
|
|
224
|
+
invalidIds.forEach(id => this.tooltipCache.delete(id))
|
|
142
225
|
}
|
|
143
226
|
|
|
144
227
|
/**
|
|
@@ -146,26 +229,33 @@ export class TooltipPlugin {
|
|
|
146
229
|
*/
|
|
147
230
|
private handleTooltip(event: PointerEvent, target: ILeaf) {
|
|
148
231
|
const id = getTooltipId(target)
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
if (
|
|
153
|
-
tooltip.update({ x: event.x, y: event.y })
|
|
154
|
-
processed = true
|
|
155
|
-
} else {
|
|
232
|
+
|
|
233
|
+
// 隐藏其他 tooltip
|
|
234
|
+
this.tooltipCache.forEach((tooltip, cacheId) => {
|
|
235
|
+
if (cacheId !== id) {
|
|
156
236
|
tooltip.hide()
|
|
157
237
|
}
|
|
158
|
-
}
|
|
238
|
+
})
|
|
159
239
|
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
240
|
+
// 检查缓存中的实例是否仍然有效(未被销毁)
|
|
241
|
+
const cachedTooltip = this.tooltipCache.get(id)
|
|
242
|
+
if (cachedTooltip && cachedTooltip.parent) {
|
|
243
|
+
// 实例有效,直接更新
|
|
244
|
+
cachedTooltip.update({ x: event.x, y: event.y })
|
|
245
|
+
} else {
|
|
246
|
+
// 实例已被销毁或不存在,移除无效缓存并创建新实例
|
|
247
|
+
if (cachedTooltip) {
|
|
248
|
+
this.tooltipCache.delete(id)
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
const tooltip = new Tooltip({
|
|
252
|
+
id,
|
|
253
|
+
pointerPos: { x: event.x, y: event.y },
|
|
254
|
+
target,
|
|
255
|
+
config: this.config,
|
|
256
|
+
})
|
|
257
|
+
this.aimLeafer.add(tooltip)
|
|
258
|
+
this.tooltipCache.set(id, tooltip)
|
|
169
259
|
}
|
|
170
260
|
}
|
|
171
261
|
|
|
@@ -173,14 +263,24 @@ export class TooltipPlugin {
|
|
|
173
263
|
* @description 销毁
|
|
174
264
|
*/
|
|
175
265
|
public destroy() {
|
|
176
|
-
|
|
177
|
-
if (
|
|
178
|
-
|
|
266
|
+
// 防止重复销毁
|
|
267
|
+
if (!this.instance) return
|
|
268
|
+
|
|
269
|
+
// 清理缓存中的所有 tooltip
|
|
270
|
+
if (this.tooltipCache) {
|
|
271
|
+
this.tooltipCache.forEach((tooltip) => {
|
|
179
272
|
tooltip.destroyTooltip()
|
|
180
|
-
|
|
273
|
+
// 使用可选链,防止 parent 为 null/undefined
|
|
274
|
+
tooltip.parent?.remove(tooltip)
|
|
181
275
|
})
|
|
276
|
+
this.tooltipCache.clear()
|
|
182
277
|
}
|
|
183
|
-
|
|
278
|
+
|
|
279
|
+
// 确保事件被正确清理
|
|
280
|
+
if (this.pointEventId) {
|
|
281
|
+
this.instance.off_(this.pointEventId)
|
|
282
|
+
}
|
|
283
|
+
|
|
184
284
|
this.instance = null
|
|
185
285
|
this.aimLeafer = null
|
|
186
286
|
}
|
package/src/constants.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @description 插件常量定义
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Tooltip 标签名
|
|
7
|
+
*/
|
|
8
|
+
export const TOOLTIP_TAG = 'Tooltip'
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Tooltip class 名称
|
|
12
|
+
*/
|
|
13
|
+
export const TOOLTIP_CLASS_NAME = 'leafer-x-tooltip'
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* 显示类型枚举
|
|
17
|
+
*/
|
|
18
|
+
export enum ShowType {
|
|
19
|
+
VALUE = 'value',
|
|
20
|
+
KEY_VALUE = 'key-value',
|
|
21
|
+
}
|
package/src/defaultConfig.ts
CHANGED
package/src/interface/config.ts
CHANGED
package/src/utils.ts
CHANGED
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
import { Box } from 'leafer-ui'
|
|
2
2
|
import { ILeaf } from '@leafer-ui/interface'
|
|
3
3
|
import { IUserConfig } from './interface'
|
|
4
|
+
import { ShowType } from './constants'
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* @description 文本尺寸缓存,避免重复计算
|
|
8
|
+
*/
|
|
9
|
+
const textSizeCache = new Map<string, { width: number; height: number }>()
|
|
10
|
+
|
|
4
11
|
/**
|
|
5
12
|
* @description 获取uuid 考虑兼容性问题采用此方法
|
|
6
13
|
* @param length id长度
|
|
@@ -9,44 +16,98 @@ import { IUserConfig } from './interface'
|
|
|
9
16
|
export const getTooltipId = function (target: ILeaf) {
|
|
10
17
|
return target.tag + target.innerId
|
|
11
18
|
}
|
|
19
|
+
|
|
12
20
|
export const handleTextStyle = function (target: ILeaf, config: IUserConfig) {
|
|
21
|
+
// 参数校验
|
|
22
|
+
if (!target || !config) {
|
|
23
|
+
console.error('handleTextStyle: Invalid parameters')
|
|
24
|
+
return { width: 100, height: 30, text: '' }
|
|
25
|
+
}
|
|
26
|
+
|
|
13
27
|
const str = handleContent(target, config)
|
|
14
28
|
const { fontSize, fontFamily, fontWeight, padding } = config.style
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
29
|
+
|
|
30
|
+
// 生成缓存 key,包含所有影响尺寸的因素
|
|
31
|
+
const cacheKey = `${str}:${fontSize}:${fontFamily}:${fontWeight}:${padding}`
|
|
32
|
+
|
|
33
|
+
// 检查缓存
|
|
34
|
+
if (textSizeCache.has(cacheKey)) {
|
|
35
|
+
const cached = textSizeCache.get(cacheKey)!
|
|
36
|
+
return { ...cached, text: str }
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
try {
|
|
40
|
+
const box = new Box({
|
|
41
|
+
children: [
|
|
42
|
+
{
|
|
43
|
+
tag: 'Text',
|
|
44
|
+
text: str,
|
|
45
|
+
fontSize,
|
|
46
|
+
fontFamily,
|
|
47
|
+
fontWeight,
|
|
48
|
+
padding,
|
|
49
|
+
},
|
|
50
|
+
],
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
const bounds = box.getBounds()
|
|
54
|
+
// 检查 bounds 是否有效
|
|
55
|
+
if (!bounds || bounds.width === undefined || bounds.height === undefined) {
|
|
56
|
+
console.warn('handleTextStyle: Invalid bounds, using default size')
|
|
57
|
+
return { width: 100, height: 30, text: str }
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const { width, height } = bounds
|
|
61
|
+
|
|
62
|
+
// 存入缓存
|
|
63
|
+
textSizeCache.set(cacheKey, { width, height })
|
|
64
|
+
|
|
65
|
+
return { width, height, text: str }
|
|
66
|
+
} catch (error) {
|
|
67
|
+
console.error('handleTextStyle: Failed to calculate text size', error)
|
|
68
|
+
return { width: 100, height: 30, text: str }
|
|
69
|
+
}
|
|
30
70
|
}
|
|
31
71
|
|
|
32
72
|
function handleContent(target: ILeaf, config: IUserConfig) {
|
|
33
73
|
let str = ''
|
|
34
|
-
|
|
35
|
-
|
|
74
|
+
// 保持 ILeaf 类型,使用 Record 进行更安全的索引访问
|
|
75
|
+
const data = target as ILeaf & Record<string, unknown>
|
|
76
|
+
|
|
36
77
|
// 如果formatter函数存在,则使用formatter函数进行格式化
|
|
37
|
-
if (config.formatter
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
78
|
+
if (config.formatter && typeof config.formatter === 'function') {
|
|
79
|
+
try {
|
|
80
|
+
const formatted = config.formatter(data)
|
|
81
|
+
if (formatted !== undefined) {
|
|
82
|
+
str = formatted
|
|
83
|
+
}
|
|
84
|
+
} catch (error) {
|
|
85
|
+
console.error('handleContent: Formatter function error', error)
|
|
86
|
+
// formatter 失败时降级到默认格式化
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// 如果formatter函数不存在或执行失败,则根据showType进行默认格式化
|
|
91
|
+
if (!str) {
|
|
92
|
+
if (config.showType === ShowType.VALUE) {
|
|
42
93
|
str += config.info
|
|
43
|
-
.map((dataName: string) =>
|
|
94
|
+
.map((dataName: string) => {
|
|
95
|
+
const value = data[dataName]
|
|
96
|
+
// 检查值是否存在且可转换为字符串
|
|
97
|
+
return value !== null && value !== undefined ? String(value) : ''
|
|
98
|
+
})
|
|
44
99
|
.join('\n')
|
|
45
|
-
} else if (config.showType
|
|
100
|
+
} else if (config.showType === ShowType.KEY_VALUE) {
|
|
46
101
|
str += config.info
|
|
47
|
-
.map((dataName: string) =>
|
|
102
|
+
.map((dataName: string) => {
|
|
103
|
+
const value = data[dataName]
|
|
104
|
+
// 检查值是否存在且可转换为字符串
|
|
105
|
+
const displayValue = value !== null && value !== undefined ? String(value) : ''
|
|
106
|
+
return `${dataName} : ${displayValue}`
|
|
107
|
+
})
|
|
48
108
|
.join('\n')
|
|
49
109
|
}
|
|
50
110
|
}
|
|
111
|
+
|
|
51
112
|
return str
|
|
52
113
|
}
|