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.
Files changed (50) hide show
  1. package/dist/zrender.js +491 -253
  2. package/dist/zrender.js.map +1 -1
  3. package/dist/zrender.min.js +1 -1
  4. package/lib/Element.d.ts +4 -0
  5. package/lib/Element.js +34 -16
  6. package/lib/Handler.js +1 -1
  7. package/lib/Storage.js +20 -20
  8. package/lib/contain/text.d.ts +14 -2
  9. package/lib/contain/text.js +65 -15
  10. package/lib/core/BoundingRect.d.ts +25 -3
  11. package/lib/core/BoundingRect.js +182 -76
  12. package/lib/core/OrientedBoundingRect.d.ts +2 -2
  13. package/lib/core/OrientedBoundingRect.js +50 -34
  14. package/lib/core/PathProxy.d.ts +1 -0
  15. package/lib/core/PathProxy.js +16 -1
  16. package/lib/core/types.d.ts +1 -0
  17. package/lib/core/util.d.ts +1 -0
  18. package/lib/core/util.js +1 -0
  19. package/lib/graphic/Displayable.js +1 -1
  20. package/lib/graphic/Text.d.ts +3 -2
  21. package/lib/graphic/Text.js +20 -13
  22. package/lib/graphic/helper/parseText.d.ts +11 -4
  23. package/lib/graphic/helper/parseText.js +71 -44
  24. package/lib/svg-legacy/helper/ClippathManager.js +6 -6
  25. package/lib/tool/color.d.ts +1 -1
  26. package/lib/tool/color.js +4 -4
  27. package/lib/tool/path.js +7 -4
  28. package/lib/zrender.d.ts +1 -1
  29. package/lib/zrender.js +1 -1
  30. package/package.json +3 -2
  31. package/src/Element.ts +69 -16
  32. package/src/Handler.ts +1 -1
  33. package/src/Storage.ts +25 -24
  34. package/src/canvas/helper.ts +1 -1
  35. package/src/contain/text.ts +103 -19
  36. package/src/core/BoundingRect.ts +308 -87
  37. package/src/core/OrientedBoundingRect.ts +86 -46
  38. package/src/core/PathProxy.ts +17 -1
  39. package/src/core/Transformable.ts +2 -0
  40. package/src/core/matrix.ts +2 -1
  41. package/src/core/types.ts +2 -0
  42. package/src/core/util.ts +3 -1
  43. package/src/graphic/Displayable.ts +1 -3
  44. package/src/graphic/Group.ts +2 -0
  45. package/src/graphic/Text.ts +59 -22
  46. package/src/graphic/helper/parseText.ts +151 -73
  47. package/src/svg-legacy/helper/ClippathManager.ts +5 -5
  48. package/src/tool/color.ts +13 -9
  49. package/src/tool/path.ts +9 -4
  50. package/src/zrender.ts +1 -1
@@ -1,6 +1,7 @@
1
1
  import * as imageHelper from '../helper/image.js';
2
- import { extend, retrieve2, retrieve3, reduce } from '../../core/util.js';
3
- import { getLineHeight, getWidth, parsePercent } from '../../contain/text.js';
2
+ import { extend, retrieve2, retrieve3, reduce, } from '../../core/util.js';
3
+ import { adjustTextX, adjustTextY, ensureFontMeasureInfo, getLineHeight, measureCharWidth, measureWidth, parsePercent, } from '../../contain/text.js';
4
+ import BoundingRect from '../../core/BoundingRect.js';
4
5
  var STYLE_REG = /\{([a-zA-Z0-9_]+)\|([^}]*)\}/g;
5
6
  export function truncateText(text, containerWidth, font, ellipsis, options) {
6
7
  var out = {};
@@ -28,18 +29,17 @@ function truncateText2(out, text, containerWidth, font, ellipsis, options) {
28
29
  function prepareTruncateOptions(containerWidth, font, ellipsis, options) {
29
30
  options = options || {};
30
31
  var preparedOpts = extend({}, options);
31
- preparedOpts.font = font;
32
32
  ellipsis = retrieve2(ellipsis, '...');
33
33
  preparedOpts.maxIterations = retrieve2(options.maxIterations, 2);
34
34
  var minChar = preparedOpts.minChar = retrieve2(options.minChar, 0);
35
- preparedOpts.cnCharWidth = getWidth('国', font);
36
- var ascCharWidth = preparedOpts.ascCharWidth = getWidth('a', font);
35
+ var fontMeasureInfo = preparedOpts.fontMeasureInfo = ensureFontMeasureInfo(font);
36
+ var ascCharWidth = fontMeasureInfo.asciiCharWidth;
37
37
  preparedOpts.placeholder = retrieve2(options.placeholder, '');
38
38
  var contentWidth = containerWidth = Math.max(0, containerWidth - 1);
39
39
  for (var i = 0; i < minChar && contentWidth >= ascCharWidth; i++) {
40
40
  contentWidth -= ascCharWidth;
41
41
  }
42
- var ellipsisWidth = getWidth(ellipsis, font);
42
+ var ellipsisWidth = measureWidth(fontMeasureInfo, ellipsis);
43
43
  if (ellipsisWidth > contentWidth) {
44
44
  ellipsis = '';
45
45
  ellipsisWidth = 0;
@@ -53,14 +53,14 @@ function prepareTruncateOptions(containerWidth, font, ellipsis, options) {
53
53
  }
54
54
  function truncateSingleLine(out, textLine, options) {
55
55
  var containerWidth = options.containerWidth;
56
- var font = options.font;
57
56
  var contentWidth = options.contentWidth;
57
+ var fontMeasureInfo = options.fontMeasureInfo;
58
58
  if (!containerWidth) {
59
59
  out.textLine = '';
60
60
  out.isTruncated = false;
61
61
  return;
62
62
  }
63
- var lineWidth = getWidth(textLine, font);
63
+ var lineWidth = measureWidth(fontMeasureInfo, textLine);
64
64
  if (lineWidth <= containerWidth) {
65
65
  out.textLine = textLine;
66
66
  out.isTruncated = false;
@@ -72,12 +72,12 @@ function truncateSingleLine(out, textLine, options) {
72
72
  break;
73
73
  }
74
74
  var subLength = j === 0
75
- ? estimateLength(textLine, contentWidth, options.ascCharWidth, options.cnCharWidth)
75
+ ? estimateLength(textLine, contentWidth, fontMeasureInfo)
76
76
  : lineWidth > 0
77
77
  ? Math.floor(textLine.length * contentWidth / lineWidth)
78
78
  : 0;
79
79
  textLine = textLine.substr(0, subLength);
80
- lineWidth = getWidth(textLine, font);
80
+ lineWidth = measureWidth(fontMeasureInfo, textLine);
81
81
  }
82
82
  if (textLine === '') {
83
83
  textLine = options.placeholder;
@@ -85,27 +85,34 @@ function truncateSingleLine(out, textLine, options) {
85
85
  out.textLine = textLine;
86
86
  out.isTruncated = true;
87
87
  }
88
- function estimateLength(text, contentWidth, ascCharWidth, cnCharWidth) {
88
+ function estimateLength(text, contentWidth, fontMeasureInfo) {
89
89
  var width = 0;
90
90
  var i = 0;
91
91
  for (var len = text.length; i < len && width < contentWidth; i++) {
92
- var charCode = text.charCodeAt(i);
93
- width += (0 <= charCode && charCode <= 127) ? ascCharWidth : cnCharWidth;
92
+ width += measureCharWidth(fontMeasureInfo, text.charCodeAt(i));
94
93
  }
95
94
  return i;
96
95
  }
97
- export function parsePlainText(text, style) {
96
+ export function parsePlainText(text, style, defaultOuterWidth, defaultOuterHeight) {
98
97
  text != null && (text += '');
99
98
  var overflow = style.overflow;
100
99
  var padding = style.padding;
100
+ var paddingH = padding ? padding[1] + padding[3] : 0;
101
+ var paddingV = padding ? padding[0] + padding[2] : 0;
101
102
  var font = style.font;
102
103
  var truncate = overflow === 'truncate';
103
104
  var calculatedLineHeight = getLineHeight(font);
104
105
  var lineHeight = retrieve2(style.lineHeight, calculatedLineHeight);
105
- var bgColorDrawn = !!(style.backgroundColor);
106
106
  var truncateLineOverflow = style.lineOverflow === 'truncate';
107
107
  var isTruncated = false;
108
108
  var width = style.width;
109
+ if (width == null && defaultOuterWidth != null) {
110
+ width = defaultOuterWidth - paddingH;
111
+ }
112
+ var height = style.height;
113
+ if (height == null && defaultOuterHeight != null) {
114
+ height = defaultOuterHeight - paddingV;
115
+ }
109
116
  var lines;
110
117
  if (width != null && (overflow === 'break' || overflow === 'breakAll')) {
111
118
  lines = text ? wrapText(text, style.font, width, overflow === 'breakAll', 0).lines : [];
@@ -114,11 +121,14 @@ export function parsePlainText(text, style) {
114
121
  lines = text ? text.split('\n') : [];
115
122
  }
116
123
  var contentHeight = lines.length * lineHeight;
117
- var height = retrieve2(style.height, contentHeight);
124
+ if (height == null) {
125
+ height = contentHeight;
126
+ }
118
127
  if (contentHeight > height && truncateLineOverflow) {
119
128
  var lineCount = Math.floor(height / lineHeight);
120
129
  isTruncated = isTruncated || (lines.length > lineCount);
121
130
  lines = lines.slice(0, lineCount);
131
+ contentHeight = lines.length * lineHeight;
122
132
  }
123
133
  if (text && truncate && width != null) {
124
134
  var options = prepareTruncateOptions(width, font, style.ellipsis, {
@@ -134,21 +144,16 @@ export function parsePlainText(text, style) {
134
144
  }
135
145
  var outerHeight = height;
136
146
  var contentWidth = 0;
147
+ var fontMeasureInfo = ensureFontMeasureInfo(font);
137
148
  for (var i = 0; i < lines.length; i++) {
138
- contentWidth = Math.max(getWidth(lines[i], font), contentWidth);
149
+ contentWidth = Math.max(measureWidth(fontMeasureInfo, lines[i]), contentWidth);
139
150
  }
140
151
  if (width == null) {
141
152
  width = contentWidth;
142
153
  }
143
- var outerWidth = contentWidth;
144
- if (padding) {
145
- outerHeight += padding[0] + padding[2];
146
- outerWidth += padding[1] + padding[3];
147
- width += padding[1] + padding[3];
148
- }
149
- if (bgColorDrawn) {
150
- outerWidth = width;
151
- }
154
+ var outerWidth = width;
155
+ outerHeight += paddingV;
156
+ outerWidth += paddingH;
152
157
  return {
153
158
  lines: lines,
154
159
  height: height,
@@ -190,14 +195,23 @@ var RichTextContentBlock = (function () {
190
195
  return RichTextContentBlock;
191
196
  }());
192
197
  export { RichTextContentBlock };
193
- export function parseRichText(text, style) {
198
+ export function parseRichText(text, style, defaultOuterWidth, defaultOuterHeight, topTextAlign) {
194
199
  var contentBlock = new RichTextContentBlock();
195
200
  text != null && (text += '');
196
201
  if (!text) {
197
202
  return contentBlock;
198
203
  }
204
+ var stlPadding = style.padding;
205
+ var stlPaddingH = stlPadding ? stlPadding[1] + stlPadding[3] : 0;
206
+ var stlPaddingV = stlPadding ? stlPadding[0] + stlPadding[2] : 0;
199
207
  var topWidth = style.width;
208
+ if (topWidth == null && defaultOuterWidth != null) {
209
+ topWidth = defaultOuterWidth - stlPaddingH;
210
+ }
200
211
  var topHeight = style.height;
212
+ if (topHeight == null && defaultOuterHeight != null) {
213
+ topHeight = defaultOuterHeight - stlPaddingV;
214
+ }
201
215
  var overflow = style.overflow;
202
216
  var wrapInfo = (overflow === 'break' || overflow === 'breakAll') && topWidth != null
203
217
  ? { width: topWidth, accumWidth: 0, breakAll: overflow === 'breakAll' }
@@ -218,7 +232,6 @@ export function parseRichText(text, style) {
218
232
  var pendingList = [];
219
233
  var calculatedHeight = 0;
220
234
  var calculatedWidth = 0;
221
- var stlPadding = style.padding;
222
235
  var truncate = overflow === 'truncate';
223
236
  var truncateLine = style.lineOverflow === 'truncate';
224
237
  var tmpTruncateOut = {};
@@ -244,7 +257,7 @@ export function parseRichText(text, style) {
244
257
  textPadding && (tokenHeight += textPadding[0] + textPadding[2]);
245
258
  token.height = tokenHeight;
246
259
  token.lineHeight = retrieve3(tokenStyle.lineHeight, style.lineHeight, tokenHeight);
247
- token.align = tokenStyle && tokenStyle.align || style.align;
260
+ token.align = tokenStyle && tokenStyle.align || topTextAlign;
248
261
  token.verticalAlign = tokenStyle && tokenStyle.verticalAlign || 'middle';
249
262
  if (truncateLine && topHeight != null && calculatedHeight + token.lineHeight > topHeight) {
250
263
  var originalLength = contentBlock.lines.length;
@@ -264,7 +277,7 @@ export function parseRichText(text, style) {
264
277
  if (typeof styleTokenWidth === 'string' && styleTokenWidth.charAt(styleTokenWidth.length - 1) === '%') {
265
278
  token.percentWidth = styleTokenWidth;
266
279
  pendingList.push(token);
267
- token.contentWidth = getWidth(token.text, font);
280
+ token.contentWidth = measureWidth(ensureFontMeasureInfo(font), token.text);
268
281
  }
269
282
  else {
270
283
  if (tokenWidthNotSpecified) {
@@ -288,11 +301,11 @@ export function parseRichText(text, style) {
288
301
  truncateText2(tmpTruncateOut, token.text, remainTruncWidth - paddingH, font, style.ellipsis, { minChar: style.truncateMinChar });
289
302
  token.text = tmpTruncateOut.text;
290
303
  contentBlock.isTruncated = contentBlock.isTruncated || tmpTruncateOut.isTruncated;
291
- token.width = token.contentWidth = getWidth(token.text, font);
304
+ token.width = token.contentWidth = measureWidth(ensureFontMeasureInfo(font), token.text);
292
305
  }
293
306
  }
294
307
  else {
295
- token.contentWidth = getWidth(token.text, font);
308
+ token.contentWidth = measureWidth(ensureFontMeasureInfo(font), token.text);
296
309
  }
297
310
  }
298
311
  token.width += paddingH;
@@ -305,10 +318,8 @@ export function parseRichText(text, style) {
305
318
  contentBlock.outerHeight = contentBlock.height = retrieve2(topHeight, calculatedHeight);
306
319
  contentBlock.contentHeight = calculatedHeight;
307
320
  contentBlock.contentWidth = calculatedWidth;
308
- if (stlPadding) {
309
- contentBlock.outerWidth += stlPadding[1] + stlPadding[3];
310
- contentBlock.outerHeight += stlPadding[0] + stlPadding[2];
311
- }
321
+ contentBlock.outerWidth += stlPaddingH;
322
+ contentBlock.outerHeight += stlPaddingV;
312
323
  for (var i = 0; i < pendingList.length; i++) {
313
324
  var token = pendingList[i];
314
325
  var percentWidth = token.percentWidth;
@@ -344,9 +355,10 @@ function pushTokens(block, str, style, wrapInfo, styleName) {
344
355
  strLines = res.lines;
345
356
  }
346
357
  }
347
- else {
358
+ if (!strLines) {
348
359
  strLines = str.split('\n');
349
360
  }
361
+ var fontMeasureInfo = ensureFontMeasureInfo(font);
350
362
  for (var i = 0; i < strLines.length; i++) {
351
363
  var text = strLines[i];
352
364
  var token = new RichTextToken();
@@ -359,7 +371,7 @@ function pushTokens(block, str, style, wrapInfo, styleName) {
359
371
  else {
360
372
  token.width = linesWidths
361
373
  ? linesWidths[i]
362
- : getWidth(text, font);
374
+ : measureWidth(fontMeasureInfo, text);
363
375
  }
364
376
  if (!i && !newLine) {
365
377
  var tokens = (lines[lines.length - 1] || (lines[0] = new RichTextLine())).tokens;
@@ -400,6 +412,7 @@ function wrapText(text, font, lineWidth, isBreakAll, lastAccumWidth) {
400
412
  var currentWord = '';
401
413
  var currentWordWidth = 0;
402
414
  var accumWidth = 0;
415
+ var fontMeasureInfo = ensureFontMeasureInfo(font);
403
416
  for (var i = 0; i < text.length; i++) {
404
417
  var ch = text.charAt(i);
405
418
  if (ch === '\n') {
@@ -415,7 +428,7 @@ function wrapText(text, font, lineWidth, isBreakAll, lastAccumWidth) {
415
428
  accumWidth = 0;
416
429
  continue;
417
430
  }
418
- var chWidth = getWidth(ch, font);
431
+ var chWidth = measureCharWidth(fontMeasureInfo, ch.charCodeAt(0));
419
432
  var inWord = isBreakAll ? false : !isWordBreakChar(ch);
420
433
  if (!lines.length
421
434
  ? lastAccumWidth + accumWidth + chWidth > lineWidth
@@ -475,11 +488,6 @@ function wrapText(text, font, lineWidth, isBreakAll, lastAccumWidth) {
475
488
  line += ch;
476
489
  }
477
490
  }
478
- if (!lines.length && !line) {
479
- line = text;
480
- currentWord = '';
481
- currentWordWidth = 0;
482
- }
483
491
  if (currentWord) {
484
492
  line += currentWord;
485
493
  }
@@ -496,3 +504,22 @@ function wrapText(text, font, lineWidth, isBreakAll, lastAccumWidth) {
496
504
  linesWidths: linesWidths
497
505
  };
498
506
  }
507
+ export function calcInnerTextOverflowArea(out, overflowRect, baseX, baseY, textAlign, textVerticalAlign) {
508
+ out.baseX = baseX;
509
+ out.baseY = baseY;
510
+ out.outerWidth = out.outerHeight = null;
511
+ if (!overflowRect) {
512
+ return;
513
+ }
514
+ var textWidth = overflowRect.width * 2;
515
+ var textHeight = overflowRect.height * 2;
516
+ BoundingRect.set(tmpCITCTextRect, adjustTextX(baseX, textWidth, textAlign), adjustTextY(baseY, textHeight, textVerticalAlign), textWidth, textHeight);
517
+ BoundingRect.intersect(overflowRect, tmpCITCTextRect, null, tmpCITCIntersectRectOpt);
518
+ var outIntersectRect = tmpCITCIntersectRectOpt.outIntersectRect;
519
+ out.outerWidth = outIntersectRect.width;
520
+ out.outerHeight = outIntersectRect.height;
521
+ out.baseX = adjustTextX(outIntersectRect.x, outIntersectRect.width, textAlign, true);
522
+ out.baseY = adjustTextY(outIntersectRect.y, outIntersectRect.height, textVerticalAlign, true);
523
+ }
524
+ var tmpCITCTextRect = new BoundingRect(0, 0, 0, 0);
525
+ var tmpCITCIntersectRectOpt = { outIntersectRect: {}, clamp: true };
@@ -1,6 +1,5 @@
1
1
  import { __extends } from "tslib";
2
2
  import Definable from './Definable.js';
3
- import * as zrUtil from '../../core/util.js';
4
3
  import { path } from '../graphic.js';
5
4
  import { isClipPathChanged } from '../../canvas/helper.js';
6
5
  import { getClipPathsKey, getIdURL } from '../../svg/helper.js';
@@ -89,13 +88,14 @@ var ClippathManager = (function (_super) {
89
88
  };
90
89
  ;
91
90
  ClippathManager.prototype.markUsed = function (displayable) {
92
- var _this = this;
93
- if (displayable.__clipPaths) {
94
- zrUtil.each(displayable.__clipPaths, function (clipPath) {
91
+ var clipPaths = displayable.__clipPaths;
92
+ if (clipPaths) {
93
+ for (var idx = 0; idx < clipPaths.length; idx++) {
94
+ var clipPath = clipPaths[idx];
95
95
  if (clipPath._dom) {
96
- _super.prototype.markDomUsed.call(_this, clipPath._dom);
96
+ _super.prototype.markDomUsed.call(this, clipPath._dom);
97
97
  }
98
- });
98
+ }
99
99
  }
100
100
  };
101
101
  ;
@@ -15,7 +15,7 @@ declare type LerpFullOutput = {
15
15
  export declare function lerp(normalizedValue: number, colors: string[], fullOutput: boolean): LerpFullOutput;
16
16
  export declare function lerp(normalizedValue: number, colors: string[]): string;
17
17
  export declare const mapToColor: typeof lerp;
18
- export declare function modifyHSL(color: string, h?: number, s?: number, l?: number): string;
18
+ export declare function modifyHSL(color: string, h?: number | ((h: number) => number), s?: number | string | ((s: number) => number), l?: number | string | ((l: number) => number)): string;
19
19
  export declare function modifyAlpha(color: string, alpha?: number): string;
20
20
  export declare function stringify(arrColor: number[], type: string): string;
21
21
  export declare function lum(color: string, backgroundLum: number): number;
package/lib/tool/color.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import LRU from '../core/LRU.js';
2
- import { extend, isGradientObject, isString, map } from '../core/util.js';
2
+ import { extend, isFunction, isGradientObject, isString, map } from '../core/util.js';
3
3
  var kCSSColorTable = {
4
4
  'transparent': [0, 0, 0, 0], 'aliceblue': [240, 248, 255, 1],
5
5
  'antiquewhite': [250, 235, 215, 1], 'aqua': [0, 255, 255, 1],
@@ -370,9 +370,9 @@ export function modifyHSL(color, h, s, l) {
370
370
  var colorArr = parse(color);
371
371
  if (color) {
372
372
  colorArr = rgba2hsla(colorArr);
373
- h != null && (colorArr[0] = clampCssAngle(h));
374
- s != null && (colorArr[1] = parseCssFloat(s));
375
- l != null && (colorArr[2] = parseCssFloat(l));
373
+ h != null && (colorArr[0] = clampCssAngle(isFunction(h) ? h(colorArr[0]) : h));
374
+ s != null && (colorArr[1] = parseCssFloat(isFunction(s) ? s(colorArr[1]) : s));
375
+ l != null && (colorArr[2] = parseCssFloat(isFunction(l) ? l(colorArr[2]) : l));
376
376
  return stringify(hsla2rgba(colorArr), 'rgba');
377
377
  }
378
378
  }
package/lib/tool/path.js CHANGED
@@ -290,16 +290,19 @@ function createPathOptions(str, opts) {
290
290
  var pathProxy = createPathProxyFromString(str);
291
291
  var innerOpts = extend({}, opts);
292
292
  innerOpts.buildPath = function (path) {
293
- if (isPathProxy(path)) {
294
- path.setData(pathProxy.data);
293
+ var beProxy = isPathProxy(path);
294
+ if (beProxy && path.canSave()) {
295
+ path.appendPath(pathProxy);
295
296
  var ctx = path.getContext();
296
297
  if (ctx) {
297
298
  path.rebuildPath(ctx, 1);
298
299
  }
299
300
  }
300
301
  else {
301
- var ctx = path;
302
- pathProxy.rebuildPath(ctx, 1);
302
+ var ctx = beProxy ? path.getContext() : path;
303
+ if (ctx) {
304
+ pathProxy.rebuildPath(ctx, 1);
305
+ }
303
306
  }
304
307
  };
305
308
  innerOpts.applyTransform = function (m) {
package/lib/zrender.d.ts CHANGED
@@ -90,7 +90,7 @@ export declare type ElementSSRData = zrUtil.HashMap<unknown>;
90
90
  export declare type ElementSSRDataGetter<T> = (el: Element) => zrUtil.HashMap<T>;
91
91
  export declare function getElementSSRData(el: Element): ElementSSRData;
92
92
  export declare function registerSSRDataGetter<T>(getter: ElementSSRDataGetter<T>): void;
93
- export declare const version = "5.6.2-dev.20250624";
93
+ export declare const version = "5.6.2-dev.20250625";
94
94
  export interface ZRenderType extends ZRender {
95
95
  }
96
96
  export {};
package/lib/zrender.js CHANGED
@@ -324,5 +324,5 @@ export function getElementSSRData(el) {
324
324
  export function registerSSRDataGetter(getter) {
325
325
  ssrDataGetter = getter;
326
326
  }
327
- export var version = '5.6.2-dev.20250624';
327
+ export var version = '5.6.2-dev.20250625';
328
328
  ;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zrender-nightly",
3
- "version": "5.6.2-dev.20250624",
3
+ "version": "5.6.2-dev.20250625",
4
4
  "description": "A lightweight graphic library providing 2d draw for Apache ECharts",
5
5
  "keywords": [
6
6
  "canvas",
@@ -25,7 +25,8 @@
25
25
  "watch:bundle": "node build/build.js --watch",
26
26
  "watch:lib": "npx tsc-watch -m ES2015 --outDir lib --synchronousWatchDirectory --onSuccess \"node build/processLib.js\"",
27
27
  "test": "npx jest --config test/ut/jest.config.js",
28
- "lint": "npx eslint src/**/*.ts"
28
+ "lint": "npx eslint src/**/*.ts",
29
+ "checktype": "tsc --noEmit"
29
30
  },
30
31
  "license": "BSD-3-Clause",
31
32
  "types": "index.d.ts",
package/src/Element.ts CHANGED
@@ -31,6 +31,7 @@ import Point from './core/Point';
31
31
  import { LIGHT_LABEL_COLOR, DARK_LABEL_COLOR } from './config';
32
32
  import { parse, stringify } from './tool/color';
33
33
  import { REDRAW_BIT } from './graphic/constants';
34
+ import { invert } from './core/matrix';
34
35
 
35
36
  export interface ElementAnimateConfig {
36
37
  duration?: number
@@ -81,7 +82,11 @@ export interface ElementTextConfig {
81
82
 
82
83
  /**
83
84
  * Rect that text will be positioned.
84
- * Default to be the rect of element.
85
+ * Default to be the boundingRect of the host element.
86
+ * The coords of `layoutRect` is based on the target element, but not global.
87
+ *
88
+ * [NOTICE]: boundingRect includes `lineWidth`, which is inconsistent with
89
+ * the general element placement principle, where `lineWidth` is not counted.
85
90
  */
86
91
  layoutRect?: RectLike
87
92
 
@@ -109,6 +114,10 @@ export interface ElementTextConfig {
109
114
 
110
115
  /**
111
116
  * If use local user space. Which will apply host's transform
117
+ *
118
+ * [NOTICE]: If the host element may rotate to non-parallel to screen x/y,
119
+ * need to use `local:true`, otherwise the transformed layout rect may not be expected.
120
+ *
112
121
  * @default false
113
122
  */
114
123
  local?: boolean
@@ -166,6 +175,16 @@ export interface ElementTextConfig {
166
175
  * In case position is not using builtin `inside` hints.
167
176
  */
168
177
  inside?: boolean
178
+
179
+ /**
180
+ * Auto calculate overflow area by `textConfig.layoutRect` (if any) or `host.boundingRect`.
181
+ * It makes sense only if label is inside. It ensure the text does not overflow the host.
182
+ * Useful in `text.style.overflow` and `text.style.lineOverflow`.
183
+ *
184
+ * If `textConfig.rotation` or `text.rotation exists`, it works correctly only when the rotated text is parallel
185
+ * to its host (i.e. 0, PI/2, PI, PI*3/2, 2*PI, ...). Do not supported other cases until a real scenario arises.
186
+ */
187
+ autoOverflowArea?: boolean
169
188
  }
170
189
  export interface ElementTextGuideLineConfig {
171
190
  /**
@@ -238,6 +257,7 @@ export interface ElementProps extends Partial<ElementEventHandlerProps>, Partial
238
257
  draggable?: boolean | 'horizontal' | 'vertical'
239
258
 
240
259
  silent?: boolean
260
+ ignoreHostSilent?: boolean
241
261
 
242
262
  ignoreClip?: boolean
243
263
  globalScaleRatio?: number
@@ -277,8 +297,9 @@ export type ElementCalculateTextPosition = (
277
297
  rect: RectLike
278
298
  ) => TextPositionCalculationResult;
279
299
 
280
- let tmpTextPosCalcRes = {} as TextPositionCalculationResult;
281
- let tmpBoundingRect = new BoundingRect(0, 0, 0, 0);
300
+ const tmpTextPosCalcRes = {} as TextPositionCalculationResult;
301
+ const tmpBoundingRect = new BoundingRect(0, 0, 0, 0);
302
+ const tmpInnerTextTrans: number[] = [];
282
303
 
283
304
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
284
305
  interface Element<Props extends ElementProps = ElementProps> extends Transformable,
@@ -313,6 +334,14 @@ class Element<Props extends ElementProps = ElementProps> {
313
334
  */
314
335
  silent: boolean
315
336
 
337
+ /**
338
+ * When this element has `__hostTarget` (e.g., this is a `textContent`), whether
339
+ * its silent is controlled by that host silent. They may need separate silent
340
+ * settings. e.g., the host do not have `fill` but only `stroke`, or their mouse
341
+ * events serve for different features.
342
+ */
343
+ ignoreHostSilent: boolean
344
+
316
345
  /**
317
346
  * 是否是 Group
318
347
  */
@@ -368,6 +397,8 @@ class Element<Props extends ElementProps = ElementProps> {
368
397
  */
369
398
  __inHover: boolean
370
399
 
400
+ __clipPaths?: Path[]
401
+
371
402
  /**
372
403
  * path to clip the elements and its children, if it is a group.
373
404
  * @see http://www.w3.org/TR/2dcontext/#clipping-region
@@ -511,9 +542,12 @@ class Element<Props extends ElementProps = ElementProps> {
511
542
  // Reset x/y/rotation
512
543
  innerTransformable.copyTransform(textEl);
513
544
 
514
- // Force set attached text's position if `position` is in config.
515
- if (textConfig.position != null) {
516
- let layoutRect = tmpBoundingRect;
545
+ const hasPosition = textConfig.position != null;
546
+ const autoOverflowArea = textConfig.autoOverflowArea;
547
+
548
+ let layoutRect: BoundingRect;
549
+ if (autoOverflowArea || hasPosition) {
550
+ layoutRect = tmpBoundingRect;
517
551
  if (textConfig.layoutRect) {
518
552
  layoutRect.copy(textConfig.layoutRect);
519
553
  }
@@ -523,7 +557,10 @@ class Element<Props extends ElementProps = ElementProps> {
523
557
  if (!isLocal) {
524
558
  layoutRect.applyTransform(this.transform);
525
559
  }
560
+ }
526
561
 
562
+ // Force set attached text's position if `position` is in config.
563
+ if (hasPosition) {
527
564
  if (this.calculateTextPosition) {
528
565
  this.calculateTextPosition(tmpTextPosCalcRes, textConfig, layoutRect);
529
566
  }
@@ -578,11 +615,27 @@ class Element<Props extends ElementProps = ElementProps> {
578
615
  }
579
616
  }
580
617
 
618
+ const innerTextDefaultStyle = this._innerTextDefaultStyle || (this._innerTextDefaultStyle = {});
619
+
620
+ if (autoOverflowArea) {
621
+ const overflowRect = innerTextDefaultStyle.overflowRect =
622
+ innerTextDefaultStyle.overflowRect || new BoundingRect(0, 0, 0, 0);
623
+ innerTransformable.getLocalTransform(tmpInnerTextTrans);
624
+ invert(tmpInnerTextTrans, tmpInnerTextTrans);
625
+ BoundingRect.copy(overflowRect, layoutRect);
626
+ // If transform to a non-orthogonal state (e.g. rotate PI/3), the result of this "apply"
627
+ // is not expected. But we don't need to address it until a real scenario arises.
628
+ overflowRect.applyTransform(tmpInnerTextTrans);
629
+ }
630
+ else {
631
+ innerTextDefaultStyle.overflowRect = null;
632
+ }
633
+ // [CAUTION] Do not change `innerTransformable` below.
634
+
581
635
  // Calculate text color
582
636
  const isInside = textConfig.inside == null // Force to be inside or not.
583
637
  ? (typeof textConfig.position === 'string' && textConfig.position.indexOf('inside') >= 0)
584
638
  : textConfig.inside;
585
- const innerTextDefaultStyle = this._innerTextDefaultStyle || (this._innerTextDefaultStyle = {});
586
639
 
587
640
  let textFill;
588
641
  let textStroke;
@@ -1021,16 +1074,16 @@ class Element<Props extends ElementProps = ElementProps> {
1021
1074
  * Return if el.silent or any ancestor element has silent true.
1022
1075
  */
1023
1076
  isSilent() {
1024
- let isSilent = this.silent;
1025
- let ancestor = this.parent;
1026
- while (!isSilent && ancestor) {
1027
- if (ancestor.silent) {
1028
- isSilent = true;
1029
- break;
1077
+ // Follow the logic of `Handler.ts`#`isHover`.
1078
+ let el: Element = this;
1079
+ while (el) {
1080
+ if (el.silent) {
1081
+ return true;
1030
1082
  }
1031
- ancestor = ancestor.parent;
1083
+ const hostEl = el.__hostTarget;
1084
+ el = hostEl ? (el.ignoreHostSilent ? null : hostEl) : el.parent;
1032
1085
  }
1033
- return isSilent;
1086
+ return false;
1034
1087
  }
1035
1088
 
1036
1089
  /**
@@ -1637,6 +1690,7 @@ class Element<Props extends ElementProps = ElementProps> {
1637
1690
 
1638
1691
  elProto.ignore =
1639
1692
  elProto.silent =
1693
+ elProto.ignoreHostSilent =
1640
1694
  elProto.isGroup =
1641
1695
  elProto.draggable =
1642
1696
  elProto.dragging =
@@ -2026,5 +2080,4 @@ function animateToShallow<T>(
2026
2080
  }
2027
2081
  }
2028
2082
 
2029
-
2030
2083
  export default Element;
package/src/Handler.ts CHANGED
@@ -504,7 +504,7 @@ function isHover(displayable: Displayable, x: number, y: number) {
504
504
  // Consider when el is textContent, also need to be silent
505
505
  // if any of its host el and its ancestors is silent.
506
506
  const hostEl = el.__hostTarget;
507
- el = hostEl ? hostEl : el.parent;
507
+ el = hostEl ? (el.ignoreHostSilent ? null : hostEl) : el.parent;
508
508
  }
509
509
  return isSilent ? SILENT : true;
510
510
  }