zrender-nightly 5.6.2-dev.20250623 → 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
|
@@ -3,11 +3,16 @@ import {
|
|
|
3
3
|
extend,
|
|
4
4
|
retrieve2,
|
|
5
5
|
retrieve3,
|
|
6
|
-
reduce
|
|
6
|
+
reduce,
|
|
7
7
|
} from '../../core/util';
|
|
8
|
-
import { TextAlign, TextVerticalAlign, ImageLike, Dictionary } from '../../core/types';
|
|
9
|
-
import { TextStyleProps } from '../Text';
|
|
10
|
-
import {
|
|
8
|
+
import { TextAlign, TextVerticalAlign, ImageLike, Dictionary, NullUndefined } from '../../core/types';
|
|
9
|
+
import { DefaultTextStyle, TextStyleProps } from '../Text';
|
|
10
|
+
import {
|
|
11
|
+
adjustTextX,
|
|
12
|
+
adjustTextY,
|
|
13
|
+
ensureFontMeasureInfo, FontMeasureInfo, getLineHeight, measureCharWidth, measureWidth, parsePercent,
|
|
14
|
+
} from '../../contain/text';
|
|
15
|
+
import BoundingRect, { BoundingRectIntersectOpt } from '../../core/BoundingRect';
|
|
11
16
|
|
|
12
17
|
const STYLE_REG = /\{([a-zA-Z0-9_]+)\|([^}]*)\}/g;
|
|
13
18
|
|
|
@@ -23,15 +28,12 @@ interface InnerTruncateOption {
|
|
|
23
28
|
}
|
|
24
29
|
|
|
25
30
|
interface InnerPreparedTruncateOption extends Required<InnerTruncateOption> {
|
|
26
|
-
font: string
|
|
27
|
-
|
|
28
31
|
ellipsis: string
|
|
29
32
|
ellipsisWidth: number
|
|
30
33
|
contentWidth: number
|
|
31
34
|
|
|
32
35
|
containerWidth: number
|
|
33
|
-
|
|
34
|
-
ascCharWidth: number
|
|
36
|
+
fontMeasureInfo: FontMeasureInfo
|
|
35
37
|
}
|
|
36
38
|
|
|
37
39
|
/**
|
|
@@ -91,16 +93,11 @@ function prepareTruncateOptions(
|
|
|
91
93
|
options = options || {};
|
|
92
94
|
let preparedOpts = extend({}, options) as InnerPreparedTruncateOption;
|
|
93
95
|
|
|
94
|
-
preparedOpts.font = font;
|
|
95
96
|
ellipsis = retrieve2(ellipsis, '...');
|
|
96
97
|
preparedOpts.maxIterations = retrieve2(options.maxIterations, 2);
|
|
97
98
|
const minChar = preparedOpts.minChar = retrieve2(options.minChar, 0);
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
preparedOpts.cnCharWidth = getWidth('国', font);
|
|
101
|
-
// FIXME
|
|
102
|
-
// Consider proportional font?
|
|
103
|
-
const ascCharWidth = preparedOpts.ascCharWidth = getWidth('a', font);
|
|
99
|
+
const fontMeasureInfo = preparedOpts.fontMeasureInfo = ensureFontMeasureInfo(font);
|
|
100
|
+
const ascCharWidth = fontMeasureInfo.asciiCharWidth;
|
|
104
101
|
preparedOpts.placeholder = retrieve2(options.placeholder, '');
|
|
105
102
|
|
|
106
103
|
// Example 1: minChar: 3, text: 'asdfzxcv', truncate result: 'asdf', but not: 'a...'.
|
|
@@ -110,7 +107,7 @@ function prepareTruncateOptions(
|
|
|
110
107
|
contentWidth -= ascCharWidth;
|
|
111
108
|
}
|
|
112
109
|
|
|
113
|
-
let ellipsisWidth =
|
|
110
|
+
let ellipsisWidth = measureWidth(fontMeasureInfo, ellipsis);
|
|
114
111
|
if (ellipsisWidth > contentWidth) {
|
|
115
112
|
ellipsis = '';
|
|
116
113
|
ellipsisWidth = 0;
|
|
@@ -132,8 +129,8 @@ function truncateSingleLine(
|
|
|
132
129
|
options: InnerPreparedTruncateOption
|
|
133
130
|
): void {
|
|
134
131
|
const containerWidth = options.containerWidth;
|
|
135
|
-
const font = options.font;
|
|
136
132
|
const contentWidth = options.contentWidth;
|
|
133
|
+
const fontMeasureInfo = options.fontMeasureInfo;
|
|
137
134
|
|
|
138
135
|
if (!containerWidth) {
|
|
139
136
|
out.textLine = '';
|
|
@@ -141,7 +138,7 @@ function truncateSingleLine(
|
|
|
141
138
|
return;
|
|
142
139
|
}
|
|
143
140
|
|
|
144
|
-
let lineWidth =
|
|
141
|
+
let lineWidth = measureWidth(fontMeasureInfo, textLine);
|
|
145
142
|
|
|
146
143
|
if (lineWidth <= containerWidth) {
|
|
147
144
|
out.textLine = textLine;
|
|
@@ -156,13 +153,13 @@ function truncateSingleLine(
|
|
|
156
153
|
}
|
|
157
154
|
|
|
158
155
|
const subLength = j === 0
|
|
159
|
-
? estimateLength(textLine, contentWidth,
|
|
156
|
+
? estimateLength(textLine, contentWidth, fontMeasureInfo)
|
|
160
157
|
: lineWidth > 0
|
|
161
158
|
? Math.floor(textLine.length * contentWidth / lineWidth)
|
|
162
159
|
: 0;
|
|
163
160
|
|
|
164
161
|
textLine = textLine.substr(0, subLength);
|
|
165
|
-
lineWidth =
|
|
162
|
+
lineWidth = measureWidth(fontMeasureInfo, textLine);
|
|
166
163
|
}
|
|
167
164
|
|
|
168
165
|
if (textLine === '') {
|
|
@@ -174,13 +171,14 @@ function truncateSingleLine(
|
|
|
174
171
|
}
|
|
175
172
|
|
|
176
173
|
function estimateLength(
|
|
177
|
-
text: string,
|
|
174
|
+
text: string,
|
|
175
|
+
contentWidth: number,
|
|
176
|
+
fontMeasureInfo: FontMeasureInfo
|
|
178
177
|
): number {
|
|
179
178
|
let width = 0;
|
|
180
179
|
let i = 0;
|
|
181
180
|
for (let len = text.length; i < len && width < contentWidth; i++) {
|
|
182
|
-
|
|
183
|
-
width += (0 <= charCode && charCode <= 127) ? ascCharWidth : cnCharWidth;
|
|
181
|
+
width += measureCharWidth(fontMeasureInfo, text.charCodeAt(i));
|
|
184
182
|
}
|
|
185
183
|
return i;
|
|
186
184
|
}
|
|
@@ -190,17 +188,17 @@ export interface PlainTextContentBlock {
|
|
|
190
188
|
// Line height of actual content.
|
|
191
189
|
calculatedLineHeight: number
|
|
192
190
|
|
|
191
|
+
// Calculated based on the text.
|
|
193
192
|
contentWidth: number
|
|
194
193
|
contentHeight: number
|
|
195
194
|
|
|
195
|
+
// i.e., `retrieve2(style.width/height, contentWidth/contentHeight)`
|
|
196
196
|
width: number
|
|
197
197
|
height: number
|
|
198
198
|
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
* and `width` is set by user.
|
|
203
|
-
*/
|
|
199
|
+
// i.e., `contentBlock.width/height + style.padding`
|
|
200
|
+
// `borderWidth` is not included here, because historically Path is placed regardless of `lineWidth`,
|
|
201
|
+
// and `outerWidth`/`outerHeight` is used to calculate placement.
|
|
204
202
|
outerWidth: number
|
|
205
203
|
outerHeight: number
|
|
206
204
|
|
|
@@ -213,23 +211,34 @@ export interface PlainTextContentBlock {
|
|
|
213
211
|
|
|
214
212
|
export function parsePlainText(
|
|
215
213
|
text: string,
|
|
216
|
-
style
|
|
214
|
+
style: Omit<TextStyleProps, 'align' | 'verticalAlign'>, // Exclude props in DefaultTextStyle
|
|
215
|
+
defaultOuterWidth: number | NullUndefined,
|
|
216
|
+
defaultOuterHeight: number | NullUndefined
|
|
217
217
|
): PlainTextContentBlock {
|
|
218
218
|
text != null && (text += '');
|
|
219
219
|
|
|
220
220
|
// textPadding has been normalized
|
|
221
221
|
const overflow = style.overflow;
|
|
222
222
|
const padding = style.padding as number[];
|
|
223
|
+
const paddingH = padding ? padding[1] + padding[3] : 0;
|
|
224
|
+
const paddingV = padding ? padding[0] + padding[2] : 0;
|
|
223
225
|
const font = style.font;
|
|
224
226
|
const truncate = overflow === 'truncate';
|
|
225
227
|
const calculatedLineHeight = getLineHeight(font);
|
|
226
228
|
const lineHeight = retrieve2(style.lineHeight, calculatedLineHeight);
|
|
227
|
-
const bgColorDrawn = !!(style.backgroundColor);
|
|
228
229
|
|
|
229
230
|
const truncateLineOverflow = style.lineOverflow === 'truncate';
|
|
230
231
|
let isTruncated = false;
|
|
231
232
|
|
|
232
233
|
let width = style.width;
|
|
234
|
+
if (width == null && defaultOuterWidth != null) {
|
|
235
|
+
width = defaultOuterWidth - paddingH;
|
|
236
|
+
}
|
|
237
|
+
let height = style.height;
|
|
238
|
+
if (height == null && defaultOuterHeight != null) {
|
|
239
|
+
height = defaultOuterHeight - paddingV;
|
|
240
|
+
}
|
|
241
|
+
|
|
233
242
|
let lines: string[];
|
|
234
243
|
|
|
235
244
|
if (width != null && (overflow === 'break' || overflow === 'breakAll')) {
|
|
@@ -239,8 +248,10 @@ export function parsePlainText(
|
|
|
239
248
|
lines = text ? text.split('\n') : [];
|
|
240
249
|
}
|
|
241
250
|
|
|
242
|
-
|
|
243
|
-
|
|
251
|
+
let contentHeight = lines.length * lineHeight;
|
|
252
|
+
if (height == null) {
|
|
253
|
+
height = contentHeight;
|
|
254
|
+
}
|
|
244
255
|
|
|
245
256
|
// Truncate lines.
|
|
246
257
|
if (contentHeight > height && truncateLineOverflow) {
|
|
@@ -248,6 +259,7 @@ export function parsePlainText(
|
|
|
248
259
|
|
|
249
260
|
isTruncated = isTruncated || (lines.length > lineCount);
|
|
250
261
|
lines = lines.slice(0, lineCount);
|
|
262
|
+
contentHeight = lines.length * lineHeight;
|
|
251
263
|
|
|
252
264
|
// TODO If show ellipse for line truncate
|
|
253
265
|
// if (style.ellipsis) {
|
|
@@ -276,25 +288,18 @@ export function parsePlainText(
|
|
|
276
288
|
// Calculate real text width and height
|
|
277
289
|
let outerHeight = height;
|
|
278
290
|
let contentWidth = 0;
|
|
291
|
+
const fontMeasureInfo = ensureFontMeasureInfo(font);
|
|
279
292
|
for (let i = 0; i < lines.length; i++) {
|
|
280
|
-
contentWidth = Math.max(
|
|
293
|
+
contentWidth = Math.max(measureWidth(fontMeasureInfo, lines[i]), contentWidth);
|
|
281
294
|
}
|
|
282
295
|
if (width == null) {
|
|
283
|
-
// When width is not explicitly set, use
|
|
296
|
+
// When width is not explicitly set, use contentWidth as width.
|
|
284
297
|
width = contentWidth;
|
|
285
298
|
}
|
|
286
299
|
|
|
287
|
-
let outerWidth =
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
outerWidth += padding[1] + padding[3];
|
|
291
|
-
width += padding[1] + padding[3];
|
|
292
|
-
}
|
|
293
|
-
|
|
294
|
-
if (bgColorDrawn) {
|
|
295
|
-
// When render background, outerWidth should be the same as width.
|
|
296
|
-
outerWidth = width;
|
|
297
|
-
}
|
|
300
|
+
let outerWidth = width;
|
|
301
|
+
outerHeight += paddingV;
|
|
302
|
+
outerWidth += paddingH;
|
|
298
303
|
|
|
299
304
|
return {
|
|
300
305
|
lines: lines,
|
|
@@ -313,10 +318,13 @@ export function parsePlainText(
|
|
|
313
318
|
class RichTextToken {
|
|
314
319
|
styleName: string
|
|
315
320
|
text: string
|
|
321
|
+
|
|
322
|
+
// Includes `tokenStyle.padding`
|
|
316
323
|
width: number
|
|
317
324
|
height: number
|
|
318
325
|
|
|
319
326
|
// Inner height exclude padding
|
|
327
|
+
// i.e., `retrieve2(tokenStyle.height, token.contentHeight)`
|
|
320
328
|
innerHeight: number
|
|
321
329
|
|
|
322
330
|
// Width and height of actual text content.
|
|
@@ -345,13 +353,16 @@ class RichTextLine {
|
|
|
345
353
|
}
|
|
346
354
|
}
|
|
347
355
|
export class RichTextContentBlock {
|
|
348
|
-
// width
|
|
356
|
+
// i.e. `retrieve2(outermostStyle.width, contentWidth)`.
|
|
357
|
+
// exclude outermost style.padding.
|
|
349
358
|
width: number = 0
|
|
350
359
|
height: number = 0
|
|
351
|
-
// Calculated text height
|
|
360
|
+
// Calculated text width/height based on content (including tokenStyle.padding).
|
|
352
361
|
contentWidth: number = 0
|
|
353
362
|
contentHeight: number = 0
|
|
354
|
-
//
|
|
363
|
+
// i.e., contentBlock.width/height + outermostStyle.padding
|
|
364
|
+
// `borderWidth` is not included here, because historically Path is placed regardless of `lineWidth`,
|
|
365
|
+
// and `outerWidth`/`outerHeight` is used to calculate placement.
|
|
355
366
|
outerWidth: number = 0
|
|
356
367
|
outerHeight: number = 0
|
|
357
368
|
lines: RichTextLine[] = []
|
|
@@ -370,7 +381,13 @@ type WrapInfo = {
|
|
|
370
381
|
* Also consider 'bbbb{a|xxx\nzzz}xxxx\naaaa'.
|
|
371
382
|
* If styleName is undefined, it is plain text.
|
|
372
383
|
*/
|
|
373
|
-
export function parseRichText(
|
|
384
|
+
export function parseRichText(
|
|
385
|
+
text: string,
|
|
386
|
+
style: Omit<TextStyleProps, 'align' | 'verticalAlign'>, // Exclude props in DefaultTextStyle
|
|
387
|
+
defaultOuterWidth: number | NullUndefined,
|
|
388
|
+
defaultOuterHeight: number | NullUndefined,
|
|
389
|
+
topTextAlign: TextAlign
|
|
390
|
+
): RichTextContentBlock {
|
|
374
391
|
const contentBlock = new RichTextContentBlock();
|
|
375
392
|
|
|
376
393
|
text != null && (text += '');
|
|
@@ -378,8 +395,19 @@ export function parseRichText(text: string, style: TextStyleProps): RichTextCont
|
|
|
378
395
|
return contentBlock;
|
|
379
396
|
}
|
|
380
397
|
|
|
381
|
-
const
|
|
382
|
-
const
|
|
398
|
+
const stlPadding = style.padding as number[];
|
|
399
|
+
const stlPaddingH = stlPadding ? stlPadding[1] + stlPadding[3] : 0;
|
|
400
|
+
const stlPaddingV = stlPadding ? stlPadding[0] + stlPadding[2] : 0;
|
|
401
|
+
|
|
402
|
+
let topWidth = style.width;
|
|
403
|
+
if (topWidth == null && defaultOuterWidth != null) {
|
|
404
|
+
topWidth = defaultOuterWidth - stlPaddingH;
|
|
405
|
+
}
|
|
406
|
+
let topHeight = style.height;
|
|
407
|
+
if (topHeight == null && defaultOuterHeight != null) {
|
|
408
|
+
topHeight = defaultOuterHeight - stlPaddingV;
|
|
409
|
+
}
|
|
410
|
+
|
|
383
411
|
const overflow = style.overflow;
|
|
384
412
|
let wrapInfo: WrapInfo = (overflow === 'break' || overflow === 'breakAll') && topWidth != null
|
|
385
413
|
? {width: topWidth, accumWidth: 0, breakAll: overflow === 'breakAll'}
|
|
@@ -406,8 +434,6 @@ export function parseRichText(text: string, style: TextStyleProps): RichTextCont
|
|
|
406
434
|
let calculatedHeight = 0;
|
|
407
435
|
let calculatedWidth = 0;
|
|
408
436
|
|
|
409
|
-
const stlPadding = style.padding as number[];
|
|
410
|
-
|
|
411
437
|
const truncate = overflow === 'truncate';
|
|
412
438
|
const truncateLine = style.lineOverflow === 'truncate';
|
|
413
439
|
const tmpTruncateOut = {} as Parameters<typeof truncateText2>[0];
|
|
@@ -446,12 +472,12 @@ export function parseRichText(text: string, style: TextStyleProps): RichTextCont
|
|
|
446
472
|
|
|
447
473
|
textPadding && (tokenHeight += textPadding[0] + textPadding[2]);
|
|
448
474
|
token.height = tokenHeight;
|
|
449
|
-
//
|
|
475
|
+
// Include padding in lineHeight.
|
|
450
476
|
token.lineHeight = retrieve3(
|
|
451
477
|
tokenStyle.lineHeight, style.lineHeight, tokenHeight
|
|
452
478
|
);
|
|
453
479
|
|
|
454
|
-
token.align = tokenStyle && tokenStyle.align ||
|
|
480
|
+
token.align = tokenStyle && tokenStyle.align || topTextAlign;
|
|
455
481
|
token.verticalAlign = tokenStyle && tokenStyle.verticalAlign || 'middle';
|
|
456
482
|
|
|
457
483
|
if (truncateLine && topHeight != null && calculatedHeight + token.lineHeight > topHeight) {
|
|
@@ -479,7 +505,7 @@ export function parseRichText(text: string, style: TextStyleProps): RichTextCont
|
|
|
479
505
|
token.percentWidth = styleTokenWidth;
|
|
480
506
|
pendingList.push(token);
|
|
481
507
|
|
|
482
|
-
token.contentWidth =
|
|
508
|
+
token.contentWidth = measureWidth(ensureFontMeasureInfo(font), token.text);
|
|
483
509
|
// Do not truncate in this case, because there is no user case
|
|
484
510
|
// and it is too complicated.
|
|
485
511
|
}
|
|
@@ -515,11 +541,11 @@ export function parseRichText(text: string, style: TextStyleProps): RichTextCont
|
|
|
515
541
|
);
|
|
516
542
|
token.text = tmpTruncateOut.text;
|
|
517
543
|
contentBlock.isTruncated = contentBlock.isTruncated || tmpTruncateOut.isTruncated;
|
|
518
|
-
token.width = token.contentWidth =
|
|
544
|
+
token.width = token.contentWidth = measureWidth(ensureFontMeasureInfo(font), token.text);
|
|
519
545
|
}
|
|
520
546
|
}
|
|
521
547
|
else {
|
|
522
|
-
token.contentWidth =
|
|
548
|
+
token.contentWidth = measureWidth(ensureFontMeasureInfo(font), token.text);
|
|
523
549
|
}
|
|
524
550
|
}
|
|
525
551
|
|
|
@@ -539,10 +565,8 @@ export function parseRichText(text: string, style: TextStyleProps): RichTextCont
|
|
|
539
565
|
contentBlock.contentHeight = calculatedHeight;
|
|
540
566
|
contentBlock.contentWidth = calculatedWidth;
|
|
541
567
|
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
contentBlock.outerHeight += stlPadding[0] + stlPadding[2];
|
|
545
|
-
}
|
|
568
|
+
contentBlock.outerWidth += stlPaddingH;
|
|
569
|
+
contentBlock.outerHeight += stlPaddingV;
|
|
546
570
|
|
|
547
571
|
for (let i = 0; i < pendingList.length; i++) {
|
|
548
572
|
const token = pendingList[i];
|
|
@@ -594,10 +618,12 @@ function pushTokens(
|
|
|
594
618
|
strLines = res.lines;
|
|
595
619
|
}
|
|
596
620
|
}
|
|
597
|
-
|
|
621
|
+
|
|
622
|
+
if (!strLines) {
|
|
598
623
|
strLines = str.split('\n');
|
|
599
624
|
}
|
|
600
625
|
|
|
626
|
+
const fontMeasureInfo = ensureFontMeasureInfo(font);
|
|
601
627
|
for (let i = 0; i < strLines.length; i++) {
|
|
602
628
|
const text = strLines[i];
|
|
603
629
|
const token = new RichTextToken();
|
|
@@ -610,8 +636,8 @@ function pushTokens(
|
|
|
610
636
|
}
|
|
611
637
|
else {
|
|
612
638
|
token.width = linesWidths
|
|
613
|
-
? linesWidths[i] //
|
|
614
|
-
:
|
|
639
|
+
? linesWidths[i] // Calculated width in the wrap
|
|
640
|
+
: measureWidth(fontMeasureInfo, text);
|
|
615
641
|
}
|
|
616
642
|
|
|
617
643
|
// The first token should be appended to the last line if not new line.
|
|
@@ -671,6 +697,11 @@ function isWordBreakChar(ch: string) {
|
|
|
671
697
|
return true;
|
|
672
698
|
}
|
|
673
699
|
|
|
700
|
+
/**
|
|
701
|
+
* NOTE: The current strategy is that if no enough space, all the text is
|
|
702
|
+
* still displayed, regardless of overflow.
|
|
703
|
+
* A clip path can be used to completely avoid overflow.
|
|
704
|
+
*/
|
|
674
705
|
function wrapText(
|
|
675
706
|
text: string,
|
|
676
707
|
font: string,
|
|
@@ -684,6 +715,7 @@ function wrapText(
|
|
|
684
715
|
let currentWord = '';
|
|
685
716
|
let currentWordWidth = 0;
|
|
686
717
|
let accumWidth = 0;
|
|
718
|
+
const fontMeasureInfo = ensureFontMeasureInfo(font);
|
|
687
719
|
|
|
688
720
|
for (let i = 0; i < text.length; i++) {
|
|
689
721
|
|
|
@@ -703,7 +735,7 @@ function wrapText(
|
|
|
703
735
|
continue;
|
|
704
736
|
}
|
|
705
737
|
|
|
706
|
-
const chWidth =
|
|
738
|
+
const chWidth = measureCharWidth(fontMeasureInfo, ch.charCodeAt(0));
|
|
707
739
|
const inWord = isBreakAll ? false : !isWordBreakChar(ch);
|
|
708
740
|
|
|
709
741
|
if (!lines.length
|
|
@@ -785,12 +817,6 @@ function wrapText(
|
|
|
785
817
|
}
|
|
786
818
|
}
|
|
787
819
|
|
|
788
|
-
if (!lines.length && !line) {
|
|
789
|
-
line = text;
|
|
790
|
-
currentWord = '';
|
|
791
|
-
currentWordWidth = 0;
|
|
792
|
-
}
|
|
793
|
-
|
|
794
820
|
// Append last line.
|
|
795
821
|
if (currentWord) {
|
|
796
822
|
line += currentWord;
|
|
@@ -811,4 +837,56 @@ function wrapText(
|
|
|
811
837
|
lines: lines,
|
|
812
838
|
linesWidths
|
|
813
839
|
};
|
|
814
|
-
}
|
|
840
|
+
}
|
|
841
|
+
|
|
842
|
+
/**
|
|
843
|
+
* @see {ElementTextConfig['autoOverflowArea']}
|
|
844
|
+
*/
|
|
845
|
+
export function calcInnerTextOverflowArea(
|
|
846
|
+
out: CalcInnerTextOverflowAreaOut,
|
|
847
|
+
overflowRect: DefaultTextStyle['overflowRect'],
|
|
848
|
+
baseX: number,
|
|
849
|
+
baseY: number,
|
|
850
|
+
textAlign: TextAlign,
|
|
851
|
+
textVerticalAlign: TextVerticalAlign
|
|
852
|
+
): void {
|
|
853
|
+
out.baseX = baseX;
|
|
854
|
+
out.baseY = baseY;
|
|
855
|
+
out.outerWidth = out.outerHeight = null;
|
|
856
|
+
|
|
857
|
+
if (!overflowRect) {
|
|
858
|
+
return;
|
|
859
|
+
}
|
|
860
|
+
|
|
861
|
+
const textWidth = overflowRect.width * 2;
|
|
862
|
+
const textHeight = overflowRect.height * 2;
|
|
863
|
+
BoundingRect.set(
|
|
864
|
+
tmpCITCTextRect,
|
|
865
|
+
adjustTextX(baseX, textWidth, textAlign),
|
|
866
|
+
adjustTextY(baseY, textHeight, textVerticalAlign),
|
|
867
|
+
textWidth,
|
|
868
|
+
textHeight
|
|
869
|
+
);
|
|
870
|
+
// If `overflow: break` and no intersection or intersect but no enough space, we still display all text
|
|
871
|
+
// on the edge regardless of the overflow. Although that might be meaningless in production env, it is
|
|
872
|
+
// logically sound and helps in debug. Therefore we use `intersectOpt.clamp`.
|
|
873
|
+
BoundingRect.intersect(overflowRect, tmpCITCTextRect, null, tmpCITCIntersectRectOpt);
|
|
874
|
+
const outIntersectRect = tmpCITCIntersectRectOpt.outIntersectRect;
|
|
875
|
+
out.outerWidth = outIntersectRect.width;
|
|
876
|
+
out.outerHeight = outIntersectRect.height;
|
|
877
|
+
out.baseX = adjustTextX(outIntersectRect.x, outIntersectRect.width, textAlign, true);
|
|
878
|
+
out.baseY = adjustTextY(outIntersectRect.y, outIntersectRect.height, textVerticalAlign, true);
|
|
879
|
+
}
|
|
880
|
+
const tmpCITCTextRect = new BoundingRect(0, 0, 0, 0);
|
|
881
|
+
const tmpCITCIntersectRectOpt = {outIntersectRect: {}, clamp: true} as BoundingRectIntersectOpt;
|
|
882
|
+
|
|
883
|
+
export type CalcInnerTextOverflowAreaOut = {
|
|
884
|
+
// The input baseX/baseY or modified baseX/baseY, must exists.
|
|
885
|
+
baseX: number
|
|
886
|
+
baseY: number
|
|
887
|
+
// Calculated outer size based on overflowRect
|
|
888
|
+
// NaN indicates don't draw.
|
|
889
|
+
outerWidth: number | NullUndefined
|
|
890
|
+
outerHeight: number | NullUndefined
|
|
891
|
+
};
|
|
892
|
+
|
|
@@ -4,7 +4,6 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import Definable from './Definable';
|
|
7
|
-
import * as zrUtil from '../../core/util';
|
|
8
7
|
import Displayable from '../../graphic/Displayable';
|
|
9
8
|
import Path from '../../graphic/Path';
|
|
10
9
|
import {path} from '../graphic';
|
|
@@ -142,13 +141,14 @@ export default class ClippathManager extends Definable {
|
|
|
142
141
|
* @param displayable displayable element
|
|
143
142
|
*/
|
|
144
143
|
markUsed(displayable: Displayable) {
|
|
145
|
-
|
|
146
|
-
if (
|
|
147
|
-
|
|
144
|
+
const clipPaths = displayable.__clipPaths;
|
|
145
|
+
if (clipPaths) {
|
|
146
|
+
for (let idx = 0; idx < clipPaths.length; idx++) {
|
|
147
|
+
const clipPath = clipPaths[idx] as PathExtended;
|
|
148
148
|
if (clipPath._dom) {
|
|
149
149
|
super.markDomUsed(clipPath._dom);
|
|
150
150
|
}
|
|
151
|
-
}
|
|
151
|
+
}
|
|
152
152
|
}
|
|
153
153
|
};
|
|
154
154
|
|
package/src/tool/color.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import LRU from '../core/LRU';
|
|
2
|
-
import { extend, isGradientObject, isString, map } from '../core/util';
|
|
2
|
+
import { extend, isFunction, isGradientObject, isString, map } from '../core/util';
|
|
3
3
|
import { GradientObject } from '../graphic/Gradient';
|
|
4
4
|
|
|
5
5
|
const kCSSColorTable = {
|
|
@@ -498,21 +498,25 @@ export const mapToColor = lerp;
|
|
|
498
498
|
|
|
499
499
|
/**
|
|
500
500
|
* @param color
|
|
501
|
-
* @param h 0 ~ 360, ignore when null.
|
|
502
|
-
* @param s 0 ~ 1, ignore when null.
|
|
503
|
-
* @param l 0 ~ 1, ignore when null.
|
|
501
|
+
* @param h 0 ~ 360, ignore when null. If function, it takes hue as argument and returns a new hue.
|
|
502
|
+
* @param s 0 ~ 1, ignore when null. If function, it takes saturation as argument and returns a new saturation.
|
|
503
|
+
* @param l 0 ~ 1, ignore when null. If function, it takes lightness as argument and returns a new lightness.
|
|
504
504
|
* @return Color string in rgba format.
|
|
505
505
|
* @memberOf module:zrender/util/color
|
|
506
506
|
*/
|
|
507
|
-
export function modifyHSL(
|
|
507
|
+
export function modifyHSL(
|
|
508
|
+
color: string,
|
|
509
|
+
h?: number | ((h: number) => number),
|
|
510
|
+
s?: number | string | ((s: number) => number),
|
|
511
|
+
l?: number | string | ((l: number) => number)
|
|
512
|
+
): string {
|
|
508
513
|
let colorArr = parse(color);
|
|
509
514
|
|
|
510
515
|
if (color) {
|
|
511
516
|
colorArr = rgba2hsla(colorArr);
|
|
512
|
-
h != null && (colorArr[0] = clampCssAngle(h));
|
|
513
|
-
s != null && (colorArr[1] = parseCssFloat(s));
|
|
514
|
-
l != null && (colorArr[2] = parseCssFloat(l));
|
|
515
|
-
|
|
517
|
+
h != null && (colorArr[0] = clampCssAngle(isFunction(h) ? h(colorArr[0]) : h));
|
|
518
|
+
s != null && (colorArr[1] = parseCssFloat(isFunction(s) ? s(colorArr[1]) : s));
|
|
519
|
+
l != null && (colorArr[2] = parseCssFloat(isFunction(l) ? l(colorArr[2]) : l));
|
|
516
520
|
return stringify(hsla2rgba(colorArr), 'rgba');
|
|
517
521
|
}
|
|
518
522
|
}
|
package/src/tool/path.ts
CHANGED
|
@@ -383,13 +383,16 @@ class SVGPath extends Path {
|
|
|
383
383
|
function isPathProxy(path: PathProxy | CanvasRenderingContext2D): path is PathProxy {
|
|
384
384
|
return (path as PathProxy).setData != null;
|
|
385
385
|
}
|
|
386
|
+
|
|
386
387
|
// TODO Optimize double memory cost problem
|
|
387
388
|
function createPathOptions(str: string, opts: SVGPathOption): InnerSVGPathOption {
|
|
388
389
|
const pathProxy = createPathProxyFromString(str);
|
|
389
390
|
const innerOpts: InnerSVGPathOption = extend({}, opts);
|
|
390
391
|
innerOpts.buildPath = function (path: PathProxy | CanvasRenderingContext2D) {
|
|
391
|
-
|
|
392
|
-
|
|
392
|
+
const beProxy = isPathProxy(path);
|
|
393
|
+
if (beProxy && path.canSave()) {
|
|
394
|
+
// path.setData(pathProxy.data);
|
|
395
|
+
path.appendPath(pathProxy);
|
|
393
396
|
// Svg and vml renderer don't have context
|
|
394
397
|
const ctx = path.getContext();
|
|
395
398
|
if (ctx) {
|
|
@@ -397,8 +400,10 @@ function createPathOptions(str: string, opts: SVGPathOption): InnerSVGPathOption
|
|
|
397
400
|
}
|
|
398
401
|
}
|
|
399
402
|
else {
|
|
400
|
-
const ctx = path;
|
|
401
|
-
|
|
403
|
+
const ctx = beProxy ? path.getContext() : path;
|
|
404
|
+
if (ctx) {
|
|
405
|
+
pathProxy.rebuildPath(ctx, 1);
|
|
406
|
+
}
|
|
402
407
|
}
|
|
403
408
|
};
|
|
404
409
|
|
package/src/zrender.ts
CHANGED
|
@@ -556,7 +556,7 @@ export function registerSSRDataGetter<T>(getter: ElementSSRDataGetter<T>) {
|
|
|
556
556
|
/**
|
|
557
557
|
* @type {string}
|
|
558
558
|
*/
|
|
559
|
-
export const version = '5.6.2-dev.
|
|
559
|
+
export const version = '5.6.2-dev.20250625';
|
|
560
560
|
|
|
561
561
|
|
|
562
562
|
export interface ZRenderType extends ZRender {};
|