@orbcharts/plugins-basic 3.0.0-alpha.61 → 3.0.0-alpha.63

Sign up to get free protection for your applications and to get access to all the features.
Files changed (78) hide show
  1. package/LICENSE +200 -200
  2. package/dist/orbcharts-plugins-basic.es.js +6113 -6065
  3. package/dist/orbcharts-plugins-basic.umd.js +10 -10
  4. package/package.json +42 -42
  5. package/src/base/BaseBarStack.ts +778 -778
  6. package/src/base/BaseBars.ts +764 -764
  7. package/src/base/BaseBarsTriangle.ts +672 -672
  8. package/src/base/BaseDots.ts +513 -513
  9. package/src/base/BaseGroupAxis.ts +637 -558
  10. package/src/base/BaseLegend.ts +641 -641
  11. package/src/base/BaseLineAreas.ts +628 -628
  12. package/src/base/BaseLines.ts +704 -704
  13. package/src/base/BaseValueAxis.ts +577 -478
  14. package/src/base/types.ts +2 -2
  15. package/src/grid/defaults.ts +128 -128
  16. package/src/grid/gridObservables.ts +541 -541
  17. package/src/grid/index.ts +15 -15
  18. package/src/grid/plugins/BarStack.ts +43 -43
  19. package/src/grid/plugins/Bars.ts +44 -44
  20. package/src/grid/plugins/BarsPN.ts +41 -41
  21. package/src/grid/plugins/BarsTriangle.ts +42 -42
  22. package/src/grid/plugins/Dots.ts +37 -37
  23. package/src/grid/plugins/GridLegend.ts +59 -59
  24. package/src/grid/plugins/GroupAux.ts +979 -976
  25. package/src/grid/plugins/GroupAxis.ts +35 -35
  26. package/src/grid/plugins/LineAreas.ts +40 -40
  27. package/src/grid/plugins/Lines.ts +40 -40
  28. package/src/grid/plugins/ScalingArea.ts +173 -173
  29. package/src/grid/plugins/ValueAxis.ts +36 -36
  30. package/src/grid/plugins/ValueStackAxis.ts +38 -38
  31. package/src/grid/types.ts +123 -123
  32. package/src/index.ts +9 -9
  33. package/src/multiGrid/defaults.ts +158 -158
  34. package/src/multiGrid/index.ts +13 -13
  35. package/src/multiGrid/multiGridObservables.ts +49 -49
  36. package/src/multiGrid/plugins/MultiBarStack.ts +78 -78
  37. package/src/multiGrid/plugins/MultiBars.ts +77 -77
  38. package/src/multiGrid/plugins/MultiBarsTriangle.ts +77 -77
  39. package/src/multiGrid/plugins/MultiDots.ts +65 -65
  40. package/src/multiGrid/plugins/MultiGridLegend.ts +89 -89
  41. package/src/multiGrid/plugins/MultiGroupAxis.ts +69 -69
  42. package/src/multiGrid/plugins/MultiLineAreas.ts +77 -77
  43. package/src/multiGrid/plugins/MultiLines.ts +77 -77
  44. package/src/multiGrid/plugins/MultiValueAxis.ts +69 -69
  45. package/src/multiGrid/plugins/MultiValueStackAxis.ts +69 -69
  46. package/src/multiGrid/plugins/OverlappingValueAxes.ts +167 -167
  47. package/src/multiGrid/plugins/OverlappingValueStackAxes.ts +168 -168
  48. package/src/multiGrid/types.ts +72 -72
  49. package/src/noneData/defaults.ts +102 -102
  50. package/src/noneData/index.ts +3 -3
  51. package/src/noneData/plugins/Container.ts +10 -10
  52. package/src/noneData/plugins/Tooltip.ts +310 -310
  53. package/src/noneData/types.ts +26 -26
  54. package/src/series/defaults.ts +144 -144
  55. package/src/series/index.ts +9 -9
  56. package/src/series/plugins/Bubbles.ts +545 -545
  57. package/src/series/plugins/Pie.ts +576 -576
  58. package/src/series/plugins/PieEventTexts.ts +262 -262
  59. package/src/series/plugins/PieLabels.ts +304 -304
  60. package/src/series/plugins/Rose.ts +472 -472
  61. package/src/series/plugins/RoseLabels.ts +362 -362
  62. package/src/series/plugins/SeriesLegend.ts +59 -59
  63. package/src/series/seriesObservables.ts +145 -145
  64. package/src/series/seriesUtils.ts +51 -51
  65. package/src/series/types.ts +83 -83
  66. package/src/tree/defaults.ts +23 -23
  67. package/src/tree/index.ts +3 -3
  68. package/src/tree/plugins/TreeLegend.ts +59 -59
  69. package/src/tree/plugins/TreeMap.ts +305 -305
  70. package/src/tree/types.ts +23 -23
  71. package/src/utils/commonUtils.ts +21 -21
  72. package/src/utils/d3Graphics.ts +124 -124
  73. package/src/utils/d3Utils.ts +73 -73
  74. package/src/utils/observables.ts +14 -14
  75. package/src/utils/orbchartsUtils.ts +100 -100
  76. package/tsconfig.base.json +13 -13
  77. package/tsconfig.json +2 -2
  78. package/vite.config.js +22 -22
@@ -1,478 +1,577 @@
1
- import * as d3 from 'd3'
2
- import {
3
- combineLatest,
4
- switchMap,
5
- distinctUntilChanged,
6
- first,
7
- map,
8
- takeUntil,
9
- Observable,
10
- Subject } from 'rxjs'
11
- import { createAxisLinearScale } from '@orbcharts/core'
12
- import type { BasePluginFn } from './types'
13
- import type {
14
- ComputedDataGrid,
15
- DataFormatterGrid,
16
- ChartParams,
17
- ComputedDatumGrid,
18
- GridContainerPosition,
19
- TransformData,
20
- EventGrid,
21
- ColorType } from '@orbcharts/core'
22
- import { parseTickFormatValue } from '../utils/d3Utils'
23
- import { getColor, getMinAndMaxValue, getClassName, getUniID } from '../utils/orbchartsUtils'
24
-
25
- export interface BaseValueAxisParams {
26
- labelOffset: [number, number]
27
- labelColorType: ColorType
28
- axisLineVisible: boolean
29
- axisLineColorType: ColorType
30
- ticks: number
31
- tickFormat: string | ((text: d3.NumberValue) => string)
32
- tickLineVisible: boolean
33
- tickPadding: number
34
- tickFullLine: boolean
35
- tickFullLineDasharray: string
36
- tickColorType: ColorType
37
- tickTextRotate: number
38
- tickTextColorType: ColorType
39
- }
40
-
41
- interface BaseLinesContext {
42
- selection: d3.Selection<any, unknown, any, unknown>
43
- computedData$: Observable<ComputedDataGrid>
44
- fullParams$: Observable<BaseValueAxisParams>
45
- fullDataFormatter$: Observable<DataFormatterGrid>
46
- fullChartParams$: Observable<ChartParams>
47
- gridAxesTransform$: Observable<TransformData>
48
- gridAxesReverseTransform$: Observable<TransformData>
49
- gridAxesSize$: Observable<{
50
- width: number;
51
- height: number;
52
- }>
53
- gridContainerPosition$: Observable<GridContainerPosition[]>
54
- isSeriesSeprate$: Observable<boolean>
55
- }
56
-
57
- interface TextAlign {
58
- textAnchor: "start" | "middle" | "end"
59
- dominantBaseline: "middle" | "auto" | "hanging"
60
- }
61
-
62
- // const pluginName = 'ValueAxis'
63
- // const containerClassName = getClassName(pluginName, 'container')
64
- // const yAxisGClassName = getClassName(pluginName, 'yAxisG')
65
- // const yAxisClassName = getClassName(pluginName, 'yAxis')
66
- // const textClassName = getClassName(pluginName, 'text')
67
- const defaultTickSize = 6
68
-
69
- function renderAxis ({ selection, yAxisClassName, textClassName, fullParams, tickTextAlign, axisLabelAlign, gridAxesSize, fullDataFormatter, fullChartParams, valueScale, textTransform, minAndMax }: {
70
- selection: d3.Selection<SVGGElement, any, any, any>,
71
- yAxisClassName: string
72
- textClassName: string
73
- fullParams: BaseValueAxisParams
74
- tickTextAlign: TextAlign
75
- axisLabelAlign: TextAlign
76
- gridAxesSize: { width: number, height: number }
77
- fullDataFormatter: DataFormatterGrid,
78
- fullChartParams: ChartParams
79
- valueScale: d3.ScaleLinear<number, number>
80
- textTransform: string,
81
- minAndMax: [number, number]
82
- }) {
83
-
84
- const yAxisSelection = selection
85
- .selectAll<SVGGElement, BaseValueAxisParams>(`g.${yAxisClassName}`)
86
- .data([fullParams])
87
- .join('g')
88
- .classed(yAxisClassName, true)
89
-
90
- const axisLabelSelection = selection
91
- .selectAll<SVGGElement, BaseValueAxisParams>(`g.${textClassName}`)
92
- .data([fullParams])
93
- .join('g')
94
- .classed(textClassName, true)
95
- .each((d, i, g) => {
96
- const text = d3.select(g[i])
97
- .selectAll<SVGTextElement, BaseValueAxisParams>(`text`)
98
- .data([d])
99
- .join(
100
- enter => {
101
- return enter
102
- .append('text')
103
- .style('font-weight', 'bold')
104
- },
105
- update => update,
106
- exit => exit.remove()
107
- )
108
- .attr('text-anchor', axisLabelAlign.textAnchor)
109
- .attr('dominant-baseline', axisLabelAlign.dominantBaseline)
110
- .attr('font-size', fullChartParams.styles.textSize)
111
- .style('fill', getColor(fullParams.labelColorType, fullChartParams))
112
- // .style('transform', textTransform)
113
- .text(d => fullDataFormatter.grid.valueAxis.label)
114
- })
115
- .attr('transform', d => `translate(${- d.tickPadding + fullParams.labelOffset[0]}, ${gridAxesSize.height + d.tickPadding + fullParams.labelOffset[1]})`)
116
-
117
- const valueLength = minAndMax[1] - minAndMax[0]
118
-
119
- // const _valueScale = d3.scaleLinear()
120
- // .domain([0, 150])
121
- // .range([416.5, 791.349])
122
-
123
- // 設定Y軸刻度
124
- const yAxis = d3.axisLeft(valueScale)
125
- .scale(valueScale)
126
- .ticks(valueLength > fullParams.ticks
127
- ? fullParams.ticks
128
- : ((minAndMax[0] === 0 && minAndMax[1] === 0)
129
- ? 1
130
- : Math.ceil(valueLength))) // 刻度分段數量
131
- .tickFormat(d => parseTickFormatValue(d, fullParams.tickFormat))
132
- .tickSize(fullParams.tickFullLine == true
133
- ? -gridAxesSize.width
134
- : defaultTickSize)
135
- .tickPadding(fullParams.tickPadding)
136
-
137
- const yAxisEl = yAxisSelection
138
- .transition()
139
- .duration(100)
140
- .call(yAxis)
141
-
142
- yAxisEl.selectAll('line')
143
- .style('fill', 'none')
144
- .style('stroke', fullParams.tickLineVisible == true ? getColor(fullParams.tickColorType, fullChartParams) : 'none')
145
- .style('stroke-dasharray', fullParams.tickFullLineDasharray)
146
- .attr('pointer-events', 'none')
147
-
148
- yAxisEl.selectAll('path')
149
- .style('fill', 'none')
150
- // .style('stroke', this.fullParams.axisLineColor!)
151
- .style('stroke', fullParams.axisLineVisible == true ? getColor(fullParams.axisLineColorType, fullChartParams) : 'none')
152
- .style('shape-rendering', 'crispEdges')
153
-
154
- // const yText = yAxisEl.selectAll('text')
155
- const yText = yAxisSelection.selectAll('text')
156
- // .style('font-family', 'sans-serif')
157
- .attr('font-size', fullChartParams.styles.textSize)
158
- .style('color', getColor(fullParams.tickTextColorType, fullChartParams))
159
- .attr('text-anchor', tickTextAlign.textAnchor)
160
- .attr('dominant-baseline', tickTextAlign.dominantBaseline)
161
- .attr('transform-origin', `-${fullParams.tickPadding + defaultTickSize} 0`)
162
- yText.style('transform', textTransform)
163
-
164
- return yAxisSelection
165
- }
166
-
167
-
168
-
169
- export const createBaseValueAxis: BasePluginFn<BaseLinesContext> = (pluginName: string, {
170
- selection,
171
- computedData$,
172
- fullParams$,
173
- fullDataFormatter$,
174
- fullChartParams$,
175
- gridAxesTransform$,
176
- gridAxesReverseTransform$,
177
- gridAxesSize$,
178
- gridContainerPosition$,
179
- isSeriesSeprate$,
180
- }) => {
181
-
182
- const destroy$ = new Subject()
183
-
184
- const containerClassName = getClassName(pluginName, 'container')
185
- const yAxisGClassName = getClassName(pluginName, 'yAxisG')
186
- const yAxisClassName = getClassName(pluginName, 'yAxis')
187
- const textClassName = getClassName(pluginName, 'text')
188
-
189
- const containerSelection$ = combineLatest({
190
- computedData: computedData$.pipe(
191
- distinctUntilChanged((a, b) => {
192
- // 只有當series的數量改變時,才重新計算
193
- return a.length === b.length
194
- }),
195
- ),
196
- isSeriesSeprate: isSeriesSeprate$
197
- }).pipe(
198
- takeUntil(destroy$),
199
- switchMap(async (d) => d),
200
- map(data => {
201
- return data.isSeriesSeprate
202
- // series分開的時候顯示各別axis
203
- ? data.computedData
204
- // series合併的時候只顯示第一個axis
205
- : [data.computedData[0]]
206
- }),
207
- map((computedData, i) => {
208
- return selection
209
- .selectAll<SVGGElement, ComputedDatumGrid[]>(`g.${containerClassName}`)
210
- .data(computedData, d => d[0] ? d[0].seriesIndex : i)
211
- .join('g')
212
- .classed(containerClassName, true)
213
- })
214
- )
215
-
216
- const axisSelection$ = containerSelection$.pipe(
217
- takeUntil(destroy$),
218
- map((containerSelection, i) => {
219
- return containerSelection
220
- .selectAll<SVGGElement, ComputedDatumGrid[]>(`g.${yAxisGClassName}`)
221
- .data([yAxisGClassName])
222
- .join('g')
223
- .classed(yAxisGClassName, true)
224
- })
225
- )
226
-
227
- combineLatest({
228
- containerSelection: containerSelection$,
229
- gridContainerPosition: gridContainerPosition$
230
- }).pipe(
231
- takeUntil(destroy$),
232
- switchMap(async d => d)
233
- ).subscribe(data => {
234
- data.containerSelection
235
- .attr('transform', (d, i) => {
236
- const gridContainerPosition = data.gridContainerPosition[i] ?? data.gridContainerPosition[0]
237
- const translate = gridContainerPosition.translate
238
- const scale = gridContainerPosition.scale
239
- return `translate(${translate[0]}, ${translate[1]}) scale(${scale[0]}, ${scale[1]})`
240
- })
241
- // .attr('opacity', 0)
242
- // .transition()
243
- // .attr('opacity', 1)
244
- })
245
-
246
- combineLatest({
247
- axisSelection: axisSelection$,
248
- gridAxesTransform: gridAxesTransform$,
249
- }).pipe(
250
- takeUntil(destroy$),
251
- switchMap(async d => d)
252
- ).subscribe(data => {
253
- data.axisSelection
254
- .style('transform', data.gridAxesTransform.value)
255
- // .attr('opacity', 0)
256
- // .transition()
257
- // .attr('opacity', 1)
258
-
259
- })
260
-
261
- // const gridAxesSize$ = gridAxisSizeObservable({
262
- // fullDataFormatter$,
263
- // layout$
264
- // })
265
-
266
- // const textTransform$: Observable<string> = new Observable(subscriber => {
267
- // combineLatest({
268
- // fullParams: fullParams$,
269
- // layout: layout$
270
- // }).pipe(
271
- // takeUntil(destroy$),
272
- // // 轉換後會退訂前一個未完成的訂閱事件,因此可以取到「同時間」最後一次的訂閱事件
273
- // switchMap(async (d) => d),
274
- // ).subscribe(data => {
275
-
276
- // const transformData = Object.assign({}, data.layout.content.axesTransformData)
277
-
278
- // const value = getAxesTransformValue({
279
- // translate: [0, 0],
280
- // scale: [transformData.scale[0] * -1, transformData.scale[1] * -1],
281
- // rotate: transformData.rotate * -1 + data.fullParams.tickTextRotate,
282
- // rotateX: transformData.rotateX * -1,
283
- // rotateY: transformData.rotateY * -1
284
- // })
285
-
286
- // subscriber.next(value)
287
- // })
288
- // })
289
- // const reverseTransform$: Observable<TransformData> = gridAxesTransform$.pipe(
290
- // takeUntil(destroy$),
291
- // map(d => {
292
- // const translate: [number, number] = [d.translate[0] * -1, d.translate[1] * -1]
293
- // const scale: [number, number] = [d.scale[0] * -1, d.scale[1] * -1]
294
- // const rotate = d.rotate * -1
295
- // const rotateX = d.rotateX * -1
296
- // const rotateY = d.rotateY * -1
297
- // return {
298
- // translate,
299
- // scale,
300
- // rotate,
301
- // rotateX,
302
- // rotateY,
303
- // value: ''
304
- // }
305
- // }),
306
- // )
307
- const textTransform$ = combineLatest({
308
- fullParams: fullParams$,
309
- fullDataFormatter: fullDataFormatter$,
310
- gridAxesReverseTransform: gridAxesReverseTransform$,
311
- gridContainerPosition: gridContainerPosition$
312
- }).pipe(
313
- takeUntil(destroy$),
314
- switchMap(async (d) => d),
315
- map(data => {
316
- const axisReverseTranslateValue = `translate(${data.gridAxesReverseTransform.translate[0]}px, ${data.gridAxesReverseTransform.translate[1]}px)`
317
- const axisReverseRotateValue = `rotate(${data.gridAxesReverseTransform.rotate}deg) rotateX(${data.gridAxesReverseTransform.rotateX}deg) rotateY(${data.gridAxesReverseTransform.rotateY}deg)`
318
- const containerScaleReverseScaleValue = `scale(${1 / data.gridContainerPosition[0].scale[0]}, ${1 / data.gridContainerPosition[0].scale[1]})`
319
- const tickTextRotateDeg = (data.fullDataFormatter.grid.groupAxis.position === 'left' && data.fullDataFormatter.grid.valueAxis.position === 'top')
320
- || (data.fullDataFormatter.grid.groupAxis.position === 'right' && data.fullDataFormatter.grid.valueAxis.position === 'bottom')
321
- ? data.fullParams.tickTextRotate + 180 // 修正文字倒轉
322
- : data.fullParams.tickTextRotate
323
-
324
- const textRotateValue = `rotate(${tickTextRotateDeg}deg)`
325
-
326
- // 必須按照順序(先抵消外層rotate,再抵消最外層scale,最後再做本身的rotate)
327
- return `${axisReverseTranslateValue} ${axisReverseRotateValue} ${containerScaleReverseScaleValue} ${textRotateValue}`
328
- }),
329
- distinctUntilChanged()
330
- )
331
-
332
- const minAndMax$: Observable<[number, number]> = new Observable(subscriber => {
333
- combineLatest({
334
- fullDataFormatter: fullDataFormatter$,
335
- gridAxesSize: gridAxesSize$,
336
- computedData: computedData$
337
- }).pipe(
338
- takeUntil(destroy$),
339
- switchMap(async (d) => d),
340
- ).subscribe(data => {
341
- const groupMin = 0
342
- const groupMax = data.computedData[0] ? data.computedData[0].length - 1 : 0
343
- const groupScaleDomainMin = data.fullDataFormatter.grid.groupAxis.scaleDomain[0] === 'auto'
344
- ? groupMin - data.fullDataFormatter.grid.groupAxis.scalePadding
345
- : data.fullDataFormatter.grid.groupAxis.scaleDomain[0] as number - data.fullDataFormatter.grid.groupAxis.scalePadding
346
- const groupScaleDomainMax = data.fullDataFormatter.grid.groupAxis.scaleDomain[1] === 'auto'
347
- ? groupMax + data.fullDataFormatter.grid.groupAxis.scalePadding
348
- : data.fullDataFormatter.grid.groupAxis.scaleDomain[1] as number + data.fullDataFormatter.grid.groupAxis.scalePadding
349
-
350
- const filteredData = data.computedData.map((d, i) => {
351
- return d.filter((_d, _i) => {
352
- return _i >= groupScaleDomainMin && _i <= groupScaleDomainMax
353
- })
354
- })
355
-
356
- const filteredMinAndMax = getMinAndMaxValue(filteredData.flat())
357
-
358
- subscriber.next(filteredMinAndMax)
359
- })
360
- })
361
-
362
- const valueScale$: Observable<d3.ScaleLinear<number, number>> = new Observable(subscriber => {
363
- combineLatest({
364
- fullDataFormatter: fullDataFormatter$,
365
- gridAxesSize: gridAxesSize$,
366
- minAndMax: minAndMax$
367
- }).pipe(
368
- takeUntil(destroy$),
369
- switchMap(async (d) => d),
370
- ).subscribe(data => {
371
-
372
- const valueScale: d3.ScaleLinear<number, number> = createAxisLinearScale({
373
- maxValue: data.minAndMax[1],
374
- minValue: data.minAndMax[0],
375
- axisWidth: data.gridAxesSize.height,
376
- scaleDomain: data.fullDataFormatter.grid.valueAxis.scaleDomain,
377
- scaleRange: data.fullDataFormatter.grid.valueAxis.scaleRange
378
- })
379
-
380
- subscriber.next(valueScale)
381
- })
382
- })
383
-
384
- const tickTextAlign$: Observable<TextAlign> = fullDataFormatter$.pipe(
385
- takeUntil(destroy$),
386
- map(d => {
387
- let textAnchor: 'start' | 'middle' | 'end' = 'start'
388
- let dominantBaseline: 'auto' | 'middle' | 'hanging' = 'hanging'
389
-
390
- if (d.grid.valueAxis.position === 'left') {
391
- textAnchor = 'end'
392
- dominantBaseline = 'middle'
393
- } else if (d.grid.valueAxis.position === 'right') {
394
- textAnchor = 'start'
395
- dominantBaseline = 'middle'
396
- } else if (d.grid.valueAxis.position === 'bottom') {
397
- textAnchor = 'middle'
398
- dominantBaseline = 'hanging'
399
- } else if (d.grid.valueAxis.position === 'top') {
400
- textAnchor = 'middle'
401
- dominantBaseline = 'auto'
402
- }
403
- return {
404
- textAnchor,
405
- dominantBaseline
406
- }
407
- })
408
- )
409
-
410
- const axisLabelAlign$: Observable<TextAlign> = fullDataFormatter$.pipe(
411
- takeUntil(destroy$),
412
- map(d => {
413
- let textAnchor: 'start' | 'middle' | 'end' = 'start'
414
- let dominantBaseline: 'auto' | 'middle' | 'hanging' = 'hanging'
415
-
416
- if (d.grid.groupAxis.position === 'bottom') {
417
- dominantBaseline = 'auto'
418
- } else if (d.grid.groupAxis.position === 'top') {
419
- dominantBaseline = 'hanging'
420
- } else if (d.grid.groupAxis.position === 'left') {
421
- textAnchor = 'start'
422
- } else if (d.grid.groupAxis.position === 'right') {
423
- textAnchor = 'end'
424
- }
425
- if (d.grid.valueAxis.position === 'left') {
426
- textAnchor = 'end'
427
- } else if (d.grid.valueAxis.position === 'right') {
428
- textAnchor = 'start'
429
- } else if (d.grid.valueAxis.position === 'bottom') {
430
- dominantBaseline = 'hanging'
431
- } else if (d.grid.valueAxis.position === 'top') {
432
- dominantBaseline = 'auto'
433
- }
434
- return {
435
- textAnchor,
436
- dominantBaseline
437
- }
438
- })
439
- )
440
-
441
-
442
- combineLatest({
443
- axisSelection: axisSelection$,
444
- fullParams: fullParams$,
445
- tickTextAlign: tickTextAlign$,
446
- axisLabelAlign: axisLabelAlign$,
447
- computedData: computedData$,
448
- gridAxesSize: gridAxesSize$,
449
- fullDataFormatter: fullDataFormatter$,
450
- fullChartParams: fullChartParams$,
451
- valueScale: valueScale$,
452
- textTransform: textTransform$,
453
- minAndMax: minAndMax$
454
- }).pipe(
455
- takeUntil(destroy$),
456
- switchMap(async (d) => d),
457
- ).subscribe(data => {
458
-
459
- renderAxis({
460
- selection: data.axisSelection,
461
- yAxisClassName,
462
- textClassName,
463
- fullParams: data.fullParams,
464
- tickTextAlign: data.tickTextAlign,
465
- axisLabelAlign: data.axisLabelAlign,
466
- gridAxesSize: data.gridAxesSize,
467
- fullDataFormatter: data.fullDataFormatter,
468
- fullChartParams: data.fullChartParams,
469
- valueScale: data.valueScale,
470
- textTransform: data.textTransform,
471
- minAndMax: data.minAndMax
472
- })
473
- })
474
-
475
- return () => {
476
- destroy$.next(undefined)
477
- }
478
- }
1
+ import * as d3 from 'd3'
2
+ import {
3
+ combineLatest,
4
+ switchMap,
5
+ distinctUntilChanged,
6
+ first,
7
+ map,
8
+ takeUntil,
9
+ Observable,
10
+ Subject } from 'rxjs'
11
+ import { createAxisLinearScale } from '@orbcharts/core'
12
+ import type { BasePluginFn } from './types'
13
+ import type {
14
+ ComputedDataGrid,
15
+ DataFormatterGrid,
16
+ ChartParams,
17
+ ComputedDatumGrid,
18
+ GridContainerPosition,
19
+ TransformData,
20
+ EventGrid,
21
+ ColorType } from '@orbcharts/core'
22
+ import { parseTickFormatValue } from '../utils/d3Utils'
23
+ import { getColor, getMinAndMaxValue, getClassName, getUniID } from '../utils/orbchartsUtils'
24
+
25
+ export interface BaseValueAxisParams {
26
+ labelOffset: [number, number]
27
+ labelColorType: ColorType
28
+ axisLineVisible: boolean
29
+ axisLineColorType: ColorType
30
+ ticks: number
31
+ tickFormat: string | ((text: d3.NumberValue) => string)
32
+ tickLineVisible: boolean
33
+ tickPadding: number
34
+ tickFullLine: boolean
35
+ tickFullLineDasharray: string
36
+ tickColorType: ColorType
37
+ tickTextRotate: number
38
+ tickTextColorType: ColorType
39
+ }
40
+
41
+ interface BaseLinesContext {
42
+ selection: d3.Selection<any, unknown, any, unknown>
43
+ computedData$: Observable<ComputedDataGrid>
44
+ fullParams$: Observable<BaseValueAxisParams>
45
+ fullDataFormatter$: Observable<DataFormatterGrid>
46
+ fullChartParams$: Observable<ChartParams>
47
+ gridAxesTransform$: Observable<TransformData>
48
+ gridAxesReverseTransform$: Observable<TransformData>
49
+ gridAxesSize$: Observable<{
50
+ width: number;
51
+ height: number;
52
+ }>
53
+ gridContainerPosition$: Observable<GridContainerPosition[]>
54
+ isSeriesSeprate$: Observable<boolean>
55
+ }
56
+
57
+ interface TextAlign {
58
+ textAnchor: "start" | "middle" | "end"
59
+ dominantBaseline: "middle" | "auto" | "hanging"
60
+ }
61
+
62
+ // const pluginName = 'ValueAxis'
63
+ // const containerClassName = getClassName(pluginName, 'container')
64
+ // const yAxisGClassName = getClassName(pluginName, 'yAxisG')
65
+ // const yAxisClassName = getClassName(pluginName, 'yAxis')
66
+ // const textClassName = getClassName(pluginName, 'text')
67
+ const defaultTickSize = 6
68
+
69
+ function renderAxisLabel ({ selection, textClassName, fullParams, axisLabelAlign, gridAxesSize, fullDataFormatter, fullChartParams, textReverseTransform }: {
70
+ selection: d3.Selection<SVGGElement, any, any, any>,
71
+ textClassName: string
72
+ fullParams: BaseValueAxisParams
73
+ axisLabelAlign: TextAlign
74
+ gridAxesSize: { width: number, height: number }
75
+ fullDataFormatter: DataFormatterGrid,
76
+ fullChartParams: ChartParams
77
+ textReverseTransform: string,
78
+ }) {
79
+ const offsetX = fullParams.tickPadding - fullParams.labelOffset[0]
80
+ const offsetY = fullParams.tickPadding + fullParams.labelOffset[1]
81
+ let labelX = 0
82
+ let labelY = 0
83
+ if (fullDataFormatter.grid.groupAxis.position === 'bottom') {
84
+ // labelY = - gridAxesSize.height - offsetY
85
+ labelY = - offsetY
86
+ if (fullDataFormatter.grid.valueAxis.position === 'left') {
87
+ labelX = - offsetX
88
+ } else if (fullDataFormatter.grid.valueAxis.position === 'right') {
89
+ labelX = offsetX
90
+ }
91
+ } else if (fullDataFormatter.grid.groupAxis.position === 'top') {
92
+ // labelY = gridAxesSize.height + offsetY
93
+ labelY = offsetY
94
+ if (fullDataFormatter.grid.valueAxis.position === 'left') {
95
+ labelX = - offsetX
96
+ } else if (fullDataFormatter.grid.valueAxis.position === 'right') {
97
+ labelX = offsetX
98
+ }
99
+ } else if (fullDataFormatter.grid.groupAxis.position === 'left') {
100
+ // labelX = gridAxesSize.width + offsetX
101
+ labelX = offsetX
102
+ if (fullDataFormatter.grid.valueAxis.position === 'bottom') {
103
+ labelY = offsetY
104
+ } else if (fullDataFormatter.grid.valueAxis.position === 'top') {
105
+ labelY = - offsetY
106
+ }
107
+ } else if (fullDataFormatter.grid.groupAxis.position === 'right') {
108
+ labelX = - offsetX
109
+ if (fullDataFormatter.grid.valueAxis.position === 'bottom') {
110
+ labelY = offsetY
111
+ } else if (fullDataFormatter.grid.valueAxis.position === 'top') {
112
+ labelY = - offsetY
113
+ }
114
+ }
115
+
116
+ const axisLabelSelection = selection
117
+ .selectAll<SVGGElement, BaseValueAxisParams>(`g.${textClassName}`)
118
+ .data([fullParams])
119
+ .join('g')
120
+ .classed(textClassName, true)
121
+ .each((d, i, g) => {
122
+ const text = d3.select(g[i])
123
+ .selectAll<SVGTextElement, BaseValueAxisParams>(`text`)
124
+ .data([d])
125
+ .join(
126
+ enter => {
127
+ return enter
128
+ .append('text')
129
+ .style('font-weight', 'bold')
130
+ },
131
+ update => update,
132
+ exit => exit.remove()
133
+ )
134
+ .attr('text-anchor', axisLabelAlign.textAnchor)
135
+ .attr('dominant-baseline', axisLabelAlign.dominantBaseline)
136
+ .attr('font-size', fullChartParams.styles.textSize)
137
+ .style('fill', getColor(fullParams.labelColorType, fullChartParams))
138
+ .style('transform', textReverseTransform)
139
+ // 偏移使用 x, y 而非 transform 才不會受到外層 scale 變形影響
140
+ .attr('x', labelX)
141
+ .attr('y', labelY)
142
+ .text(d => fullDataFormatter.grid.valueAxis.label)
143
+ })
144
+ .attr('transform', d => `translate(0, ${gridAxesSize.height})`)
145
+ // .attr('transform', d => `translate(${- fullParams.tickPadding + fullParams.labelOffset[0]}, ${gridAxesSize.height + fullParams.tickPadding + fullParams.labelOffset[1]})`)
146
+
147
+
148
+ }
149
+
150
+ function renderAxis ({ selection, yAxisClassName, fullParams, tickTextAlign, gridAxesSize, fullDataFormatter, fullChartParams, valueScale, textReverseTransformWithRotate, minAndMax }: {
151
+ selection: d3.Selection<SVGGElement, any, any, any>,
152
+ yAxisClassName: string
153
+ fullParams: BaseValueAxisParams
154
+ tickTextAlign: TextAlign
155
+ gridAxesSize: { width: number, height: number }
156
+ fullDataFormatter: DataFormatterGrid,
157
+ fullChartParams: ChartParams
158
+ valueScale: d3.ScaleLinear<number, number>
159
+ textReverseTransformWithRotate: string,
160
+ minAndMax: [number, number]
161
+ }) {
162
+
163
+ const yAxisSelection = selection
164
+ .selectAll<SVGGElement, BaseValueAxisParams>(`g.${yAxisClassName}`)
165
+ .data([fullParams])
166
+ .join('g')
167
+ .classed(yAxisClassName, true)
168
+
169
+ const valueLength = minAndMax[1] - minAndMax[0]
170
+
171
+ // const _valueScale = d3.scaleLinear()
172
+ // .domain([0, 150])
173
+ // .range([416.5, 791.349])
174
+
175
+ // 刻度文字偏移
176
+ let tickPadding = 0
177
+ let textY = 0
178
+ if (fullDataFormatter.grid.valueAxis.position === 'left') {
179
+ tickPadding = fullParams.tickPadding
180
+ textY = 0
181
+ } else if (fullDataFormatter.grid.valueAxis.position === 'right') {
182
+ tickPadding = - fullParams.tickPadding
183
+ textY = 0
184
+ } else if (fullDataFormatter.grid.valueAxis.position === 'bottom') {
185
+ tickPadding = 0
186
+ textY = fullParams.tickPadding
187
+ } else if (fullDataFormatter.grid.valueAxis.position === 'top') {
188
+ tickPadding = 0
189
+ textY = - fullParams.tickPadding
190
+ }
191
+
192
+ // 設定Y軸刻度
193
+ const yAxis = d3.axisLeft(valueScale)
194
+ .scale(valueScale)
195
+ .ticks(valueLength > fullParams.ticks
196
+ ? fullParams.ticks
197
+ : ((minAndMax[0] === 0 && minAndMax[1] === 0)
198
+ ? 1
199
+ : Math.ceil(valueLength))) // 刻度分段數量
200
+ .tickFormat(d => parseTickFormatValue(d, fullParams.tickFormat))
201
+ .tickSize(fullParams.tickFullLine == true
202
+ ? -gridAxesSize.width
203
+ : defaultTickSize)
204
+ .tickPadding(tickPadding)
205
+
206
+ const yAxisEl = yAxisSelection
207
+ .transition()
208
+ .duration(100)
209
+ .call(yAxis)
210
+
211
+ yAxisEl.selectAll('line')
212
+ .style('fill', 'none')
213
+ .style('stroke', fullParams.tickLineVisible == true ? getColor(fullParams.tickColorType, fullChartParams) : 'none')
214
+ .style('stroke-dasharray', fullParams.tickFullLineDasharray)
215
+ .attr('pointer-events', 'none')
216
+
217
+ yAxisEl.selectAll('path')
218
+ .style('fill', 'none')
219
+ // .style('stroke', this.fullParams.axisLineColor!)
220
+ .style('stroke', fullParams.axisLineVisible == true ? getColor(fullParams.axisLineColorType, fullChartParams) : 'none')
221
+ .style('shape-rendering', 'crispEdges')
222
+
223
+ // const yText = yAxisEl.selectAll('text')
224
+ const yText = yAxisSelection.selectAll('text')
225
+ // .style('font-family', 'sans-serif')
226
+ .attr('font-size', fullChartParams.styles.textSize)
227
+ .style('color', getColor(fullParams.tickTextColorType, fullChartParams))
228
+ .attr('text-anchor', tickTextAlign.textAnchor)
229
+ .attr('dominant-baseline', tickTextAlign.dominantBaseline)
230
+ // .attr('dy', 0)
231
+ .attr('y', textY)
232
+ yText.style('transform', textReverseTransformWithRotate)
233
+
234
+ // 抵消掉預設的偏移
235
+ if (fullDataFormatter.grid.valueAxis.position === 'bottom' || fullDataFormatter.grid.valueAxis.position === 'top') {
236
+ yText.attr('dy', 0)
237
+ }
238
+
239
+ return yAxisSelection
240
+ }
241
+
242
+
243
+
244
+ export const createBaseValueAxis: BasePluginFn<BaseLinesContext> = (pluginName: string, {
245
+ selection,
246
+ computedData$,
247
+ fullParams$,
248
+ fullDataFormatter$,
249
+ fullChartParams$,
250
+ gridAxesTransform$,
251
+ gridAxesReverseTransform$,
252
+ gridAxesSize$,
253
+ gridContainerPosition$,
254
+ isSeriesSeprate$,
255
+ }) => {
256
+
257
+ const destroy$ = new Subject()
258
+
259
+ const containerClassName = getClassName(pluginName, 'container')
260
+ const yAxisGClassName = getClassName(pluginName, 'yAxisG')
261
+ const yAxisClassName = getClassName(pluginName, 'yAxis')
262
+ const textClassName = getClassName(pluginName, 'text')
263
+
264
+ const containerSelection$ = combineLatest({
265
+ computedData: computedData$.pipe(
266
+ distinctUntilChanged((a, b) => {
267
+ // 只有當series的數量改變時,才重新計算
268
+ return a.length === b.length
269
+ }),
270
+ ),
271
+ isSeriesSeprate: isSeriesSeprate$
272
+ }).pipe(
273
+ takeUntil(destroy$),
274
+ switchMap(async (d) => d),
275
+ map(data => {
276
+ return data.isSeriesSeprate
277
+ // series分開的時候顯示各別axis
278
+ ? data.computedData
279
+ // series合併的時候只顯示第一個axis
280
+ : [data.computedData[0]]
281
+ }),
282
+ map((computedData, i) => {
283
+ return selection
284
+ .selectAll<SVGGElement, ComputedDatumGrid[]>(`g.${containerClassName}`)
285
+ .data(computedData, d => d[0] ? d[0].seriesIndex : i)
286
+ .join('g')
287
+ .classed(containerClassName, true)
288
+ })
289
+ )
290
+
291
+ const axisSelection$ = containerSelection$.pipe(
292
+ takeUntil(destroy$),
293
+ map((containerSelection, i) => {
294
+ return containerSelection
295
+ .selectAll<SVGGElement, ComputedDatumGrid[]>(`g.${yAxisGClassName}`)
296
+ .data([yAxisGClassName])
297
+ .join('g')
298
+ .classed(yAxisGClassName, true)
299
+ })
300
+ )
301
+
302
+ combineLatest({
303
+ containerSelection: containerSelection$,
304
+ gridContainerPosition: gridContainerPosition$
305
+ }).pipe(
306
+ takeUntil(destroy$),
307
+ switchMap(async d => d)
308
+ ).subscribe(data => {
309
+ data.containerSelection
310
+ .attr('transform', (d, i) => {
311
+ const gridContainerPosition = data.gridContainerPosition[i] ?? data.gridContainerPosition[0]
312
+ const translate = gridContainerPosition.translate
313
+ const scale = gridContainerPosition.scale
314
+ return `translate(${translate[0]}, ${translate[1]}) scale(${scale[0]}, ${scale[1]})`
315
+ })
316
+ // .attr('opacity', 0)
317
+ // .transition()
318
+ // .attr('opacity', 1)
319
+ })
320
+
321
+ combineLatest({
322
+ axisSelection: axisSelection$,
323
+ gridAxesTransform: gridAxesTransform$,
324
+ }).pipe(
325
+ takeUntil(destroy$),
326
+ switchMap(async d => d)
327
+ ).subscribe(data => {
328
+ data.axisSelection
329
+ .style('transform', data.gridAxesTransform.value)
330
+ // .attr('opacity', 0)
331
+ // .transition()
332
+ // .attr('opacity', 1)
333
+
334
+ })
335
+
336
+ // const gridAxesSize$ = gridAxisSizeObservable({
337
+ // fullDataFormatter$,
338
+ // layout$
339
+ // })
340
+
341
+ // const textReverseTransform$: Observable<string> = new Observable(subscriber => {
342
+ // combineLatest({
343
+ // fullParams: fullParams$,
344
+ // layout: layout$
345
+ // }).pipe(
346
+ // takeUntil(destroy$),
347
+ // // 轉換後會退訂前一個未完成的訂閱事件,因此可以取到「同時間」最後一次的訂閱事件
348
+ // switchMap(async (d) => d),
349
+ // ).subscribe(data => {
350
+
351
+ // const transformData = Object.assign({}, data.layout.content.axesTransformData)
352
+
353
+ // const value = getAxesTransformValue({
354
+ // translate: [0, 0],
355
+ // scale: [transformData.scale[0] * -1, transformData.scale[1] * -1],
356
+ // rotate: transformData.rotate * -1 + data.fullParams.tickTextRotate,
357
+ // rotateX: transformData.rotateX * -1,
358
+ // rotateY: transformData.rotateY * -1
359
+ // })
360
+
361
+ // subscriber.next(value)
362
+ // })
363
+ // })
364
+ // const reverseTransform$: Observable<TransformData> = gridAxesTransform$.pipe(
365
+ // takeUntil(destroy$),
366
+ // map(d => {
367
+ // const translate: [number, number] = [d.translate[0] * -1, d.translate[1] * -1]
368
+ // const scale: [number, number] = [d.scale[0] * -1, d.scale[1] * -1]
369
+ // const rotate = d.rotate * -1
370
+ // const rotateX = d.rotateX * -1
371
+ // const rotateY = d.rotateY * -1
372
+ // return {
373
+ // translate,
374
+ // scale,
375
+ // rotate,
376
+ // rotateX,
377
+ // rotateY,
378
+ // value: ''
379
+ // }
380
+ // }),
381
+ // )
382
+ const textReverseTransform$ = combineLatest({
383
+ gridAxesReverseTransform: gridAxesReverseTransform$,
384
+ gridContainerPosition: gridContainerPosition$
385
+ }).pipe(
386
+ takeUntil(destroy$),
387
+ switchMap(async (d) => d),
388
+ map(data => {
389
+ // const axisReverseTranslateValue = `translate(${data.gridAxesReverseTransform.translate[0]}px, ${data.gridAxesReverseTransform.translate[1]}px)`
390
+ const axesRotateXYReverseValue = `rotateX(${data.gridAxesReverseTransform.rotateX}deg) rotateY(${data.gridAxesReverseTransform.rotateY}deg)`
391
+ const axesRotateReverseValue = `rotate(${data.gridAxesReverseTransform.rotate}deg)`
392
+ const containerScaleReverseValue = `scale(${1 / data.gridContainerPosition[0].scale[0]}, ${1 / data.gridContainerPosition[0].scale[1]})`
393
+ // 必須按照順序(先抵消外層rotate,再抵消最外層scale)
394
+ return `${axesRotateXYReverseValue} ${axesRotateReverseValue} ${containerScaleReverseValue}`
395
+ }),
396
+ distinctUntilChanged()
397
+ )
398
+
399
+ const textReverseTransformWithRotate$ = combineLatest({
400
+ textReverseTransform: textReverseTransform$,
401
+ fullParams: fullParams$,
402
+ }).pipe(
403
+ takeUntil(destroy$),
404
+ switchMap(async (d) => d),
405
+ map(data => {
406
+ // 必須按照順序(先抵消外層rotate,再抵消最外層scale,最後再做本身的rotate)
407
+ return `${data.textReverseTransform} rotate(${data.fullParams.tickTextRotate}deg)`
408
+ })
409
+ )
410
+
411
+ const minAndMax$: Observable<[number, number]> = new Observable(subscriber => {
412
+ combineLatest({
413
+ fullDataFormatter: fullDataFormatter$,
414
+ gridAxesSize: gridAxesSize$,
415
+ computedData: computedData$
416
+ }).pipe(
417
+ takeUntil(destroy$),
418
+ switchMap(async (d) => d),
419
+ ).subscribe(data => {
420
+ const groupMin = 0
421
+ const groupMax = data.computedData[0] ? data.computedData[0].length - 1 : 0
422
+ const groupScaleDomainMin = data.fullDataFormatter.grid.groupAxis.scaleDomain[0] === 'auto'
423
+ ? groupMin - data.fullDataFormatter.grid.groupAxis.scalePadding
424
+ : data.fullDataFormatter.grid.groupAxis.scaleDomain[0] as number - data.fullDataFormatter.grid.groupAxis.scalePadding
425
+ const groupScaleDomainMax = data.fullDataFormatter.grid.groupAxis.scaleDomain[1] === 'auto'
426
+ ? groupMax + data.fullDataFormatter.grid.groupAxis.scalePadding
427
+ : data.fullDataFormatter.grid.groupAxis.scaleDomain[1] as number + data.fullDataFormatter.grid.groupAxis.scalePadding
428
+
429
+ const filteredData = data.computedData.map((d, i) => {
430
+ return d.filter((_d, _i) => {
431
+ return _i >= groupScaleDomainMin && _i <= groupScaleDomainMax
432
+ })
433
+ })
434
+
435
+ const filteredMinAndMax = getMinAndMaxValue(filteredData.flat())
436
+ if (filteredMinAndMax[0] === filteredMinAndMax[1]) {
437
+ filteredMinAndMax[0] = filteredMinAndMax[1] - 1 // 避免最大及最小值相同造成無法計算scale
438
+ }
439
+ subscriber.next(filteredMinAndMax)
440
+ })
441
+ })
442
+
443
+ const valueScale$: Observable<d3.ScaleLinear<number, number>> = new Observable(subscriber => {
444
+ combineLatest({
445
+ fullDataFormatter: fullDataFormatter$,
446
+ gridAxesSize: gridAxesSize$,
447
+ minAndMax: minAndMax$
448
+ }).pipe(
449
+ takeUntil(destroy$),
450
+ switchMap(async (d) => d),
451
+ ).subscribe(data => {
452
+
453
+ const valueScale: d3.ScaleLinear<number, number> = createAxisLinearScale({
454
+ maxValue: data.minAndMax[1],
455
+ minValue: data.minAndMax[0],
456
+ axisWidth: data.gridAxesSize.height,
457
+ scaleDomain: data.fullDataFormatter.grid.valueAxis.scaleDomain,
458
+ scaleRange: data.fullDataFormatter.grid.valueAxis.scaleRange
459
+ })
460
+
461
+ subscriber.next(valueScale)
462
+ })
463
+ })
464
+
465
+ const tickTextAlign$: Observable<TextAlign> = combineLatest({
466
+ fullDataFormatter: fullDataFormatter$,
467
+ fullParams: fullParams$
468
+ }).pipe(
469
+ takeUntil(destroy$),
470
+ switchMap(async (d) => d),
471
+ map(data => {
472
+ let textAnchor: 'start' | 'middle' | 'end' = 'start'
473
+ let dominantBaseline: 'auto' | 'middle' | 'hanging' = 'hanging'
474
+
475
+ if (data.fullDataFormatter.grid.valueAxis.position === 'left') {
476
+ textAnchor = 'end'
477
+ dominantBaseline = 'middle'
478
+ } else if (data.fullDataFormatter.grid.valueAxis.position === 'right') {
479
+ textAnchor = 'start'
480
+ dominantBaseline = 'middle'
481
+ } else if (data.fullDataFormatter.grid.valueAxis.position === 'bottom') {
482
+ textAnchor = data.fullParams.tickTextRotate
483
+ ? 'end'
484
+ : 'middle'
485
+ dominantBaseline = 'hanging'
486
+ } else if (data.fullDataFormatter.grid.valueAxis.position === 'top') {
487
+ textAnchor = data.fullParams.tickTextRotate
488
+ ? 'start'
489
+ : 'middle'
490
+ dominantBaseline = 'auto'
491
+ }
492
+ return {
493
+ textAnchor,
494
+ dominantBaseline
495
+ }
496
+ })
497
+ )
498
+
499
+ const axisLabelAlign$: Observable<TextAlign> = fullDataFormatter$.pipe(
500
+ takeUntil(destroy$),
501
+ map(d => {
502
+ let textAnchor: 'start' | 'middle' | 'end' = 'start'
503
+ let dominantBaseline: 'auto' | 'middle' | 'hanging' = 'hanging'
504
+
505
+ if (d.grid.groupAxis.position === 'bottom') {
506
+ dominantBaseline = 'auto'
507
+ } else if (d.grid.groupAxis.position === 'top') {
508
+ dominantBaseline = 'hanging'
509
+ } else if (d.grid.groupAxis.position === 'left') {
510
+ textAnchor = 'start'
511
+ } else if (d.grid.groupAxis.position === 'right') {
512
+ textAnchor = 'end'
513
+ }
514
+ if (d.grid.valueAxis.position === 'left') {
515
+ textAnchor = 'end'
516
+ } else if (d.grid.valueAxis.position === 'right') {
517
+ textAnchor = 'start'
518
+ } else if (d.grid.valueAxis.position === 'bottom') {
519
+ dominantBaseline = 'hanging'
520
+ } else if (d.grid.valueAxis.position === 'top') {
521
+ dominantBaseline = 'auto'
522
+ }
523
+ return {
524
+ textAnchor,
525
+ dominantBaseline
526
+ }
527
+ })
528
+ )
529
+
530
+
531
+ combineLatest({
532
+ axisSelection: axisSelection$,
533
+ fullParams: fullParams$,
534
+ tickTextAlign: tickTextAlign$,
535
+ axisLabelAlign: axisLabelAlign$,
536
+ computedData: computedData$,
537
+ gridAxesSize: gridAxesSize$,
538
+ fullDataFormatter: fullDataFormatter$,
539
+ fullChartParams: fullChartParams$,
540
+ valueScale: valueScale$,
541
+ textReverseTransform: textReverseTransform$,
542
+ textReverseTransformWithRotate: textReverseTransformWithRotate$,
543
+ minAndMax: minAndMax$
544
+ }).pipe(
545
+ takeUntil(destroy$),
546
+ switchMap(async (d) => d),
547
+ ).subscribe(data => {
548
+
549
+ renderAxis({
550
+ selection: data.axisSelection,
551
+ yAxisClassName,
552
+ fullParams: data.fullParams,
553
+ tickTextAlign: data.tickTextAlign,
554
+ gridAxesSize: data.gridAxesSize,
555
+ fullDataFormatter: data.fullDataFormatter,
556
+ fullChartParams: data.fullChartParams,
557
+ valueScale: data.valueScale,
558
+ textReverseTransformWithRotate: data.textReverseTransformWithRotate,
559
+ minAndMax: data.minAndMax
560
+ })
561
+
562
+ renderAxisLabel({
563
+ selection: data.axisSelection,
564
+ textClassName,
565
+ fullParams: data.fullParams,
566
+ axisLabelAlign: data.axisLabelAlign,
567
+ gridAxesSize: data.gridAxesSize,
568
+ fullDataFormatter: data.fullDataFormatter,
569
+ fullChartParams: data.fullChartParams,
570
+ textReverseTransform: data.textReverseTransform,
571
+ })
572
+ })
573
+
574
+ return () => {
575
+ destroy$.next(undefined)
576
+ }
577
+ }