@easyv/charts 1.2.0 → 1.2.1

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 (86) hide show
  1. package/.babelrc +8 -8
  2. package/.husky/commit-msg +3 -3
  3. package/CHANGELOG.md +18 -18
  4. package/commitlint.config.js +1 -1
  5. package/lib/components/AnimateData.js +36 -36
  6. package/lib/components/Axis.js +329 -329
  7. package/lib/components/Background.js +2 -2
  8. package/lib/components/Band.js +173 -173
  9. package/lib/components/Brush.js +201 -201
  10. package/lib/components/Carousel.js +164 -164
  11. package/lib/components/Chart.js +111 -111
  12. package/lib/components/ChartContainer.js +58 -58
  13. package/lib/components/ConicalGradient.js +264 -264
  14. package/lib/components/ExtentData.js +45 -45
  15. package/lib/components/FilterData.js +53 -53
  16. package/lib/components/Indicator.js +2 -2
  17. package/lib/components/Label.js +278 -278
  18. package/lib/components/Legend.js +154 -154
  19. package/lib/components/Lighter.js +179 -179
  20. package/lib/components/Line.js +181 -181
  21. package/lib/components/LinearGradient.js +2 -2
  22. package/lib/components/Mapping.js +127 -127
  23. package/lib/components/PieChart.js +1061 -1061
  24. package/lib/components/StackData.js +45 -45
  25. package/lib/components/StereoBar.js +336 -336
  26. package/lib/components/Tooltip.js +155 -155
  27. package/lib/components/index.js +194 -194
  28. package/lib/css/index.module.css +41 -41
  29. package/lib/css/piechart.module.css +26 -26
  30. package/lib/element/ConicGradient.js +72 -72
  31. package/lib/formatter/legend.js +91 -91
  32. package/lib/hooks/index.js +62 -62
  33. package/lib/hooks/useAnimateData.js +88 -88
  34. package/lib/hooks/useAxes.js +135 -135
  35. package/lib/hooks/useCarouselAxisX.js +184 -184
  36. package/lib/hooks/useExtentData.js +128 -128
  37. package/lib/hooks/useFilterData.js +112 -112
  38. package/lib/hooks/useStackData.js +134 -134
  39. package/lib/hooks/useTooltip.js +10 -10
  40. package/lib/index.js +84 -84
  41. package/lib/utils/index.js +832 -832
  42. package/package.json +51 -51
  43. package/src/components/AnimateData.tsx +24 -24
  44. package/src/components/Axis.tsx +354 -354
  45. package/src/components/Background.tsx +45 -45
  46. package/src/components/Band.tsx +173 -173
  47. package/src/components/Brush.js +159 -159
  48. package/src/components/Carousel.tsx +144 -144
  49. package/src/components/Chart.js +99 -99
  50. package/src/components/ChartContainer.tsx +63 -63
  51. package/src/components/ConicalGradient.js +258 -258
  52. package/src/components/ExtentData.js +17 -17
  53. package/src/components/FilterData.js +23 -23
  54. package/src/components/Indicator.js +13 -13
  55. package/src/components/Label.js +206 -206
  56. package/src/components/Legend.js +158 -158
  57. package/src/components/Lighter.jsx +173 -173
  58. package/src/components/Line.js +144 -144
  59. package/src/components/LinearGradient.js +29 -29
  60. package/src/components/Mapping.js +71 -71
  61. package/src/components/Marquee.js +74 -0
  62. package/src/components/PieChart.js +1097 -1097
  63. package/src/components/StackData.js +20 -20
  64. package/src/components/StereoBar.tsx +310 -310
  65. package/src/components/Tooltip.js +169 -169
  66. package/src/components/index.js +51 -51
  67. package/src/context/index.js +2 -2
  68. package/src/css/index.module.css +41 -41
  69. package/src/css/piechart.module.css +26 -26
  70. package/src/element/ConicGradient.jsx +55 -55
  71. package/src/element/Line.tsx +33 -33
  72. package/src/element/index.ts +3 -3
  73. package/src/formatter/index.js +1 -1
  74. package/src/formatter/legend.js +90 -90
  75. package/src/hooks/index.js +17 -17
  76. package/src/hooks/useAnimateData.ts +67 -67
  77. package/src/hooks/useAxes.js +144 -144
  78. package/src/hooks/useCarouselAxisX.js +163 -163
  79. package/src/hooks/useExtentData.js +88 -88
  80. package/src/hooks/useFilterData.js +72 -72
  81. package/src/hooks/useStackData.js +100 -100
  82. package/src/hooks/useTooltip.ts +96 -96
  83. package/src/index.js +6 -6
  84. package/src/types/index.d.ts +67 -67
  85. package/src/utils/index.js +696 -696
  86. package/tsconfig.json +22 -22
@@ -1,696 +1,696 @@
1
- import { getColor } from '@easyv/utils';
2
- import { toFixed } from '@easyv/utils/lib/common/utils';
3
- import {
4
- scaleOrdinal as ordinal,
5
- range as sequence,
6
- ascending,
7
- descending,
8
- sum,
9
- } from 'd3v7';
10
- import { renderToStaticMarkup } from 'react-dom/server';
11
- import { toPath } from 'svg-points';
12
-
13
- const defaultSize = 10;
14
- const defaultBackground = '#000000';
15
- const defaultIcon = {
16
- width: defaultSize,
17
- height: defaultSize,
18
- background: defaultBackground,
19
- };
20
- const defaultLineIcon = {
21
- width: defaultSize,
22
- height: 2,
23
- background: defaultBackground,
24
- };
25
- const SvgBackground = ({
26
- fill: {
27
- type,
28
- pure,
29
- linear: { angle, opacity, stops },
30
- },
31
- pattern: {
32
- path = '',
33
- width = '100%',
34
- height = '100%',
35
- boderColor: stroke = 'transparent',
36
- boderWidth = 0,
37
- },
38
- }) => {
39
- return (
40
- <svg
41
- preserveAspectRatio='none'
42
- xmlns='http://www.w3.org/2000/svg'
43
- width={width}
44
- height={height}
45
- >
46
- <defs>
47
- <linearGradient
48
- id='linearGradient'
49
- x1='0%'
50
- y1='0%'
51
- x2='0%'
52
- y2='100%'
53
- gradientTransform={'rotate(' + (angle + 180) + ', 0.5, 0.5)'}
54
- >
55
- {stops.map(({ offset, color }, index) => (
56
- <stop
57
- key={index}
58
- offset={offset + '%'}
59
- stopColor={color}
60
- stopOpacity={opacity}
61
- />
62
- ))}
63
- </linearGradient>
64
- </defs>
65
- <path
66
- d={path}
67
- fill={type === 'pure' ? pure : 'url(#linearGradient)'}
68
- stroke={stroke}
69
- strokeWidth={boderWidth}
70
- />
71
- </svg>
72
- );
73
- };
74
- const getColorList = ({ type, pure, linear: { stops, angle, opacity } }) => {
75
- if (type == 'pure') {
76
- return [
77
- { color: pure, offset: 1 },
78
- { color: pure, offset: 0 },
79
- ];
80
- }
81
- return stops.map(({ color, offset }) => ({ color, offset: offset / 100 }));
82
- };
83
- const getIcon = (type, icon) => {
84
- switch (type) {
85
- case 'area':
86
- case 'line':
87
- return icon
88
- ? {
89
- ...defaultLineIcon,
90
- ...icon,
91
- }
92
- : defaultLineIcon;
93
- default:
94
- return icon
95
- ? {
96
- ...defaultIcon,
97
- ...icon,
98
- }
99
- : defaultIcon;
100
- }
101
- };
102
-
103
- const dateFormat = (date, fmt) => {
104
- date = new Date(date);
105
- const o = {
106
- 'M+': date.getMonth() + 1, //月份
107
- 'D+': date.getDate(), //日
108
- 'H+': date.getHours(), //小时
109
- 'h+': date.getHours() % 12 == 0 ? 12 : date.getHours() % 12, //小时
110
- 'm+': date.getMinutes(), //分
111
- 's+': date.getSeconds(), //秒
112
- S: date.getMilliseconds(), //毫秒
113
- X: '星期' + '日一二三四五六'.charAt(date.getDay()),
114
- W: new Array(
115
- 'Sunday',
116
- 'Monday',
117
- 'Tuesday',
118
- 'Wednesday',
119
- 'Thursday',
120
- 'Friday',
121
- 'Saturday'
122
- )[date.getDay()],
123
- w: new Array('Sun.', 'Mon.', ' Tues.', 'Wed.', ' Thur.', 'Fri.', 'Sat.')[
124
- date.getDay()
125
- ],
126
- };
127
- if (/(Y+)/.test(fmt))
128
- fmt = fmt.replace(
129
- RegExp.$1,
130
- (date.getFullYear() + '').substr(4 - RegExp.$1.length)
131
- );
132
- for (var k in o)
133
- if (new RegExp('(' + k + ')').test(fmt))
134
- fmt = fmt.replace(
135
- RegExp.$1,
136
- RegExp.$1.length == 1 ? o[k] : ('00' + o[k]).substr(('' + o[k]).length)
137
- );
138
- return fmt;
139
- };
140
- const getBreakWord = (str, breakNumber) => {
141
- const re = new RegExp('([^]){1,' + breakNumber + '}', 'g');
142
- return str.match(re);
143
- };
144
-
145
- //x轴标签逻辑
146
-
147
- const getTicksOfAxis = (domain, ticksCount, showLast) => {
148
- let len = domain.length;
149
- if (ticksCount < 2 || ticksCount > len) return domain;
150
- let step = Math.floor((len - ticksCount) / (ticksCount - 1));
151
- const ticksArr = domain.filter(function (d, i) {
152
- return i % (step + 1) === 0;
153
- });
154
- let Tlen = ticksArr.length;
155
- let lastIndex = domain.findIndex((d) => d == ticksArr[Tlen - 1]);
156
- if (showLast) {
157
- len % ticksCount == 0 || len - 1 - lastIndex >= Math.round(len / Tlen / 2)
158
- ? null
159
- : ticksArr.pop();
160
- ticksArr.push(domain[len - 1]);
161
- }
162
- return ticksArr;
163
- };
164
-
165
- const getTickCoord = ({
166
- orientation,
167
- coordinate,
168
- tickSize = 6,
169
- x = 0,
170
- y = 0,
171
- }) => {
172
- let x1, x2, y1, y2;
173
- switch (orientation) {
174
- case 'top':
175
- x1 = x2 = coordinate;
176
- y2 = y;
177
- y1 = y2 - tickSize;
178
- break;
179
- case 'left':
180
- y1 = y2 = coordinate;
181
- x2 = x;
182
- x1 = x2 - tickSize;
183
- break;
184
- case 'right':
185
- y1 = y2 = coordinate;
186
- x2 = x;
187
- x1 = x2 + tickSize;
188
- break;
189
- default:
190
- x1 = x2 = coordinate;
191
- y2 = y;
192
- y1 = y2 + tickSize;
193
- break;
194
- }
195
- return { x1, x2, y1, y2 };
196
- };
197
- const getGridCoord = ({ orientation, coordinate, end }) => {
198
- let x1, x2, y1, y2;
199
- switch (orientation) {
200
- case 'top':
201
- x1 = x2 = coordinate;
202
- y1 = 0;
203
- y2 = end;
204
- break;
205
- case 'bottom':
206
- x1 = x2 = coordinate;
207
- y1 = 0;
208
- y2 = end * -1;
209
- break;
210
- case 'left':
211
- y1 = y2 = coordinate;
212
- x1 = 0;
213
- x2 = end;
214
- break;
215
- case 'right':
216
- y1 = y2 = coordinate;
217
- x1 = 0;
218
- x2 = end * -1;
219
- break;
220
- }
221
- return { x1, x2, y1, y2 };
222
- };
223
-
224
- const identity = (d) => d;
225
-
226
- //获取鼠标指针坐标
227
- const getMousePos = (evt, dom) => {
228
- var rect = dom.getBoundingClientRect();
229
- return {
230
- x: evt.clientX - rect.left,
231
- y: evt.clientY - rect.top,
232
- w: rect.width,
233
- h: rect.height,
234
- };
235
- };
236
-
237
- const getFontStyle = (
238
- { color, bold, italic, fontSize, fontFamily, letterSpacing },
239
- type
240
- ) => {
241
- if (type == 'svg') {
242
- return {
243
- fontSize,
244
- fontFamily,
245
- letterSpacing,
246
- fill: color,
247
- fontWeight: bold ? 'bold' : 'normal',
248
- fontStyle: italic ? 'italic' : 'normal',
249
- };
250
- }
251
- return {
252
- fontSize,
253
- fontFamily,
254
- letterSpacing,
255
- color,
256
- fontWeight: bold ? 'bold' : 'normal',
257
- fontStyle: italic ? 'italic' : 'normal',
258
- };
259
- };
260
-
261
- const getMargin = ({ marginTop, marginRight, marginBottom, marginLeft }) =>
262
- marginTop +
263
- 'px ' +
264
- marginRight +
265
- 'px ' +
266
- marginBottom +
267
- 'px ' +
268
- marginLeft +
269
- 'px';
270
- const getTranslate3d = ({ x = 0, y = 0, z = 0 }) =>
271
- 'translate3d(' + x + 'px, ' + y + 'px, ' + z + 'px)';
272
- const getTranslate2d = ({ x = 0, y = 0 }) => 'translate(' + x + ', ' + y + ')';
273
- function band() {
274
- var scale = ordinal().unknown(undefined),
275
- domain = scale.domain,
276
- ordinalRange = scale.range,
277
- r0 = 0,
278
- r1 = 1,
279
- step,
280
- bandwidth,
281
- round = false,
282
- paddingInner = 0,
283
- paddingOuter = 0,
284
- // seriesPaddingInner = 0,
285
- // seriesPaddingOuter = 0,
286
- // seriesLength = 0,
287
- align = 0.5;
288
-
289
- delete scale.unknown;
290
-
291
- function rescale() {
292
- var n = domain().length,
293
- reverse = r1 < r0,
294
- start = reverse ? r1 : r0,
295
- stop = reverse ? r0 : r1;
296
- step = (stop - start) / Math.max(1, n - paddingOuter * 2);
297
- if (round) step = Math.floor(step);
298
- start += (stop - start - step * n) * align;
299
- bandwidth = step;
300
- if (round) (start = Math.round(start)), (bandwidth = Math.round(bandwidth));
301
- var values = sequence(n).map(function (i) {
302
- return start + step * i + step / 2;
303
- });
304
- return ordinalRange(reverse ? values.reverse() : values);
305
- }
306
-
307
- scale.domain = function (_) {
308
- return arguments.length ? (domain(_), rescale()) : domain();
309
- };
310
-
311
- scale.range = function (_) {
312
- return arguments.length
313
- ? (([r0, r1] = _), (r0 = +r0), (r1 = +r1), rescale())
314
- : [r0, r1];
315
- };
316
-
317
- scale.rangeRound = function (_) {
318
- return ([r0, r1] = _), (r0 = +r0), (r1 = +r1), (round = true), rescale();
319
- };
320
-
321
- scale.bandwidth = function () {
322
- return bandwidth;
323
- };
324
-
325
- scale.step = function () {
326
- return step;
327
- };
328
-
329
- scale.seriesBandwidth = function () {
330
- return seriesBandwidth;
331
- };
332
-
333
- scale.seriesStep = function () {
334
- return seriesStep;
335
- };
336
-
337
- scale.round = function (_) {
338
- return arguments.length ? ((round = !!_), rescale()) : round;
339
- };
340
-
341
- scale.padding = function (_) {
342
- return arguments.length
343
- ? ((paddingInner = Math.min(1, (paddingOuter = +_))), rescale())
344
- : paddingInner;
345
- };
346
-
347
- scale.paddingInner = function (_) {
348
- return arguments.length
349
- ? ((paddingInner = Math.min(1, _)), rescale())
350
- : paddingInner;
351
- };
352
-
353
- scale.paddingOuter = function (_) {
354
- return arguments.length ? ((paddingOuter = +_), rescale()) : paddingOuter;
355
- };
356
-
357
- scale.align = function (_) {
358
- return arguments.length
359
- ? ((align = Math.max(0, Math.min(1, _))), rescale())
360
- : align;
361
- };
362
-
363
- scale.copy = function () {
364
- return band(domain(), [r0, r1])
365
- .round(round)
366
- .paddingInner(paddingInner)
367
- .paddingOuter(paddingOuter)
368
- .align(align);
369
- };
370
-
371
- return initRange.apply(rescale(), arguments);
372
- }
373
-
374
- function initRange(domain, range) {
375
- switch (arguments.length) {
376
- case 0:
377
- break;
378
- case 1:
379
- this.range(domain);
380
- break;
381
- default:
382
- this.range(range).domain(domain);
383
- break;
384
- }
385
- return this;
386
- }
387
-
388
- const getStacks = (series) => {
389
- const tmp = [];
390
- series.forEach(({ type, stack, yOrZ }, name) => {
391
- const current = tmp.find(
392
- ({ type: _type, stack: _stack, yOrZ: _yOrZ }) =>
393
- _type == type && stack && _stack == stack && yOrZ == _yOrZ
394
- );
395
- if (!current) {
396
- const common = {
397
- type,
398
- stack,
399
- positive: 0,
400
- negative: 0,
401
- yOrZ,
402
- s: [name],
403
- };
404
- if (type === 'band') {
405
- const index = tmp.filter((item) => item.type === 'band').length;
406
- tmp.push({
407
- ...common,
408
- index,
409
- });
410
- } else {
411
- tmp.push({
412
- ...common,
413
- index: 0,
414
- });
415
- }
416
- } else {
417
- current.s.push(name);
418
- }
419
- });
420
- return tmp;
421
- };
422
-
423
- const dataYOrZ = (data, { y: seriesY, z: seriesZ }) => {
424
- const tmp = {
425
- y: [],
426
- z: [],
427
- };
428
- for (let i = 0, j = data.length; i < j; i++) {
429
- const d = data[i];
430
- if (seriesY.get(d.s)) {
431
- tmp.y.push(d);
432
- continue;
433
- }
434
- if (seriesZ.get(d.s)) {
435
- tmp.z.push(d);
436
- }
437
- }
438
- return tmp;
439
- };
440
-
441
- const seriesYOrZ = (series) => {
442
- const y = new Map();
443
- const z = new Map();
444
- series.forEach((value, key) => {
445
- if (value.yOrZ === 'y') {
446
- y.set(key, value);
447
- } else {
448
- z.set(key, value);
449
- }
450
- });
451
- return { y, z };
452
- };
453
-
454
- const resetStacks = (stacks) => {
455
- stacks.forEach((stack) => {
456
- stack.positive = 0;
457
- stack.negative = 0;
458
- });
459
- };
460
-
461
- const getCurrentStack = (stack, stackMap) =>
462
- stackMap.find(
463
- ({ stack: _stack, type: _type, yOrZ: _yOrZ, s: _s }) =>
464
- _type == stack.type &&
465
- _stack == stack.stack &&
466
- _yOrZ == stack.yOrZ &&
467
- _s.includes(stack.name)
468
- );
469
-
470
- const getBandBackground = (pattern, fill) => {
471
- if (!(pattern && pattern.path)) return getColor(fill);
472
- const { backgroundSize = '100% 100%', ..._pattern } = pattern;
473
- return (
474
- 'center top / ' +
475
- backgroundSize +
476
- ' url("data:image/svg+xml,' +
477
- encodeURIComponent(
478
- renderToStaticMarkup(<SvgBackground fill={fill} pattern={_pattern} />)
479
- ) +
480
- '")'
481
- );
482
- };
483
- const getBandwidth = (step, paddingOuter) =>
484
- step / Math.max(1, 1 + paddingOuter);
485
-
486
- const getBandSeriesStepAndWidth = ({ width, paddingInner, bandLength }) => {
487
- const seriesStep = width / Math.max(1, bandLength - paddingInner);
488
- const seriesWidth = seriesStep * (1 - paddingInner);
489
- return {
490
- seriesStep,
491
- seriesWidth,
492
- };
493
- };
494
- const isValidHttpUrl = (string) => {
495
- let url;
496
-
497
- try {
498
- url = new URL(string);
499
- } catch (_) {
500
- return false;
501
- }
502
-
503
- return url.protocol === 'http:' || url.protocol === 'https:';
504
- };
505
-
506
- const getChildren = (svgStr) => {
507
- const wrapper = document.createElement('div');
508
- wrapper.innerHTML = svgStr;
509
- const { childNodes } = wrapper;
510
- const svgDom = [...childNodes].find((item) => item.tagName === 'svg');
511
-
512
- if (!!svgDom) {
513
- return [...svgDom.childNodes];
514
- }
515
-
516
- return null;
517
- };
518
-
519
- const filterChildren = (children, tagNames) => {
520
- return children.reduce((prev, node) => {
521
- let { nodeName } = node;
522
-
523
- if (tagNames.indexOf(nodeName) > -1) {
524
- if (nodeName === 'g') {
525
- return filterChildren([...node.childNodes], tagNames);
526
- } else {
527
- prev.push(node);
528
- }
529
- }
530
-
531
- return prev;
532
- }, []);
533
- };
534
-
535
- const getDomPath = (node) => {
536
- switch (node.nodeName) {
537
- case 'circle':
538
- return toPath({
539
- type: 'circle',
540
- cx: +node.getAttribute('cx') || 0,
541
- cy: +node.getAttribute('cy') || 0,
542
- r: +node.getAttribute('r') || 0,
543
- });
544
-
545
- case 'ellipse':
546
- return toPath({
547
- type: 'ellipse',
548
- cx: +node.getAttribute('cx') || 0,
549
- cy: +node.getAttribute('cy') || 0,
550
- rx: +node.getAttribute('rx') || 0,
551
- ry: +node.getAttribute('ry') || 0,
552
- });
553
-
554
- case 'line':
555
- return toPath({
556
- type: 'line',
557
- x1: +node.getAttribute('x1') || 0,
558
- x2: +node.getAttribute('x2') || 0,
559
- y1: +node.getAttribute('y1') || 0,
560
- y2: +node.getAttribute('y2') || 0,
561
- });
562
-
563
- case 'path':
564
- return toPath({
565
- type: 'path',
566
- d: node.getAttribute('d') || '',
567
- });
568
-
569
- case 'polygon':
570
- return toPath({
571
- type: 'polyline',
572
- points: node.getAttribute('points') || '',
573
- });
574
-
575
- case 'polyline':
576
- return toPath({
577
- type: 'polyline',
578
- points: node.getAttribute('points') || '',
579
- });
580
-
581
- case 'rect':
582
- return toPath({
583
- type: 'rect',
584
- height: +node.getAttribute('height') || 0,
585
- width: +node.getAttribute('width') || 0,
586
- x: +node.getAttribute('x') || 0,
587
- y: +node.getAttribute('y') || 0,
588
- rx: +node.getAttribute('rx') || 0,
589
- ry: +node.getAttribute('ry') || 0,
590
- });
591
- }
592
- };
593
-
594
- const sortPie = (data, order) => {
595
- const _data = data.map((item) => ({ ...item }));
596
- switch (order) {
597
- case '':
598
- _data.sort(({ index: a }, { index: b }) => ascending(a, b));
599
- break;
600
- case 'desc':
601
- _data.sort(({ value: a }, { value: b }) => descending(a, b));
602
- break;
603
- case 'asc':
604
- _data.sort(({ value: a }, { value: b }) => ascending(a, b));
605
- break;
606
- }
607
- return _data;
608
- };
609
-
610
- // const getDataWithPercent = (data = [], precision = 0, type) => {
611
- // const digits = Math.pow(10, precision);
612
- // const targetSeats = digits * 100;
613
-
614
- // const total = sum(data, (d) => d.value);
615
-
616
- // const votesPerQuota = data.map((d, index) => ({
617
- // ...d,
618
- // vote: Math.round((d.value / total) * digits * 100),
619
- // index,
620
- // }));
621
- // const currentSum = sum(votesPerQuota, (d) => d.vote);
622
- // const remainder = targetSeats - currentSum;
623
- // console.log(type+":",votesPerQuota, toFixed);
624
- // votesPerQuota.sort(({ value: a }, { value: b }) => (a % total) - (b % total));
625
-
626
- // const tmp = votesPerQuota.map(({ vote, ...data }, index) => ({
627
- // ...data,
628
- // percent: toFixed((vote + (index < remainder ? 1 : 0)) / digits, precision),
629
- // }));
630
-
631
- // return tmp;
632
- // };
633
-
634
- const getDataWithPercent = (data = [], precision = 0) => {
635
- const digits = Math.pow(10, precision);
636
- const targetSeats = digits * 100;
637
-
638
- const total = sum(data, (d) => d.value);
639
-
640
- const votesPerQuota = data.map((d, index) => ({
641
- ...d,
642
- vote: Math.round((d.value / total) * digits * 100),
643
- index,
644
- }));
645
- const currentSum = sum(votesPerQuota, (d) => d.vote);
646
-
647
- let remainder = targetSeats - currentSum;
648
- votesPerQuota.sort(({ value: a }, { value: b }) => (a % total) - (b % total));
649
-
650
- const tmp = votesPerQuota.map(({ vote, value, ...data }, index) => {
651
- let obj = {
652
- ...data,
653
- value,
654
- percent: toFixed(
655
- (vote + (value && value != 0 ? remainder : 0)) / digits,
656
- precision
657
- ),
658
- };
659
- if (value && value != 0) {
660
- remainder = 0;
661
- }
662
- return obj;
663
- });
664
- return tmp;
665
- };
666
-
667
- export {
668
- dateFormat,
669
- getBreakWord,
670
- getTicksOfAxis,
671
- getTickCoord,
672
- getGridCoord,
673
- identity,
674
- getMousePos,
675
- getFontStyle,
676
- getMargin,
677
- getTranslate3d,
678
- getTranslate2d,
679
- band,
680
- getIcon,
681
- getColorList,
682
- getStacks,
683
- dataYOrZ,
684
- seriesYOrZ,
685
- resetStacks,
686
- getCurrentStack,
687
- getBandBackground,
688
- getBandwidth,
689
- getBandSeriesStepAndWidth,
690
- isValidHttpUrl,
691
- getChildren,
692
- filterChildren,
693
- getDomPath,
694
- sortPie,
695
- getDataWithPercent,
696
- };
1
+ import { getColor } from '@easyv/utils';
2
+ import { toFixed } from '@easyv/utils/lib/common/utils';
3
+ import {
4
+ scaleOrdinal as ordinal,
5
+ range as sequence,
6
+ ascending,
7
+ descending,
8
+ sum,
9
+ } from 'd3v7';
10
+ import { renderToStaticMarkup } from 'react-dom/server';
11
+ import { toPath } from 'svg-points';
12
+
13
+ const defaultSize = 10;
14
+ const defaultBackground = '#000000';
15
+ const defaultIcon = {
16
+ width: defaultSize,
17
+ height: defaultSize,
18
+ background: defaultBackground,
19
+ };
20
+ const defaultLineIcon = {
21
+ width: defaultSize,
22
+ height: 2,
23
+ background: defaultBackground,
24
+ };
25
+ const SvgBackground = ({
26
+ fill: {
27
+ type,
28
+ pure,
29
+ linear: { angle, opacity, stops },
30
+ },
31
+ pattern: {
32
+ path = '',
33
+ width = '100%',
34
+ height = '100%',
35
+ boderColor: stroke = 'transparent',
36
+ boderWidth = 0,
37
+ },
38
+ }) => {
39
+ return (
40
+ <svg
41
+ preserveAspectRatio='none'
42
+ xmlns='http://www.w3.org/2000/svg'
43
+ width={width}
44
+ height={height}
45
+ >
46
+ <defs>
47
+ <linearGradient
48
+ id='linearGradient'
49
+ x1='0%'
50
+ y1='0%'
51
+ x2='0%'
52
+ y2='100%'
53
+ gradientTransform={'rotate(' + (angle + 180) + ', 0.5, 0.5)'}
54
+ >
55
+ {stops.map(({ offset, color }, index) => (
56
+ <stop
57
+ key={index}
58
+ offset={offset + '%'}
59
+ stopColor={color}
60
+ stopOpacity={opacity}
61
+ />
62
+ ))}
63
+ </linearGradient>
64
+ </defs>
65
+ <path
66
+ d={path}
67
+ fill={type === 'pure' ? pure : 'url(#linearGradient)'}
68
+ stroke={stroke}
69
+ strokeWidth={boderWidth}
70
+ />
71
+ </svg>
72
+ );
73
+ };
74
+ const getColorList = ({ type, pure, linear: { stops, angle, opacity } }) => {
75
+ if (type == 'pure') {
76
+ return [
77
+ { color: pure, offset: 1 },
78
+ { color: pure, offset: 0 },
79
+ ];
80
+ }
81
+ return stops.map(({ color, offset }) => ({ color, offset: offset / 100 }));
82
+ };
83
+ const getIcon = (type, icon) => {
84
+ switch (type) {
85
+ case 'area':
86
+ case 'line':
87
+ return icon
88
+ ? {
89
+ ...defaultLineIcon,
90
+ ...icon,
91
+ }
92
+ : defaultLineIcon;
93
+ default:
94
+ return icon
95
+ ? {
96
+ ...defaultIcon,
97
+ ...icon,
98
+ }
99
+ : defaultIcon;
100
+ }
101
+ };
102
+
103
+ const dateFormat = (date, fmt) => {
104
+ date = new Date(date);
105
+ const o = {
106
+ 'M+': date.getMonth() + 1, //月份
107
+ 'D+': date.getDate(), //日
108
+ 'H+': date.getHours(), //小时
109
+ 'h+': date.getHours() % 12 == 0 ? 12 : date.getHours() % 12, //小时
110
+ 'm+': date.getMinutes(), //分
111
+ 's+': date.getSeconds(), //秒
112
+ S: date.getMilliseconds(), //毫秒
113
+ X: '星期' + '日一二三四五六'.charAt(date.getDay()),
114
+ W: new Array(
115
+ 'Sunday',
116
+ 'Monday',
117
+ 'Tuesday',
118
+ 'Wednesday',
119
+ 'Thursday',
120
+ 'Friday',
121
+ 'Saturday'
122
+ )[date.getDay()],
123
+ w: new Array('Sun.', 'Mon.', ' Tues.', 'Wed.', ' Thur.', 'Fri.', 'Sat.')[
124
+ date.getDay()
125
+ ],
126
+ };
127
+ if (/(Y+)/.test(fmt))
128
+ fmt = fmt.replace(
129
+ RegExp.$1,
130
+ (date.getFullYear() + '').substr(4 - RegExp.$1.length)
131
+ );
132
+ for (var k in o)
133
+ if (new RegExp('(' + k + ')').test(fmt))
134
+ fmt = fmt.replace(
135
+ RegExp.$1,
136
+ RegExp.$1.length == 1 ? o[k] : ('00' + o[k]).substr(('' + o[k]).length)
137
+ );
138
+ return fmt;
139
+ };
140
+ const getBreakWord = (str, breakNumber) => {
141
+ const re = new RegExp('([^]){1,' + breakNumber + '}', 'g');
142
+ return str.match(re);
143
+ };
144
+
145
+ //x轴标签逻辑
146
+
147
+ const getTicksOfAxis = (domain, ticksCount, showLast) => {
148
+ let len = domain.length;
149
+ if (ticksCount < 2 || ticksCount > len) return domain;
150
+ let step = Math.floor((len - ticksCount) / (ticksCount - 1));
151
+ const ticksArr = domain.filter(function (d, i) {
152
+ return i % (step + 1) === 0;
153
+ });
154
+ let Tlen = ticksArr.length;
155
+ let lastIndex = domain.findIndex((d) => d == ticksArr[Tlen - 1]);
156
+ if (showLast) {
157
+ len % ticksCount == 0 || len - 1 - lastIndex >= Math.round(len / Tlen / 2)
158
+ ? null
159
+ : ticksArr.pop();
160
+ ticksArr.push(domain[len - 1]);
161
+ }
162
+ return ticksArr;
163
+ };
164
+
165
+ const getTickCoord = ({
166
+ orientation,
167
+ coordinate,
168
+ tickSize = 6,
169
+ x = 0,
170
+ y = 0,
171
+ }) => {
172
+ let x1, x2, y1, y2;
173
+ switch (orientation) {
174
+ case 'top':
175
+ x1 = x2 = coordinate;
176
+ y2 = y;
177
+ y1 = y2 - tickSize;
178
+ break;
179
+ case 'left':
180
+ y1 = y2 = coordinate;
181
+ x2 = x;
182
+ x1 = x2 - tickSize;
183
+ break;
184
+ case 'right':
185
+ y1 = y2 = coordinate;
186
+ x2 = x;
187
+ x1 = x2 + tickSize;
188
+ break;
189
+ default:
190
+ x1 = x2 = coordinate;
191
+ y2 = y;
192
+ y1 = y2 + tickSize;
193
+ break;
194
+ }
195
+ return { x1, x2, y1, y2 };
196
+ };
197
+ const getGridCoord = ({ orientation, coordinate, end }) => {
198
+ let x1, x2, y1, y2;
199
+ switch (orientation) {
200
+ case 'top':
201
+ x1 = x2 = coordinate;
202
+ y1 = 0;
203
+ y2 = end;
204
+ break;
205
+ case 'bottom':
206
+ x1 = x2 = coordinate;
207
+ y1 = 0;
208
+ y2 = end * -1;
209
+ break;
210
+ case 'left':
211
+ y1 = y2 = coordinate;
212
+ x1 = 0;
213
+ x2 = end;
214
+ break;
215
+ case 'right':
216
+ y1 = y2 = coordinate;
217
+ x1 = 0;
218
+ x2 = end * -1;
219
+ break;
220
+ }
221
+ return { x1, x2, y1, y2 };
222
+ };
223
+
224
+ const identity = (d) => d;
225
+
226
+ //获取鼠标指针坐标
227
+ const getMousePos = (evt, dom) => {
228
+ var rect = dom.getBoundingClientRect();
229
+ return {
230
+ x: evt.clientX - rect.left,
231
+ y: evt.clientY - rect.top,
232
+ w: rect.width,
233
+ h: rect.height,
234
+ };
235
+ };
236
+
237
+ const getFontStyle = (
238
+ { color, bold, italic, fontSize, fontFamily, letterSpacing },
239
+ type
240
+ ) => {
241
+ if (type == 'svg') {
242
+ return {
243
+ fontSize,
244
+ fontFamily,
245
+ letterSpacing,
246
+ fill: color,
247
+ fontWeight: bold ? 'bold' : 'normal',
248
+ fontStyle: italic ? 'italic' : 'normal',
249
+ };
250
+ }
251
+ return {
252
+ fontSize,
253
+ fontFamily,
254
+ letterSpacing,
255
+ color,
256
+ fontWeight: bold ? 'bold' : 'normal',
257
+ fontStyle: italic ? 'italic' : 'normal',
258
+ };
259
+ };
260
+
261
+ const getMargin = ({ marginTop, marginRight, marginBottom, marginLeft }) =>
262
+ marginTop +
263
+ 'px ' +
264
+ marginRight +
265
+ 'px ' +
266
+ marginBottom +
267
+ 'px ' +
268
+ marginLeft +
269
+ 'px';
270
+ const getTranslate3d = ({ x = 0, y = 0, z = 0 }) =>
271
+ 'translate3d(' + x + 'px, ' + y + 'px, ' + z + 'px)';
272
+ const getTranslate2d = ({ x = 0, y = 0 }) => 'translate(' + x + ', ' + y + ')';
273
+ function band() {
274
+ var scale = ordinal().unknown(undefined),
275
+ domain = scale.domain,
276
+ ordinalRange = scale.range,
277
+ r0 = 0,
278
+ r1 = 1,
279
+ step,
280
+ bandwidth,
281
+ round = false,
282
+ paddingInner = 0,
283
+ paddingOuter = 0,
284
+ // seriesPaddingInner = 0,
285
+ // seriesPaddingOuter = 0,
286
+ // seriesLength = 0,
287
+ align = 0.5;
288
+
289
+ delete scale.unknown;
290
+
291
+ function rescale() {
292
+ var n = domain().length,
293
+ reverse = r1 < r0,
294
+ start = reverse ? r1 : r0,
295
+ stop = reverse ? r0 : r1;
296
+ step = (stop - start) / Math.max(1, n - paddingOuter * 2);
297
+ if (round) step = Math.floor(step);
298
+ start += (stop - start - step * n) * align;
299
+ bandwidth = step;
300
+ if (round) (start = Math.round(start)), (bandwidth = Math.round(bandwidth));
301
+ var values = sequence(n).map(function (i) {
302
+ return start + step * i + step / 2;
303
+ });
304
+ return ordinalRange(reverse ? values.reverse() : values);
305
+ }
306
+
307
+ scale.domain = function (_) {
308
+ return arguments.length ? (domain(_), rescale()) : domain();
309
+ };
310
+
311
+ scale.range = function (_) {
312
+ return arguments.length
313
+ ? (([r0, r1] = _), (r0 = +r0), (r1 = +r1), rescale())
314
+ : [r0, r1];
315
+ };
316
+
317
+ scale.rangeRound = function (_) {
318
+ return ([r0, r1] = _), (r0 = +r0), (r1 = +r1), (round = true), rescale();
319
+ };
320
+
321
+ scale.bandwidth = function () {
322
+ return bandwidth;
323
+ };
324
+
325
+ scale.step = function () {
326
+ return step;
327
+ };
328
+
329
+ scale.seriesBandwidth = function () {
330
+ return seriesBandwidth;
331
+ };
332
+
333
+ scale.seriesStep = function () {
334
+ return seriesStep;
335
+ };
336
+
337
+ scale.round = function (_) {
338
+ return arguments.length ? ((round = !!_), rescale()) : round;
339
+ };
340
+
341
+ scale.padding = function (_) {
342
+ return arguments.length
343
+ ? ((paddingInner = Math.min(1, (paddingOuter = +_))), rescale())
344
+ : paddingInner;
345
+ };
346
+
347
+ scale.paddingInner = function (_) {
348
+ return arguments.length
349
+ ? ((paddingInner = Math.min(1, _)), rescale())
350
+ : paddingInner;
351
+ };
352
+
353
+ scale.paddingOuter = function (_) {
354
+ return arguments.length ? ((paddingOuter = +_), rescale()) : paddingOuter;
355
+ };
356
+
357
+ scale.align = function (_) {
358
+ return arguments.length
359
+ ? ((align = Math.max(0, Math.min(1, _))), rescale())
360
+ : align;
361
+ };
362
+
363
+ scale.copy = function () {
364
+ return band(domain(), [r0, r1])
365
+ .round(round)
366
+ .paddingInner(paddingInner)
367
+ .paddingOuter(paddingOuter)
368
+ .align(align);
369
+ };
370
+
371
+ return initRange.apply(rescale(), arguments);
372
+ }
373
+
374
+ function initRange(domain, range) {
375
+ switch (arguments.length) {
376
+ case 0:
377
+ break;
378
+ case 1:
379
+ this.range(domain);
380
+ break;
381
+ default:
382
+ this.range(range).domain(domain);
383
+ break;
384
+ }
385
+ return this;
386
+ }
387
+
388
+ const getStacks = (series) => {
389
+ const tmp = [];
390
+ series.forEach(({ type, stack, yOrZ }, name) => {
391
+ const current = tmp.find(
392
+ ({ type: _type, stack: _stack, yOrZ: _yOrZ }) =>
393
+ _type == type && stack && _stack == stack && yOrZ == _yOrZ
394
+ );
395
+ if (!current) {
396
+ const common = {
397
+ type,
398
+ stack,
399
+ positive: 0,
400
+ negative: 0,
401
+ yOrZ,
402
+ s: [name],
403
+ };
404
+ if (type === 'band') {
405
+ const index = tmp.filter((item) => item.type === 'band').length;
406
+ tmp.push({
407
+ ...common,
408
+ index,
409
+ });
410
+ } else {
411
+ tmp.push({
412
+ ...common,
413
+ index: 0,
414
+ });
415
+ }
416
+ } else {
417
+ current.s.push(name);
418
+ }
419
+ });
420
+ return tmp;
421
+ };
422
+
423
+ const dataYOrZ = (data, { y: seriesY, z: seriesZ }) => {
424
+ const tmp = {
425
+ y: [],
426
+ z: [],
427
+ };
428
+ for (let i = 0, j = data.length; i < j; i++) {
429
+ const d = data[i];
430
+ if (seriesY.get(d.s)) {
431
+ tmp.y.push(d);
432
+ continue;
433
+ }
434
+ if (seriesZ.get(d.s)) {
435
+ tmp.z.push(d);
436
+ }
437
+ }
438
+ return tmp;
439
+ };
440
+
441
+ const seriesYOrZ = (series) => {
442
+ const y = new Map();
443
+ const z = new Map();
444
+ series.forEach((value, key) => {
445
+ if (value.yOrZ === 'y') {
446
+ y.set(key, value);
447
+ } else {
448
+ z.set(key, value);
449
+ }
450
+ });
451
+ return { y, z };
452
+ };
453
+
454
+ const resetStacks = (stacks) => {
455
+ stacks.forEach((stack) => {
456
+ stack.positive = 0;
457
+ stack.negative = 0;
458
+ });
459
+ };
460
+
461
+ const getCurrentStack = (stack, stackMap) =>
462
+ stackMap.find(
463
+ ({ stack: _stack, type: _type, yOrZ: _yOrZ, s: _s }) =>
464
+ _type == stack.type &&
465
+ _stack == stack.stack &&
466
+ _yOrZ == stack.yOrZ &&
467
+ _s.includes(stack.name)
468
+ );
469
+
470
+ const getBandBackground = (pattern, fill) => {
471
+ if (!(pattern && pattern.path)) return getColor(fill);
472
+ const { backgroundSize = '100% 100%', ..._pattern } = pattern;
473
+ return (
474
+ 'center top / ' +
475
+ backgroundSize +
476
+ ' url("data:image/svg+xml,' +
477
+ encodeURIComponent(
478
+ renderToStaticMarkup(<SvgBackground fill={fill} pattern={_pattern} />)
479
+ ) +
480
+ '")'
481
+ );
482
+ };
483
+ const getBandwidth = (step, paddingOuter) =>
484
+ step / Math.max(1, 1 + paddingOuter);
485
+
486
+ const getBandSeriesStepAndWidth = ({ width, paddingInner, bandLength }) => {
487
+ const seriesStep = width / Math.max(1, bandLength - paddingInner);
488
+ const seriesWidth = seriesStep * (1 - paddingInner);
489
+ return {
490
+ seriesStep,
491
+ seriesWidth,
492
+ };
493
+ };
494
+ const isValidHttpUrl = (string) => {
495
+ let url;
496
+
497
+ try {
498
+ url = new URL(string);
499
+ } catch (_) {
500
+ return false;
501
+ }
502
+
503
+ return url.protocol === 'http:' || url.protocol === 'https:';
504
+ };
505
+
506
+ const getChildren = (svgStr) => {
507
+ const wrapper = document.createElement('div');
508
+ wrapper.innerHTML = svgStr;
509
+ const { childNodes } = wrapper;
510
+ const svgDom = [...childNodes].find((item) => item.tagName === 'svg');
511
+
512
+ if (!!svgDom) {
513
+ return [...svgDom.childNodes];
514
+ }
515
+
516
+ return null;
517
+ };
518
+
519
+ const filterChildren = (children, tagNames) => {
520
+ return children.reduce((prev, node) => {
521
+ let { nodeName } = node;
522
+
523
+ if (tagNames.indexOf(nodeName) > -1) {
524
+ if (nodeName === 'g') {
525
+ return filterChildren([...node.childNodes], tagNames);
526
+ } else {
527
+ prev.push(node);
528
+ }
529
+ }
530
+
531
+ return prev;
532
+ }, []);
533
+ };
534
+
535
+ const getDomPath = (node) => {
536
+ switch (node.nodeName) {
537
+ case 'circle':
538
+ return toPath({
539
+ type: 'circle',
540
+ cx: +node.getAttribute('cx') || 0,
541
+ cy: +node.getAttribute('cy') || 0,
542
+ r: +node.getAttribute('r') || 0,
543
+ });
544
+
545
+ case 'ellipse':
546
+ return toPath({
547
+ type: 'ellipse',
548
+ cx: +node.getAttribute('cx') || 0,
549
+ cy: +node.getAttribute('cy') || 0,
550
+ rx: +node.getAttribute('rx') || 0,
551
+ ry: +node.getAttribute('ry') || 0,
552
+ });
553
+
554
+ case 'line':
555
+ return toPath({
556
+ type: 'line',
557
+ x1: +node.getAttribute('x1') || 0,
558
+ x2: +node.getAttribute('x2') || 0,
559
+ y1: +node.getAttribute('y1') || 0,
560
+ y2: +node.getAttribute('y2') || 0,
561
+ });
562
+
563
+ case 'path':
564
+ return toPath({
565
+ type: 'path',
566
+ d: node.getAttribute('d') || '',
567
+ });
568
+
569
+ case 'polygon':
570
+ return toPath({
571
+ type: 'polyline',
572
+ points: node.getAttribute('points') || '',
573
+ });
574
+
575
+ case 'polyline':
576
+ return toPath({
577
+ type: 'polyline',
578
+ points: node.getAttribute('points') || '',
579
+ });
580
+
581
+ case 'rect':
582
+ return toPath({
583
+ type: 'rect',
584
+ height: +node.getAttribute('height') || 0,
585
+ width: +node.getAttribute('width') || 0,
586
+ x: +node.getAttribute('x') || 0,
587
+ y: +node.getAttribute('y') || 0,
588
+ rx: +node.getAttribute('rx') || 0,
589
+ ry: +node.getAttribute('ry') || 0,
590
+ });
591
+ }
592
+ };
593
+
594
+ const sortPie = (data, order) => {
595
+ const _data = data.map((item) => ({ ...item }));
596
+ switch (order) {
597
+ case '':
598
+ _data.sort(({ index: a }, { index: b }) => ascending(a, b));
599
+ break;
600
+ case 'desc':
601
+ _data.sort(({ value: a }, { value: b }) => descending(a, b));
602
+ break;
603
+ case 'asc':
604
+ _data.sort(({ value: a }, { value: b }) => ascending(a, b));
605
+ break;
606
+ }
607
+ return _data;
608
+ };
609
+
610
+ // const getDataWithPercent = (data = [], precision = 0, type) => {
611
+ // const digits = Math.pow(10, precision);
612
+ // const targetSeats = digits * 100;
613
+
614
+ // const total = sum(data, (d) => d.value);
615
+
616
+ // const votesPerQuota = data.map((d, index) => ({
617
+ // ...d,
618
+ // vote: Math.round((d.value / total) * digits * 100),
619
+ // index,
620
+ // }));
621
+ // const currentSum = sum(votesPerQuota, (d) => d.vote);
622
+ // const remainder = targetSeats - currentSum;
623
+ // console.log(type+":",votesPerQuota, toFixed);
624
+ // votesPerQuota.sort(({ value: a }, { value: b }) => (a % total) - (b % total));
625
+
626
+ // const tmp = votesPerQuota.map(({ vote, ...data }, index) => ({
627
+ // ...data,
628
+ // percent: toFixed((vote + (index < remainder ? 1 : 0)) / digits, precision),
629
+ // }));
630
+
631
+ // return tmp;
632
+ // };
633
+
634
+ const getDataWithPercent = (data = [], precision = 0) => {
635
+ const digits = Math.pow(10, precision);
636
+ const targetSeats = digits * 100;
637
+
638
+ const total = sum(data, (d) => d.value);
639
+
640
+ const votesPerQuota = data.map((d, index) => ({
641
+ ...d,
642
+ vote: Math.round((d.value / total) * digits * 100),
643
+ index,
644
+ }));
645
+ const currentSum = sum(votesPerQuota, (d) => d.vote);
646
+
647
+ let remainder = targetSeats - currentSum;
648
+ votesPerQuota.sort(({ value: a }, { value: b }) => (a % total) - (b % total));
649
+
650
+ const tmp = votesPerQuota.map(({ vote, value, ...data }, index) => {
651
+ let obj = {
652
+ ...data,
653
+ value,
654
+ percent: toFixed(
655
+ (vote + (value && value != 0 ? remainder : 0)) / digits,
656
+ precision
657
+ ),
658
+ };
659
+ if (value && value != 0) {
660
+ remainder = 0;
661
+ }
662
+ return obj;
663
+ });
664
+ return tmp;
665
+ };
666
+
667
+ export {
668
+ dateFormat,
669
+ getBreakWord,
670
+ getTicksOfAxis,
671
+ getTickCoord,
672
+ getGridCoord,
673
+ identity,
674
+ getMousePos,
675
+ getFontStyle,
676
+ getMargin,
677
+ getTranslate3d,
678
+ getTranslate2d,
679
+ band,
680
+ getIcon,
681
+ getColorList,
682
+ getStacks,
683
+ dataYOrZ,
684
+ seriesYOrZ,
685
+ resetStacks,
686
+ getCurrentStack,
687
+ getBandBackground,
688
+ getBandwidth,
689
+ getBandSeriesStepAndWidth,
690
+ isValidHttpUrl,
691
+ getChildren,
692
+ filterChildren,
693
+ getDomPath,
694
+ sortPie,
695
+ getDataWithPercent,
696
+ };