@orbcharts/core 3.0.0-beta.3 → 3.0.0-beta.4
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 +2623 -2338
- package/dist/orbcharts-core.umd.js +4 -4
- package/dist/src/utils/d3Scale.d.ts +28 -0
- package/dist/src/utils/gridObservables.d.ts +29 -19
- package/dist/src/utils/index.d.ts +1 -1
- package/dist/src/utils/multiGridObservables.d.ts +2 -2
- package/dist/src/utils/multiValueObservables.d.ts +73 -0
- package/dist/src/utils/orbchartsUtils.d.ts +19 -5
- package/dist/src/utils/seriesObservables.d.ts +4 -4
- package/dist/src/utils/treeObservables.d.ts +2 -5
- 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 +505 -505
- package/src/base/createBasePlugin.ts +153 -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 +235 -232
- 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 +176 -155
- package/src/grid/dataFormatterValidator.ts +101 -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 +41 -41
- package/src/multiGrid/dataFormatterValidator.ts +115 -115
- package/src/multiGrid/dataValidator.ts +12 -12
- package/src/multiValue/computedDataFn.ts +110 -176
- package/src/multiValue/contextObserverCallback.ts +160 -12
- package/src/multiValue/dataFormatterValidator.ts +9 -9
- package/src/multiValue/dataValidator.ts +9 -9
- package/src/relationship/computedDataFn.ts +125 -125
- package/src/relationship/contextObserverCallback.ts +12 -12
- package/src/relationship/dataFormatterValidator.ts +9 -9
- package/src/relationship/dataValidator.ts +9 -9
- package/src/series/computedDataFn.ts +88 -88
- package/src/series/contextObserverCallback.ts +100 -100
- package/src/series/dataFormatterValidator.ts +41 -41
- package/src/series/dataValidator.ts +12 -12
- package/src/tree/computedDataFn.ts +129 -130
- package/src/tree/contextObserverCallback.ts +58 -61
- 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 -0
- package/src/utils/errorMessage.ts +42 -42
- package/src/utils/gridObservables.ts +671 -614
- package/src/utils/index.ts +9 -9
- package/src/utils/multiGridObservables.ts +392 -366
- package/src/utils/multiValueObservables.ts +643 -0
- package/src/utils/observables.ts +219 -219
- package/src/utils/orbchartsUtils.ts +377 -352
- package/src/utils/seriesObservables.ts +175 -175
- package/src/utils/treeObservables.ts +105 -94
- package/src/utils/validator.ts +126 -125
- package/tsconfig.base.json +13 -13
- package/tsconfig.json +2 -2
- package/vite-env.d.ts +6 -6
- package/vite.config.js +22 -22
- package/dist/src/utils/d3Utils.d.ts +0 -19
- package/src/utils/d3Utils.ts +0 -108
@@ -1,615 +1,672 @@
|
|
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
|
-
ComputedDataGrid,
|
20
|
-
DataTypeMap,
|
21
|
-
DataGridDatum,
|
22
|
-
ComputedDatumGrid,
|
23
|
-
DataFormatterTypeMap,
|
24
|
-
DataFormatterGrid,
|
25
|
-
DataFormatterValueAxis,
|
26
|
-
DataFormatterGroupAxis,
|
27
|
-
ComputedLayoutDatumGrid,
|
28
|
-
ComputedLayoutDataGrid,
|
29
|
-
|
30
|
-
HighlightTarget,
|
31
|
-
Layout,
|
32
|
-
TransformData } from '../../lib/core-types'
|
33
|
-
import { getMinAndMaxGrid } from './orbchartsUtils'
|
34
|
-
import {
|
35
|
-
import { calcGridContainerLayout } from './orbchartsUtils'
|
36
|
-
import { getMinAndMaxValue } from './orbchartsUtils'
|
37
|
-
|
38
|
-
export const gridComputedLayoutDataObservable = ({ computedData$, fullDataFormatter$, layout$ }: {
|
39
|
-
computedData$: Observable<ComputedDataTypeMap<'grid'>>
|
40
|
-
fullDataFormatter$: Observable<DataFormatterTypeMap<'grid'>>
|
41
|
-
layout$: Observable<Layout>
|
42
|
-
}): Observable<ComputedLayoutDatumGrid[][]> => {
|
43
|
-
|
44
|
-
// 未篩選group範圍前的group scale( * 不受到dataFormatter設定影響)
|
45
|
-
function createOriginGroupScale (computedData: ComputedDatumGrid[][], dataFormatter: DataFormatterGrid, layout: Layout) {
|
46
|
-
const groupAxisWidth = (dataFormatter.grid.groupAxis.position === 'top' || dataFormatter.grid.groupAxis.position === 'bottom')
|
47
|
-
? layout.width
|
48
|
-
: layout.height
|
49
|
-
const groupEndIndex = computedData[0] ? computedData[0].length - 1 : 0
|
50
|
-
const groupScale: d3.ScaleLinear<number, number> =
|
51
|
-
maxValue: groupEndIndex,
|
52
|
-
minValue: 0,
|
53
|
-
axisWidth: groupAxisWidth,
|
54
|
-
scaleDomain: [0, groupEndIndex], // 不使用dataFormatter設定
|
55
|
-
scaleRange: [0, 1] // 不使用dataFormatter設定
|
56
|
-
})
|
57
|
-
|
58
|
-
return groupScale
|
59
|
-
}
|
60
|
-
|
61
|
-
// 未篩選group範圍及visible前的value scale( * 不受到dataFormatter設定影響)
|
62
|
-
function createOriginValueScale (computedData: ComputedDatumGrid[][], dataFormatter: DataFormatterGrid, layout: Layout) {
|
63
|
-
const valueAxisWidth = (dataFormatter.grid.valueAxis.position === 'left' || dataFormatter.grid.valueAxis.position === 'right')
|
64
|
-
? layout.height
|
65
|
-
: layout.width
|
66
|
-
|
67
|
-
const listData = computedData.flat()
|
68
|
-
const [minValue, maxValue] = getMinAndMaxValue(listData)
|
69
|
-
|
70
|
-
const valueScale: d3.ScaleLinear<number, number> =
|
71
|
-
maxValue,
|
72
|
-
minValue,
|
73
|
-
axisWidth: valueAxisWidth,
|
74
|
-
// scaleDomain: [minValue, maxValue], // 不使用dataFormatter設定
|
75
|
-
scaleDomain: ['auto', 'auto'], // 不使用dataFormatter設定 --> 以0為基準到最大或最小值為範圍( * 如果是使用[minValue, maxValue]的話,在兩者很接近的情況下有可能造成scale倍率過高而svg變型時失真的情況)
|
76
|
-
scaleRange: [0, 1] // 不使用dataFormatter設定
|
77
|
-
})
|
78
|
-
|
79
|
-
return valueScale
|
80
|
-
}
|
81
|
-
|
82
|
-
return combineLatest({
|
83
|
-
computedData: computedData$,
|
84
|
-
fullDataFormatter: fullDataFormatter$,
|
85
|
-
layout: layout$
|
86
|
-
}).pipe(
|
87
|
-
switchMap(async d => d),
|
88
|
-
map(data => {
|
89
|
-
const groupScale = createOriginGroupScale(data.computedData, data.fullDataFormatter, data.layout)
|
90
|
-
const valueScale = createOriginValueScale(data.computedData, data.fullDataFormatter, data.layout)
|
91
|
-
const zeroY = valueScale(0)
|
92
|
-
|
93
|
-
return data.computedData.map((seriesData, seriesIndex) => {
|
94
|
-
return seriesData.map((groupDatum, groupIndex) => {
|
95
|
-
const axisX = groupScale(groupIndex)
|
96
|
-
const axisY = valueScale(groupDatum.value ?? 0)
|
97
|
-
return {
|
98
|
-
...groupDatum,
|
99
|
-
axisX,
|
100
|
-
axisY,
|
101
|
-
axisYFromZero: axisY - zeroY
|
102
|
-
}
|
103
|
-
})
|
104
|
-
})
|
105
|
-
})
|
106
|
-
)
|
107
|
-
}
|
108
|
-
|
109
|
-
export const
|
110
|
-
fullDataFormatter$: Observable<
|
111
|
-
layout$: Observable<Layout>
|
112
|
-
}): Observable<
|
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
|
-
translate,
|
245
|
-
scale,
|
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
|
-
if (
|
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
|
-
const
|
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
|
-
|
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
|
+
ComputedDataGrid,
|
20
|
+
DataTypeMap,
|
21
|
+
DataGridDatum,
|
22
|
+
ComputedDatumGrid,
|
23
|
+
DataFormatterTypeMap,
|
24
|
+
DataFormatterGrid,
|
25
|
+
DataFormatterValueAxis,
|
26
|
+
DataFormatterGroupAxis,
|
27
|
+
ComputedLayoutDatumGrid,
|
28
|
+
ComputedLayoutDataGrid,
|
29
|
+
ContainerPositionScaled,
|
30
|
+
HighlightTarget,
|
31
|
+
Layout,
|
32
|
+
TransformData } from '../../lib/core-types'
|
33
|
+
import { getMinAndMaxGrid } from './orbchartsUtils'
|
34
|
+
import { createValueToAxisScale, createLabelToAxisScale, createAxisToLabelIndexScale } from './d3Scale'
|
35
|
+
import { calcGridContainerLayout } from './orbchartsUtils'
|
36
|
+
import { getMinAndMaxValue } from './orbchartsUtils'
|
37
|
+
|
38
|
+
export const gridComputedLayoutDataObservable = ({ computedData$, fullDataFormatter$, layout$ }: {
|
39
|
+
computedData$: Observable<ComputedDataTypeMap<'grid'>>
|
40
|
+
fullDataFormatter$: Observable<DataFormatterTypeMap<'grid'>>
|
41
|
+
layout$: Observable<Layout>
|
42
|
+
}): Observable<ComputedLayoutDatumGrid[][]> => {
|
43
|
+
|
44
|
+
// 未篩選group範圍前的group scale( * 不受到dataFormatter設定影響)
|
45
|
+
function createOriginGroupScale (computedData: ComputedDatumGrid[][], dataFormatter: DataFormatterGrid, layout: Layout) {
|
46
|
+
const groupAxisWidth = (dataFormatter.grid.groupAxis.position === 'top' || dataFormatter.grid.groupAxis.position === 'bottom')
|
47
|
+
? layout.width
|
48
|
+
: layout.height
|
49
|
+
const groupEndIndex = computedData[0] ? computedData[0].length - 1 : 0
|
50
|
+
const groupScale: d3.ScaleLinear<number, number> = createValueToAxisScale({
|
51
|
+
maxValue: groupEndIndex,
|
52
|
+
minValue: 0,
|
53
|
+
axisWidth: groupAxisWidth,
|
54
|
+
scaleDomain: [0, groupEndIndex], // 不使用dataFormatter設定
|
55
|
+
scaleRange: [0, 1] // 不使用dataFormatter設定
|
56
|
+
})
|
57
|
+
|
58
|
+
return groupScale
|
59
|
+
}
|
60
|
+
|
61
|
+
// 未篩選group範圍及visible前的value scale( * 不受到dataFormatter設定影響)
|
62
|
+
function createOriginValueScale (computedData: ComputedDatumGrid[][], dataFormatter: DataFormatterGrid, layout: Layout) {
|
63
|
+
const valueAxisWidth = (dataFormatter.grid.valueAxis.position === 'left' || dataFormatter.grid.valueAxis.position === 'right')
|
64
|
+
? layout.height
|
65
|
+
: layout.width
|
66
|
+
|
67
|
+
const listData = computedData.flat()
|
68
|
+
const [minValue, maxValue] = getMinAndMaxValue(listData)
|
69
|
+
|
70
|
+
const valueScale: d3.ScaleLinear<number, number> = createValueToAxisScale({
|
71
|
+
maxValue,
|
72
|
+
minValue,
|
73
|
+
axisWidth: valueAxisWidth,
|
74
|
+
// scaleDomain: [minValue, maxValue], // 不使用dataFormatter設定
|
75
|
+
scaleDomain: ['auto', 'auto'], // 不使用dataFormatter設定 --> 以0為基準到最大或最小值為範圍( * 如果是使用[minValue, maxValue]的話,在兩者很接近的情況下有可能造成scale倍率過高而svg變型時失真的情況)
|
76
|
+
scaleRange: [0, 1] // 不使用dataFormatter設定
|
77
|
+
})
|
78
|
+
|
79
|
+
return valueScale
|
80
|
+
}
|
81
|
+
|
82
|
+
return combineLatest({
|
83
|
+
computedData: computedData$,
|
84
|
+
fullDataFormatter: fullDataFormatter$,
|
85
|
+
layout: layout$
|
86
|
+
}).pipe(
|
87
|
+
switchMap(async d => d),
|
88
|
+
map(data => {
|
89
|
+
const groupScale = createOriginGroupScale(data.computedData, data.fullDataFormatter, data.layout)
|
90
|
+
const valueScale = createOriginValueScale(data.computedData, data.fullDataFormatter, data.layout)
|
91
|
+
const zeroY = valueScale(0)
|
92
|
+
|
93
|
+
return data.computedData.map((seriesData, seriesIndex) => {
|
94
|
+
return seriesData.map((groupDatum, groupIndex) => {
|
95
|
+
const axisX = groupScale(groupIndex)
|
96
|
+
const axisY = valueScale(groupDatum.value ?? 0)
|
97
|
+
return {
|
98
|
+
...groupDatum,
|
99
|
+
axisX,
|
100
|
+
axisY,
|
101
|
+
axisYFromZero: axisY - zeroY
|
102
|
+
}
|
103
|
+
})
|
104
|
+
})
|
105
|
+
})
|
106
|
+
)
|
107
|
+
}
|
108
|
+
|
109
|
+
export const gridAxesSizeObservable = ({ fullDataFormatter$, layout$ }: {
|
110
|
+
fullDataFormatter$: Observable<DataFormatterGrid>
|
111
|
+
layout$: Observable<Layout>
|
112
|
+
}): Observable<{
|
113
|
+
width: number;
|
114
|
+
height: number;
|
115
|
+
}> => {
|
116
|
+
const destroy$ = new Subject()
|
117
|
+
|
118
|
+
function calcAxesSize ({ xAxisPosition, yAxisPosition, width, height }: {
|
119
|
+
xAxisPosition: AxisPosition
|
120
|
+
yAxisPosition: AxisPosition
|
121
|
+
width: number
|
122
|
+
height: number
|
123
|
+
}) {
|
124
|
+
if ((xAxisPosition === 'bottom' || xAxisPosition === 'top') && (yAxisPosition === 'left' || yAxisPosition === 'right')) {
|
125
|
+
return { width, height }
|
126
|
+
} else if ((xAxisPosition === 'left' || xAxisPosition === 'right') && (yAxisPosition === 'bottom' || yAxisPosition === 'top')) {
|
127
|
+
return {
|
128
|
+
width: height,
|
129
|
+
height: width
|
130
|
+
}
|
131
|
+
} else {
|
132
|
+
// default
|
133
|
+
return { width, height }
|
134
|
+
}
|
135
|
+
}
|
136
|
+
|
137
|
+
return new Observable(subscriber => {
|
138
|
+
combineLatest({
|
139
|
+
fullDataFormatter: fullDataFormatter$,
|
140
|
+
layout: layout$
|
141
|
+
}).pipe(
|
142
|
+
takeUntil(destroy$),
|
143
|
+
switchMap(async (d) => d),
|
144
|
+
).subscribe(data => {
|
145
|
+
|
146
|
+
const axisSize = calcAxesSize({
|
147
|
+
xAxisPosition: data.fullDataFormatter.grid.groupAxis.position,
|
148
|
+
yAxisPosition: data.fullDataFormatter.grid.valueAxis.position,
|
149
|
+
width: data.layout.width,
|
150
|
+
height: data.layout.height,
|
151
|
+
})
|
152
|
+
|
153
|
+
subscriber.next(axisSize)
|
154
|
+
|
155
|
+
return function unsubscribe () {
|
156
|
+
destroy$.next(undefined)
|
157
|
+
}
|
158
|
+
})
|
159
|
+
})
|
160
|
+
}
|
161
|
+
|
162
|
+
// export const gridHighlightObservable = ({ computedData$, fullChartParams$, event$ }: {
|
163
|
+
// computedData$: Observable<ComputedDataTypeMap<'grid'>>
|
164
|
+
// fullChartParams$: Observable<ChartParams>
|
165
|
+
// event$: Subject<any>
|
166
|
+
// }): Observable<string[]> => {
|
167
|
+
// const datumList$ = computedData$.pipe(
|
168
|
+
// map(d => d.flat())
|
169
|
+
// )
|
170
|
+
// return highlightObservable ({ datumList$, fullChartParams$, event$ })
|
171
|
+
// }
|
172
|
+
|
173
|
+
export const gridSeriesLabelsObservable = ({ computedData$ }: { computedData$: Observable<ComputedDataTypeMap<'grid'>> }) => {
|
174
|
+
return computedData$.pipe(
|
175
|
+
map(data => {
|
176
|
+
return data
|
177
|
+
.filter(series => series.length)
|
178
|
+
.map(series => {
|
179
|
+
return series[0].seriesLabel
|
180
|
+
})
|
181
|
+
}),
|
182
|
+
distinctUntilChanged((a, b) => {
|
183
|
+
return JSON.stringify(a).length === JSON.stringify(b).length
|
184
|
+
}),
|
185
|
+
)
|
186
|
+
}
|
187
|
+
|
188
|
+
export const gridVisibleComputedDataObservable = ({ computedData$ }: { computedData$: Observable<ComputedDataTypeMap<'grid'>> }) => {
|
189
|
+
return computedData$.pipe(
|
190
|
+
map(data => {
|
191
|
+
const visibleComputedData = data
|
192
|
+
.map(d => {
|
193
|
+
return d.filter(_d => {
|
194
|
+
return _d.visible == true
|
195
|
+
})
|
196
|
+
})
|
197
|
+
.filter(d => d.length)
|
198
|
+
return visibleComputedData
|
199
|
+
})
|
200
|
+
)
|
201
|
+
}
|
202
|
+
|
203
|
+
export const gridVisibleComputedLayoutDataObservable = ({ computedLayoutData$ }: { computedLayoutData$: Observable<ComputedLayoutDataGrid> }) => {
|
204
|
+
return computedLayoutData$.pipe(
|
205
|
+
map(data => {
|
206
|
+
const visibleComputedData = data
|
207
|
+
.map(d => {
|
208
|
+
return d.filter(_d => {
|
209
|
+
return _d.visible == true
|
210
|
+
})
|
211
|
+
})
|
212
|
+
.filter(d => d.length)
|
213
|
+
return visibleComputedData
|
214
|
+
})
|
215
|
+
)
|
216
|
+
}
|
217
|
+
|
218
|
+
// 所有container位置(對應series)
|
219
|
+
export const gridContainerPositionObservable = ({ computedData$, fullDataFormatter$, layout$ }: {
|
220
|
+
computedData$: Observable<ComputedDataTypeMap<'grid'>>
|
221
|
+
fullDataFormatter$: Observable<DataFormatterTypeMap<'grid'>>
|
222
|
+
layout$: Observable<Layout>
|
223
|
+
}): Observable<ContainerPositionScaled[]> => {
|
224
|
+
|
225
|
+
const gridContainerPosition$ = combineLatest({
|
226
|
+
computedData: computedData$,
|
227
|
+
fullDataFormatter: fullDataFormatter$,
|
228
|
+
layout: layout$,
|
229
|
+
}).pipe(
|
230
|
+
switchMap(async (d) => d),
|
231
|
+
map(data => {
|
232
|
+
|
233
|
+
if (data.fullDataFormatter.grid.separateSeries) {
|
234
|
+
// -- 依slotIndexes計算 --
|
235
|
+
return calcGridContainerLayout(data.layout, data.fullDataFormatter.container, data.computedData.length)
|
236
|
+
// return data.computedData.map((seriesData, seriesIndex) => {
|
237
|
+
// const columnIndex = seriesIndex % data.fullDataFormatter.container.columnAmount
|
238
|
+
// const rowIndex = Math.floor(seriesIndex / data.fullDataFormatter.container.columnAmount)
|
239
|
+
// const { translate, scale } = calcGridContainerPosition(data.layout, data.fullDataFormatter.container, rowIndex, columnIndex)
|
240
|
+
// return {
|
241
|
+
// slotIndex: seriesIndex,
|
242
|
+
// rowIndex,
|
243
|
+
// columnIndex,
|
244
|
+
// translate,
|
245
|
+
// scale,
|
246
|
+
// }
|
247
|
+
// })
|
248
|
+
} else {
|
249
|
+
// -- 無拆分 --
|
250
|
+
const gridContainerPositionArr = calcGridContainerLayout(data.layout, data.fullDataFormatter.container, 1)
|
251
|
+
return data.computedData.map((d, i) => gridContainerPositionArr[0]) // 每個series相同位置
|
252
|
+
// const columnIndex = 0
|
253
|
+
// const rowIndex = 0
|
254
|
+
// return data.computedData.map((seriesData, seriesIndex) => {
|
255
|
+
// const { translate, scale } = calcGridContainerPosition(data.layout, data.fullDataFormatter.container, rowIndex, columnIndex)
|
256
|
+
// return {
|
257
|
+
// slotIndex: 0,
|
258
|
+
// rowIndex,
|
259
|
+
// columnIndex,
|
260
|
+
// translate,
|
261
|
+
// scale,
|
262
|
+
// }
|
263
|
+
// })
|
264
|
+
}
|
265
|
+
})
|
266
|
+
)
|
267
|
+
|
268
|
+
return gridContainerPosition$
|
269
|
+
}
|
270
|
+
|
271
|
+
// 將原本的value全部替換成加總後的value
|
272
|
+
export const computedStackedDataObservables = ({ isSeriesSeprate$, computedData$ }: {
|
273
|
+
isSeriesSeprate$: Observable<boolean>
|
274
|
+
computedData$: Observable<ComputedDataGrid>
|
275
|
+
}): Observable<ComputedDataGrid> => {
|
276
|
+
const stackedData$: Observable<ComputedDataGrid> = computedData$.pipe(
|
277
|
+
map(data => {
|
278
|
+
// 將同一group的value加總起來
|
279
|
+
const stackedValue = new Array(data[0] ? data[0].length : 0)
|
280
|
+
.fill(null)
|
281
|
+
.map((_, i) => {
|
282
|
+
return data.reduce((prev, current) => {
|
283
|
+
if (current && current[i]) {
|
284
|
+
const currentValue = current[i].value == null || current[i].visible == false
|
285
|
+
? 0
|
286
|
+
: current[i].value!
|
287
|
+
return prev + currentValue
|
288
|
+
}
|
289
|
+
return prev
|
290
|
+
}, 0)
|
291
|
+
})
|
292
|
+
// 將原本的value全部替換成加總後的value
|
293
|
+
const computedData = data.map((series, seriesIndex) => {
|
294
|
+
return series.map((d, i) => {
|
295
|
+
return {
|
296
|
+
...d,
|
297
|
+
value: stackedValue[i],
|
298
|
+
}
|
299
|
+
})
|
300
|
+
})
|
301
|
+
return computedData
|
302
|
+
}),
|
303
|
+
)
|
304
|
+
|
305
|
+
return isSeriesSeprate$.pipe(
|
306
|
+
switchMap(isSeriesSeprate => {
|
307
|
+
return iif(() => isSeriesSeprate, computedData$, stackedData$)
|
308
|
+
})
|
309
|
+
)
|
310
|
+
}
|
311
|
+
|
312
|
+
export const groupScaleDomainValueObservable = ({ computedData$, fullDataFormatter$ }: {
|
313
|
+
computedData$: Observable<ComputedDataGrid>
|
314
|
+
fullDataFormatter$: Observable<DataFormatterTypeMap<'grid'>>
|
315
|
+
}): Observable<[number, number]> => {
|
316
|
+
return combineLatest({
|
317
|
+
computedData: computedData$,
|
318
|
+
fullDataFormatter: fullDataFormatter$
|
319
|
+
}).pipe(
|
320
|
+
switchMap(async (d) => d),
|
321
|
+
map(data => {
|
322
|
+
const groupAxis = data.fullDataFormatter.grid.groupAxis
|
323
|
+
const groupMin = 0
|
324
|
+
const groupMax = data.computedData[0] ? data.computedData[0].length - 1 : 0
|
325
|
+
// const groupScaleDomainMin = groupAxis.scaleDomain[0] === 'min'
|
326
|
+
// ? groupMin - groupAxis.scalePadding
|
327
|
+
// : groupAxis.scaleDomain[0] as number - groupAxis.scalePadding
|
328
|
+
const groupScaleDomainMin = groupAxis.scaleDomain[0] - groupAxis.scalePadding
|
329
|
+
const groupScaleDomainMax = groupAxis.scaleDomain[1] === 'max'
|
330
|
+
? groupMax + groupAxis.scalePadding
|
331
|
+
: groupAxis.scaleDomain[1] as number + groupAxis.scalePadding
|
332
|
+
|
333
|
+
return [groupScaleDomainMin, groupScaleDomainMax]
|
334
|
+
})
|
335
|
+
)
|
336
|
+
}
|
337
|
+
|
338
|
+
export const filteredMinMaxValueObservable = ({ computedData$, groupScaleDomainValue$ }: {
|
339
|
+
computedData$: Observable<ComputedDataGrid>
|
340
|
+
// fullDataFormatter$: Observable<DataFormatterTypeMap<'grid'>>
|
341
|
+
groupScaleDomainValue$: Observable<[number, number]>
|
342
|
+
}) => {
|
343
|
+
return combineLatest({
|
344
|
+
computedData: computedData$,
|
345
|
+
// fullDataFormatter: fullDataFormatter$,
|
346
|
+
groupScaleDomainValue: groupScaleDomainValue$
|
347
|
+
}).pipe(
|
348
|
+
map(data => {
|
349
|
+
const filteredData = data.computedData.map((d, i) => {
|
350
|
+
return d.filter((_d, _i) => {
|
351
|
+
return _i >= data.groupScaleDomainValue[0] && _i <= data.groupScaleDomainValue[1] && _d.visible == true
|
352
|
+
})
|
353
|
+
})
|
354
|
+
|
355
|
+
const filteredMinAndMax = getMinAndMaxGrid(filteredData)
|
356
|
+
// if (filteredMinAndMax[0] === filteredMinAndMax[1]) {
|
357
|
+
// filteredMinAndMax[0] = filteredMinAndMax[1] - 1 // 避免最大及最小值相同造成無法計算scale
|
358
|
+
// }
|
359
|
+
return filteredMinAndMax
|
360
|
+
}),
|
361
|
+
)
|
362
|
+
}
|
363
|
+
|
364
|
+
export const gridAxesTransformObservable = ({ fullDataFormatter$, layout$ }: {
|
365
|
+
fullDataFormatter$: Observable<DataFormatterTypeMap<'grid'>>
|
366
|
+
layout$: Observable<Layout>
|
367
|
+
}): Observable<TransformData> => {
|
368
|
+
const destroy$ = new Subject()
|
369
|
+
|
370
|
+
function calcAxesTransform ({ xAxis, yAxis, width, height }: {
|
371
|
+
xAxis: DataFormatterGroupAxis | DataFormatterValueAxis,
|
372
|
+
yAxis: DataFormatterValueAxis,
|
373
|
+
width: number,
|
374
|
+
height: number
|
375
|
+
}): TransformData {
|
376
|
+
if (!xAxis || !yAxis) {
|
377
|
+
return {
|
378
|
+
translate: [0, 0],
|
379
|
+
scale: [1, 1],
|
380
|
+
rotate: 0,
|
381
|
+
rotateX: 0,
|
382
|
+
rotateY: 0,
|
383
|
+
value: ''
|
384
|
+
}
|
385
|
+
}
|
386
|
+
// const width = size.width - fullChartParams.layout.left - fullChartParams.layout.right
|
387
|
+
// const height = size.height - fullChartParams.layout.top - fullChartParams.layout.bottom
|
388
|
+
let translateX = 0
|
389
|
+
let translateY = 0
|
390
|
+
let rotate = 0
|
391
|
+
let rotateX = 0
|
392
|
+
let rotateY = 0
|
393
|
+
if (xAxis.position === 'bottom') {
|
394
|
+
if (yAxis.position === 'left') {
|
395
|
+
rotateX = 180
|
396
|
+
translateY = height
|
397
|
+
} else if (yAxis.position === 'right') {
|
398
|
+
rotateX = 180
|
399
|
+
rotateY = 180
|
400
|
+
translateX = width
|
401
|
+
translateY = height
|
402
|
+
} else {
|
403
|
+
// 預設
|
404
|
+
rotateX = 180
|
405
|
+
translateY = height
|
406
|
+
}
|
407
|
+
} else if (xAxis.position === 'top') {
|
408
|
+
if (yAxis.position === 'left') {
|
409
|
+
} else if (yAxis.position === 'right') {
|
410
|
+
rotateY = 180
|
411
|
+
translateX = width
|
412
|
+
} else {
|
413
|
+
// 預設
|
414
|
+
rotateX = 180
|
415
|
+
translateY = height
|
416
|
+
}
|
417
|
+
} else if (xAxis.position === 'left') {
|
418
|
+
if (yAxis.position === 'bottom') {
|
419
|
+
rotate = -90
|
420
|
+
translateY = height
|
421
|
+
} else if (yAxis.position === 'top') {
|
422
|
+
rotate = -90
|
423
|
+
rotateY = 180
|
424
|
+
} else {
|
425
|
+
// 預設
|
426
|
+
rotateX = 180
|
427
|
+
translateY = height
|
428
|
+
}
|
429
|
+
} else if (xAxis.position === 'right') {
|
430
|
+
if (yAxis.position === 'bottom') {
|
431
|
+
rotate = -90
|
432
|
+
rotateX = 180
|
433
|
+
translateY = height
|
434
|
+
translateX = width
|
435
|
+
} else if (yAxis.position === 'top') {
|
436
|
+
rotate = -90
|
437
|
+
rotateX = 180
|
438
|
+
rotateY = 180
|
439
|
+
translateX = width
|
440
|
+
} else {
|
441
|
+
// 預設
|
442
|
+
rotateX = 180
|
443
|
+
translateY = height
|
444
|
+
}
|
445
|
+
} else {
|
446
|
+
// 預設
|
447
|
+
rotateX = 180
|
448
|
+
translateY = height
|
449
|
+
}
|
450
|
+
// selection.style('transform', `translate(${translateX}px, ${translateY}px) rotate(${rotate}deg) rotateX(${rotateX}deg) rotateY(${rotateY}deg)`)
|
451
|
+
|
452
|
+
return {
|
453
|
+
translate: [translateX, translateY],
|
454
|
+
scale: [1, 1],
|
455
|
+
rotate,
|
456
|
+
rotateX,
|
457
|
+
rotateY,
|
458
|
+
value: `translate(${translateX}px, ${translateY}px) rotate(${rotate}deg) rotateX(${rotateX}deg) rotateY(${rotateY}deg)`
|
459
|
+
}
|
460
|
+
}
|
461
|
+
|
462
|
+
return new Observable(subscriber => {
|
463
|
+
combineLatest({
|
464
|
+
fullDataFormatter: fullDataFormatter$,
|
465
|
+
layout: layout$
|
466
|
+
}).pipe(
|
467
|
+
takeUntil(destroy$),
|
468
|
+
switchMap(async (d) => d),
|
469
|
+
).subscribe(data => {
|
470
|
+
const axesTransformData = calcAxesTransform({
|
471
|
+
xAxis: data.fullDataFormatter.grid.groupAxis,
|
472
|
+
yAxis: data.fullDataFormatter.grid.valueAxis,
|
473
|
+
width: data.layout.width,
|
474
|
+
height: data.layout.height
|
475
|
+
})
|
476
|
+
|
477
|
+
subscriber.next(axesTransformData)
|
478
|
+
})
|
479
|
+
|
480
|
+
return function unscbscribe () {
|
481
|
+
destroy$.next(undefined)
|
482
|
+
}
|
483
|
+
})
|
484
|
+
}
|
485
|
+
|
486
|
+
|
487
|
+
export const gridAxesReverseTransformObservable = ({ gridAxesTransform$ }: {
|
488
|
+
gridAxesTransform$: Observable<TransformData>
|
489
|
+
}): Observable<TransformData> => {
|
490
|
+
return gridAxesTransform$.pipe(
|
491
|
+
map(d => {
|
492
|
+
// const translate: [number, number] = [d.translate[0] * -1, d.translate[1] * -1]
|
493
|
+
const translate: [number, number] = [0, 0] // 無需逆轉
|
494
|
+
const scale: [number, number] = [1 / d.scale[0], 1 / d.scale[1]]
|
495
|
+
const rotate = d.rotate * -1
|
496
|
+
const rotateX = d.rotateX * -1
|
497
|
+
const rotateY = d.rotateY * -1
|
498
|
+
return {
|
499
|
+
translate,
|
500
|
+
scale,
|
501
|
+
rotate,
|
502
|
+
rotateX,
|
503
|
+
rotateY,
|
504
|
+
value: `translate(${translate[0]}px, ${translate[1]}px) rotateX(${rotateX}deg) rotateY(${rotateY}deg) rotate(${rotate}deg)`
|
505
|
+
}
|
506
|
+
}),
|
507
|
+
)
|
508
|
+
}
|
509
|
+
|
510
|
+
export const gridGraphicTransformObservable = ({ computedData$, groupScaleDomainValue$, filteredMinMaxValue$, fullDataFormatter$, layout$ }: {
|
511
|
+
computedData$: Observable<ComputedDataTypeMap<'grid'>>
|
512
|
+
groupScaleDomainValue$: Observable<[number, number]>
|
513
|
+
filteredMinMaxValue$: Observable<[number, number]>
|
514
|
+
fullDataFormatter$: Observable<DataFormatterTypeMap<'grid'>>
|
515
|
+
layout$: Observable<Layout>
|
516
|
+
}): Observable<TransformData> => {
|
517
|
+
const destroy$ = new Subject()
|
518
|
+
|
519
|
+
function calcGridDataAreaTransform ({ data, groupAxis, valueAxis, groupScaleDomainValue, filteredMinMaxValue, width, height }: {
|
520
|
+
data: ComputedDataTypeMap<'grid'>
|
521
|
+
groupAxis: DataFormatterGroupAxis
|
522
|
+
valueAxis: DataFormatterValueAxis
|
523
|
+
groupScaleDomainValue: [number, number],
|
524
|
+
filteredMinMaxValue: [number, number],
|
525
|
+
width: number
|
526
|
+
height: number
|
527
|
+
}): TransformData {
|
528
|
+
let translateX = 0
|
529
|
+
let translateY = 0
|
530
|
+
let scaleX = 0
|
531
|
+
let scaleY = 0
|
532
|
+
|
533
|
+
// -- groupScale --
|
534
|
+
const groupAxisWidth = (groupAxis.position === 'top' || groupAxis.position === 'bottom')
|
535
|
+
? width
|
536
|
+
: height
|
537
|
+
const groupMin = 0
|
538
|
+
const groupMax = data[0] ? data[0].length - 1 : 0
|
539
|
+
// const groupScaleDomainMin = groupAxis.scaleDomain[0] - groupAxis.scalePadding
|
540
|
+
// const groupScaleDomainMax = groupAxis.scaleDomain[1] === 'max'
|
541
|
+
// ? groupMax + groupAxis.scalePadding
|
542
|
+
// : groupAxis.scaleDomain[1] as number + groupAxis.scalePadding
|
543
|
+
|
544
|
+
const groupScale: d3.ScaleLinear<number, number> = createValueToAxisScale({
|
545
|
+
maxValue: groupMax,
|
546
|
+
minValue: groupMin,
|
547
|
+
axisWidth: groupAxisWidth,
|
548
|
+
// scaleDomain: groupAxis.scaleDomain,
|
549
|
+
scaleDomain: groupScaleDomainValue,
|
550
|
+
scaleRange: [0, 1]
|
551
|
+
})
|
552
|
+
|
553
|
+
// -- translateX, scaleX --
|
554
|
+
const rangeMinX = groupScale(groupMin)
|
555
|
+
const rangeMaxX = groupScale(groupMax)
|
556
|
+
if (groupMin == groupMax) {
|
557
|
+
// 當group只有一個
|
558
|
+
translateX = 0
|
559
|
+
scaleX = 1
|
560
|
+
} else {
|
561
|
+
translateX = rangeMinX
|
562
|
+
const gWidth = rangeMaxX - rangeMinX
|
563
|
+
scaleX = gWidth / groupAxisWidth
|
564
|
+
}
|
565
|
+
|
566
|
+
// -- valueScale --
|
567
|
+
// const filteredData = data.map((d, i) => {
|
568
|
+
// return d.filter((_d, _i) => {
|
569
|
+
// return _i >= groupScaleDomainMin && _i <= groupScaleDomainMax && _d.visible == true
|
570
|
+
// })
|
571
|
+
// })
|
572
|
+
|
573
|
+
// const filteredMinAndMax = getMinAndMaxGrid(filteredData)
|
574
|
+
// if (filteredMinAndMax[0] === filteredMinAndMax[1]) {
|
575
|
+
// filteredMinAndMax[0] = filteredMinAndMax[1] - 1 // 避免最大及最小值相同造成無法計算scale
|
576
|
+
// }
|
577
|
+
|
578
|
+
const valueAxisWidth = (valueAxis.position === 'left' || valueAxis.position === 'right')
|
579
|
+
? height
|
580
|
+
: width
|
581
|
+
|
582
|
+
const valueScale: d3.ScaleLinear<number, number> = createValueToAxisScale({
|
583
|
+
maxValue: filteredMinMaxValue[1],
|
584
|
+
minValue: filteredMinMaxValue[0],
|
585
|
+
axisWidth: valueAxisWidth,
|
586
|
+
scaleDomain: valueAxis.scaleDomain,
|
587
|
+
scaleRange: valueAxis.scaleRange
|
588
|
+
})
|
589
|
+
|
590
|
+
// -- translateY, scaleY --
|
591
|
+
const minAndMax = getMinAndMaxGrid(data)
|
592
|
+
if (minAndMax[0] === minAndMax[1]) {
|
593
|
+
minAndMax[0] = minAndMax[1] - 1 // 避免最大及最小值相同造成無法計算scale
|
594
|
+
}
|
595
|
+
// const rangeMinY = valueScale(minAndMax[0])
|
596
|
+
const rangeMinY = valueScale(minAndMax[0] > 0 ? 0 : minAndMax[0]) // * 因為原本的座標就是以 0 到最大值或最小值範範圍計算的,所以這邊也是用同樣的方式計算
|
597
|
+
const rangeMaxY = valueScale(minAndMax[1] < 0 ? 0 : minAndMax[1]) // * 因為原本的座標就是以 0 到最大值或最小值範範圍計算的,所以這邊也是用同樣的方式計算
|
598
|
+
translateY = rangeMinY
|
599
|
+
const gHeight = rangeMaxY - rangeMinY
|
600
|
+
scaleY = gHeight / valueAxisWidth
|
601
|
+
|
602
|
+
return {
|
603
|
+
translate: [translateX, translateY],
|
604
|
+
scale: [scaleX, scaleY],
|
605
|
+
rotate: 0,
|
606
|
+
rotateX: 0,
|
607
|
+
rotateY: 0,
|
608
|
+
value: `translate(${translateX}px, ${translateY}px) scale(${scaleX}, ${scaleY})`
|
609
|
+
}
|
610
|
+
}
|
611
|
+
|
612
|
+
return new Observable(subscriber => {
|
613
|
+
combineLatest({
|
614
|
+
computedData: computedData$,
|
615
|
+
groupScaleDomainValue: groupScaleDomainValue$,
|
616
|
+
filteredMinMaxValue: filteredMinMaxValue$,
|
617
|
+
fullDataFormatter: fullDataFormatter$,
|
618
|
+
layout: layout$
|
619
|
+
}).pipe(
|
620
|
+
takeUntil(destroy$),
|
621
|
+
switchMap(async (d) => d),
|
622
|
+
).subscribe(data => {
|
623
|
+
const dataAreaTransformData = calcGridDataAreaTransform ({
|
624
|
+
data: data.computedData,
|
625
|
+
groupAxis: data.fullDataFormatter.grid.groupAxis,
|
626
|
+
valueAxis: data.fullDataFormatter.grid.valueAxis,
|
627
|
+
groupScaleDomainValue: data.groupScaleDomainValue,
|
628
|
+
filteredMinMaxValue: data.filteredMinMaxValue,
|
629
|
+
width: data.layout.width,
|
630
|
+
height: data.layout.height
|
631
|
+
})
|
632
|
+
|
633
|
+
subscriber.next(dataAreaTransformData)
|
634
|
+
})
|
635
|
+
|
636
|
+
return function unscbscribe () {
|
637
|
+
destroy$.next(undefined)
|
638
|
+
}
|
639
|
+
})
|
640
|
+
}
|
641
|
+
|
642
|
+
export const gridGraphicReverseScaleObservable = ({ gridContainerPosition$, gridAxesTransform$, gridGraphicTransform$ }: {
|
643
|
+
gridContainerPosition$: Observable<ContainerPositionScaled[]>
|
644
|
+
gridAxesTransform$: Observable<TransformData>
|
645
|
+
gridGraphicTransform$: Observable<TransformData>
|
646
|
+
}): Observable<[number, number][]> => {
|
647
|
+
return combineLatest({
|
648
|
+
gridContainerPosition: gridContainerPosition$,
|
649
|
+
gridAxesTransform: gridAxesTransform$,
|
650
|
+
gridGraphicTransform: gridGraphicTransform$,
|
651
|
+
}).pipe(
|
652
|
+
switchMap(async (d) => d),
|
653
|
+
map(data => {
|
654
|
+
if (data.gridAxesTransform.rotate == 0 || data.gridAxesTransform.rotate == 180) {
|
655
|
+
return data.gridContainerPosition.map((series, seriesIndex) => {
|
656
|
+
return [
|
657
|
+
1 / data.gridGraphicTransform.scale[0] / data.gridContainerPosition[seriesIndex].scale[0],
|
658
|
+
1 / data.gridGraphicTransform.scale[1] / data.gridContainerPosition[seriesIndex].scale[1],
|
659
|
+
]
|
660
|
+
})
|
661
|
+
} else {
|
662
|
+
return data.gridContainerPosition.map((series, seriesIndex) => {
|
663
|
+
// 由於有垂直的旋轉,所以外層 (container) x和y的scale要互換
|
664
|
+
return [
|
665
|
+
1 / data.gridGraphicTransform.scale[0] / data.gridContainerPosition[seriesIndex].scale[1],
|
666
|
+
1 / data.gridGraphicTransform.scale[1] / data.gridContainerPosition[seriesIndex].scale[0],
|
667
|
+
]
|
668
|
+
})
|
669
|
+
}
|
670
|
+
}),
|
671
|
+
)
|
615
672
|
}
|