@orbcharts/core 3.0.0-beta.8 → 3.0.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.
- package/LICENSE +200 -200
- package/dist/orbcharts-core.es.js +2734 -2353
- package/dist/orbcharts-core.umd.js +4 -4
- package/dist/src/defaults.d.ts +2 -1
- package/dist/src/utils/gridObservables.d.ts +8 -4
- package/dist/src/utils/index.d.ts +0 -3
- package/dist/src/utils/multiGridObservables.d.ts +3 -2
- package/dist/src/utils/multiValueObservables.d.ts +76 -29
- package/dist/src/utils/observables.d.ts +8 -1
- package/dist/src/utils/orbchartsUtils.d.ts +9 -9
- package/dist/src/utils/seriesObservables.d.ts +1 -1
- package/lib/core-types.ts +7 -7
- package/package.json +42 -42
- package/src/AbstractChart.ts +57 -57
- package/src/GridChart.ts +24 -24
- package/src/MultiGridChart.ts +24 -24
- package/src/MultiValueChart.ts +24 -24
- package/src/RelationshipChart.ts +24 -24
- package/src/SeriesChart.ts +24 -24
- package/src/TreeChart.ts +24 -24
- package/src/base/createBaseChart.ts +506 -505
- package/src/base/createBasePlugin.ts +154 -153
- package/src/base/validators/chartOptionsValidator.ts +23 -23
- package/src/base/validators/chartParamsValidator.ts +133 -133
- package/src/base/validators/elementValidator.ts +13 -13
- package/src/base/validators/pluginsValidator.ts +14 -14
- package/src/defaults.ts +282 -238
- package/src/defineGridPlugin.ts +3 -3
- package/src/defineMultiGridPlugin.ts +3 -3
- package/src/defineMultiValuePlugin.ts +3 -3
- package/src/defineNoneDataPlugin.ts +4 -4
- package/src/defineRelationshipPlugin.ts +3 -3
- package/src/defineSeriesPlugin.ts +3 -3
- package/src/defineTreePlugin.ts +3 -3
- package/src/grid/computedDataFn.ts +129 -129
- package/src/grid/contextObserverCallback.ts +198 -176
- package/src/grid/dataFormatterValidator.ts +120 -101
- package/src/grid/dataValidator.ts +12 -12
- package/src/index.ts +20 -20
- package/src/multiGrid/computedDataFn.ts +123 -123
- package/src/multiGrid/contextObserverCallback.ts +72 -41
- package/src/multiGrid/dataFormatterValidator.ts +115 -115
- package/src/multiGrid/dataValidator.ts +12 -12
- package/src/multiValue/computedDataFn.ts +113 -110
- package/src/multiValue/contextObserverCallback.ts +276 -160
- package/src/multiValue/dataFormatterValidator.ts +89 -9
- package/src/multiValue/dataValidator.ts +12 -9
- package/src/relationship/computedDataFn.ts +159 -144
- package/src/relationship/contextObserverCallback.ts +80 -80
- package/src/relationship/dataFormatterValidator.ts +13 -9
- package/src/relationship/dataValidator.ts +13 -9
- package/src/series/computedDataFn.ts +88 -88
- package/src/series/contextObserverCallback.ts +107 -100
- package/src/series/dataFormatterValidator.ts +41 -41
- package/src/series/dataValidator.ts +12 -12
- package/src/tree/computedDataFn.ts +129 -129
- package/src/tree/contextObserverCallback.ts +58 -58
- package/src/tree/dataFormatterValidator.ts +13 -13
- package/src/tree/dataValidator.ts +13 -13
- package/src/utils/commonUtils.ts +55 -55
- package/src/utils/d3Scale.ts +198 -198
- package/src/utils/errorMessage.ts +42 -42
- package/src/utils/gridObservables.ts +705 -683
- package/src/utils/index.ts +10 -10
- package/src/utils/multiGridObservables.ts +401 -392
- package/src/utils/multiValueObservables.ts +1044 -662
- package/src/utils/observables.ts +281 -219
- package/src/utils/orbchartsUtils.ts +377 -377
- package/src/utils/relationshipObservables.ts +84 -84
- package/src/utils/seriesObservables.ts +175 -175
- package/src/utils/treeObservables.ts +105 -105
- package/src/utils/validator.ts +126 -126
- package/tsconfig.base.json +13 -13
- package/tsconfig.json +2 -2
- package/vite-env.d.ts +6 -6
- package/vite.config.js +22 -22
@@ -1,662 +1,1044 @@
|
|
1
|
-
import {
|
2
|
-
combineLatest,
|
3
|
-
distinctUntilChanged,
|
4
|
-
iif,
|
5
|
-
filter,
|
6
|
-
map,
|
7
|
-
merge,
|
8
|
-
takeUntil,
|
9
|
-
shareReplay,
|
10
|
-
switchMap,
|
11
|
-
Subject,
|
12
|
-
Observable } from 'rxjs'
|
13
|
-
import type {
|
14
|
-
AxisPosition,
|
15
|
-
ChartType,
|
16
|
-
ChartParams,
|
17
|
-
ComputedDataTypeMap,
|
18
|
-
ComputedDatumTypeMap,
|
19
|
-
ComputedDataMultiValue,
|
20
|
-
ComputedDatumMultiValue,
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
import {
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
}
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
//
|
120
|
-
//
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
//
|
129
|
-
//
|
130
|
-
//
|
131
|
-
//
|
132
|
-
//
|
133
|
-
|
134
|
-
//
|
135
|
-
//
|
136
|
-
//
|
137
|
-
//
|
138
|
-
//
|
139
|
-
//
|
140
|
-
//
|
141
|
-
//
|
142
|
-
//
|
143
|
-
//
|
144
|
-
//
|
145
|
-
//
|
146
|
-
//
|
147
|
-
|
148
|
-
//
|
149
|
-
//
|
150
|
-
//
|
151
|
-
//
|
152
|
-
//
|
153
|
-
//
|
154
|
-
//
|
155
|
-
//
|
156
|
-
//
|
157
|
-
|
158
|
-
//
|
159
|
-
//
|
160
|
-
//
|
161
|
-
//
|
162
|
-
//
|
163
|
-
//
|
164
|
-
//
|
165
|
-
//
|
166
|
-
//
|
167
|
-
|
168
|
-
//
|
169
|
-
//
|
170
|
-
//
|
171
|
-
//
|
172
|
-
|
173
|
-
//
|
174
|
-
//
|
175
|
-
|
176
|
-
//
|
177
|
-
//
|
178
|
-
//
|
179
|
-
//
|
180
|
-
//
|
181
|
-
|
182
|
-
|
183
|
-
//
|
184
|
-
//
|
185
|
-
|
186
|
-
//
|
187
|
-
//
|
188
|
-
//
|
189
|
-
//
|
190
|
-
//
|
191
|
-
|
192
|
-
|
193
|
-
//
|
194
|
-
//
|
195
|
-
//
|
196
|
-
//
|
197
|
-
//
|
198
|
-
//
|
199
|
-
//
|
200
|
-
//
|
201
|
-
//
|
202
|
-
//
|
203
|
-
//
|
204
|
-
//
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
//
|
209
|
-
//
|
210
|
-
//
|
211
|
-
//
|
212
|
-
//
|
213
|
-
//
|
214
|
-
// }
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
//
|
219
|
-
//
|
220
|
-
//
|
221
|
-
//
|
222
|
-
//
|
223
|
-
//
|
224
|
-
//
|
225
|
-
//
|
226
|
-
|
227
|
-
//
|
228
|
-
//
|
229
|
-
//
|
230
|
-
//
|
231
|
-
//
|
232
|
-
//
|
233
|
-
//
|
234
|
-
//
|
235
|
-
|
236
|
-
//
|
237
|
-
//
|
238
|
-
//
|
239
|
-
//
|
240
|
-
// }
|
241
|
-
//
|
242
|
-
//
|
243
|
-
//
|
244
|
-
|
245
|
-
|
246
|
-
//
|
247
|
-
//
|
248
|
-
//
|
249
|
-
//
|
250
|
-
//
|
251
|
-
|
252
|
-
//
|
253
|
-
|
254
|
-
|
255
|
-
//
|
256
|
-
//
|
257
|
-
//
|
258
|
-
//
|
259
|
-
//
|
260
|
-
|
261
|
-
|
262
|
-
//
|
263
|
-
|
264
|
-
//
|
265
|
-
//
|
266
|
-
//
|
267
|
-
//
|
268
|
-
// )
|
269
|
-
//
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
}) => {
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
}
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
|
412
|
-
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
|
429
|
-
|
430
|
-
|
431
|
-
|
432
|
-
|
433
|
-
|
434
|
-
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
|
439
|
-
|
440
|
-
|
441
|
-
|
442
|
-
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
|
447
|
-
|
448
|
-
}
|
449
|
-
|
450
|
-
|
451
|
-
|
452
|
-
|
453
|
-
|
454
|
-
|
455
|
-
|
456
|
-
|
457
|
-
|
458
|
-
|
459
|
-
|
460
|
-
|
461
|
-
|
462
|
-
|
463
|
-
|
464
|
-
|
465
|
-
|
466
|
-
|
467
|
-
|
468
|
-
|
469
|
-
|
470
|
-
|
471
|
-
|
472
|
-
|
473
|
-
|
474
|
-
|
475
|
-
|
476
|
-
|
477
|
-
|
478
|
-
|
479
|
-
|
480
|
-
|
481
|
-
|
482
|
-
|
483
|
-
|
484
|
-
|
485
|
-
|
486
|
-
|
487
|
-
|
488
|
-
|
489
|
-
|
490
|
-
|
491
|
-
|
492
|
-
|
493
|
-
|
494
|
-
|
495
|
-
|
496
|
-
|
497
|
-
|
498
|
-
|
499
|
-
|
500
|
-
|
501
|
-
|
502
|
-
|
503
|
-
|
504
|
-
|
505
|
-
|
506
|
-
|
507
|
-
|
508
|
-
|
509
|
-
|
510
|
-
|
511
|
-
|
512
|
-
//
|
513
|
-
|
514
|
-
|
515
|
-
|
516
|
-
|
517
|
-
|
518
|
-
|
519
|
-
|
520
|
-
|
521
|
-
|
522
|
-
|
523
|
-
|
524
|
-
|
525
|
-
|
526
|
-
|
527
|
-
|
528
|
-
|
529
|
-
|
530
|
-
|
531
|
-
|
532
|
-
|
533
|
-
|
534
|
-
|
535
|
-
|
536
|
-
|
537
|
-
|
538
|
-
|
539
|
-
|
540
|
-
|
541
|
-
|
542
|
-
|
543
|
-
|
544
|
-
|
545
|
-
|
546
|
-
|
547
|
-
|
548
|
-
|
549
|
-
|
550
|
-
|
551
|
-
|
552
|
-
|
553
|
-
|
554
|
-
|
555
|
-
|
556
|
-
|
557
|
-
|
558
|
-
|
559
|
-
|
560
|
-
|
561
|
-
|
562
|
-
|
563
|
-
|
564
|
-
|
565
|
-
|
566
|
-
|
567
|
-
|
568
|
-
|
569
|
-
|
570
|
-
|
571
|
-
|
572
|
-
|
573
|
-
|
574
|
-
|
575
|
-
|
576
|
-
|
577
|
-
|
578
|
-
|
579
|
-
|
580
|
-
|
581
|
-
|
582
|
-
|
583
|
-
|
584
|
-
|
585
|
-
|
586
|
-
|
587
|
-
|
588
|
-
|
589
|
-
|
590
|
-
|
591
|
-
|
592
|
-
|
593
|
-
|
594
|
-
|
595
|
-
|
596
|
-
|
597
|
-
|
598
|
-
|
599
|
-
|
600
|
-
|
601
|
-
|
602
|
-
|
603
|
-
|
604
|
-
|
605
|
-
|
606
|
-
|
607
|
-
|
608
|
-
|
609
|
-
|
610
|
-
|
611
|
-
|
612
|
-
|
613
|
-
|
614
|
-
|
615
|
-
|
616
|
-
|
617
|
-
|
618
|
-
|
619
|
-
|
620
|
-
|
621
|
-
|
622
|
-
|
623
|
-
|
624
|
-
|
625
|
-
|
626
|
-
|
627
|
-
|
628
|
-
|
629
|
-
|
630
|
-
}
|
631
|
-
|
632
|
-
|
633
|
-
|
634
|
-
|
635
|
-
|
636
|
-
}
|
637
|
-
|
638
|
-
|
639
|
-
|
640
|
-
|
641
|
-
|
642
|
-
|
643
|
-
|
644
|
-
|
645
|
-
|
646
|
-
|
647
|
-
|
648
|
-
|
649
|
-
|
650
|
-
|
651
|
-
|
652
|
-
|
653
|
-
|
654
|
-
|
655
|
-
|
656
|
-
|
657
|
-
|
658
|
-
|
659
|
-
|
660
|
-
|
661
|
-
|
662
|
-
|
1
|
+
import {
|
2
|
+
combineLatest,
|
3
|
+
distinctUntilChanged,
|
4
|
+
iif,
|
5
|
+
filter,
|
6
|
+
map,
|
7
|
+
merge,
|
8
|
+
takeUntil,
|
9
|
+
shareReplay,
|
10
|
+
switchMap,
|
11
|
+
Subject,
|
12
|
+
Observable } from 'rxjs'
|
13
|
+
import type {
|
14
|
+
AxisPosition,
|
15
|
+
ChartType,
|
16
|
+
ChartParams,
|
17
|
+
ComputedDataTypeMap,
|
18
|
+
ComputedDatumTypeMap,
|
19
|
+
ComputedDataMultiValue,
|
20
|
+
ComputedDatumMultiValue,
|
21
|
+
ComputedDatumWithSumMultiValue,
|
22
|
+
ContainerSize,
|
23
|
+
DataFormatterTypeMap,
|
24
|
+
DataFormatterMultiValue,
|
25
|
+
DataFormatterXYAxis,
|
26
|
+
ComputedXYDatumMultiValue,
|
27
|
+
ComputedXYDataMultiValue,
|
28
|
+
ContainerPositionScaled,
|
29
|
+
HighlightTarget,
|
30
|
+
Layout,
|
31
|
+
TransformData } from '../../lib/core-types'
|
32
|
+
import { getMinMax, getMinMaxMultiValue } from './orbchartsUtils'
|
33
|
+
import { createValueToAxisScale, createLabelToAxisScale, createAxisToLabelIndexScale } from './d3Scale'
|
34
|
+
import { calcContainerPositionScaled } from './orbchartsUtils'
|
35
|
+
|
36
|
+
export const xyMinMaxObservable = ({ computedData$, xyValueIndex$ }: {
|
37
|
+
computedData$: Observable<ComputedDataTypeMap<'multiValue'>>
|
38
|
+
xyValueIndex$: Observable<[number, number]>
|
39
|
+
}) => {
|
40
|
+
return combineLatest({
|
41
|
+
computedData: computedData$,
|
42
|
+
xyValueIndex: xyValueIndex$,
|
43
|
+
}).pipe(
|
44
|
+
map(data => {
|
45
|
+
const flatData = data.computedData.flat()
|
46
|
+
const [minX, maxX] = getMinMax(flatData.map(d => d.value[data.xyValueIndex[0]]))
|
47
|
+
const [minY, maxY] = getMinMax(flatData.map(d => d.value[data.xyValueIndex[1]]))
|
48
|
+
return { minX, maxX, minY, maxY }
|
49
|
+
})
|
50
|
+
)
|
51
|
+
}
|
52
|
+
|
53
|
+
export const computedXYDataObservable = ({ computedData$, xyMinMax$, xyValueIndex$, fullDataFormatter$, layout$ }: {
|
54
|
+
computedData$: Observable<ComputedDataTypeMap<'multiValue'>>
|
55
|
+
xyMinMax$: Observable<{ minX: number, maxX: number, minY: number, maxY: number }>
|
56
|
+
xyValueIndex$: Observable<[number, number]>
|
57
|
+
fullDataFormatter$: Observable<DataFormatterTypeMap<'multiValue'>>
|
58
|
+
layout$: Observable<Layout>
|
59
|
+
}): Observable<ComputedXYDataMultiValue> => {
|
60
|
+
|
61
|
+
// 未篩選範圍前的 scale
|
62
|
+
function createOriginXScale (xyMinMax: { minX: number, maxX: number, minY: number, maxY: number }, layout: Layout) {
|
63
|
+
let maxValue = xyMinMax.maxX
|
64
|
+
let minValue = xyMinMax.minX
|
65
|
+
if (minValue === maxValue && maxValue === 0) {
|
66
|
+
// 避免最大及最小值相同造成無法計算scale
|
67
|
+
maxValue = 1
|
68
|
+
}
|
69
|
+
const valueScale: d3.ScaleLinear<number, number> = createValueToAxisScale({
|
70
|
+
maxValue,
|
71
|
+
minValue,
|
72
|
+
axisWidth: layout.width,
|
73
|
+
scaleDomain: ['auto', 'auto'], // 不使用dataFormatter設定 --> 以0為基準到最大或最小值為範圍( * 如果是使用[minValue, maxValue]的話,在兩者很接近的情況下有可能造成scale倍率過高而svg變型時失真的情況)
|
74
|
+
scaleRange: [0, 1] // 不使用dataFormatter設定
|
75
|
+
})
|
76
|
+
|
77
|
+
return valueScale
|
78
|
+
}
|
79
|
+
|
80
|
+
// 未篩選範圍及visible前的 scale
|
81
|
+
function createOriginYScale (xyMinMax: { minX: number, maxX: number, minY: number, maxY: number }, layout: Layout) {
|
82
|
+
let maxValue = xyMinMax.maxY
|
83
|
+
let minValue = xyMinMax.minY
|
84
|
+
if (minValue === maxValue && maxValue === 0) {
|
85
|
+
// 避免最大及最小值相同造成無法計算scale
|
86
|
+
maxValue = 1
|
87
|
+
}
|
88
|
+
const valueScale: d3.ScaleLinear<number, number> = createValueToAxisScale({
|
89
|
+
maxValue,
|
90
|
+
minValue,
|
91
|
+
axisWidth: layout.height,
|
92
|
+
scaleDomain: ['auto', 'auto'], // 不使用dataFormatter設定 --> 以0為基準到最大或最小值為範圍( * 如果是使用[minValue, maxValue]的話,在兩者很接近的情況下有可能造成scale倍率過高而svg變型時失真的情況)
|
93
|
+
scaleRange: [0, 1], // 不使用dataFormatter設定
|
94
|
+
reverse: true
|
95
|
+
})
|
96
|
+
|
97
|
+
return valueScale
|
98
|
+
}
|
99
|
+
|
100
|
+
return combineLatest({
|
101
|
+
computedData: computedData$,
|
102
|
+
xyMinMax: xyMinMax$,
|
103
|
+
xyValueIndex: xyValueIndex$,
|
104
|
+
fullDataFormatter: fullDataFormatter$,
|
105
|
+
layout: layout$
|
106
|
+
}).pipe(
|
107
|
+
switchMap(async d => d),
|
108
|
+
map(data => {
|
109
|
+
|
110
|
+
const xScale = createOriginXScale(data.xyMinMax, data.layout)
|
111
|
+
const yScale = createOriginYScale(data.xyMinMax, data.layout)
|
112
|
+
|
113
|
+
return data.computedData
|
114
|
+
.map((categoryData, categoryIndex) => {
|
115
|
+
return categoryData.map((datum, datumIndex) => {
|
116
|
+
return {
|
117
|
+
...datum,
|
118
|
+
axisX: xScale(datum.value[data.xyValueIndex[0]] ?? 0),
|
119
|
+
// axisY: data.layout.height - yScale(datum.value[1] ?? 0), // y軸的繪圖座標是從上到下,所以反轉
|
120
|
+
axisY: yScale(datum.value[data.xyValueIndex[1]] ?? 0), // y軸的繪圖座標是從上到下,所以反轉
|
121
|
+
}
|
122
|
+
})
|
123
|
+
})
|
124
|
+
})
|
125
|
+
)
|
126
|
+
}
|
127
|
+
|
128
|
+
// export const multiValueAxesTransformObservable = ({ fullDataFormatter$, layout$ }: {
|
129
|
+
// fullDataFormatter$: Observable<DataFormatterTypeMap<'multiValue'>>
|
130
|
+
// layout$: Observable<Layout>
|
131
|
+
// }): Observable<TransformData> => {
|
132
|
+
// const destroy$ = new Subject()
|
133
|
+
|
134
|
+
// function calcAxesTransform ({ xAxis, yAxis, width, height }: {
|
135
|
+
// xAxis: DataFormatterXYAxis,
|
136
|
+
// yAxis: DataFormatterXYAxis,
|
137
|
+
// width: number,
|
138
|
+
// height: number
|
139
|
+
// }): TransformData {
|
140
|
+
// if (!xAxis || !yAxis) {
|
141
|
+
// return {
|
142
|
+
// translate: [0, 0],
|
143
|
+
// scale: [1, 1],
|
144
|
+
// rotate: 0,
|
145
|
+
// rotateX: 0,
|
146
|
+
// rotateY: 0,
|
147
|
+
// value: ''
|
148
|
+
// }
|
149
|
+
// }
|
150
|
+
// // const width = size.width - fullChartParams.layout.left - fullChartParams.layout.right
|
151
|
+
// // const height = size.height - fullChartParams.layout.top - fullChartParams.layout.bottom
|
152
|
+
// let translateX = 0
|
153
|
+
// let translateY = height
|
154
|
+
// let rotate = 0
|
155
|
+
// let rotateX = 180
|
156
|
+
// let rotateY = 0
|
157
|
+
|
158
|
+
// return {
|
159
|
+
// translate: [translateX, translateY],
|
160
|
+
// scale: [1, 1],
|
161
|
+
// rotate,
|
162
|
+
// rotateX,
|
163
|
+
// rotateY,
|
164
|
+
// value: `translate(${translateX}px, ${translateY}px) rotate(${rotate}deg) rotateX(${rotateX}deg) rotateY(${rotateY}deg)`
|
165
|
+
// }
|
166
|
+
// }
|
167
|
+
|
168
|
+
// return new Observable(subscriber => {
|
169
|
+
// combineLatest({
|
170
|
+
// fullDataFormatter: fullDataFormatter$,
|
171
|
+
// layout: layout$
|
172
|
+
// }).pipe(
|
173
|
+
// takeUntil(destroy$),
|
174
|
+
// switchMap(async (d) => d),
|
175
|
+
// ).subscribe(data => {
|
176
|
+
// const axesTransformData = calcAxesTransform({
|
177
|
+
// xAxis: data.fullDataFormatter.xAxis,
|
178
|
+
// yAxis: data.fullDataFormatter.yAxis,
|
179
|
+
// width: data.layout.width,
|
180
|
+
// height: data.layout.height
|
181
|
+
// })
|
182
|
+
|
183
|
+
// subscriber.next(axesTransformData)
|
184
|
+
// })
|
185
|
+
|
186
|
+
// return function unscbscribe () {
|
187
|
+
// destroy$.next(undefined)
|
188
|
+
// }
|
189
|
+
// })
|
190
|
+
// }
|
191
|
+
|
192
|
+
|
193
|
+
// export const multiValueAxesReverseTransformObservable = ({ multiValueAxesTransform$ }: {
|
194
|
+
// multiValueAxesTransform$: Observable<TransformData>
|
195
|
+
// }): Observable<TransformData> => {
|
196
|
+
// return multiValueAxesTransform$.pipe(
|
197
|
+
// map(d => {
|
198
|
+
// // const translate: [number, number] = [d.translate[0] * -1, d.translate[1] * -1]
|
199
|
+
// const translate: [number, number] = [0, 0] // 無需逆轉
|
200
|
+
// const scale: [number, number] = [1 / d.scale[0], 1 / d.scale[1]]
|
201
|
+
// const rotate = d.rotate * -1
|
202
|
+
// const rotateX = d.rotateX * -1
|
203
|
+
// const rotateY = d.rotateY * -1
|
204
|
+
// return {
|
205
|
+
// translate,
|
206
|
+
// scale,
|
207
|
+
// rotate,
|
208
|
+
// rotateX,
|
209
|
+
// rotateY,
|
210
|
+
// value: `translate(${translate[0]}px, ${translate[1]}px) rotateX(${rotateX}deg) rotateY(${rotateY}deg) rotate(${rotate}deg)`
|
211
|
+
// }
|
212
|
+
// }),
|
213
|
+
// )
|
214
|
+
// }
|
215
|
+
|
216
|
+
|
217
|
+
|
218
|
+
// export const multiValueAxesSizeObservable = ({ fullDataFormatter$, layout$ }: {
|
219
|
+
// fullDataFormatter$: Observable<DataFormatterMultiValue>
|
220
|
+
// layout$: Observable<Layout>
|
221
|
+
// }): Observable<{
|
222
|
+
// width: number;
|
223
|
+
// height: number;
|
224
|
+
// }> => {
|
225
|
+
// const destroy$ = new Subject()
|
226
|
+
|
227
|
+
// function calcAxesSize ({ xAxisPosition, yAxisPosition, width, height }: {
|
228
|
+
// xAxisPosition: AxisPosition
|
229
|
+
// yAxisPosition: AxisPosition
|
230
|
+
// width: number
|
231
|
+
// height: number
|
232
|
+
// }) {
|
233
|
+
// if ((xAxisPosition === 'bottom' || xAxisPosition === 'top') && (yAxisPosition === 'left' || yAxisPosition === 'right')) {
|
234
|
+
// return { width, height }
|
235
|
+
// } else if ((xAxisPosition === 'left' || xAxisPosition === 'right') && (yAxisPosition === 'bottom' || yAxisPosition === 'top')) {
|
236
|
+
// return {
|
237
|
+
// width: height,
|
238
|
+
// height: width
|
239
|
+
// }
|
240
|
+
// } else {
|
241
|
+
// // default
|
242
|
+
// return { width, height }
|
243
|
+
// }
|
244
|
+
// }
|
245
|
+
|
246
|
+
// return new Observable(subscriber => {
|
247
|
+
// combineLatest({
|
248
|
+
// fullDataFormatter: fullDataFormatter$,
|
249
|
+
// layout: layout$
|
250
|
+
// }).pipe(
|
251
|
+
// takeUntil(destroy$),
|
252
|
+
// switchMap(async (d) => d),
|
253
|
+
// ).subscribe(data => {
|
254
|
+
|
255
|
+
// const axisSize = calcAxesSize({
|
256
|
+
// xAxisPosition: 'bottom',
|
257
|
+
// yAxisPosition: 'left',
|
258
|
+
// width: data.layout.width,
|
259
|
+
// height: data.layout.height,
|
260
|
+
// })
|
261
|
+
|
262
|
+
// subscriber.next(axisSize)
|
263
|
+
|
264
|
+
// return function unsubscribe () {
|
265
|
+
// destroy$.next(undefined)
|
266
|
+
// }
|
267
|
+
// })
|
268
|
+
// })
|
269
|
+
// }
|
270
|
+
|
271
|
+
// export const highlightObservable = ({ computedData$, fullChartParams$, event$ }: {
|
272
|
+
// computedData$: Observable<ComputedDataTypeMap<'multiValue'>>
|
273
|
+
// fullChartParams$: Observable<ChartParams>
|
274
|
+
// event$: Subject<any>
|
275
|
+
// }): Observable<string[]> => {
|
276
|
+
// const datumList$ = computedData$.pipe(
|
277
|
+
// map(d => d.flat())
|
278
|
+
// )
|
279
|
+
// return highlightObservable ({ datumList$, fullChartParams$, event$ })
|
280
|
+
// }
|
281
|
+
|
282
|
+
export const categoryLabelsObservable = ({ computedData$, fullDataFormatter$ }: {
|
283
|
+
computedData$: Observable<ComputedDataTypeMap<'multiValue'>>
|
284
|
+
fullDataFormatter$: Observable<DataFormatterTypeMap<'multiValue'>>
|
285
|
+
}) => {
|
286
|
+
return computedData$.pipe(
|
287
|
+
map(data => {
|
288
|
+
return data
|
289
|
+
.map(d => d[0] ? d[0].categoryLabel : '')
|
290
|
+
// .filter(d => d != null && d != '')
|
291
|
+
}),
|
292
|
+
distinctUntilChanged((a, b) => {
|
293
|
+
return JSON.stringify(a).length === JSON.stringify(b).length
|
294
|
+
}),
|
295
|
+
)
|
296
|
+
}
|
297
|
+
|
298
|
+
export const visibleComputedDataObservable = ({ computedData$ }: { computedData$: Observable<ComputedDataTypeMap<'multiValue'>> }) => {
|
299
|
+
return computedData$.pipe(
|
300
|
+
map(data => {
|
301
|
+
return data
|
302
|
+
.map(categoryData => {
|
303
|
+
return categoryData.filter(d => d.visible == true)
|
304
|
+
})
|
305
|
+
.filter(categoryData => {
|
306
|
+
return categoryData.length > 0
|
307
|
+
})
|
308
|
+
})
|
309
|
+
)
|
310
|
+
}
|
311
|
+
|
312
|
+
export const visibleComputedSumDataObservable = ({ visibleComputedData$ }: { visibleComputedData$: Observable<ComputedDataMultiValue> }) => {
|
313
|
+
return visibleComputedData$.pipe(
|
314
|
+
map(data => {
|
315
|
+
return data.map(categoryData => {
|
316
|
+
return categoryData
|
317
|
+
.map(d => {
|
318
|
+
let newDatum = d as ComputedDatumWithSumMultiValue
|
319
|
+
// 新增總計資料欄位
|
320
|
+
newDatum.sum = newDatum.value.reduce((acc, curr) => acc + curr, 0)
|
321
|
+
return newDatum
|
322
|
+
})
|
323
|
+
})
|
324
|
+
})
|
325
|
+
)
|
326
|
+
}
|
327
|
+
|
328
|
+
// Ranking資料 - 用 value[index] 排序
|
329
|
+
export const visibleComputedRankingByIndexDataObservable = ({ xyValueIndex$, isCategorySeprate$, visibleComputedData$ }: {
|
330
|
+
xyValueIndex$: Observable<[number, number]>
|
331
|
+
isCategorySeprate$: Observable<boolean>
|
332
|
+
visibleComputedData$: Observable<ComputedDatumMultiValue[][]>
|
333
|
+
}) => {
|
334
|
+
|
335
|
+
return combineLatest({
|
336
|
+
isCategorySeprate: isCategorySeprate$,
|
337
|
+
xyValueIndex: xyValueIndex$,
|
338
|
+
visibleComputedData: visibleComputedData$
|
339
|
+
}).pipe(
|
340
|
+
switchMap(async d => d),
|
341
|
+
map(data => {
|
342
|
+
const xValueIndex = data.xyValueIndex[0]
|
343
|
+
// -- category 分開 --
|
344
|
+
if (data.isCategorySeprate) {
|
345
|
+
return data.visibleComputedData
|
346
|
+
.map(categoryData => {
|
347
|
+
return categoryData
|
348
|
+
.sort((a, b) => {
|
349
|
+
const bValue = b.value[xValueIndex] ?? - Infinity // - Infinity 為最小值
|
350
|
+
const aValue = a.value[xValueIndex] ?? - Infinity
|
351
|
+
|
352
|
+
return bValue - aValue
|
353
|
+
})
|
354
|
+
})
|
355
|
+
// -- 用 value[index] 排序 --
|
356
|
+
} else {
|
357
|
+
return [
|
358
|
+
data.visibleComputedData
|
359
|
+
.flat()
|
360
|
+
.sort((a, b) => {
|
361
|
+
const bValue = b.value[xValueIndex] ?? - Infinity // - Infinity 為最小值
|
362
|
+
const aValue = a.value[xValueIndex] ?? - Infinity
|
363
|
+
|
364
|
+
return bValue - aValue
|
365
|
+
})
|
366
|
+
]
|
367
|
+
}
|
368
|
+
})
|
369
|
+
)
|
370
|
+
}
|
371
|
+
|
372
|
+
// Ranking資料 - 用所有 valueIndex 加總資料排序
|
373
|
+
export const visibleComputedRankingBySumDataObservable = ({ isCategorySeprate$, visibleComputedSumData$ }: {
|
374
|
+
isCategorySeprate$: Observable<boolean>
|
375
|
+
// visibleComputedData$: Observable<ComputedDatumMultiValue[][]>
|
376
|
+
visibleComputedSumData$: Observable<ComputedDatumWithSumMultiValue[][]>
|
377
|
+
}) => {
|
378
|
+
|
379
|
+
return combineLatest({
|
380
|
+
isCategorySeprate: isCategorySeprate$,
|
381
|
+
visibleComputedSumData: visibleComputedSumData$
|
382
|
+
}).pipe(
|
383
|
+
switchMap(async d => d),
|
384
|
+
map(data => {
|
385
|
+
// -- category 分開 --
|
386
|
+
if (data.isCategorySeprate) {
|
387
|
+
return data.visibleComputedSumData
|
388
|
+
.map(categoryData => {
|
389
|
+
return categoryData
|
390
|
+
.sort((a, b) => b.sum - a.sum)
|
391
|
+
})
|
392
|
+
// -- 用 value[index] 排序 --
|
393
|
+
} else {
|
394
|
+
return [
|
395
|
+
data.visibleComputedSumData
|
396
|
+
.flat()
|
397
|
+
.sort((a, b) => b.sum - a.sum)
|
398
|
+
]
|
399
|
+
}
|
400
|
+
})
|
401
|
+
)
|
402
|
+
}
|
403
|
+
|
404
|
+
export const visibleComputedXYDataObservable = ({ computedXYData$ }: { computedXYData$: Observable<ComputedXYDataMultiValue> }) => {
|
405
|
+
return computedXYData$.pipe(
|
406
|
+
map(data => {
|
407
|
+
return data
|
408
|
+
.map(categoryData => {
|
409
|
+
return categoryData.filter(d => d.visible == true)
|
410
|
+
})
|
411
|
+
.filter(categoryData => {
|
412
|
+
return categoryData.length > 0
|
413
|
+
})
|
414
|
+
})
|
415
|
+
)
|
416
|
+
}
|
417
|
+
|
418
|
+
// 所有container位置(對應category)
|
419
|
+
export const containerPositionObservable = ({ computedData$, fullDataFormatter$, layout$ }: {
|
420
|
+
computedData$: Observable<ComputedDataTypeMap<'multiValue'>>
|
421
|
+
fullDataFormatter$: Observable<DataFormatterTypeMap<'multiValue'>>
|
422
|
+
layout$: Observable<Layout>
|
423
|
+
}): Observable<ContainerPositionScaled[]> => {
|
424
|
+
|
425
|
+
const containerPosition$ = combineLatest({
|
426
|
+
computedData: computedData$,
|
427
|
+
fullDataFormatter: fullDataFormatter$,
|
428
|
+
layout: layout$,
|
429
|
+
}).pipe(
|
430
|
+
switchMap(async (d) => d),
|
431
|
+
map(data => {
|
432
|
+
|
433
|
+
if (data.fullDataFormatter.separateCategory) {
|
434
|
+
// -- 依slotIndexes計算 --
|
435
|
+
return calcContainerPositionScaled(data.layout, data.fullDataFormatter.container, data.computedData.length)
|
436
|
+
// return data.computedData.map((seriesData, seriesIndex) => {
|
437
|
+
// const columnIndex = seriesIndex % data.fullDataFormatter.container.columnAmount
|
438
|
+
// const rowIndex = Math.floor(seriesIndex / data.fullDataFormatter.container.columnAmount)
|
439
|
+
// const { translate, scale } = calcMultiValueContainerPosition(data.layout, data.fullDataFormatter.container, rowIndex, columnIndex)
|
440
|
+
// return {
|
441
|
+
// slotIndex: seriesIndex,
|
442
|
+
// rowIndex,
|
443
|
+
// columnIndex,
|
444
|
+
// translate,
|
445
|
+
// scale,
|
446
|
+
// }
|
447
|
+
// })
|
448
|
+
} else {
|
449
|
+
// -- 無拆分 --
|
450
|
+
const containerPositionArr = calcContainerPositionScaled(data.layout, data.fullDataFormatter.container, 1)
|
451
|
+
return data.computedData.map((d, i) => containerPositionArr[0]) // 每個series相同位置
|
452
|
+
// const columnIndex = 0
|
453
|
+
// const rowIndex = 0
|
454
|
+
// return data.computedData.map((seriesData, seriesIndex) => {
|
455
|
+
// const { translate, scale } = calcMultiValueContainerPosition(data.layout, data.fullDataFormatter.container, rowIndex, columnIndex)
|
456
|
+
// return {
|
457
|
+
// slotIndex: 0,
|
458
|
+
// rowIndex,
|
459
|
+
// columnIndex,
|
460
|
+
// translate,
|
461
|
+
// scale,
|
462
|
+
// }
|
463
|
+
// })
|
464
|
+
}
|
465
|
+
})
|
466
|
+
)
|
467
|
+
|
468
|
+
return containerPosition$
|
469
|
+
}
|
470
|
+
|
471
|
+
// export const containerSizeObservable = ({ layout$, containerPosition$ }: {
|
472
|
+
// layout$: Observable<Layout>
|
473
|
+
// containerPosition$: Observable<ContainerPositionScaled[]>
|
474
|
+
// }) => {
|
475
|
+
// const rowAmount$ = containerPosition$.pipe(
|
476
|
+
// map(containerPosition => {
|
477
|
+
// const maxRowIndex = containerPosition.reduce((acc, current) => {
|
478
|
+
// return current.rowIndex > acc ? current.rowIndex : acc
|
479
|
+
// }, 0)
|
480
|
+
// return maxRowIndex + 1
|
481
|
+
// }),
|
482
|
+
// distinctUntilChanged(),
|
483
|
+
// )
|
484
|
+
|
485
|
+
// const columnAmount$ = containerPosition$.pipe(
|
486
|
+
// map(containerPosition => {
|
487
|
+
// const maxColumnIndex = containerPosition.reduce((acc, current) => {
|
488
|
+
// return current.columnIndex > acc ? current.columnIndex : acc
|
489
|
+
// }, 0)
|
490
|
+
// return maxColumnIndex + 1
|
491
|
+
// }),
|
492
|
+
// distinctUntilChanged()
|
493
|
+
// )
|
494
|
+
|
495
|
+
// return combineLatest({
|
496
|
+
// layout: layout$,
|
497
|
+
// rowAmount: rowAmount$,
|
498
|
+
// columnAmount: columnAmount$
|
499
|
+
// }).pipe(
|
500
|
+
// switchMap(async (d) => d),
|
501
|
+
// map(data => {
|
502
|
+
// const width = (data.layout.rootWidth / data.columnAmount) - (data.layout.left + data.layout.right)
|
503
|
+
// const height = (data.layout.rootHeight / data.rowAmount) - (data.layout.top + data.layout.bottom)
|
504
|
+
// return {
|
505
|
+
// width,
|
506
|
+
// height
|
507
|
+
// }
|
508
|
+
// }),
|
509
|
+
// distinctUntilChanged((a, b) => a.width === b.width && a.height === b.height),
|
510
|
+
// shareReplay(1)
|
511
|
+
// )
|
512
|
+
// }
|
513
|
+
|
514
|
+
export const filteredXYMinMaxDataObservable = ({ visibleComputedXYData$, xyMinMax$, xyValueIndex$, fullDataFormatter$ }: {
|
515
|
+
visibleComputedXYData$: Observable<ComputedXYDataMultiValue>
|
516
|
+
xyMinMax$: Observable<{ minX: number, maxX: number, minY: number, maxY: number }>
|
517
|
+
xyValueIndex$: Observable<[number, number]>
|
518
|
+
fullDataFormatter$: Observable<DataFormatterTypeMap<'multiValue'>>
|
519
|
+
}) => {
|
520
|
+
return combineLatest({
|
521
|
+
visibleComputedXYData: visibleComputedXYData$,
|
522
|
+
xyMinMax: xyMinMax$,
|
523
|
+
xyValueIndex: xyValueIndex$,
|
524
|
+
fullDataFormatter: fullDataFormatter$,
|
525
|
+
}).pipe(
|
526
|
+
map(data => {
|
527
|
+
// 所有可見資料依 dataFormatter 的 scale 設定篩選出最大小值
|
528
|
+
const { minX, maxX, minY, maxY } = (() => {
|
529
|
+
|
530
|
+
let { minX, maxX, minY, maxY } = data.xyMinMax
|
531
|
+
|
532
|
+
if (data.fullDataFormatter.xAxis.scaleDomain[0] === 'auto' && minX > 0) {
|
533
|
+
minX = 0
|
534
|
+
} else if (typeof data.fullDataFormatter.xAxis.scaleDomain[0] === 'number') {
|
535
|
+
minX = data.fullDataFormatter.xAxis.scaleDomain[0] as number
|
536
|
+
}
|
537
|
+
if (data.fullDataFormatter.xAxis.scaleDomain[1] === 'auto' && maxX < 0) {
|
538
|
+
maxX = 0
|
539
|
+
} else if (typeof data.fullDataFormatter.xAxis.scaleDomain[1] === 'number') {
|
540
|
+
maxX = data.fullDataFormatter.xAxis.scaleDomain[1] as number
|
541
|
+
}
|
542
|
+
if (data.fullDataFormatter.yAxis.scaleDomain[0] === 'auto' && minY > 0) {
|
543
|
+
minY = 0
|
544
|
+
} else if (typeof data.fullDataFormatter.yAxis.scaleDomain[0] === 'number') {
|
545
|
+
minY = data.fullDataFormatter.yAxis.scaleDomain[0] as number
|
546
|
+
}
|
547
|
+
if (data.fullDataFormatter.yAxis.scaleDomain[1] === 'auto' && maxY < 0) {
|
548
|
+
maxY = 0
|
549
|
+
} else if (typeof data.fullDataFormatter.yAxis.scaleDomain[1] === 'number') {
|
550
|
+
maxY = data.fullDataFormatter.yAxis.scaleDomain[1] as number
|
551
|
+
}
|
552
|
+
|
553
|
+
return { minX, maxX, minY, maxY }
|
554
|
+
})()
|
555
|
+
// console.log({ minX, maxX, minY, maxY })
|
556
|
+
let datumList: ComputedXYDatumMultiValue[] = []
|
557
|
+
let minXDatum: ComputedXYDatumMultiValue | null = null
|
558
|
+
let maxXDatum: ComputedXYDatumMultiValue | null = null
|
559
|
+
let minYDatum: ComputedXYDatumMultiValue | null = null
|
560
|
+
let maxYDatum: ComputedXYDatumMultiValue | null = null
|
561
|
+
// console.log('data.visibleComputedXYData', data.visibleComputedXYData)
|
562
|
+
// minX, maxX, minY, maxY 範圍內的最大最小值資料
|
563
|
+
// console.log({ minX, maxX, minY, maxY })
|
564
|
+
for (let categoryData of data.visibleComputedXYData) {
|
565
|
+
for (let datum of categoryData) {
|
566
|
+
const xValue = datum.value[data.xyValueIndex[0]]
|
567
|
+
const yValue = datum.value[data.xyValueIndex[1]]
|
568
|
+
// 比較矩形範圍(所以 minX, maxX, minY, maxY 要同時比較)
|
569
|
+
if (xValue >= minX && xValue <= maxX && yValue >= minY && yValue <= maxY) {
|
570
|
+
datumList.push(datum)
|
571
|
+
if (minXDatum == null || xValue < minXDatum.value[data.xyValueIndex[0]]) {
|
572
|
+
minXDatum = datum
|
573
|
+
}
|
574
|
+
if (maxXDatum == null || xValue > maxXDatum.value[data.xyValueIndex[0]]) {
|
575
|
+
maxXDatum = datum
|
576
|
+
}
|
577
|
+
if (minYDatum == null || yValue < minYDatum.value[data.xyValueIndex[1]]) {
|
578
|
+
minYDatum = datum
|
579
|
+
}
|
580
|
+
if (maxYDatum == null || yValue > maxYDatum.value[data.xyValueIndex[1]]) {
|
581
|
+
maxYDatum = datum
|
582
|
+
}
|
583
|
+
}
|
584
|
+
}
|
585
|
+
}
|
586
|
+
|
587
|
+
return {
|
588
|
+
datumList,
|
589
|
+
minXDatum,
|
590
|
+
maxXDatum,
|
591
|
+
minYDatum,
|
592
|
+
maxYDatum
|
593
|
+
}
|
594
|
+
})
|
595
|
+
)
|
596
|
+
}
|
597
|
+
|
598
|
+
// export const visibleComputedRankingDataObservable = ({ visibleComputedData$ }: {
|
599
|
+
// visibleComputedData$: Observable<ComputedDatumMultiValue[][]>
|
600
|
+
// }) => {
|
601
|
+
// return visibleComputedData$.pipe(
|
602
|
+
// map(visibleComputedData => visibleComputedData
|
603
|
+
// .flat()
|
604
|
+
// .map(d => {
|
605
|
+
// // 新增總計資料欄位
|
606
|
+
// ;(d as any)._sum = d.value.reduce((acc, curr) => acc + curr, 0)
|
607
|
+
// return d
|
608
|
+
// })
|
609
|
+
// .sort((a: any, b: any) => b._sum - a._sum)
|
610
|
+
// )
|
611
|
+
// )
|
612
|
+
|
613
|
+
// // const labelAmountLimit$ = combineLatest({
|
614
|
+
// // layout: layout$,
|
615
|
+
// // textSizePx: textSizePx$,
|
616
|
+
// // sortedLabels: sortedLabels$
|
617
|
+
// // }).pipe(
|
618
|
+
// // switchMap(async (d) => d),
|
619
|
+
// // map(data => {
|
620
|
+
// // const lineHeight = data.textSizePx * 2 // 2倍行高
|
621
|
+
// // const labelAmountLimit = Math.floor(data.layout.height / lineHeight)
|
622
|
+
// // return labelAmountLimit
|
623
|
+
// // }),
|
624
|
+
// // distinctUntilChanged()
|
625
|
+
// // )
|
626
|
+
|
627
|
+
// // return combineLatest({
|
628
|
+
// // sortedLabels: sortedLabels$,
|
629
|
+
// // labelAmountLimit: labelAmountLimit$
|
630
|
+
// // }).pipe(
|
631
|
+
// // map(data => {
|
632
|
+
// // return data.sortedLabels.slice(0, data.labelAmountLimit)
|
633
|
+
// // })
|
634
|
+
// // )
|
635
|
+
|
636
|
+
// }
|
637
|
+
|
638
|
+
// export const rankingAmountLimitObservable = ({ layout$, textSizePx$ }: {
|
639
|
+
// layout$: Observable<Layout>
|
640
|
+
// textSizePx$: Observable<number>
|
641
|
+
// }) => {
|
642
|
+
// return combineLatest({
|
643
|
+
// layout: layout$,
|
644
|
+
// textSizePx: textSizePx$
|
645
|
+
// }).pipe(
|
646
|
+
// switchMap(async (d) => d),
|
647
|
+
// map(data => {
|
648
|
+
// const lineHeight = data.textSizePx * 2 // 2倍行高
|
649
|
+
// const labelAmountLimit = Math.floor(data.layout.height / lineHeight)
|
650
|
+
// return labelAmountLimit
|
651
|
+
// }),
|
652
|
+
// distinctUntilChanged()
|
653
|
+
// )
|
654
|
+
// }
|
655
|
+
|
656
|
+
// export const rankingScaleObservable = ({ layout$, visibleComputedRankingData$, rankingAmountLimit$ }: {
|
657
|
+
// layout$: Observable<Layout>
|
658
|
+
// visibleComputedRankingData$: Observable<ComputedDatumMultiValue[]>
|
659
|
+
// rankingAmountLimit$: Observable<number>
|
660
|
+
// }) => {
|
661
|
+
// return combineLatest({
|
662
|
+
// layout: layout$,
|
663
|
+
// rankingAmountLimit: rankingAmountLimit$,
|
664
|
+
// visibleComputedRankingData: visibleComputedRankingData$,
|
665
|
+
// }).pipe(
|
666
|
+
// switchMap(async (d) => d),
|
667
|
+
// map(data => {
|
668
|
+
// let labelAmount = 0
|
669
|
+
// let lineHeight = 0
|
670
|
+
// let totalHeight = 0
|
671
|
+
// if (data.visibleComputedRankingData.length > data.rankingAmountLimit) {
|
672
|
+
// labelAmount = data.rankingAmountLimit
|
673
|
+
// lineHeight = data.layout.height / labelAmount
|
674
|
+
// totalHeight = lineHeight * labelAmount // 用全部的數量來算而不是要顯示的數量(要超出圖軸高度)
|
675
|
+
// } else {
|
676
|
+
// labelAmount = data.visibleComputedRankingData.length
|
677
|
+
// lineHeight = data.layout.height / labelAmount
|
678
|
+
// totalHeight = data.layout.height
|
679
|
+
// }
|
680
|
+
|
681
|
+
// return createLabelToAxisScale({
|
682
|
+
// axisLabels: data.visibleComputedRankingData.map(d => d.label),
|
683
|
+
// axisWidth: totalHeight,
|
684
|
+
// padding: 0.5
|
685
|
+
// })
|
686
|
+
// })
|
687
|
+
// )
|
688
|
+
// }
|
689
|
+
|
690
|
+
export const graphicTransformObservable = ({ xyMinMax$, xyValueIndex$, filteredXYMinMaxData$, fullDataFormatter$, layout$ }: {
|
691
|
+
xyMinMax$: Observable<{ minX: number, maxX: number, minY: number, maxY: number }>
|
692
|
+
xyValueIndex$: Observable<[number, number]>
|
693
|
+
filteredXYMinMaxData$: Observable<{
|
694
|
+
minXDatum: ComputedXYDatumMultiValue
|
695
|
+
maxXDatum: ComputedXYDatumMultiValue
|
696
|
+
minYDatum: ComputedXYDatumMultiValue
|
697
|
+
maxYDatum: ComputedXYDatumMultiValue
|
698
|
+
}>
|
699
|
+
fullDataFormatter$: Observable<DataFormatterTypeMap<'multiValue'>>
|
700
|
+
layout$: Observable<Layout>
|
701
|
+
}): Observable<TransformData> => {
|
702
|
+
const destroy$ = new Subject()
|
703
|
+
|
704
|
+
function calcDataAreaTransform ({ xyMinMax, xyValueIndex, filteredXYMinMaxData, xAxis, yAxis, width, height }: {
|
705
|
+
xyMinMax: { minX: number, maxX: number, minY: number, maxY: number }
|
706
|
+
xyValueIndex: [number, number]
|
707
|
+
filteredXYMinMaxData: {
|
708
|
+
minXDatum: ComputedXYDatumMultiValue
|
709
|
+
maxXDatum: ComputedXYDatumMultiValue
|
710
|
+
minYDatum: ComputedXYDatumMultiValue
|
711
|
+
maxYDatum: ComputedXYDatumMultiValue
|
712
|
+
}
|
713
|
+
xAxis: DataFormatterXYAxis
|
714
|
+
yAxis: DataFormatterXYAxis
|
715
|
+
width: number
|
716
|
+
height: number
|
717
|
+
}): TransformData {
|
718
|
+
// const flatData = data.flat()
|
719
|
+
|
720
|
+
let translateX = 0
|
721
|
+
let translateY = 0
|
722
|
+
let scaleX = 0
|
723
|
+
let scaleY = 0
|
724
|
+
|
725
|
+
// // minX, maxX, filteredMinX, filteredMaxX
|
726
|
+
// let filteredMinX = 0
|
727
|
+
// let filteredMaxX = 0
|
728
|
+
// let [minX, maxX] = getMinMax(flatData.map(d => d.value[0]))
|
729
|
+
// if (minX === maxX) {
|
730
|
+
// minX = maxX - 1 // 避免最大及最小值相同造成無法計算scale
|
731
|
+
// }
|
732
|
+
// if (xAxis.scaleDomain[0] === 'auto' && filteredMinX > 0) {
|
733
|
+
// filteredMinX = 0
|
734
|
+
// } else if (typeof xAxis.scaleDomain[0] === 'number') {
|
735
|
+
// filteredMinX = xAxis.scaleDomain[0] as number
|
736
|
+
// } else {
|
737
|
+
// filteredMinX = minX
|
738
|
+
// }
|
739
|
+
// if (xAxis.scaleDomain[1] === 'auto' && filteredMaxX < 0) {
|
740
|
+
// filteredMaxX = 0
|
741
|
+
// } else if (typeof xAxis.scaleDomain[1] === 'number') {
|
742
|
+
// filteredMaxX = xAxis.scaleDomain[1] as number
|
743
|
+
// } else {
|
744
|
+
// filteredMaxX = maxX
|
745
|
+
// }
|
746
|
+
// if (filteredMinX === filteredMaxX) {
|
747
|
+
// filteredMinX = filteredMaxX - 1 // 避免最大及最小值相同造成無法計算scale
|
748
|
+
// }
|
749
|
+
|
750
|
+
// // minY, maxY, filteredMinY, filteredMaxY
|
751
|
+
// let filteredMinY = 0
|
752
|
+
// let filteredMaxY = 0
|
753
|
+
// let [minY, maxY] = getMinMax(flatData.map(d => d.value[1]))
|
754
|
+
// console.log('filteredXYMinMaxData', filteredXYMinMaxData)
|
755
|
+
let { minX, maxX, minY, maxY } = xyMinMax
|
756
|
+
// console.log({ minX, maxX, minY, maxY })
|
757
|
+
let filteredMinX = filteredXYMinMaxData.minXDatum.value[xyValueIndex[0]] ?? 0
|
758
|
+
let filteredMaxX = filteredXYMinMaxData.maxXDatum.value[xyValueIndex[0]] ?? 0
|
759
|
+
let filteredMinY = filteredXYMinMaxData.minYDatum.value[xyValueIndex[1]] ?? 0
|
760
|
+
let filteredMaxY = filteredXYMinMaxData.maxYDatum.value[xyValueIndex[1]] ?? 0
|
761
|
+
|
762
|
+
// if (yAxis.scaleDomain[0] === 'auto' && filteredMinY > 0) {
|
763
|
+
// filteredMinY = 0
|
764
|
+
// } else if (typeof yAxis.scaleDomain[0] === 'number') {
|
765
|
+
// filteredMinY = yAxis.scaleDomain[0] as number
|
766
|
+
// } else {
|
767
|
+
// filteredMinY = minY
|
768
|
+
// }
|
769
|
+
// if (yAxis.scaleDomain[1] === 'auto' && filteredMaxY < 0) {
|
770
|
+
// filteredMaxY = 0
|
771
|
+
// } else if (typeof yAxis.scaleDomain[1] === 'number') {
|
772
|
+
// filteredMaxY = yAxis.scaleDomain[1] as number
|
773
|
+
// } else {
|
774
|
+
// filteredMaxY = maxY
|
775
|
+
// }
|
776
|
+
|
777
|
+
// console.log({ minX, maxX, minY, maxY, filteredMinX, filteredMaxX, filteredMinY, filteredMaxY })
|
778
|
+
if (filteredMinX === filteredMaxX && filteredMaxX === 0) {
|
779
|
+
// 避免最大及最小值相同造成無法計算scale
|
780
|
+
filteredMaxX = 1
|
781
|
+
}
|
782
|
+
if (filteredMinY === filteredMaxY && filteredMaxY === 0) {
|
783
|
+
// 避免最大及最小值相同造成無法計算scale
|
784
|
+
filteredMaxY = 1
|
785
|
+
}
|
786
|
+
if (minX === maxX && maxX === 0) {
|
787
|
+
// 避免最大及最小值相同造成無法計算scale
|
788
|
+
maxX = 1
|
789
|
+
}
|
790
|
+
if (minY === maxY && maxY === 0) {
|
791
|
+
// 避免最大及最小值相同造成無法計算scale
|
792
|
+
maxY = 1
|
793
|
+
}
|
794
|
+
// -- xScale --
|
795
|
+
const xScale: d3.ScaleLinear<number, number> = createValueToAxisScale({
|
796
|
+
maxValue: filteredMaxX,
|
797
|
+
minValue: filteredMinX,
|
798
|
+
axisWidth: width,
|
799
|
+
scaleDomain: xAxis.scaleDomain,
|
800
|
+
scaleRange: xAxis.scaleRange
|
801
|
+
})
|
802
|
+
|
803
|
+
// -- translateX, scaleX --
|
804
|
+
const rangeMinX = xScale(minX > 0 ? 0 : minX) // * 因為原本的座標就是以 0 到最大值或最小值範範圍計算的,所以這邊也是用同樣的方式計算
|
805
|
+
const rangeMaxX = xScale(maxX < 0 ? 0 : maxX) // * 因為原本的座標就是以 0 到最大值或最小值範範圍計算的,所以這邊也是用同樣的方式計算
|
806
|
+
translateX = rangeMinX
|
807
|
+
const gWidth = rangeMaxX - rangeMinX
|
808
|
+
scaleX = gWidth / width
|
809
|
+
// console.log({ gWidth, width, rangeMaxX, rangeMinX, scaleX, translateX })
|
810
|
+
// -- yScale --
|
811
|
+
const yScale: d3.ScaleLinear<number, number> = createValueToAxisScale({
|
812
|
+
maxValue: filteredMaxY,
|
813
|
+
minValue: filteredMinY,
|
814
|
+
axisWidth: height,
|
815
|
+
scaleDomain: yAxis.scaleDomain,
|
816
|
+
scaleRange: yAxis.scaleRange,
|
817
|
+
reverse: true
|
818
|
+
})
|
819
|
+
|
820
|
+
// -- translateY, scaleY --
|
821
|
+
const rangeMinY = yScale(minY > 0 ? 0 : minY) // * 因為原本的座標就是以 0 到最大值或最小值範範圍計算的,所以這邊也是用同樣的方式計算
|
822
|
+
const rangeMaxY = yScale(maxY < 0 ? 0 : maxY) // * 因為原本的座標就是以 0 到最大值或最小值範範圍計算的,所以這邊也是用同樣的方式計算
|
823
|
+
translateY = rangeMaxY // 最大值的 y 最小(最上方)
|
824
|
+
const gHeight = rangeMinY - rangeMaxY // 最大的 y 減最小的 y
|
825
|
+
scaleY = gHeight / height
|
826
|
+
|
827
|
+
return {
|
828
|
+
translate: [translateX, translateY],
|
829
|
+
scale: [scaleX, scaleY],
|
830
|
+
rotate: 0,
|
831
|
+
rotateX: 0,
|
832
|
+
rotateY: 0,
|
833
|
+
value: `translate(${translateX}px, ${translateY}px) scale(${scaleX}, ${scaleY})`
|
834
|
+
}
|
835
|
+
}
|
836
|
+
|
837
|
+
return new Observable(subscriber => {
|
838
|
+
combineLatest({
|
839
|
+
xyMinMax: xyMinMax$,
|
840
|
+
xyValueIndex: xyValueIndex$,
|
841
|
+
filteredXYMinMaxData: filteredXYMinMaxData$,
|
842
|
+
fullDataFormatter: fullDataFormatter$,
|
843
|
+
layout: layout$
|
844
|
+
}).pipe(
|
845
|
+
takeUntil(destroy$),
|
846
|
+
switchMap(async (d) => d),
|
847
|
+
).subscribe(data => {
|
848
|
+
if (!data.filteredXYMinMaxData.minXDatum || !data.filteredXYMinMaxData.maxXDatum
|
849
|
+
|| data.filteredXYMinMaxData.minXDatum.value[data.xyValueIndex[0]] == null || data.filteredXYMinMaxData.maxXDatum.value[data.xyValueIndex[0]] == null
|
850
|
+
|| !data.filteredXYMinMaxData.minYDatum || !data.filteredXYMinMaxData.maxYDatum
|
851
|
+
|| data.filteredXYMinMaxData.minYDatum.value[data.xyValueIndex[1]] == null || data.filteredXYMinMaxData.maxYDatum.value[data.xyValueIndex[1]] == null
|
852
|
+
) {
|
853
|
+
return
|
854
|
+
}
|
855
|
+
const dataAreaTransformData = calcDataAreaTransform({
|
856
|
+
xyMinMax: data.xyMinMax,
|
857
|
+
xyValueIndex: data.xyValueIndex,
|
858
|
+
filteredXYMinMaxData: data.filteredXYMinMaxData,
|
859
|
+
xAxis: data.fullDataFormatter.xAxis,
|
860
|
+
yAxis: data.fullDataFormatter.yAxis,
|
861
|
+
width: data.layout.width,
|
862
|
+
height: data.layout.height
|
863
|
+
})
|
864
|
+
|
865
|
+
// console.log('dataAreaTransformData', dataAreaTransformData)
|
866
|
+
|
867
|
+
subscriber.next(dataAreaTransformData)
|
868
|
+
})
|
869
|
+
|
870
|
+
return function unscbscribe () {
|
871
|
+
destroy$.next(undefined)
|
872
|
+
}
|
873
|
+
})
|
874
|
+
}
|
875
|
+
|
876
|
+
export const graphicReverseScaleObservable = ({ containerPosition$, graphicTransform$ }: {
|
877
|
+
containerPosition$: Observable<ContainerPositionScaled[]>
|
878
|
+
// multiValueAxesTransform$: Observable<TransformData>
|
879
|
+
graphicTransform$: Observable<TransformData>
|
880
|
+
}): Observable<[number, number][]> => {
|
881
|
+
return combineLatest({
|
882
|
+
containerPosition: containerPosition$,
|
883
|
+
// multiValueAxesTransform: multiValueAxesTransform$,
|
884
|
+
graphicTransform: graphicTransform$,
|
885
|
+
}).pipe(
|
886
|
+
switchMap(async (d) => d),
|
887
|
+
map(data => {
|
888
|
+
// if (data.multiValueAxesTransform.rotate == 0 || data.multiValueAxesTransform.rotate == 180) {
|
889
|
+
return data.containerPosition.map((series, seriesIndex) => {
|
890
|
+
return [
|
891
|
+
1 / data.graphicTransform.scale[0] / data.containerPosition[seriesIndex].scale[0],
|
892
|
+
1 / data.graphicTransform.scale[1] / data.containerPosition[seriesIndex].scale[1],
|
893
|
+
]
|
894
|
+
})
|
895
|
+
// } else {
|
896
|
+
// return data.containerPosition.map((series, seriesIndex) => {
|
897
|
+
// // 由於有垂直的旋轉,所以外層 (container) x和y的scale要互換
|
898
|
+
// return [
|
899
|
+
// 1 / data.graphicTransform.scale[0] / data.containerPosition[seriesIndex].scale[1],
|
900
|
+
// 1 / data.graphicTransform.scale[1] / data.containerPosition[seriesIndex].scale[0],
|
901
|
+
// ]
|
902
|
+
// })
|
903
|
+
// }
|
904
|
+
}),
|
905
|
+
)
|
906
|
+
}
|
907
|
+
|
908
|
+
// X 軸圖軸 - 用 value[index]
|
909
|
+
export const xScaleObservable = ({ visibleComputedSumData$, fullDataFormatter$, filteredXYMinMaxData$, containerSize$ }: {
|
910
|
+
visibleComputedSumData$: Observable<ComputedDatumMultiValue[][]>
|
911
|
+
fullDataFormatter$: Observable<DataFormatterMultiValue>
|
912
|
+
filteredXYMinMaxData$: Observable<{
|
913
|
+
minXDatum: ComputedXYDatumMultiValue
|
914
|
+
maxXDatum: ComputedXYDatumMultiValue
|
915
|
+
minYDatum: ComputedXYDatumMultiValue
|
916
|
+
maxYDatum: ComputedXYDatumMultiValue
|
917
|
+
}>
|
918
|
+
// layout$: Observable<Layout>
|
919
|
+
containerSize$: Observable<ContainerSize>
|
920
|
+
}) => {
|
921
|
+
return combineLatest({
|
922
|
+
visibleComputedSumData: visibleComputedSumData$,
|
923
|
+
fullDataFormatter: fullDataFormatter$,
|
924
|
+
containerSize: containerSize$,
|
925
|
+
// xyMinMax: xyMinMax$
|
926
|
+
filteredXYMinMaxData: filteredXYMinMaxData$
|
927
|
+
}).pipe(
|
928
|
+
switchMap(async (d) => d),
|
929
|
+
map(data => {
|
930
|
+
const valueIndex = data.fullDataFormatter.xAxis.valueIndex
|
931
|
+
if (!data.filteredXYMinMaxData.minXDatum || !data.filteredXYMinMaxData.maxXDatum
|
932
|
+
// || data.filteredXYMinMaxData.minXDatum.value[valueIndex] == null || data.filteredXYMinMaxData.maxXDatum.value[valueIndex] == null
|
933
|
+
) {
|
934
|
+
return
|
935
|
+
}
|
936
|
+
let maxValue: number | null = data.filteredXYMinMaxData.maxXDatum.value[valueIndex]
|
937
|
+
let minValue: number | null = data.filteredXYMinMaxData.minXDatum.value[valueIndex]
|
938
|
+
if (maxValue === minValue && maxValue === 0) {
|
939
|
+
// 避免最大及最小值同等於 0 造成無法計算scale
|
940
|
+
maxValue = 1
|
941
|
+
}
|
942
|
+
|
943
|
+
const xScale: d3.ScaleLinear<number, number> = createValueToAxisScale({
|
944
|
+
maxValue,
|
945
|
+
minValue,
|
946
|
+
axisWidth: data.containerSize.width,
|
947
|
+
scaleDomain: data.fullDataFormatter.xAxis.scaleDomain,
|
948
|
+
scaleRange: data.fullDataFormatter.xAxis.scaleRange,
|
949
|
+
})
|
950
|
+
return xScale
|
951
|
+
})
|
952
|
+
)
|
953
|
+
}
|
954
|
+
|
955
|
+
// X 軸圖軸 - 用所有 valueIndex 加總資料
|
956
|
+
export const xSumScaleObservable = ({ fullDataFormatter$, filteredXYMinMaxData$, containerSize$ }: {
|
957
|
+
// valueIndex$: Observable<number>
|
958
|
+
fullDataFormatter$: Observable<DataFormatterMultiValue>
|
959
|
+
filteredXYMinMaxData$: Observable<{
|
960
|
+
minXDatum: ComputedXYDatumMultiValue
|
961
|
+
maxXDatum: ComputedXYDatumMultiValue
|
962
|
+
minYDatum: ComputedXYDatumMultiValue
|
963
|
+
maxYDatum: ComputedXYDatumMultiValue
|
964
|
+
}>
|
965
|
+
// layout$: Observable<Layout>
|
966
|
+
containerSize$: Observable<ContainerSize>
|
967
|
+
}) => {
|
968
|
+
return combineLatest({
|
969
|
+
// valueIndex: valueIndex$,
|
970
|
+
fullDataFormatter: fullDataFormatter$,
|
971
|
+
containerSize: containerSize$,
|
972
|
+
// xyMinMax: xyMinMax$
|
973
|
+
filteredXYMinMaxData: filteredXYMinMaxData$
|
974
|
+
}).pipe(
|
975
|
+
switchMap(async (d) => d),
|
976
|
+
map(data => {
|
977
|
+
const valueIndex = data.fullDataFormatter.xAxis.valueIndex
|
978
|
+
if (!data.filteredXYMinMaxData.minXDatum || !data.filteredXYMinMaxData.maxXDatum
|
979
|
+
// || data.filteredXYMinMaxData.minXDatum.value[valueIndex] == null || data.filteredXYMinMaxData.maxXDatum.value[valueIndex] == null
|
980
|
+
) {
|
981
|
+
return
|
982
|
+
}
|
983
|
+
let maxValue: number | null = data.filteredXYMinMaxData.maxXDatum.value[valueIndex]
|
984
|
+
let minValue: number | null = data.filteredXYMinMaxData.minXDatum.value[valueIndex]
|
985
|
+
if (maxValue === minValue && maxValue === 0) {
|
986
|
+
// 避免最大及最小值同等於 0 造成無法計算scale
|
987
|
+
maxValue = 1
|
988
|
+
}
|
989
|
+
|
990
|
+
const xScale: d3.ScaleLinear<number, number> = createValueToAxisScale({
|
991
|
+
maxValue,
|
992
|
+
minValue,
|
993
|
+
axisWidth: data.containerSize.width,
|
994
|
+
scaleDomain: data.fullDataFormatter.xAxis.scaleDomain,
|
995
|
+
scaleRange: data.fullDataFormatter.xAxis.scaleRange,
|
996
|
+
})
|
997
|
+
return xScale
|
998
|
+
})
|
999
|
+
)
|
1000
|
+
}
|
1001
|
+
|
1002
|
+
export const yScaleObservable = ({ fullDataFormatter$, filteredXYMinMaxData$, containerSize$ }: {
|
1003
|
+
fullDataFormatter$: Observable<DataFormatterMultiValue>
|
1004
|
+
filteredXYMinMaxData$: Observable<{
|
1005
|
+
minXDatum: ComputedXYDatumMultiValue
|
1006
|
+
maxXDatum: ComputedXYDatumMultiValue
|
1007
|
+
minYDatum: ComputedXYDatumMultiValue
|
1008
|
+
maxYDatum: ComputedXYDatumMultiValue
|
1009
|
+
}>
|
1010
|
+
containerSize$: Observable<ContainerSize>
|
1011
|
+
}) => {
|
1012
|
+
return combineLatest({
|
1013
|
+
fullDataFormatter: fullDataFormatter$,
|
1014
|
+
containerSize: containerSize$,
|
1015
|
+
// xyMinMax: observer.xyMinMax$
|
1016
|
+
filteredXYMinMaxData: filteredXYMinMaxData$
|
1017
|
+
}).pipe(
|
1018
|
+
switchMap(async (d) => d),
|
1019
|
+
map(data => {
|
1020
|
+
const valueIndex = data.fullDataFormatter.yAxis.valueIndex
|
1021
|
+
if (!data.filteredXYMinMaxData.minYDatum || !data.filteredXYMinMaxData.maxYDatum
|
1022
|
+
|| data.filteredXYMinMaxData.minYDatum.value[valueIndex] == null || data.filteredXYMinMaxData.maxYDatum.value[valueIndex] == null
|
1023
|
+
) {
|
1024
|
+
return
|
1025
|
+
}
|
1026
|
+
let maxValue = data.filteredXYMinMaxData.maxYDatum.value[valueIndex]
|
1027
|
+
let minValue = data.filteredXYMinMaxData.minYDatum.value[valueIndex]
|
1028
|
+
if (maxValue === minValue && maxValue === 0) {
|
1029
|
+
// 避免最大及最小值同等於 0 造成無法計算scale
|
1030
|
+
maxValue = 1
|
1031
|
+
}
|
1032
|
+
|
1033
|
+
const yScale: d3.ScaleLinear<number, number> = createValueToAxisScale({
|
1034
|
+
maxValue,
|
1035
|
+
minValue,
|
1036
|
+
axisWidth: data.containerSize.height,
|
1037
|
+
scaleDomain: data.fullDataFormatter.yAxis.scaleDomain,
|
1038
|
+
scaleRange: data.fullDataFormatter.yAxis.scaleRange,
|
1039
|
+
reverse: true
|
1040
|
+
})
|
1041
|
+
return yScale
|
1042
|
+
})
|
1043
|
+
)
|
1044
|
+
}
|