@orbcharts/core 3.0.0-beta.1 → 3.0.0-beta.10

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