@publishfx/publish-chart 1.3.1 → 1.4.0

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.
@@ -0,0 +1,496 @@
1
+ import { jsx, jsxs } from "react/jsx-runtime";
2
+ import react, { memo, useEffect, useMemo, useState } from "react";
3
+ import { Axis, Chart, Legend, Line, Tooltip, View } from "bizcharts";
4
+ import styled_components from "styled-components";
5
+ import lib from "@antv/data-set/lib";
6
+ import { CompareChange } from "@publishfx/publish-components";
7
+ import { calculateBarWidth, getAxisFormat, getAxisHorPaddingByText } from "../../utils/chartHelpers.js";
8
+ import { defaultChartConfig, nodeMap } from "../../core/ChartConfig.js";
9
+ import { formatIndicatorV2 } from "../../utils/formatters.js";
10
+ import AuxiliaryLine from "../shared/AuxiliaryLine.js";
11
+ import { NodeGeom } from "../shared/NodeGeom.js";
12
+ import XAxisBackground from "../shared/XAxisBackground.js";
13
+ const StyledTooltip = styled_components.div`
14
+ display: 'table';
15
+ .table-row {
16
+ display: table-row;
17
+ }
18
+ .table-cell {
19
+ display: table-cell;
20
+ }
21
+ .padding-top-10 {
22
+ padding-top: 10px;
23
+ }
24
+ .padding-right-10 {
25
+ padding-right: 10px;
26
+ }
27
+ .padding-left-10 {
28
+ padding-left: 10px;
29
+ }
30
+ .font-weight-bold {
31
+ font-weight: bold;
32
+ }
33
+ `;
34
+ const defaultColorPalette = [
35
+ '#5B8FF9',
36
+ '#61DDAA',
37
+ '#65789B',
38
+ '#F6BD16',
39
+ '#6F5F6F',
40
+ '#FF84C6',
41
+ '#8D57E3',
42
+ '#32A3FF',
43
+ '#4B91F3',
44
+ '#3E1A9C'
45
+ ];
46
+ const getPrefixMap = (keys)=>keys.reduce((acc, curr)=>{
47
+ const prefix = curr.split('_')[0];
48
+ if (!acc[prefix]) acc[prefix] = [];
49
+ acc[prefix].push(curr);
50
+ return acc;
51
+ }, {});
52
+ const GroupLineCompare = ({ height, data, x = 'groupName', y = '', legend = 'groupType', indicatorMap, config, auxiliaryLineData, nodeSetting = {
53
+ showType: 0,
54
+ type: []
55
+ }, highlightDate })=>{
56
+ const [colorMap, setColorMap] = useState({});
57
+ const [checkedLegendItems, setCheckedLegendItems] = useState(new Set());
58
+ const [legendItems, setLegendItems] = useState([]);
59
+ const [axisHorPadding, setAxisHorPadding] = useState(0);
60
+ const [padding, setPadding] = useState([
61
+ 20,
62
+ 10,
63
+ 10,
64
+ 0
65
+ ]);
66
+ const [mainBarSize, setMainBarSize] = useState(void 0);
67
+ const yAxis = 'groupValue';
68
+ const { isDataTag = true, isLegend = true, isHighlight = true } = config || {};
69
+ const filterData = useMemo(()=>{
70
+ const ds = new lib();
71
+ const dv = ds.createView().source(data);
72
+ if ('' !== y) {
73
+ dv.transform({
74
+ type: 'map',
75
+ callback (row) {
76
+ row[yAxis] = '' !== row[yAxis] ? +row[yAxis] : '-';
77
+ return row;
78
+ }
79
+ });
80
+ dv.transform({
81
+ type: 'filter',
82
+ callback (row) {
83
+ return '-' !== row[yAxis];
84
+ }
85
+ });
86
+ }
87
+ return dv.rows;
88
+ }, [
89
+ data
90
+ ]);
91
+ const transformData = useMemo(()=>filterData.reduce((prev, curr)=>{
92
+ const compareCurr = {
93
+ ...curr,
94
+ groupType: `${curr.groupType}_compare`,
95
+ groupValue: curr.compareValue
96
+ };
97
+ prev.push(curr, compareCurr);
98
+ return prev;
99
+ }, []), [
100
+ filterData
101
+ ]);
102
+ const maxY = useMemo(()=>{
103
+ let maxValue = Math.max(...transformData?.length ? transformData.map((item)=>+item[yAxis]) : [
104
+ 0
105
+ ]);
106
+ if (auxiliaryLineData?.length) {
107
+ const maxAuxiliaryLine = Math.max(...auxiliaryLineData.map((item)=>+item.value));
108
+ if (maxAuxiliaryLine > maxValue) maxValue = maxAuxiliaryLine;
109
+ }
110
+ return maxValue;
111
+ }, [
112
+ transformData,
113
+ auxiliaryLineData
114
+ ]);
115
+ useEffect(()=>{
116
+ if (maxY > Math.max(...transformData?.length ? transformData.map((item)=>+item[yAxis]) : [
117
+ 0
118
+ ])) setPadding((pre)=>[
119
+ 25,
120
+ pre[1],
121
+ pre[2],
122
+ pre[3]
123
+ ]);
124
+ }, [
125
+ maxY,
126
+ transformData
127
+ ]);
128
+ useEffect(()=>{
129
+ const groupTypeSet = new Set();
130
+ transformData.forEach((item)=>{
131
+ groupTypeSet.add(item.groupType);
132
+ });
133
+ const groupTypeArr = [
134
+ ...groupTypeSet
135
+ ];
136
+ const prefixMap = getPrefixMap(groupTypeArr);
137
+ const colorMap = {};
138
+ let colorIndex = 0;
139
+ for(const prefix in prefixMap)if (prefixMap.hasOwnProperty(prefix)) {
140
+ const color = defaultColorPalette[colorIndex];
141
+ prefixMap[prefix].forEach((key)=>{
142
+ colorMap[key] = color;
143
+ });
144
+ colorIndex++;
145
+ }
146
+ const groupTypeLegendArr = groupTypeArr.filter((type)=>!type.includes('_compare'));
147
+ const legendItems = groupTypeLegendArr.map((item)=>({
148
+ id: item,
149
+ name: item,
150
+ value: item,
151
+ marker: {
152
+ style: {
153
+ fill: colorMap[item]
154
+ }
155
+ }
156
+ }));
157
+ setColorMap(colorMap);
158
+ setLegendItems(legendItems);
159
+ setCheckedLegendItems(groupTypeSet);
160
+ }, [
161
+ transformData
162
+ ]);
163
+ transformData.forEach((item)=>{
164
+ const infos = [
165
+ ...item?.nodeInfos?.info || [],
166
+ ...item?.nodeInfos?.infosCompare || []
167
+ ];
168
+ const len = infos.length || 0;
169
+ item.nodeLen = len;
170
+ if (0 === len) return;
171
+ item.node = 0;
172
+ item.color = 1 == len ? nodeMap.get(infos[0].type)?.color : 'l (0) 0:#32C5FF 0.44:#B620E0 0.99:#F7B500';
173
+ });
174
+ const [pointP, setPointP] = useState({
175
+ x: 0,
176
+ y: 0
177
+ });
178
+ const [pointData, setPointData] = useState({
179
+ info: [],
180
+ infosCompare: []
181
+ });
182
+ useEffect(()=>{
183
+ setPointP({
184
+ x: 0,
185
+ y: 0
186
+ });
187
+ setPointData({
188
+ info: [],
189
+ infosCompare: []
190
+ });
191
+ }, [
192
+ data
193
+ ]);
194
+ const filterFn = useMemo(()=>(item)=>highlightDate?.includes(item.groupName) ?? false, [
195
+ highlightDate
196
+ ]);
197
+ const nodeViewData = useMemo(()=>{
198
+ const uniqueMap = new Map();
199
+ transformData.forEach((item)=>{
200
+ const hasNode = (item?.nodeInfos?.info?.length || 0) > 0 || (item?.nodeInfos?.infosCompare?.length || 0) > 0;
201
+ if (hasNode && !uniqueMap.has(item.groupName)) uniqueMap.set(item.groupName, {
202
+ groupName: item.groupName,
203
+ node: 0,
204
+ nodeInfos: item.nodeInfos,
205
+ color: item.color,
206
+ [legend]: 'NodeEvent'
207
+ });
208
+ });
209
+ return Array.from(uniqueMap.values());
210
+ }, [
211
+ transformData
212
+ ]);
213
+ return /*#__PURE__*/ jsxs(Chart, {
214
+ height: height || 300,
215
+ data: transformData,
216
+ ...defaultChartConfig.baseChartConfig,
217
+ appendPadding: padding,
218
+ scale: {
219
+ [yAxis]: {
220
+ type: 'linear',
221
+ max: maxY,
222
+ nice: true
223
+ }
224
+ },
225
+ onPointMouseover: (e)=>{
226
+ if (1 == nodeSetting.showType) {
227
+ setPointP({
228
+ x: e.data.x,
229
+ y: e.data.y
230
+ });
231
+ setPointData(e.data.data.nodeInfos);
232
+ }
233
+ },
234
+ onAfterrender: (_e, chart)=>{
235
+ const estimatedBarWidth = calculateBarWidth(chart, transformData, x, 0.5);
236
+ if (void 0 !== estimatedBarWidth) setMainBarSize(estimatedBarWidth);
237
+ },
238
+ children: [
239
+ /*#__PURE__*/ jsx(XAxisBackground, {
240
+ x: x,
241
+ data: transformData,
242
+ isHighlight: isHighlight,
243
+ filterFn: filterFn,
244
+ dataLength: transformData.length,
245
+ mainBarSize: mainBarSize
246
+ }),
247
+ /*#__PURE__*/ jsx(Line, {
248
+ position: `${x}*${yAxis}`,
249
+ style: [
250
+ legend,
251
+ (legend)=>{
252
+ const res = {
253
+ cursor: 'pointer'
254
+ };
255
+ if (checkedLegendItems.has(legend)) {
256
+ res.strokeOpacity = 1;
257
+ if (legend.includes('_compare')) return {
258
+ lineDash: [
259
+ 4,
260
+ 4
261
+ ]
262
+ };
263
+ } else res.strokeOpacity = 0;
264
+ return res;
265
+ }
266
+ ],
267
+ color: [
268
+ legend,
269
+ (legend)=>colorMap[legend]
270
+ ],
271
+ label: [
272
+ `${legend}*${yAxis}`,
273
+ (legend, value)=>({
274
+ content: isDataTag ? formatIndicatorV2(value, indicatorMap[y]) : null,
275
+ style: {
276
+ opacity: checkedLegendItems.has(legend) ? 1 : 0
277
+ }
278
+ })
279
+ ],
280
+ shape: [
281
+ legend,
282
+ (legend)=>{
283
+ if (legend.includes('_compare')) return 'dash';
284
+ return 'line';
285
+ }
286
+ ]
287
+ }),
288
+ /*#__PURE__*/ jsx(Tooltip, {
289
+ shared: true,
290
+ showCrosshairs: true,
291
+ children: (title, items)=>{
292
+ const originItems = items?.filter((item)=>!item.name.includes('_compare'));
293
+ return /*#__PURE__*/ jsx("div", {
294
+ style: {
295
+ padding: '10px 0'
296
+ },
297
+ children: items?.length ? /*#__PURE__*/ jsxs(StyledTooltip, {
298
+ children: [
299
+ originItems?.map((it, index)=>{
300
+ const compareItem = items.find((item)=>item.name === `${it.name}_compare`) || {};
301
+ return /*#__PURE__*/ jsxs(react.Fragment, {
302
+ children: [
303
+ !index && /*#__PURE__*/ jsxs("div", {
304
+ className: "table-row",
305
+ children: [
306
+ /*#__PURE__*/ jsx("div", {
307
+ className: "table-cell"
308
+ }),
309
+ /*#__PURE__*/ jsx("div", {
310
+ className: "table-cell padding-right-10 padding-left-10",
311
+ children: title
312
+ }),
313
+ /*#__PURE__*/ jsx("div", {
314
+ className: "table-cell padding-right-10 padding-left-10",
315
+ children: compareItem.data?.compareTime || '-'
316
+ }),
317
+ /*#__PURE__*/ jsx("div", {
318
+ className: "table-cell",
319
+ children: "相比变化"
320
+ })
321
+ ]
322
+ }),
323
+ /*#__PURE__*/ jsxs("div", {
324
+ className: "table-row",
325
+ children: [
326
+ /*#__PURE__*/ jsxs("div", {
327
+ className: "table-cell padding-top-10",
328
+ children: [
329
+ /*#__PURE__*/ jsx("span", {
330
+ style: {
331
+ width: '8px',
332
+ height: '8px',
333
+ backgroundColor: it.color,
334
+ display: 'inline-block',
335
+ borderRadius: '50%',
336
+ marginRight: '8px'
337
+ }
338
+ }),
339
+ it.name
340
+ ]
341
+ }),
342
+ /*#__PURE__*/ jsx("div", {
343
+ className: "table-cell padding-right-10 padding-left-10 font-weight-bold",
344
+ children: formatIndicatorV2(it.value, indicatorMap[y])
345
+ }),
346
+ /*#__PURE__*/ jsx("div", {
347
+ className: "table-cell padding-right-10 padding-left-10 font-weight-bold",
348
+ children: formatIndicatorV2(compareItem.value, indicatorMap[y])
349
+ }),
350
+ /*#__PURE__*/ jsx("div", {
351
+ className: "table-cell font-weight-bold",
352
+ children: /*#__PURE__*/ jsx(CompareChange, {
353
+ value: it.data.change,
354
+ fontSize: 12
355
+ })
356
+ })
357
+ ]
358
+ })
359
+ ]
360
+ }, index);
361
+ }),
362
+ auxiliaryLineData && auxiliaryLineData.map((item, index)=>/*#__PURE__*/ jsxs("div", {
363
+ className: "table-row",
364
+ children: [
365
+ /*#__PURE__*/ jsxs("div", {
366
+ className: "table-cell padding-top-10",
367
+ style: {
368
+ paddingLeft: '16px'
369
+ },
370
+ children: [
371
+ item.name,
372
+ ":"
373
+ ]
374
+ }),
375
+ /*#__PURE__*/ jsx("div", {
376
+ className: "table-cell"
377
+ }),
378
+ /*#__PURE__*/ jsx("div", {
379
+ className: "table-cell"
380
+ }),
381
+ /*#__PURE__*/ jsx("div", {
382
+ className: "table-cell",
383
+ children: formatIndicatorV2(item.value, indicatorMap[y])
384
+ })
385
+ ]
386
+ }, index))
387
+ ]
388
+ }) : title
389
+ });
390
+ }
391
+ }),
392
+ auxiliaryLineData?.length > 0 && /*#__PURE__*/ jsxs(View, {
393
+ data: transformData,
394
+ scale: {
395
+ [yAxis]: {
396
+ type: 'linear',
397
+ max: maxY,
398
+ nice: true
399
+ }
400
+ },
401
+ padding: [
402
+ 0,
403
+ 0,
404
+ 0,
405
+ -axisHorPadding
406
+ ],
407
+ children: [
408
+ /*#__PURE__*/ jsx(Axis, {
409
+ name: yAxis,
410
+ visible: false
411
+ }),
412
+ /*#__PURE__*/ jsx(Axis, {
413
+ name: x,
414
+ visible: false
415
+ }),
416
+ /*#__PURE__*/ jsx(Line, {
417
+ position: `${x}*${yAxis}`,
418
+ visible: false
419
+ }),
420
+ auxiliaryLineData.map((item, index)=>/*#__PURE__*/ jsx(AuxiliaryLine, {
421
+ name: item.name,
422
+ value: item.value
423
+ }, index))
424
+ ]
425
+ }, axisHorPadding),
426
+ /*#__PURE__*/ jsx(Legend, {
427
+ custom: true,
428
+ position: "bottom-left",
429
+ name: legend,
430
+ items: legendItems,
431
+ filter: (name)=>checkedLegendItems.has(name),
432
+ onChange: (e)=>{
433
+ const { unchecked, name } = e.item;
434
+ if (unchecked) {
435
+ checkedLegendItems.delete(name);
436
+ checkedLegendItems.delete(`${name}_compare`);
437
+ } else checkedLegendItems.add(name).add(`${name}_compare`);
438
+ setCheckedLegendItems(new Set([
439
+ ...checkedLegendItems
440
+ ]));
441
+ },
442
+ maxItemWidth: 1,
443
+ visible: isLegend,
444
+ itemHeight: 14
445
+ }),
446
+ /*#__PURE__*/ jsx(Legend, {
447
+ name: "color",
448
+ visible: false
449
+ }),
450
+ /*#__PURE__*/ jsx(Axis, {
451
+ name: yAxis,
452
+ label: {
453
+ formatter (val) {
454
+ setAxisHorPadding(getAxisHorPaddingByText(val, indicatorMap, y) - 22);
455
+ return getAxisFormat(val, indicatorMap, y);
456
+ }
457
+ }
458
+ }),
459
+ /*#__PURE__*/ jsx(Axis, {
460
+ name: x,
461
+ label: {
462
+ autoEllipsis: true
463
+ }
464
+ }),
465
+ nodeViewData.length > 0 && 1 == nodeSetting.showType && /*#__PURE__*/ jsxs(View, {
466
+ data: nodeViewData,
467
+ scale: {
468
+ node: {
469
+ min: 0,
470
+ max: 1
471
+ },
472
+ groupName: {
473
+ type: 'cat'
474
+ }
475
+ },
476
+ children: [
477
+ /*#__PURE__*/ jsx(Axis, {
478
+ name: "node",
479
+ visible: false
480
+ }),
481
+ /*#__PURE__*/ jsx(Legend, {
482
+ name: "color",
483
+ visible: false
484
+ }),
485
+ /*#__PURE__*/ jsx(NodeGeom, {
486
+ pointData: pointData,
487
+ pointP: pointP,
488
+ isLegend: isLegend
489
+ })
490
+ ]
491
+ })
492
+ ]
493
+ }, nodeSetting?.showType + JSON.stringify(config));
494
+ };
495
+ const composite_GroupLineCompare = /*#__PURE__*/ memo(GroupLineCompare);
496
+ export { composite_GroupLineCompare as default };
@@ -0,0 +1,2 @@
1
+ declare const _default: import("react").MemoExoticComponent<({ height, data, x, legend, indicatorMap, config, auxiliaryLineData, nodeSetting, highlightDate, timeRange, }: any) => JSX.Element>;
2
+ export default _default;