@easyv/charts 1.10.14 → 1.10.16

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.
@@ -92,13 +92,20 @@ export const pieLegendFormatter = (series, props) => {
92
92
 
93
93
  const _color = seriesColorType == "pure" ? pure : stops[0].color;
94
94
  const textMarginLeft = 5;
95
+ const { adaptiveMaxWidth, isPieAdaptive, chartWidth } = props;
96
+ const isSideAdaptive = !!adaptiveMaxWidth;
97
+ const isTopBottomAdaptive = isPieAdaptive && !isSideAdaptive;
98
+ const nameOverflowType =
99
+ isSideAdaptive || isTopBottomAdaptive ? "ellipsis" : textOverflow;
95
100
 
96
- // 1. 计算每列宽度(加上间距)
101
+ // 1. 计算每列宽度(加上间距);正上/正下自适应不按全局列宽对齐
97
102
  let columns = [];
98
- if (showName) columns.push(`${props.nameMaxWidth}px`);
99
- if (showValue) columns.push(`${props.valueMaxWidth + valueGap}px`);
100
- if (showPercent) columns.push(`${props.percentMaxWidth + percentGap}px`);
101
- if (series.fieldsData.length > 0) {
103
+ if (!isTopBottomAdaptive) {
104
+ if (showName) columns.push(`${props.nameMaxWidth}px`);
105
+ if (showValue) columns.push(`${props.valueMaxWidth + valueGap}px`);
106
+ if (showPercent) columns.push(`${props.percentMaxWidth + percentGap}px`);
107
+ }
108
+ if (!isTopBottomAdaptive && series.fieldsData.length > 0) {
102
109
  //网格布局新增的各列宽度
103
110
  series.fieldsData.forEach((item) => {
104
111
  const idx = item.fieldsColumnIndex ?? 0;
@@ -135,6 +142,66 @@ export const pieLegendFormatter = (series, props) => {
135
142
  });
136
143
  }
137
144
 
145
+ const scaleColumnsToMax = (cols, maxTotal) => {
146
+ const widths = cols.map((c) => parseFloat(c) || 0);
147
+ const total = widths.reduce((a, b) => a + b, 0);
148
+ if (!total || total <= maxTotal) return cols.join(" ");
149
+ const scale = maxTotal / total;
150
+ return widths
151
+ .map((w) => `${Math.max(1, Math.floor(w * scale))}px`)
152
+ .join(" ");
153
+ };
154
+
155
+ const sideGridMaxWidth = isSideAdaptive
156
+ ? Math.max(
157
+ 0,
158
+ adaptiveMaxWidth -
159
+ (icon
160
+ ? (parseFloat(icon.width) || 0) +
161
+ (parseFloat(icon.marginRight) || 0)
162
+ : 0),
163
+ )
164
+ : adaptiveMaxWidth;
165
+
166
+ const contentStyle = isSideAdaptive
167
+ ? {
168
+ display: "grid",
169
+ gridTemplateColumns: scaleColumnsToMax(columns, sideGridMaxWidth),
170
+ width: "max-content",
171
+ maxWidth: "100%",
172
+ minWidth: 0,
173
+ overflow: "hidden",
174
+ boxSizing: "border-box",
175
+ }
176
+ : isTopBottomAdaptive
177
+ ? {
178
+ display: "flex",
179
+ flexDirection: "row",
180
+ alignItems: "center",
181
+ flexWrap: "nowrap",
182
+ width: "max-content",
183
+ maxWidth: chartWidth ? `${chartWidth}px` : "100%",
184
+ minWidth: 0,
185
+ overflow: "hidden",
186
+ boxSizing: "border-box",
187
+ gap: `${valueGap}px ${percentGap}px`,
188
+ }
189
+ : {
190
+ width: `calc( 100% + ${textMarginLeft + valueGap + percentGap}px )`,
191
+ gridTemplateColumns: columns.join(" "),
192
+ overflowX: "visible",
193
+ };
194
+
195
+ const contentClassName = isTopBottomAdaptive
196
+ ? undefined
197
+ : isSideAdaptive
198
+ ? showName && showValue && showPercent
199
+ ? css.showAllStyle
200
+ : css.notShowAllStyle
201
+ : showName && showValue && showPercent
202
+ ? css.showAllStyle
203
+ : css.notShowAllStyle;
204
+
138
205
  return (
139
206
  <>
140
207
  {icon && (
@@ -142,30 +209,33 @@ export const pieLegendFormatter = (series, props) => {
142
209
  style={{
143
210
  ...icon,
144
211
  marginRight: icon.marginRight,
212
+ flexShrink: 0,
145
213
  transform: `translate(${nameX}px, ${nameY}px)`,
146
214
  }}
147
215
  />
148
216
  )}
149
- <div
150
- className={
151
- showName && showValue && showPercent
152
- ? css.showAllStyle
153
- : css.notShowAllStyle
154
- }
155
- style={{
156
- width: `calc( 100% + ${textMarginLeft + valueGap + percentGap}px )`,
157
- gridTemplateColumns: columns.join(" "),
158
- overflowX: "visible",
159
- }}
160
- >
217
+ <div className={contentClassName} style={contentStyle}>
161
218
  {showName && (
162
219
  <TextOverflow
163
220
  value={displayName}
164
- type={textOverflow}
221
+ type={nameOverflowType}
165
222
  speed={speed}
166
223
  style={{
167
- width: maxWidth,
224
+ width: isSideAdaptive
225
+ ? "100%"
226
+ : isTopBottomAdaptive
227
+ ? "auto"
228
+ : maxWidth,
229
+ maxWidth: isSideAdaptive
230
+ ? "100%"
231
+ : isTopBottomAdaptive
232
+ ? "none"
233
+ : maxWidth,
234
+ minWidth: isSideAdaptive ? 0 : undefined,
235
+ flexShrink: isTopBottomAdaptive ? 1 : undefined,
168
236
  marginLeft: textMarginLeft,
237
+ // whiteSpace: "nowrap",
238
+ overflow: "hidden",
169
239
  ...getFontStyle(nameFont),
170
240
  transform: `translate(${nameX}px, ${nameY}px)`,
171
241
  }}
@@ -177,12 +247,17 @@ export const pieLegendFormatter = (series, props) => {
177
247
  display: "flex",
178
248
  whiteSpace: "nowrap",
179
249
  ...getFontStyle(valueFont),
180
- marginLeft: valueGap,
250
+ marginLeft: isSideAdaptive || isTopBottomAdaptive ? 0 : valueGap,
251
+ flexShrink: isTopBottomAdaptive ? 0 : undefined,
181
252
  transform: `translate(${valueX}px,${valueY}px)`,
182
253
  color: valueSameColor ? _color : valueFont.color,
183
254
  alignItems: "center",
184
- justifyContent: alignToJustify(valueAlign ?? "center"),
185
- textAlign: alignToTextAlign(valueAlign),
255
+ justifyContent: alignToJustify(
256
+ isTopBottomAdaptive ? "left" : (valueAlign ?? "center"),
257
+ ),
258
+ textAlign: alignToTextAlign(
259
+ isTopBottomAdaptive ? "left" : valueAlign,
260
+ ),
186
261
  }}
187
262
  >
188
263
  <span>
@@ -207,66 +282,74 @@ export const pieLegendFormatter = (series, props) => {
207
282
  display: "flex",
208
283
  whiteSpace: "nowrap",
209
284
  ...getFontStyle(percentFont),
210
- marginLeft: percentGap,
285
+ marginLeft:
286
+ isSideAdaptive || isTopBottomAdaptive ? 0 : percentGap,
287
+ flexShrink: isTopBottomAdaptive ? 0 : undefined,
211
288
  transform: `translate(${percentX}px,${percentY}px)`,
212
289
  color: percentSameColor ? _color : percentFont.color,
213
290
  alignItems: "center",
214
- justifyContent: alignToJustify(percentAlign),
215
- textAlign: alignToTextAlign(percentAlign),
291
+ justifyContent: alignToJustify(
292
+ isTopBottomAdaptive ? "left" : percentAlign,
293
+ ),
294
+ textAlign: alignToTextAlign(
295
+ isTopBottomAdaptive ? "left" : percentAlign,
296
+ ),
216
297
  }}
217
298
  >
218
299
  {percent + "%"}
219
300
  </span>
220
301
  )}
221
- {series.fieldsData?.map(
222
- (
223
- item,
224
- index, //渲染网格布局新增的各列
225
- ) => (
302
+ {series.fieldsData?.map((item, index) => (
303
+ <span
304
+ key={fieldColumnKeys[item.fieldsColumnIndex ?? index] ?? index}
305
+ style={{
306
+ display: "flex",
307
+ boxSizing: "border-box",
308
+ width: isTopBottomAdaptive ? "auto" : "100%",
309
+ minWidth: 0,
310
+ flexShrink: isTopBottomAdaptive ? 0 : undefined,
311
+ alignItems: "center",
312
+ justifyContent: alignToJustify(
313
+ isTopBottomAdaptive ? "left" : (item.align ?? "center"),
314
+ ),
315
+ textAlign: alignToTextAlign(
316
+ isTopBottomAdaptive ? "left" : (item.align ?? "center"),
317
+ ),
318
+ overflow:
319
+ isSideAdaptive || isTopBottomAdaptive ? "hidden" : "visible",
320
+ whiteSpace: "nowrap",
321
+ ...getFontStyle(item.font),
322
+ color: item.sameColor ? _color : item.font.color,
323
+ }}
324
+ >
226
325
  <span
227
- key={fieldColumnKeys[item.fieldsColumnIndex ?? index] ?? index}
228
326
  style={{
229
- display: "flex",
230
- boxSizing: "border-box",
231
- width: "100%",
232
- minWidth: 0,
327
+ display: "inline-flex",
233
328
  alignItems: "center",
234
- justifyContent: alignToJustify(item.align ?? "center"),
235
- textAlign: alignToTextAlign(item.align ?? "center"),
236
- overflow: "visible",
237
- ...getFontStyle(item.font),
238
- color: item.sameColor ? _color : item.font.color,
329
+ flexWrap: "nowrap",
330
+ whiteSpace: "nowrap",
331
+ marginLeft: item.translate?.x ?? 0,
332
+ marginTop: item.translate?.y ?? 0,
239
333
  }}
240
334
  >
241
- <span
242
- style={{
243
- display: "inline-flex",
244
- alignItems: "center",
245
- flexWrap: "nowrap",
246
- whiteSpace: "nowrap",
247
- marginLeft: item.translate?.x ?? 0,
248
- marginTop: item.translate?.y ?? 0,
249
- }}
250
- >
251
- <span style={{ whiteSpace: "nowrap" }}>{item.value}</span>
252
- {item.suffix?.show &&
253
- item.suffix?.text != null &&
254
- String(item.suffix.text) !== "" && (
255
- <span
256
- style={{
257
- whiteSpace: "nowrap",
258
- fontSize: item.suffix.fontSize,
259
- marginLeft: item.suffix.translate?.x ?? 0,
260
- marginTop: item.suffix.translate?.y ?? 0,
261
- }}
262
- >
263
- {item.suffix.text}
264
- </span>
265
- )}
266
- </span>
335
+ <span style={{ whiteSpace: "nowrap" }}>{item.value}</span>
336
+ {item.suffix?.show &&
337
+ item.suffix?.text != null &&
338
+ String(item.suffix.text) !== "" && (
339
+ <span
340
+ style={{
341
+ whiteSpace: "nowrap",
342
+ fontSize: item.suffix.fontSize,
343
+ marginLeft: item.suffix.translate?.x ?? 0,
344
+ marginTop: item.suffix.translate?.y ?? 0,
345
+ }}
346
+ >
347
+ {item.suffix.text}
348
+ </span>
349
+ )}
267
350
  </span>
268
- ),
269
- )}
351
+ </span>
352
+ ))}
270
353
  </div>
271
354
  </>
272
355
  );
@@ -0,0 +1,28 @@
1
+ /**
2
+ * 解析图例 layout.alignment(如 "center top"、"right top")
3
+ * 格式:{水平对齐} {位置},位置为 top | right | left | bottom
4
+ */
5
+ export const parseLegendAlignment = (alignment = "right center") => {
6
+ const [_alignment, position] = alignment.split(" ");
7
+ const isCenterTopOrBottom =
8
+ (position === "top" || position === "bottom") && _alignment === "center";
9
+ const isSidePlacement =
10
+ position === "left" ||
11
+ position === "right" ||
12
+ ((position === "top" || position === "bottom") && _alignment !== "center");
13
+ return {
14
+ alignment: _alignment,
15
+ position,
16
+ isCenterTopOrBottom,
17
+ isSidePlacement,
18
+ };
19
+ };
20
+
21
+ export const getPieAdaptiveMarginPreset = (show, alignment, presets) => {
22
+ if (!show) return presets.hidden;
23
+ const { alignment: mainAlign, position, isCenterTopOrBottom } =
24
+ parseLegendAlignment(alignment);
25
+ if (isCenterTopOrBottom) return presets[position];
26
+ if (position === "left" || mainAlign === "left") return presets.left;
27
+ return presets.right;
28
+ };