@orbcharts/plugins-basic 3.0.0-alpha.62 → 3.0.0-alpha.64
Sign up to get free protection for your applications and to get access to all the features.
- package/dist/orbcharts-plugins-basic.es.js +6117 -6067
- package/dist/orbcharts-plugins-basic.umd.js +10 -10
- package/package.json +2 -2
- package/src/base/BaseGroupAxis.ts +141 -62
- package/src/base/BaseLegend.ts +1 -0
- package/src/base/BaseValueAxis.ts +142 -45
- package/src/grid/defaults.ts +1 -1
- package/src/grid/plugins/GroupAux.ts +31 -28
- package/src/multiGrid/plugins/OverlappingValueAxes.ts +3 -0
- package/src/multiGrid/plugins/OverlappingValueStackAxes.ts +1 -0
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@orbcharts/plugins-basic",
|
3
|
-
"version": "3.0.0-alpha.
|
3
|
+
"version": "3.0.0-alpha.64",
|
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.
|
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
|
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
|
-
|
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
|
-
|
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
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
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([
|
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(
|
118
|
-
|
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
|
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
|
-
|
128
|
-
const xAxis = d3.axisTop(groupScale)
|
191
|
+
const xAxis = d3.axisBottom(groupScale)
|
129
192
|
.scale(groupScale)
|
130
|
-
.ticks(
|
193
|
+
.ticks(fullParams.ticks === 'all'
|
131
194
|
? allTicksAmount
|
132
|
-
:
|
195
|
+
: fullParams.ticks > allTicksAmount
|
133
196
|
? allTicksAmount // 不顯示超過groupLabels數量的刻度
|
134
|
-
:
|
135
|
-
.tickSize(
|
136
|
-
?
|
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,
|
205
|
+
return parseTickFormatValue(groupLabel, fullParams.tickFormat)
|
143
206
|
})
|
144
|
-
.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',
|
156
|
-
.style('stroke-dasharray',
|
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',
|
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',
|
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(
|
246
|
+
.style('color', getColor(fullParams.tickTextColorType, chartParams))
|
184
247
|
.attr('text-anchor', tickTextAlign.textAnchor)
|
185
248
|
.attr('dominant-baseline', tickTextAlign.dominantBaseline)
|
186
|
-
.attr('
|
187
|
-
.style('transform',
|
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
|
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
|
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
|
352
|
-
const
|
353
|
-
const
|
354
|
-
|
355
|
-
|
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
|
-
? '
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
552
|
-
|
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
|
|
package/src/base/BaseLegend.ts
CHANGED
@@ -66,26 +66,52 @@ interface TextAlign {
|
|
66
66
|
// const textClassName = getClassName(pluginName, 'text')
|
67
67
|
const defaultTickSize = 6
|
68
68
|
|
69
|
-
function
|
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
|
-
|
80
|
-
textTransform: string,
|
81
|
-
minAndMax: [number, number]
|
77
|
+
textReverseTransform: string,
|
82
78
|
}) {
|
83
|
-
|
84
|
-
const
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
.
|
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
|
-
|
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(
|
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(
|
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('
|
162
|
-
|
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
|
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
|
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
|
318
|
-
const
|
319
|
-
const
|
320
|
-
|
321
|
-
|
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> =
|
465
|
+
const tickTextAlign$: Observable<TextAlign> = combineLatest({
|
466
|
+
fullDataFormatter: fullDataFormatter$,
|
467
|
+
fullParams: fullParams$
|
468
|
+
}).pipe(
|
387
469
|
takeUntil(destroy$),
|
388
|
-
|
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 (
|
475
|
+
if (data.fullDataFormatter.grid.valueAxis.position === 'left') {
|
393
476
|
textAnchor = 'end'
|
394
477
|
dominantBaseline = 'middle'
|
395
|
-
} else if (
|
478
|
+
} else if (data.fullDataFormatter.grid.valueAxis.position === 'right') {
|
396
479
|
textAnchor = 'start'
|
397
480
|
dominantBaseline = 'middle'
|
398
|
-
} else if (
|
399
|
-
textAnchor =
|
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 (
|
402
|
-
textAnchor =
|
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
|
-
|
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
|
-
|
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 () => {
|
package/src/grid/defaults.ts
CHANGED
@@ -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:
|
42
|
+
labelPadding: 20,
|
43
43
|
labelRotate: 0
|
44
44
|
}
|
45
45
|
DEFAULT_GROUP_AREA_PARAMS.labelTextFormat.toString = () => `text => text`
|