zrender-nightly 5.6.2-dev.20250624 → 5.6.2-dev.20250625
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/zrender.js +491 -253
- package/dist/zrender.js.map +1 -1
- package/dist/zrender.min.js +1 -1
- package/lib/Element.d.ts +4 -0
- package/lib/Element.js +34 -16
- package/lib/Handler.js +1 -1
- package/lib/Storage.js +20 -20
- package/lib/contain/text.d.ts +14 -2
- package/lib/contain/text.js +65 -15
- package/lib/core/BoundingRect.d.ts +25 -3
- package/lib/core/BoundingRect.js +182 -76
- package/lib/core/OrientedBoundingRect.d.ts +2 -2
- package/lib/core/OrientedBoundingRect.js +50 -34
- package/lib/core/PathProxy.d.ts +1 -0
- package/lib/core/PathProxy.js +16 -1
- package/lib/core/types.d.ts +1 -0
- package/lib/core/util.d.ts +1 -0
- package/lib/core/util.js +1 -0
- package/lib/graphic/Displayable.js +1 -1
- package/lib/graphic/Text.d.ts +3 -2
- package/lib/graphic/Text.js +20 -13
- package/lib/graphic/helper/parseText.d.ts +11 -4
- package/lib/graphic/helper/parseText.js +71 -44
- package/lib/svg-legacy/helper/ClippathManager.js +6 -6
- package/lib/tool/color.d.ts +1 -1
- package/lib/tool/color.js +4 -4
- package/lib/tool/path.js +7 -4
- package/lib/zrender.d.ts +1 -1
- package/lib/zrender.js +1 -1
- package/package.json +3 -2
- package/src/Element.ts +69 -16
- package/src/Handler.ts +1 -1
- package/src/Storage.ts +25 -24
- package/src/canvas/helper.ts +1 -1
- package/src/contain/text.ts +103 -19
- package/src/core/BoundingRect.ts +308 -87
- package/src/core/OrientedBoundingRect.ts +86 -46
- package/src/core/PathProxy.ts +17 -1
- package/src/core/Transformable.ts +2 -0
- package/src/core/matrix.ts +2 -1
- package/src/core/types.ts +2 -0
- package/src/core/util.ts +3 -1
- package/src/graphic/Displayable.ts +1 -3
- package/src/graphic/Group.ts +2 -0
- package/src/graphic/Text.ts +59 -22
- package/src/graphic/helper/parseText.ts +151 -73
- package/src/svg-legacy/helper/ClippathManager.ts +5 -5
- package/src/tool/color.ts +13 -9
- package/src/tool/path.ts +9 -4
- package/src/zrender.ts +1 -1
package/src/Storage.ts
CHANGED
|
@@ -8,6 +8,7 @@ import timsort from './core/timsort';
|
|
|
8
8
|
import Displayable from './graphic/Displayable';
|
|
9
9
|
import Path from './graphic/Path';
|
|
10
10
|
import { REDRAW_BIT } from './graphic/constants';
|
|
11
|
+
import { NullUndefined } from './core/types';
|
|
11
12
|
|
|
12
13
|
let invalidZErrorLogged = false;
|
|
13
14
|
function logInvalidZError() {
|
|
@@ -83,7 +84,7 @@ export default class Storage {
|
|
|
83
84
|
|
|
84
85
|
private _updateAndAddDisplayable(
|
|
85
86
|
el: Element,
|
|
86
|
-
|
|
87
|
+
parentClipPaths: Path[] | NullUndefined,
|
|
87
88
|
includeIgnore?: boolean
|
|
88
89
|
) {
|
|
89
90
|
if (el.ignore && !includeIgnore) {
|
|
@@ -95,18 +96,21 @@ export default class Storage {
|
|
|
95
96
|
el.afterUpdate();
|
|
96
97
|
|
|
97
98
|
const userSetClipPath = el.getClipPath();
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
if (
|
|
106
|
-
|
|
99
|
+
const parentHasClipPaths = parentClipPaths && parentClipPaths.length;
|
|
100
|
+
let clipPathIdx = 0;
|
|
101
|
+
let thisClipPaths = el.__clipPaths;
|
|
102
|
+
|
|
103
|
+
if (!el.ignoreClip
|
|
104
|
+
&& (parentHasClipPaths || userSetClipPath)
|
|
105
|
+
) { // has clipPath in this pass
|
|
106
|
+
if (!thisClipPaths) {
|
|
107
|
+
thisClipPaths = el.__clipPaths = [];
|
|
107
108
|
}
|
|
108
|
-
|
|
109
|
-
|
|
109
|
+
if (parentHasClipPaths) {
|
|
110
|
+
// PENDING: performance?
|
|
111
|
+
for (let idx = 0; idx < parentClipPaths.length; idx++) {
|
|
112
|
+
thisClipPaths[clipPathIdx++] = parentClipPaths[idx];
|
|
113
|
+
}
|
|
110
114
|
}
|
|
111
115
|
|
|
112
116
|
let currentClipPath = userSetClipPath;
|
|
@@ -118,13 +122,17 @@ export default class Storage {
|
|
|
118
122
|
currentClipPath.parent = parentClipPath as Group;
|
|
119
123
|
currentClipPath.updateTransform();
|
|
120
124
|
|
|
121
|
-
|
|
125
|
+
thisClipPaths[clipPathIdx++] = currentClipPath;
|
|
122
126
|
|
|
123
127
|
parentClipPath = currentClipPath;
|
|
124
128
|
currentClipPath = currentClipPath.getClipPath();
|
|
125
129
|
}
|
|
126
130
|
}
|
|
127
131
|
|
|
132
|
+
if (thisClipPaths) { // Remove other old clipPath in array.
|
|
133
|
+
thisClipPaths.length = clipPathIdx;
|
|
134
|
+
}
|
|
135
|
+
|
|
128
136
|
// ZRText and Group and combining morphing Path may use children
|
|
129
137
|
if ((el as GroupLike).childrenRef) {
|
|
130
138
|
const children = (el as GroupLike).childrenRef();
|
|
@@ -137,7 +145,7 @@ export default class Storage {
|
|
|
137
145
|
child.__dirty |= REDRAW_BIT;
|
|
138
146
|
}
|
|
139
147
|
|
|
140
|
-
this._updateAndAddDisplayable(child,
|
|
148
|
+
this._updateAndAddDisplayable(child, thisClipPaths, includeIgnore);
|
|
141
149
|
}
|
|
142
150
|
|
|
143
151
|
// Mark group clean here
|
|
@@ -146,13 +154,6 @@ export default class Storage {
|
|
|
146
154
|
}
|
|
147
155
|
else {
|
|
148
156
|
const disp = el as Displayable;
|
|
149
|
-
// Element is displayable
|
|
150
|
-
if (clipPaths && clipPaths.length) {
|
|
151
|
-
disp.__clipPaths = clipPaths;
|
|
152
|
-
}
|
|
153
|
-
else if (disp.__clipPaths && disp.__clipPaths.length > 0) {
|
|
154
|
-
disp.__clipPaths = [];
|
|
155
|
-
}
|
|
156
157
|
|
|
157
158
|
// Avoid invalid z, z2, zlevel cause sorting error.
|
|
158
159
|
if (isNaN(disp.z)) {
|
|
@@ -174,18 +175,18 @@ export default class Storage {
|
|
|
174
175
|
// Add decal
|
|
175
176
|
const decalEl = (el as Path).getDecalElement && (el as Path).getDecalElement();
|
|
176
177
|
if (decalEl) {
|
|
177
|
-
this._updateAndAddDisplayable(decalEl,
|
|
178
|
+
this._updateAndAddDisplayable(decalEl, thisClipPaths, includeIgnore);
|
|
178
179
|
}
|
|
179
180
|
|
|
180
181
|
// Add attached text element and guide line.
|
|
181
182
|
const textGuide = el.getTextGuideLine();
|
|
182
183
|
if (textGuide) {
|
|
183
|
-
this._updateAndAddDisplayable(textGuide,
|
|
184
|
+
this._updateAndAddDisplayable(textGuide, thisClipPaths, includeIgnore);
|
|
184
185
|
}
|
|
185
186
|
|
|
186
187
|
const textEl = el.getTextContent();
|
|
187
188
|
if (textEl) {
|
|
188
|
-
this._updateAndAddDisplayable(textEl,
|
|
189
|
+
this._updateAndAddDisplayable(textEl, thisClipPaths, includeIgnore);
|
|
189
190
|
}
|
|
190
191
|
}
|
|
191
192
|
|
package/src/canvas/helper.ts
CHANGED
|
@@ -82,8 +82,8 @@ export function getCanvasGradient(this: void, ctx: CanvasRenderingContext2D, obj
|
|
|
82
82
|
return canvasGradient;
|
|
83
83
|
}
|
|
84
84
|
|
|
85
|
+
// [CAVEAT] Assume the clipPaths array is never modified during a batch of `isClipPathChanged` calling.
|
|
85
86
|
export function isClipPathChanged(clipPaths: Path[], prevClipPaths: Path[]): boolean {
|
|
86
|
-
// displayable.__clipPaths can only be `null`/`undefined` or an non-empty array.
|
|
87
87
|
if (clipPaths === prevClipPaths || (!clipPaths && !prevClipPaths)) {
|
|
88
88
|
return false;
|
|
89
89
|
}
|
package/src/contain/text.ts
CHANGED
|
@@ -1,25 +1,110 @@
|
|
|
1
1
|
import BoundingRect, { RectLike } from '../core/BoundingRect';
|
|
2
|
-
import {
|
|
2
|
+
import { TextAlign, TextVerticalAlign, BuiltinTextPosition } from '../core/types';
|
|
3
3
|
import LRU from '../core/LRU';
|
|
4
4
|
import { DEFAULT_FONT, platformApi } from '../core/platform';
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
/**
|
|
7
|
+
* @deprecated But keep for possible outside usage.
|
|
8
|
+
* Use `ensureFontMeasureInfo` + `measureWidth` instead.
|
|
9
|
+
*/
|
|
8
10
|
export function getWidth(text: string, font: string): number {
|
|
11
|
+
return measureWidth(ensureFontMeasureInfo(font), text);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export interface FontMeasureInfo {
|
|
15
|
+
font: string;
|
|
16
|
+
strWidthCache: LRU<number>;
|
|
17
|
+
// Key: char code, index: 0~127 (include 127)
|
|
18
|
+
asciiWidthMap: number[] | null | undefined;
|
|
19
|
+
asciiWidthMapTried: boolean;
|
|
20
|
+
// Default width char width used both in non-ascii and line height.
|
|
21
|
+
stWideCharWidth: number;
|
|
22
|
+
// Default asc char width
|
|
23
|
+
asciiCharWidth: number;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function ensureFontMeasureInfo(font: string): FontMeasureInfo {
|
|
27
|
+
if (!_fontMeasureInfoCache) {
|
|
28
|
+
_fontMeasureInfoCache = new LRU(100);
|
|
29
|
+
}
|
|
9
30
|
font = font || DEFAULT_FONT;
|
|
10
|
-
let
|
|
11
|
-
if (!
|
|
12
|
-
|
|
31
|
+
let measureInfo = _fontMeasureInfoCache.get(font);
|
|
32
|
+
if (!measureInfo) {
|
|
33
|
+
measureInfo = {
|
|
34
|
+
font: font,
|
|
35
|
+
strWidthCache: new LRU(500),
|
|
36
|
+
asciiWidthMap: null, // Init lazily for performance.
|
|
37
|
+
asciiWidthMapTried: false,
|
|
38
|
+
// FIXME
|
|
39
|
+
// Other languages?
|
|
40
|
+
// FIXME
|
|
41
|
+
// Consider proportional font?
|
|
42
|
+
stWideCharWidth: platformApi.measureText('国', font).width,
|
|
43
|
+
asciiCharWidth: platformApi.measureText('a', font).width,
|
|
44
|
+
};
|
|
45
|
+
_fontMeasureInfoCache.put(font, measureInfo);
|
|
13
46
|
}
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
47
|
+
return measureInfo;
|
|
48
|
+
}
|
|
49
|
+
let _fontMeasureInfoCache: LRU<FontMeasureInfo>;
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* For getting more precise result in truncate.
|
|
53
|
+
* non-monospace font vary in char width.
|
|
54
|
+
* But if it is time consuming in some platform, return null/undefined.
|
|
55
|
+
* @return Key: char code, index: 0~127 (include 127)
|
|
56
|
+
*/
|
|
57
|
+
function tryCreateASCIIWidthMap(font: string): FontMeasureInfo['asciiWidthMap'] {
|
|
58
|
+
// PENDING: is it necessary? Re-examine it if bad case reported.
|
|
59
|
+
if (_getASCIIWidthMapLongCount >= GET_ASCII_WIDTH_LONG_COUNT_MAX) {
|
|
60
|
+
return;
|
|
18
61
|
}
|
|
62
|
+
font = font || DEFAULT_FONT;
|
|
63
|
+
const asciiWidthMap = [];
|
|
64
|
+
const start = +(new Date());
|
|
65
|
+
// 0~31 and 127 may also have width, and may vary in some fonts.
|
|
66
|
+
for (let code = 0; code <= 127; code++) {
|
|
67
|
+
asciiWidthMap[code] = platformApi.measureText(String.fromCharCode(code), font).width;
|
|
68
|
+
}
|
|
69
|
+
const cost = +(new Date()) - start;
|
|
70
|
+
if (cost > 16) {
|
|
71
|
+
_getASCIIWidthMapLongCount = GET_ASCII_WIDTH_LONG_COUNT_MAX;
|
|
72
|
+
}
|
|
73
|
+
else if (cost > 2) {
|
|
74
|
+
_getASCIIWidthMapLongCount++;
|
|
75
|
+
}
|
|
76
|
+
return asciiWidthMap;
|
|
77
|
+
}
|
|
78
|
+
let _getASCIIWidthMapLongCount: number = 0;
|
|
79
|
+
const GET_ASCII_WIDTH_LONG_COUNT_MAX = 5;
|
|
19
80
|
|
|
81
|
+
/**
|
|
82
|
+
* Hot path, performance sensitive.
|
|
83
|
+
*/
|
|
84
|
+
export function measureCharWidth(fontMeasureInfo: FontMeasureInfo, charCode: number): number {
|
|
85
|
+
if (!fontMeasureInfo.asciiWidthMapTried) {
|
|
86
|
+
fontMeasureInfo.asciiWidthMap = tryCreateASCIIWidthMap(fontMeasureInfo.font);
|
|
87
|
+
fontMeasureInfo.asciiWidthMapTried = true;
|
|
88
|
+
}
|
|
89
|
+
return (0 <= charCode && charCode <= 127)
|
|
90
|
+
? (fontMeasureInfo.asciiWidthMap != null
|
|
91
|
+
? fontMeasureInfo.asciiWidthMap[charCode]
|
|
92
|
+
: fontMeasureInfo.asciiCharWidth
|
|
93
|
+
)
|
|
94
|
+
: fontMeasureInfo.stWideCharWidth;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export function measureWidth(fontMeasureInfo: FontMeasureInfo, text: string): number {
|
|
98
|
+
const strWidthCache = fontMeasureInfo.strWidthCache;
|
|
99
|
+
let width = strWidthCache.get(text);
|
|
100
|
+
if (width == null) {
|
|
101
|
+
width = platformApi.measureText(text, fontMeasureInfo.font).width;
|
|
102
|
+
strWidthCache.put(text, width);
|
|
103
|
+
}
|
|
20
104
|
return width;
|
|
21
105
|
}
|
|
22
106
|
|
|
107
|
+
|
|
23
108
|
/**
|
|
24
109
|
*
|
|
25
110
|
* Get bounding rect for inner usage(TSpan)
|
|
@@ -31,7 +116,7 @@ export function innerGetBoundingRect(
|
|
|
31
116
|
textAlign?: TextAlign,
|
|
32
117
|
textBaseline?: TextVerticalAlign
|
|
33
118
|
): BoundingRect {
|
|
34
|
-
const width =
|
|
119
|
+
const width = measureWidth(ensureFontMeasureInfo(font), text);
|
|
35
120
|
const height = getLineHeight(font);
|
|
36
121
|
|
|
37
122
|
const x = adjustTextX(0, width, textAlign);
|
|
@@ -68,31 +153,30 @@ export function getBoundingRect(
|
|
|
68
153
|
}
|
|
69
154
|
}
|
|
70
155
|
|
|
71
|
-
export function adjustTextX(x: number, width: number, textAlign: TextAlign): number {
|
|
156
|
+
export function adjustTextX(x: number, width: number, textAlign: TextAlign, inverse?: boolean): number {
|
|
72
157
|
// TODO Right to left language
|
|
73
158
|
if (textAlign === 'right') {
|
|
74
|
-
x -= width;
|
|
159
|
+
!inverse ? (x -= width) : (x += width);
|
|
75
160
|
}
|
|
76
161
|
else if (textAlign === 'center') {
|
|
77
|
-
x -= width / 2;
|
|
162
|
+
!inverse ? (x -= width / 2) : (x += width / 2);
|
|
78
163
|
}
|
|
79
164
|
return x;
|
|
80
165
|
}
|
|
81
166
|
|
|
82
|
-
export function adjustTextY(y: number, height: number, verticalAlign: TextVerticalAlign): number {
|
|
167
|
+
export function adjustTextY(y: number, height: number, verticalAlign: TextVerticalAlign, inverse?: boolean): number {
|
|
83
168
|
if (verticalAlign === 'middle') {
|
|
84
|
-
y -= height / 2;
|
|
169
|
+
!inverse ? (y -= height / 2) : (y += height / 2);
|
|
85
170
|
}
|
|
86
171
|
else if (verticalAlign === 'bottom') {
|
|
87
|
-
y -= height;
|
|
172
|
+
!inverse ? (y -= height) : (y += height);
|
|
88
173
|
}
|
|
89
174
|
return y;
|
|
90
175
|
}
|
|
91
176
|
|
|
92
|
-
|
|
93
177
|
export function getLineHeight(font?: string): number {
|
|
94
178
|
// FIXME A rough approach.
|
|
95
|
-
return
|
|
179
|
+
return ensureFontMeasureInfo(font).stWideCharWidth;
|
|
96
180
|
}
|
|
97
181
|
|
|
98
182
|
export function measureText(text: string, font?: string): {
|