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

Sign up to get free protection for your applications and to get access to all the features.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@orbcharts/plugins-basic",
3
- "version": "3.0.0-alpha.62",
3
+ "version": "3.0.0-alpha.63",
4
4
  "description": "plugins for OrbCharts",
5
5
  "author": "Blue Planet Inc.",
6
6
  "license": "Apache-2.0",
@@ -35,7 +35,7 @@
35
35
  "vite-plugin-dts": "^3.7.3"
36
36
  },
37
37
  "dependencies": {
38
- "@orbcharts/core": "^3.0.0-alpha.57",
38
+ "@orbcharts/core": "^3.0.0-alpha.58",
39
39
  "d3": "^7.8.5",
40
40
  "rxjs": "^7.8.1"
41
41
  }
@@ -69,33 +69,54 @@ interface TextAlign {
69
69
  // const groupingLabelClassName = getClassName(pluginName, 'groupingLabel')
70
70
  const defaultTickSize = 6
71
71
 
72
- function renderAxis ({ selection, xAxisClassName, groupingLabelClassName, params, tickTextAlign, axisLabelAlign, gridAxesSize, fullDataFormatter, chartParams, groupScale, groupScaleDomain, groupLabels, textTransform }: {
72
+ function renderAxisLabel ({ selection, groupingLabelClassName, fullParams, axisLabelAlign, gridAxesSize, fullDataFormatter, chartParams, textReverseTransform }: {
73
73
  selection: d3.Selection<SVGGElement, any, any, any>,
74
- xAxisClassName: string
75
74
  groupingLabelClassName: string
76
- params: BaseGroupAxisParams
77
- tickTextAlign: TextAlign
75
+ fullParams: BaseGroupAxisParams
78
76
  axisLabelAlign: TextAlign
79
77
  gridAxesSize: { width: number, height: number }
80
78
  fullDataFormatter: DataFormatterGrid,
81
79
  chartParams: ChartParams
82
- // groupScale: d3.ScalePoint<string>
83
- groupScale: d3.ScaleLinear<number, number>
84
- groupScaleDomain: number[]
85
- groupLabels: string[]
86
- textTransform: string
87
- // tickTextFormatter: string | ((label: any) => string)
80
+ textReverseTransform: string
88
81
  }) {
89
-
90
- const xAxisSelection = selection
91
- .selectAll<SVGGElement, BaseGroupAxisParams>(`g.${xAxisClassName}`)
92
- .data([params])
93
- .join('g')
94
- .classed(xAxisClassName, true)
82
+
83
+ const offsetX = fullParams.tickPadding + fullParams.labelOffset[0]
84
+ const offsetY = fullParams.tickPadding + fullParams.labelOffset[1]
85
+ let labelX = 0
86
+ let labelY = 0
87
+ if (fullDataFormatter.grid.groupAxis.position === 'bottom') {
88
+ labelY = offsetY
89
+ if (fullDataFormatter.grid.valueAxis.position === 'left') {
90
+ labelX = offsetX
91
+ } else if (fullDataFormatter.grid.valueAxis.position === 'right') {
92
+ labelX = - offsetX
93
+ }
94
+ } else if (fullDataFormatter.grid.groupAxis.position === 'top') {
95
+ labelY = - offsetY
96
+ if (fullDataFormatter.grid.valueAxis.position === 'left') {
97
+ labelX = offsetX
98
+ } else if (fullDataFormatter.grid.valueAxis.position === 'right') {
99
+ labelX = - offsetX
100
+ }
101
+ } else if (fullDataFormatter.grid.groupAxis.position === 'left') {
102
+ labelX = - offsetX
103
+ if (fullDataFormatter.grid.valueAxis.position === 'bottom') {
104
+ labelY = - offsetY
105
+ } else if (fullDataFormatter.grid.valueAxis.position === 'top') {
106
+ labelY = offsetY
107
+ }
108
+ } else if (fullDataFormatter.grid.groupAxis.position === 'right') {
109
+ labelX = offsetX
110
+ if (fullDataFormatter.grid.valueAxis.position === 'bottom') {
111
+ labelY = - offsetY
112
+ } else if (fullDataFormatter.grid.valueAxis.position === 'top') {
113
+ labelY = offsetY
114
+ }
115
+ }
95
116
 
96
117
  const axisLabelSelection = selection
97
118
  .selectAll<SVGGElement, BaseGroupAxisParams>(`g.${groupingLabelClassName}`)
98
- .data([params])
119
+ .data([fullParams])
99
120
  .join('g')
100
121
  .classed(groupingLabelClassName, true)
101
122
  .each((d, i, g) => {
@@ -114,34 +135,76 @@ function renderAxis ({ selection, xAxisClassName, groupingLabelClassName, params
114
135
  .attr('text-anchor', axisLabelAlign.textAnchor)
115
136
  .attr('dominant-baseline', axisLabelAlign.dominantBaseline)
116
137
  .attr('font-size', chartParams.styles.textSize)
117
- .style('fill', getColor(params.labelColorType, chartParams))
118
- // .style('transform', textTransform)
138
+ .style('fill', getColor(fullParams.labelColorType, chartParams))
139
+ .style('transform', textReverseTransform)
140
+ // 偏移使用 x, y 而非 transform 才不會受到外層 scale 變形影響
141
+ .attr('x', labelX)
142
+ .attr('y', labelY)
119
143
  .text(d => fullDataFormatter.grid.groupAxis.label)
120
144
  })
121
- .attr('transform', d => `translate(${gridAxesSize.width + d.tickPadding + params.labelOffset[0]}, ${- d.tickPadding - defaultTickSize - params.labelOffset[1]})`)
145
+ .attr('transform', d => `translate(${gridAxesSize.width}, 0)`)
146
+ // .attr('transform', d => `translate(${gridAxesSize.width + d.tickPadding + fullParams.labelOffset[0]}, ${- d.tickPadding - fullParams.labelOffset[1]})`)
147
+
148
+ }
149
+
150
+ function renderAxis ({ selection, xAxisClassName, fullParams, tickTextAlign, gridAxesSize, fullDataFormatter, chartParams, groupScale, groupScaleDomain, groupLabels, textReverseTransformWithRotate }: {
151
+ selection: d3.Selection<SVGGElement, any, any, any>,
152
+ xAxisClassName: string
153
+ fullParams: BaseGroupAxisParams
154
+ tickTextAlign: TextAlign
155
+ gridAxesSize: { width: number, height: number }
156
+ fullDataFormatter: DataFormatterGrid,
157
+ chartParams: ChartParams
158
+ groupScale: d3.ScaleLinear<number, number>
159
+ groupScaleDomain: number[]
160
+ groupLabels: string[]
161
+ textReverseTransformWithRotate: string
162
+ }) {
163
+
164
+ const xAxisSelection = selection
165
+ .selectAll<SVGGElement, BaseGroupAxisParams>(`g.${xAxisClassName}`)
166
+ .data([fullParams])
167
+ .join('g')
168
+ .classed(xAxisClassName, true)
122
169
 
123
170
  // 計算所有範圍內groupLabels數量(顯示所有刻度)
124
171
  const allTicksAmount = Math.floor(groupScaleDomain[1]) - Math.ceil(groupScaleDomain[0]) + 1
125
172
 
173
+ // 刻度文字偏移
174
+ let tickPadding = 0
175
+ let textX = 0
176
+ if (fullDataFormatter.grid.groupAxis.position === 'left') {
177
+ tickPadding = 0
178
+ textX = - fullParams.tickPadding
179
+ } else if (fullDataFormatter.grid.groupAxis.position === 'right') {
180
+ tickPadding = 0
181
+ textX = fullParams.tickPadding
182
+ } else if (fullDataFormatter.grid.groupAxis.position === 'bottom') {
183
+ tickPadding = fullParams.tickPadding
184
+ textX = 0
185
+ } else if (fullDataFormatter.grid.groupAxis.position === 'top') {
186
+ tickPadding = - fullParams.tickPadding
187
+ textX = - 0
188
+ }
189
+
126
190
  // 設定X軸刻度
127
- // const xAxis = d3.axisBottom(groupScale)
128
- const xAxis = d3.axisTop(groupScale)
191
+ const xAxis = d3.axisBottom(groupScale)
129
192
  .scale(groupScale)
130
- .ticks(params.ticks === 'all'
193
+ .ticks(fullParams.ticks === 'all'
131
194
  ? allTicksAmount
132
- : params.ticks > allTicksAmount
195
+ : fullParams.ticks > allTicksAmount
133
196
  ? allTicksAmount // 不顯示超過groupLabels數量的刻度
134
- : params.ticks)
135
- .tickSize(params.tickFullLine == true
136
- ? -gridAxesSize.height
137
- : defaultTickSize)
197
+ : fullParams.ticks)
198
+ .tickSize(fullParams.tickFullLine == true
199
+ ? gridAxesSize.height
200
+ : - defaultTickSize)
138
201
  .tickSizeOuter(0)
139
202
  .tickFormat((groupIndex: number) => {
140
203
  // 用index對應到groupLabel
141
204
  const groupLabel = groupLabels[groupIndex] ?? '' // 非整數index不顯示
142
- return parseTickFormatValue(groupLabel, params.tickFormat)
205
+ return parseTickFormatValue(groupLabel, fullParams.tickFormat)
143
206
  })
144
- .tickPadding(params.tickPadding)
207
+ .tickPadding(tickPadding)
145
208
 
146
209
  const xAxisEl = xAxisSelection
147
210
  .transition()
@@ -152,13 +215,13 @@ function renderAxis ({ selection, xAxisClassName, groupingLabelClassName, params
152
215
 
153
216
  xAxisEl.selectAll('line')
154
217
  .style('fill', 'none')
155
- .style('stroke', params.tickLineVisible == true ? getColor(params.tickColorType, chartParams) : 'none')
156
- .style('stroke-dasharray', params.tickFullLineDasharray)
218
+ .style('stroke', fullParams.tickLineVisible == true ? getColor(fullParams.tickColorType, chartParams) : 'none')
219
+ .style('stroke-dasharray', fullParams.tickFullLineDasharray)
157
220
  .attr('pointer-events', 'none')
158
221
 
159
222
  xAxisEl.selectAll('path')
160
223
  .style('fill', 'none')
161
- .style('stroke', params.axisLineVisible == true ? getColor(params.axisLineColorType, chartParams) : 'none')
224
+ .style('stroke', fullParams.axisLineVisible == true ? getColor(fullParams.axisLineColorType, chartParams) : 'none')
162
225
  .style('shape-rendering', 'crispEdges')
163
226
 
164
227
  // const xText = xAxisEl.selectAll('text')
@@ -174,18 +237,22 @@ function renderAxis ({ selection, xAxisClassName, groupingLabelClassName, params
174
237
  // .attr('text-anchor', tickTextAlign.textAnchor)
175
238
  // .attr('dominant-baseline', tickTextAlign.dominantBaseline)
176
239
  // .attr('transform-origin', `0 -${params.tickPadding + defaultTickSize}`)
177
- // .style('transform', textTransform)
240
+ // .style('transform', textReverseTransform)
178
241
  // })
179
242
  const xText = xAxisSelection.selectAll('text')
180
243
  // .style('font-family', 'sans-serif')
181
244
  .attr('font-size', chartParams.styles.textSize)
182
245
  // .style('font-weight', 'bold')
183
- .style('color', getColor(params.tickTextColorType, chartParams))
246
+ .style('color', getColor(fullParams.tickTextColorType, chartParams))
184
247
  .attr('text-anchor', tickTextAlign.textAnchor)
185
248
  .attr('dominant-baseline', tickTextAlign.dominantBaseline)
186
- .attr('transform-origin', `0 -${params.tickPadding + defaultTickSize}`)
187
- .style('transform', textTransform)
188
-
249
+ .attr('x', textX)
250
+ .style('transform', textReverseTransformWithRotate)
251
+
252
+ // 抵消掉預設的偏移
253
+ // if (fullDataFormatter.grid.groupAxis.position === 'left' || fullDataFormatter.grid.groupAxis.position === 'right') {
254
+ xText.attr('dy', 0)
255
+ // }
189
256
 
190
257
  return xAxisSelection
191
258
  }
@@ -297,7 +364,7 @@ export const createBaseGroupAxis: BasePluginFn<BaseGroupAxisContext> = ((pluginN
297
364
  // })
298
365
  // )
299
366
 
300
- // const textTransform$: Observable<string> = new Observable(subscriber => {
367
+ // const textReverseTransform$: Observable<string> = new Observable(subscriber => {
301
368
  // combineLatest({
302
369
  // params: fullParams$,
303
370
  // gridAxesTransform: gridAxesTransform$
@@ -338,31 +405,34 @@ export const createBaseGroupAxis: BasePluginFn<BaseGroupAxisContext> = ((pluginN
338
405
  // }
339
406
  // }),
340
407
  // )
341
- const textTransform$ = combineLatest({
342
- fullParams: fullParams$,
343
- fullDataFormatter: fullDataFormatter$,
408
+ const textReverseTransform$ = combineLatest({
344
409
  gridAxesReverseTransform: gridAxesReverseTransform$,
345
410
  gridContainerPosition: gridContainerPosition$
346
411
  }).pipe(
347
412
  takeUntil(destroy$),
348
413
  switchMap(async (d) => d),
349
414
  map(data => {
350
- const axisReverseTranslateValue = `translate(${data.gridAxesReverseTransform.translate[0]}px, ${data.gridAxesReverseTransform.translate[1]}px)`
351
- const axisReverseRotateValue = `rotate(${data.gridAxesReverseTransform.rotate}deg) rotateX(${data.gridAxesReverseTransform.rotateX}deg) rotateY(${data.gridAxesReverseTransform.rotateY}deg)`
352
- const containerScaleReverseScaleValue = `scale(${1 / data.gridContainerPosition[0].scale[0]}, ${1 / data.gridContainerPosition[0].scale[1]})`
353
- const tickTextRotateDeg = (data.fullDataFormatter.grid.groupAxis.position === 'left' && data.fullDataFormatter.grid.valueAxis.position === 'top')
354
- || (data.fullDataFormatter.grid.groupAxis.position === 'right' && data.fullDataFormatter.grid.valueAxis.position === 'bottom')
355
- ? data.fullParams.tickTextRotate + 180 // 修正文字倒轉
356
- : data.fullParams.tickTextRotate
357
-
358
- const textRotateValue = `rotate(${tickTextRotateDeg}deg)`
359
-
360
- // 必須按照順序(先抵消外層rotate,再抵消最外層scale,最後再做本身的rotate)
361
- return `${axisReverseTranslateValue} ${axisReverseRotateValue} ${containerScaleReverseScaleValue} ${textRotateValue}`
415
+ // const axisReverseTranslateValue = `translate(${data.gridAxesReverseTransform.translate[0]}px, ${data.gridAxesReverseTransform.translate[1]}px)`
416
+ const axesRotateXYReverseValue = `rotateX(${data.gridAxesReverseTransform.rotateX}deg) rotateY(${data.gridAxesReverseTransform.rotateY}deg)`
417
+ const axesRotateReverseValue = `rotate(${data.gridAxesReverseTransform.rotate}deg)`
418
+ const containerScaleReverseValue = `scale(${1 / data.gridContainerPosition[0].scale[0]}, ${1 / data.gridContainerPosition[0].scale[1]})`
419
+ // 必須按照順序(先抵消外層rotate,再抵消最外層scale)
420
+ return `${axesRotateXYReverseValue} ${axesRotateReverseValue} ${containerScaleReverseValue}`
362
421
  }),
363
422
  distinctUntilChanged()
364
423
  )
365
424
 
425
+ const textReverseTransformWithRotate$ = combineLatest({
426
+ textReverseTransform: textReverseTransform$,
427
+ fullParams: fullParams$,
428
+ }).pipe(
429
+ takeUntil(destroy$),
430
+ switchMap(async (d) => d),
431
+ map(data => {
432
+ // 必須按照順序(先抵消外層rotate,再抵消最外層scale,最後再做本身的rotate)
433
+ return `${data.textReverseTransform} rotate(${data.fullParams.tickTextRotate}deg)`
434
+ })
435
+ )
366
436
 
367
437
  // 使用pointScale計算非連續性比例尺
368
438
  // const groupScale$: Observable<d3.ScalePoint<string>> = new Observable(subscriber => {
@@ -469,7 +539,7 @@ export const createBaseGroupAxis: BasePluginFn<BaseGroupAxisContext> = ((pluginN
469
539
  dominantBaseline = 'hanging'
470
540
  } else if (data.fullDataFormatter.grid.groupAxis.position === 'top') {
471
541
  textAnchor = data.fullParams.tickTextRotate
472
- ? 'end'
542
+ ? 'start'
473
543
  : 'middle'
474
544
  dominantBaseline = 'auto'
475
545
  } else if (data.fullDataFormatter.grid.groupAxis.position === 'left') {
@@ -519,7 +589,7 @@ export const createBaseGroupAxis: BasePluginFn<BaseGroupAxisContext> = ((pluginN
519
589
 
520
590
  combineLatest({
521
591
  axisSelection: axisSelection$,
522
- params: fullParams$,
592
+ fullParams: fullParams$,
523
593
  tickTextAlign: tickTextAlign$,
524
594
  axisLabelAlign: axisLabelAlign$,
525
595
  gridAxesSize: gridAxesSize$,
@@ -528,7 +598,8 @@ export const createBaseGroupAxis: BasePluginFn<BaseGroupAxisContext> = ((pluginN
528
598
  groupScale: groupScale$,
529
599
  groupScaleDomain: groupScaleDomain$,
530
600
  groupLabels: groupLabels$,
531
- textTransform: textTransform$,
601
+ textReverseTransform: textReverseTransform$,
602
+ textReverseTransformWithRotate: textReverseTransformWithRotate$,
532
603
  // tickTextFormatter: tickTextFormatter$
533
604
  }).pipe(
534
605
  takeUntil(destroy$),
@@ -538,18 +609,26 @@ export const createBaseGroupAxis: BasePluginFn<BaseGroupAxisContext> = ((pluginN
538
609
  renderAxis({
539
610
  selection: data.axisSelection,
540
611
  xAxisClassName,
541
- groupingLabelClassName,
542
- params: data.params,
612
+ fullParams: data.fullParams,
543
613
  tickTextAlign: data.tickTextAlign,
544
- axisLabelAlign: data.axisLabelAlign,
545
614
  gridAxesSize: data.gridAxesSize,
546
615
  fullDataFormatter: data.fullDataFormatter,
547
616
  chartParams: data.chartParams,
548
617
  groupScale: data.groupScale,
549
618
  groupScaleDomain: data.groupScaleDomain,
550
619
  groupLabels: data.groupLabels,
551
- textTransform: data.textTransform,
552
- // tickTextFormatter: data.tickTextFormatter
620
+ textReverseTransformWithRotate: data.textReverseTransformWithRotate,
621
+ })
622
+
623
+ renderAxisLabel({
624
+ selection: data.axisSelection,
625
+ groupingLabelClassName,
626
+ fullParams: data.fullParams,
627
+ axisLabelAlign: data.axisLabelAlign,
628
+ gridAxesSize: data.gridAxesSize,
629
+ fullDataFormatter: data.fullDataFormatter,
630
+ chartParams: data.chartParams,
631
+ textReverseTransform: data.textReverseTransform,
553
632
  })
554
633
  })
555
634
 
@@ -66,26 +66,52 @@ interface TextAlign {
66
66
  // const textClassName = getClassName(pluginName, 'text')
67
67
  const defaultTickSize = 6
68
68
 
69
- function renderAxis ({ selection, yAxisClassName, textClassName, fullParams, tickTextAlign, axisLabelAlign, gridAxesSize, fullDataFormatter, fullChartParams, valueScale, textTransform, minAndMax }: {
69
+ function renderAxisLabel ({ selection, textClassName, fullParams, axisLabelAlign, gridAxesSize, fullDataFormatter, fullChartParams, textReverseTransform }: {
70
70
  selection: d3.Selection<SVGGElement, any, any, any>,
71
- yAxisClassName: string
72
71
  textClassName: string
73
72
  fullParams: BaseValueAxisParams
74
- tickTextAlign: TextAlign
75
73
  axisLabelAlign: TextAlign
76
74
  gridAxesSize: { width: number, height: number }
77
75
  fullDataFormatter: DataFormatterGrid,
78
76
  fullChartParams: ChartParams
79
- valueScale: d3.ScaleLinear<number, number>
80
- textTransform: string,
81
- minAndMax: [number, number]
77
+ textReverseTransform: string,
82
78
  }) {
83
-
84
- const yAxisSelection = selection
85
- .selectAll<SVGGElement, BaseValueAxisParams>(`g.${yAxisClassName}`)
86
- .data([fullParams])
87
- .join('g')
88
- .classed(yAxisClassName, true)
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
+ }
89
115
 
90
116
  const axisLabelSelection = selection
91
117
  .selectAll<SVGGElement, BaseValueAxisParams>(`g.${textClassName}`)
@@ -109,10 +135,36 @@ function renderAxis ({ selection, yAxisClassName, textClassName, fullParams, tic
109
135
  .attr('dominant-baseline', axisLabelAlign.dominantBaseline)
110
136
  .attr('font-size', fullChartParams.styles.textSize)
111
137
  .style('fill', getColor(fullParams.labelColorType, fullChartParams))
112
- // .style('transform', textTransform)
138
+ .style('transform', textReverseTransform)
139
+ // 偏移使用 x, y 而非 transform 才不會受到外層 scale 變形影響
140
+ .attr('x', labelX)
141
+ .attr('y', labelY)
113
142
  .text(d => fullDataFormatter.grid.valueAxis.label)
114
143
  })
115
- .attr('transform', d => `translate(${- d.tickPadding + fullParams.labelOffset[0]}, ${gridAxesSize.height + d.tickPadding + fullParams.labelOffset[1]})`)
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)
116
168
 
117
169
  const valueLength = minAndMax[1] - minAndMax[0]
118
170
 
@@ -120,6 +172,23 @@ function renderAxis ({ selection, yAxisClassName, textClassName, fullParams, tic
120
172
  // .domain([0, 150])
121
173
  // .range([416.5, 791.349])
122
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
+
123
192
  // 設定Y軸刻度
124
193
  const yAxis = d3.axisLeft(valueScale)
125
194
  .scale(valueScale)
@@ -132,7 +201,7 @@ function renderAxis ({ selection, yAxisClassName, textClassName, fullParams, tic
132
201
  .tickSize(fullParams.tickFullLine == true
133
202
  ? -gridAxesSize.width
134
203
  : defaultTickSize)
135
- .tickPadding(fullParams.tickPadding)
204
+ .tickPadding(tickPadding)
136
205
 
137
206
  const yAxisEl = yAxisSelection
138
207
  .transition()
@@ -158,8 +227,14 @@ function renderAxis ({ selection, yAxisClassName, textClassName, fullParams, tic
158
227
  .style('color', getColor(fullParams.tickTextColorType, fullChartParams))
159
228
  .attr('text-anchor', tickTextAlign.textAnchor)
160
229
  .attr('dominant-baseline', tickTextAlign.dominantBaseline)
161
- .attr('transform-origin', `-${fullParams.tickPadding + defaultTickSize} 0`)
162
- yText.style('transform', textTransform)
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
+ }
163
238
 
164
239
  return yAxisSelection
165
240
  }
@@ -263,7 +338,7 @@ export const createBaseValueAxis: BasePluginFn<BaseLinesContext> = (pluginName:
263
338
  // layout$
264
339
  // })
265
340
 
266
- // const textTransform$: Observable<string> = new Observable(subscriber => {
341
+ // const textReverseTransform$: Observable<string> = new Observable(subscriber => {
267
342
  // combineLatest({
268
343
  // fullParams: fullParams$,
269
344
  // layout: layout$
@@ -304,31 +379,35 @@ export const createBaseValueAxis: BasePluginFn<BaseLinesContext> = (pluginName:
304
379
  // }
305
380
  // }),
306
381
  // )
307
- const textTransform$ = combineLatest({
308
- fullParams: fullParams$,
309
- fullDataFormatter: fullDataFormatter$,
382
+ const textReverseTransform$ = combineLatest({
310
383
  gridAxesReverseTransform: gridAxesReverseTransform$,
311
384
  gridContainerPosition: gridContainerPosition$
312
385
  }).pipe(
313
386
  takeUntil(destroy$),
314
387
  switchMap(async (d) => d),
315
388
  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}`
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}`
328
395
  }),
329
396
  distinctUntilChanged()
330
397
  )
331
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
+
332
411
  const minAndMax$: Observable<[number, number]> = new Observable(subscriber => {
333
412
  combineLatest({
334
413
  fullDataFormatter: fullDataFormatter$,
@@ -383,23 +462,31 @@ export const createBaseValueAxis: BasePluginFn<BaseLinesContext> = (pluginName:
383
462
  })
384
463
  })
385
464
 
386
- const tickTextAlign$: Observable<TextAlign> = fullDataFormatter$.pipe(
465
+ const tickTextAlign$: Observable<TextAlign> = combineLatest({
466
+ fullDataFormatter: fullDataFormatter$,
467
+ fullParams: fullParams$
468
+ }).pipe(
387
469
  takeUntil(destroy$),
388
- map(d => {
470
+ switchMap(async (d) => d),
471
+ map(data => {
389
472
  let textAnchor: 'start' | 'middle' | 'end' = 'start'
390
473
  let dominantBaseline: 'auto' | 'middle' | 'hanging' = 'hanging'
391
474
 
392
- if (d.grid.valueAxis.position === 'left') {
475
+ if (data.fullDataFormatter.grid.valueAxis.position === 'left') {
393
476
  textAnchor = 'end'
394
477
  dominantBaseline = 'middle'
395
- } else if (d.grid.valueAxis.position === 'right') {
478
+ } else if (data.fullDataFormatter.grid.valueAxis.position === 'right') {
396
479
  textAnchor = 'start'
397
480
  dominantBaseline = 'middle'
398
- } else if (d.grid.valueAxis.position === 'bottom') {
399
- textAnchor = 'middle'
481
+ } else if (data.fullDataFormatter.grid.valueAxis.position === 'bottom') {
482
+ textAnchor = data.fullParams.tickTextRotate
483
+ ? 'end'
484
+ : 'middle'
400
485
  dominantBaseline = 'hanging'
401
- } else if (d.grid.valueAxis.position === 'top') {
402
- textAnchor = 'middle'
486
+ } else if (data.fullDataFormatter.grid.valueAxis.position === 'top') {
487
+ textAnchor = data.fullParams.tickTextRotate
488
+ ? 'start'
489
+ : 'middle'
403
490
  dominantBaseline = 'auto'
404
491
  }
405
492
  return {
@@ -451,7 +538,8 @@ export const createBaseValueAxis: BasePluginFn<BaseLinesContext> = (pluginName:
451
538
  fullDataFormatter: fullDataFormatter$,
452
539
  fullChartParams: fullChartParams$,
453
540
  valueScale: valueScale$,
454
- textTransform: textTransform$,
541
+ textReverseTransform: textReverseTransform$,
542
+ textReverseTransformWithRotate: textReverseTransformWithRotate$,
455
543
  minAndMax: minAndMax$
456
544
  }).pipe(
457
545
  takeUntil(destroy$),
@@ -461,17 +549,26 @@ export const createBaseValueAxis: BasePluginFn<BaseLinesContext> = (pluginName:
461
549
  renderAxis({
462
550
  selection: data.axisSelection,
463
551
  yAxisClassName,
464
- textClassName,
465
552
  fullParams: data.fullParams,
466
553
  tickTextAlign: data.tickTextAlign,
467
- axisLabelAlign: data.axisLabelAlign,
468
554
  gridAxesSize: data.gridAxesSize,
469
555
  fullDataFormatter: data.fullDataFormatter,
470
556
  fullChartParams: data.fullChartParams,
471
557
  valueScale: data.valueScale,
472
- textTransform: data.textTransform,
558
+ textReverseTransformWithRotate: data.textReverseTransformWithRotate,
473
559
  minAndMax: data.minAndMax
474
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
+ })
475
572
  })
476
573
 
477
574
  return () => {
@@ -39,7 +39,7 @@ export const DEFAULT_GROUP_AREA_PARAMS: GroupAuxParams = {
39
39
  labelColorType: 'primary',
40
40
  labelTextColorType: 'background',
41
41
  labelTextFormat: text => text,
42
- labelPadding: 24,
42
+ labelPadding: 20,
43
43
  labelRotate: 0
44
44
  }
45
45
  DEFAULT_GROUP_AREA_PARAMS.labelTextFormat.toString = () => `text => text`