@orbcharts/plugins-basic 3.0.0-alpha.24
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +201 -0
- package/package.json +41 -0
- package/src/grid/defaults.ts +95 -0
- package/src/grid/gridObservables.ts +114 -0
- package/src/grid/index.ts +12 -0
- package/src/grid/plugins/BarStack.ts +661 -0
- package/src/grid/plugins/Bars.ts +604 -0
- package/src/grid/plugins/BarsTriangle.ts +594 -0
- package/src/grid/plugins/Dots.ts +427 -0
- package/src/grid/plugins/GroupArea.ts +636 -0
- package/src/grid/plugins/GroupAxis.ts +363 -0
- package/src/grid/plugins/Lines.ts +528 -0
- package/src/grid/plugins/Ranking.ts +0 -0
- package/src/grid/plugins/RankingAxis.ts +0 -0
- package/src/grid/plugins/ScalingArea.ts +168 -0
- package/src/grid/plugins/ValueAxis.ts +356 -0
- package/src/grid/plugins/ValueStackAxis.ts +372 -0
- package/src/grid/types.ts +102 -0
- package/src/index.ts +7 -0
- package/src/multiGrid/index.ts +0 -0
- package/src/multiGrid/plugins/Diverging.ts +0 -0
- package/src/multiGrid/plugins/DivergingAxes.ts +0 -0
- package/src/multiGrid/plugins/TwoScaleAxes.ts +0 -0
- package/src/multiGrid/plugins/TwoScales.ts +0 -0
- package/src/multiValue/index.ts +0 -0
- package/src/multiValue/plugins/Scatter.ts +0 -0
- package/src/multiValue/plugins/ScatterAxes.ts +0 -0
- package/src/noneData/defaults.ts +47 -0
- package/src/noneData/index.ts +4 -0
- package/src/noneData/plugins/Container.ts +11 -0
- package/src/noneData/plugins/Tooltip.ts +305 -0
- package/src/noneData/types.ts +26 -0
- package/src/relationship/index.ts +0 -0
- package/src/relationship/plugins/Relationship.ts +0 -0
- package/src/series/defaults.ts +82 -0
- package/src/series/index.ts +6 -0
- package/src/series/plugins/Bubbles.ts +553 -0
- package/src/series/plugins/Pie.ts +603 -0
- package/src/series/plugins/PieEventTexts.ts +194 -0
- package/src/series/plugins/PieLabels.ts +289 -0
- package/src/series/plugins/Waffle.ts +0 -0
- package/src/series/seriesUtils.ts +51 -0
- package/src/series/types.ts +53 -0
- package/src/tree/index.ts +0 -0
- package/src/tree/plugins/TreeMap.ts +0 -0
- package/src/utils/commonUtils.ts +22 -0
- package/src/utils/d3Graphics.ts +125 -0
- package/src/utils/d3Utils.ts +73 -0
- package/src/utils/observables.ts +14 -0
- package/src/utils/orbchartsUtils.ts +70 -0
- package/tsconfig.json +14 -0
- package/vite.config.js +45 -0
@@ -0,0 +1,661 @@
|
|
1
|
+
import * as d3 from 'd3'
|
2
|
+
import {
|
3
|
+
combineLatest,
|
4
|
+
switchMap,
|
5
|
+
map,
|
6
|
+
first,
|
7
|
+
takeUntil,
|
8
|
+
distinctUntilChanged,
|
9
|
+
Subject,
|
10
|
+
Observable } from 'rxjs'
|
11
|
+
// import type { Subject } from 'rxjs'
|
12
|
+
import { defineGridPlugin } from '@orbcharts/core'
|
13
|
+
import type {
|
14
|
+
ComputedDataGrid,
|
15
|
+
ComputedDatumGrid,
|
16
|
+
EventSeries,
|
17
|
+
ChartParams,
|
18
|
+
DataSeriesDatum,
|
19
|
+
Layout } from '@orbcharts/core'
|
20
|
+
import type { BarStackPluginParams } from '../types'
|
21
|
+
import { DEFAULT_BAR_STACK_PLUGIN_PARAMS } from '../defaults'
|
22
|
+
import { getD3TransitionEase } from '../../utils/d3Utils'
|
23
|
+
import { getClassName, getUniID } from '../../utils/orbchartsUtils'
|
24
|
+
|
25
|
+
interface GraphicDatum extends ComputedDatumGrid {
|
26
|
+
_barStartY: number // bar的起點y座標
|
27
|
+
_barHeight: number // bar的高度
|
28
|
+
}
|
29
|
+
|
30
|
+
interface RenderBarParams {
|
31
|
+
selection: d3.Selection<SVGGElement, unknown, any, any>
|
32
|
+
data: GraphicDatum[][]
|
33
|
+
zeroY: number
|
34
|
+
groupLabels: string[]
|
35
|
+
// barScale: d3.ScalePoint<string>
|
36
|
+
params: BarStackPluginParams
|
37
|
+
chartParams: ChartParams
|
38
|
+
barWidth: number
|
39
|
+
transformedBarRadius: [number, number]
|
40
|
+
delayGroup: number
|
41
|
+
transitionItem: number
|
42
|
+
}
|
43
|
+
|
44
|
+
type ClipPathDatum = {
|
45
|
+
id: string;
|
46
|
+
// x: number;
|
47
|
+
// y: number;
|
48
|
+
width: number;
|
49
|
+
height: number;
|
50
|
+
}
|
51
|
+
|
52
|
+
const pluginName = 'BarStack'
|
53
|
+
const gClassName = getClassName(pluginName, 'g')
|
54
|
+
const gContentClassName = getClassName(pluginName, 'g-content')
|
55
|
+
// group的delay在動畫中的佔比(剩餘部份的時間為圖形本身的動畫時間,因為delay時間和最後一個group的動畫時間加總為1)
|
56
|
+
const groupDelayProportionOfDuration = 0.3
|
57
|
+
|
58
|
+
function calcBarWidth ({ axisWidth, groupAmount, barGroupPadding = 0 }: {
|
59
|
+
axisWidth: number
|
60
|
+
groupAmount: number
|
61
|
+
barGroupPadding: number
|
62
|
+
}) {
|
63
|
+
const eachGroupWidth = axisWidth / (groupAmount - 1)
|
64
|
+
const width = eachGroupWidth - barGroupPadding
|
65
|
+
return width > 1 ? width : 1
|
66
|
+
|
67
|
+
}
|
68
|
+
|
69
|
+
// function makeBarScale (barWidth: number, seriesLabels: string[], params: BarStackPluginParams) {
|
70
|
+
// const barHalfWidth = barWidth! / 2
|
71
|
+
// const barGroupWidth = barWidth * seriesLabels.length + params.barPadding! * seriesLabels.length
|
72
|
+
// return d3.scalePoint()
|
73
|
+
// .domain(seriesLabels)
|
74
|
+
// .range([-barGroupWidth / 2 + barHalfWidth, barGroupWidth / 2 - barHalfWidth])
|
75
|
+
// }
|
76
|
+
|
77
|
+
function calcDelayGroup (barGroupAmount: number, totalDuration: number) {
|
78
|
+
if (barGroupAmount <= 1) {
|
79
|
+
// 一筆內計算會出錯所以不算
|
80
|
+
return 0
|
81
|
+
}
|
82
|
+
return totalDuration / (barGroupAmount - 1) * groupDelayProportionOfDuration // 依group數量計算
|
83
|
+
}
|
84
|
+
|
85
|
+
function calctransitionItem (barGroupAmount: number, totalDuration: number) {
|
86
|
+
if (barGroupAmount <= 1) {
|
87
|
+
// 一筆內不會有delay
|
88
|
+
return totalDuration
|
89
|
+
}
|
90
|
+
return totalDuration * (1 - groupDelayProportionOfDuration) // delay後剩餘的時間
|
91
|
+
}
|
92
|
+
|
93
|
+
function renderRectBars ({ selection, data, zeroY, groupLabels, params, chartParams, barWidth, transformedBarRadius, delayGroup, transitionItem }: RenderBarParams) {
|
94
|
+
|
95
|
+
const barHalfWidth = barWidth! / 2
|
96
|
+
|
97
|
+
const barGroup = selection
|
98
|
+
.selectAll<SVGGElement, ComputedDatumGrid[]>(`g.${gClassName}`)
|
99
|
+
.data(data, (d, i) => groupLabels[i])
|
100
|
+
.join(
|
101
|
+
enter => {
|
102
|
+
return enter
|
103
|
+
.append('g')
|
104
|
+
.classed(gClassName, true)
|
105
|
+
.attr('cursor', 'pointer')
|
106
|
+
},
|
107
|
+
update => update,
|
108
|
+
exit => exit.remove()
|
109
|
+
)
|
110
|
+
.attr('transform', (d, i) => `translate(${d[0] ? d[0].axisX : 0}, ${0})`)
|
111
|
+
.each((d, i, g) => {
|
112
|
+
const bars = d3.select(g[i])
|
113
|
+
.selectAll<SVGGElement, ComputedDatumGrid>('g')
|
114
|
+
.data(d, _d => _d.id)
|
115
|
+
.join(
|
116
|
+
enter => {
|
117
|
+
return enter
|
118
|
+
.append('g')
|
119
|
+
.classed(gContentClassName, true)
|
120
|
+
},
|
121
|
+
update => update,
|
122
|
+
exit => exit.remove()
|
123
|
+
)
|
124
|
+
.each((_d, _i, _g) => {
|
125
|
+
const rect = d3.select(_g[_i])
|
126
|
+
.selectAll<SVGRectElement, ComputedDatumGrid>('rect')
|
127
|
+
.data([_d], _d => _d.id)
|
128
|
+
.join(
|
129
|
+
enter => {
|
130
|
+
return enter
|
131
|
+
.append('rect')
|
132
|
+
.attr('y', d => zeroY)
|
133
|
+
.attr('height', d => 0)
|
134
|
+
},
|
135
|
+
update => update,
|
136
|
+
exit => exit.remove()
|
137
|
+
)
|
138
|
+
.attr('rx', transformedBarRadius[0])
|
139
|
+
.attr('ry', transformedBarRadius[1])
|
140
|
+
.attr('fill', d => d.color)
|
141
|
+
.attr('transform', `translate(${-barHalfWidth}, 0)`)
|
142
|
+
.attr('x', d => 0)
|
143
|
+
.attr('width', barWidth!)
|
144
|
+
.transition()
|
145
|
+
.duration(transitionItem)
|
146
|
+
.ease(getD3TransitionEase(chartParams.transitionEase))
|
147
|
+
.delay((d, i) => d.groupIndex * delayGroup)
|
148
|
+
.attr('y', d => d._barStartY)
|
149
|
+
.attr('height', d => Math.abs(d._barHeight))
|
150
|
+
})
|
151
|
+
|
152
|
+
})
|
153
|
+
|
154
|
+
const graphicBarSelection: d3.Selection<SVGRectElement, ComputedDatumGrid, SVGGElement, unknown> = barGroup.selectAll(`g.${gContentClassName}`)
|
155
|
+
|
156
|
+
|
157
|
+
return graphicBarSelection
|
158
|
+
}
|
159
|
+
|
160
|
+
function renderClipPath ({ defsSelection, clipPathData }: {
|
161
|
+
defsSelection: d3.Selection<SVGDefsElement, any, any, any>
|
162
|
+
clipPathData: ClipPathDatum[]
|
163
|
+
}) {
|
164
|
+
const clipPath = defsSelection
|
165
|
+
.selectAll<SVGClipPathElement, Layout>('clipPath')
|
166
|
+
.data(clipPathData)
|
167
|
+
.join(
|
168
|
+
enter => {
|
169
|
+
return enter
|
170
|
+
.append('clipPath')
|
171
|
+
},
|
172
|
+
update => update,
|
173
|
+
exit => exit.remove()
|
174
|
+
)
|
175
|
+
.attr('id', d => d.id)
|
176
|
+
.each((d, i, g) => {
|
177
|
+
const rect = d3.select(g[i])
|
178
|
+
.selectAll<SVGRectElement, typeof d>('rect')
|
179
|
+
.data([d])
|
180
|
+
.join(
|
181
|
+
enter => {
|
182
|
+
return enter
|
183
|
+
.append('rect')
|
184
|
+
},
|
185
|
+
update => update,
|
186
|
+
exit => exit.remove()
|
187
|
+
)
|
188
|
+
.attr('x', 0)
|
189
|
+
.attr('y', 0)
|
190
|
+
.attr('width', _d => _d.width)
|
191
|
+
.attr('height', _d => _d.height)
|
192
|
+
})
|
193
|
+
}
|
194
|
+
|
195
|
+
function highlight ({ selection, ids, fullChartParams }: {
|
196
|
+
selection: d3.Selection<any, ComputedDatumGrid, any, any>
|
197
|
+
ids: string[]
|
198
|
+
fullChartParams: ChartParams
|
199
|
+
}) {
|
200
|
+
selection.interrupt('highlight')
|
201
|
+
|
202
|
+
if (!ids.length) {
|
203
|
+
// remove highlight
|
204
|
+
selection
|
205
|
+
.transition('highlight')
|
206
|
+
.duration(200)
|
207
|
+
.style('opacity', 1)
|
208
|
+
return
|
209
|
+
}
|
210
|
+
|
211
|
+
selection
|
212
|
+
.each((d, i, n) => {
|
213
|
+
if (ids.includes(d.id)) {
|
214
|
+
d3.select(n[i])
|
215
|
+
.style('opacity', 1)
|
216
|
+
} else {
|
217
|
+
d3.select(n[i])
|
218
|
+
.style('opacity', fullChartParams.styles.unhighlightedOpacity)
|
219
|
+
}
|
220
|
+
})
|
221
|
+
}
|
222
|
+
|
223
|
+
|
224
|
+
export const BarStack = defineGridPlugin(pluginName, DEFAULT_BAR_STACK_PLUGIN_PARAMS)(({ selection, name, subject, observer }) => {
|
225
|
+
const destroy$ = new Subject()
|
226
|
+
|
227
|
+
const clipPathID = getUniID(pluginName, 'clipPath-box')
|
228
|
+
|
229
|
+
const axisSelection: d3.Selection<SVGGElement, any, any, any> = selection
|
230
|
+
.append('g')
|
231
|
+
.attr('clip-path', `url(#${clipPathID})`)
|
232
|
+
const defsSelection: d3.Selection<SVGDefsElement, ComputedDatumGrid, any, any> = axisSelection.append('defs')
|
233
|
+
const graphicGSelection: d3.Selection<SVGGElement, any, any, any> = axisSelection.append('g')
|
234
|
+
const barSelection$: Subject<d3.Selection<SVGRectElement, ComputedDatumGrid, SVGGElement, unknown>> = new Subject()
|
235
|
+
|
236
|
+
observer.gridAxesTransform$
|
237
|
+
.pipe(
|
238
|
+
takeUntil(destroy$),
|
239
|
+
map(d => d.value),
|
240
|
+
distinctUntilChanged()
|
241
|
+
).subscribe(d => {
|
242
|
+
axisSelection
|
243
|
+
.style('transform', d)
|
244
|
+
})
|
245
|
+
|
246
|
+
observer.gridGraphicTransform$
|
247
|
+
.pipe(
|
248
|
+
takeUntil(destroy$),
|
249
|
+
switchMap(async d => d.value),
|
250
|
+
distinctUntilChanged()
|
251
|
+
).subscribe(d => {
|
252
|
+
graphicGSelection
|
253
|
+
.transition()
|
254
|
+
.duration(50)
|
255
|
+
.style('transform', d)
|
256
|
+
})
|
257
|
+
|
258
|
+
// const axisSize$ = gridAxisSizeObservable({
|
259
|
+
// dataFormatter$,
|
260
|
+
// observer.layout$
|
261
|
+
// })
|
262
|
+
|
263
|
+
// const visibleComputedData$ = observer.computedData$.pipe(
|
264
|
+
// takeUntil(destroy$),
|
265
|
+
// map(data => {
|
266
|
+
// const visibleComputedData = data
|
267
|
+
// .map(d => {
|
268
|
+
// return d.filter(_d => {
|
269
|
+
// return _d.visible == true
|
270
|
+
// })
|
271
|
+
// })
|
272
|
+
// .filter(d => d.length)
|
273
|
+
// // console.log('visibleComputedData', visibleComputedData)
|
274
|
+
// return visibleComputedData
|
275
|
+
// })
|
276
|
+
// )
|
277
|
+
|
278
|
+
const zeroY$ = observer.visibleComputedData$.pipe(
|
279
|
+
map(d => d[0] && d[0][0]
|
280
|
+
? d[0][0].axisY - d[0][0].axisYFromZero
|
281
|
+
: 0),
|
282
|
+
distinctUntilChanged()
|
283
|
+
)
|
284
|
+
|
285
|
+
const barWidth$ = new Observable<number>(subscriber => {
|
286
|
+
combineLatest({
|
287
|
+
computedData: observer.computedData$,
|
288
|
+
// visibleComputedData: observer.visibleComputedData$,
|
289
|
+
params: observer.fullParams$,
|
290
|
+
axisSize: observer.gridAxesSize$
|
291
|
+
}).pipe(
|
292
|
+
switchMap(async d => d)
|
293
|
+
).subscribe(data => {
|
294
|
+
const barWidth = data.params.barWidth
|
295
|
+
? data.params.barWidth
|
296
|
+
: calcBarWidth({
|
297
|
+
axisWidth: data.axisSize.width,
|
298
|
+
groupAmount: data.computedData[0] ? data.computedData[0].length : 0,
|
299
|
+
barGroupPadding: data.params.barGroupPadding
|
300
|
+
})
|
301
|
+
subscriber.next(barWidth)
|
302
|
+
})
|
303
|
+
}).pipe(
|
304
|
+
takeUntil(destroy$),
|
305
|
+
distinctUntilChanged()
|
306
|
+
)
|
307
|
+
|
308
|
+
// 圓角的值 [rx, ry]
|
309
|
+
const transformedBarRadius$: Observable<[number, number]> = combineLatest({
|
310
|
+
gridGraphicTransform: observer.gridGraphicTransform$,
|
311
|
+
barWidth: barWidth$,
|
312
|
+
params: observer.fullParams$
|
313
|
+
}).pipe(
|
314
|
+
takeUntil(destroy$),
|
315
|
+
switchMap(async data => data),
|
316
|
+
map(data => {
|
317
|
+
const barHalfWidth = data.barWidth! / 2
|
318
|
+
const radius = data.params.barRadius === true ? barHalfWidth
|
319
|
+
: data.params.barRadius === false ? 0
|
320
|
+
: typeof data.params.barRadius == 'number' ? data.params.barRadius
|
321
|
+
: 0
|
322
|
+
const transformedRx = radius == 0
|
323
|
+
? 0
|
324
|
+
: radius / data.gridGraphicTransform.scale[0] // 反向外層scale的變型
|
325
|
+
const transformedRy = radius == 0
|
326
|
+
? 0
|
327
|
+
: radius / data.gridGraphicTransform.scale[1]
|
328
|
+
return [transformedRx, transformedRy]
|
329
|
+
})
|
330
|
+
)
|
331
|
+
|
332
|
+
// const seriesLabels$ = observer.visibleComputedData$.pipe(
|
333
|
+
// takeUntil(destroy$),
|
334
|
+
// map(data => {
|
335
|
+
// const SeriesLabelSet: Set<string> = new Set()
|
336
|
+
// data.forEach(d => {
|
337
|
+
// d.forEach(_d => {
|
338
|
+
// SeriesLabelSet.add(_d.seriesLabel)
|
339
|
+
// })
|
340
|
+
// })
|
341
|
+
// return Array.from(SeriesLabelSet)
|
342
|
+
// })
|
343
|
+
// )
|
344
|
+
|
345
|
+
const groupLabels$ = observer.visibleComputedData$.pipe(
|
346
|
+
takeUntil(destroy$),
|
347
|
+
map(data => {
|
348
|
+
const GroupLabelSet: Set<string> = new Set()
|
349
|
+
data.forEach(d => {
|
350
|
+
d.forEach(_d => {
|
351
|
+
GroupLabelSet.add(_d.groupLabel)
|
352
|
+
})
|
353
|
+
})
|
354
|
+
return Array.from(GroupLabelSet)
|
355
|
+
})
|
356
|
+
)
|
357
|
+
|
358
|
+
// const barScale$: Observable<d3.ScalePoint<string>> = new Observable(subscriber => {
|
359
|
+
// combineLatest({
|
360
|
+
// seriesLabels: seriesLabels$,
|
361
|
+
// barWidth: barWidth$,
|
362
|
+
// params: observer.fullParams$,
|
363
|
+
// }).pipe(
|
364
|
+
// takeUntil(destroy$),
|
365
|
+
// switchMap(async d => d)
|
366
|
+
// ).subscribe(data => {
|
367
|
+
// const barScale = makeBarScale(data.barWidth, data.seriesLabels, data.params)
|
368
|
+
// subscriber.next(barScale)
|
369
|
+
// })
|
370
|
+
// })
|
371
|
+
|
372
|
+
const transitionDuration$ = observer.fullChartParams$.pipe(
|
373
|
+
takeUntil(destroy$),
|
374
|
+
map(d => d.transitionDuration),
|
375
|
+
distinctUntilChanged()
|
376
|
+
)
|
377
|
+
|
378
|
+
const delayGroup$ = new Observable<number>(subscriber => {
|
379
|
+
combineLatest({
|
380
|
+
groupLabels: groupLabels$,
|
381
|
+
transitionDuration: transitionDuration$,
|
382
|
+
}).pipe(
|
383
|
+
switchMap(async d => d)
|
384
|
+
).subscribe(data => {
|
385
|
+
const delay = calcDelayGroup(data.groupLabels.length, data.transitionDuration)
|
386
|
+
subscriber.next(delay)
|
387
|
+
})
|
388
|
+
}).pipe(
|
389
|
+
takeUntil(destroy$),
|
390
|
+
distinctUntilChanged()
|
391
|
+
)
|
392
|
+
|
393
|
+
const transitionItem$ = new Observable<number>(subscriber => {
|
394
|
+
combineLatest({
|
395
|
+
groupLabels: groupLabels$,
|
396
|
+
transitionDuration: transitionDuration$
|
397
|
+
}).pipe(
|
398
|
+
switchMap(async d => d)
|
399
|
+
).subscribe(data => {
|
400
|
+
const transition = calctransitionItem(data.groupLabels.length, data.transitionDuration)
|
401
|
+
subscriber.next(transition)
|
402
|
+
})
|
403
|
+
}).pipe(
|
404
|
+
takeUntil(destroy$),
|
405
|
+
distinctUntilChanged()
|
406
|
+
)
|
407
|
+
|
408
|
+
const transposedVisibleData$: Observable<ComputedDataGrid> = observer.visibleComputedData$.pipe(
|
409
|
+
takeUntil(destroy$),
|
410
|
+
map(data => {
|
411
|
+
console.log('visibleComputedData', data)
|
412
|
+
// 取得原始陣列的維度
|
413
|
+
const rows = data.length;
|
414
|
+
const cols = data.reduce((prev, current) => {
|
415
|
+
return Math.max(prev, current.length)
|
416
|
+
}, 0)
|
417
|
+
|
418
|
+
// 初始化轉換後的陣列
|
419
|
+
const transposedArray = new Array(cols).fill(null).map(() => new Array(rows).fill(null))
|
420
|
+
|
421
|
+
// 遍歷原始陣列,進行轉換
|
422
|
+
for (let i = 0; i < rows; i++) {
|
423
|
+
for (let j = 0; j < cols; j++) {
|
424
|
+
transposedArray[j][i] = data[i][j]
|
425
|
+
}
|
426
|
+
}
|
427
|
+
return transposedArray
|
428
|
+
})
|
429
|
+
)
|
430
|
+
|
431
|
+
const yRatio$ = combineLatest({
|
432
|
+
transposedVisibleData: transposedVisibleData$,
|
433
|
+
dataFormatter: observer.fullDataFormatter$,
|
434
|
+
}).pipe(
|
435
|
+
takeUntil(destroy$),
|
436
|
+
switchMap(async d => d),
|
437
|
+
map(data => {
|
438
|
+
const groupMin = 0
|
439
|
+
const groupMax = data.transposedVisibleData.length - 1
|
440
|
+
const groupScaleDomainMin = data.dataFormatter.groupAxis.scaleDomain[0] === 'auto'
|
441
|
+
? groupMin - data.dataFormatter.groupAxis.scalePadding
|
442
|
+
: data.dataFormatter.groupAxis.scaleDomain[0] as number - data.dataFormatter.groupAxis.scalePadding
|
443
|
+
const groupScaleDomainMax = data.dataFormatter.groupAxis.scaleDomain[1] === 'auto'
|
444
|
+
? groupMax + data.dataFormatter.groupAxis.scalePadding
|
445
|
+
: data.dataFormatter.groupAxis.scaleDomain[1] as number + data.dataFormatter.groupAxis.scalePadding
|
446
|
+
|
447
|
+
const filteredData = data.transposedVisibleData
|
448
|
+
.map(d => {
|
449
|
+
return d.filter((_d, i) => {
|
450
|
+
return _d.groupIndex >= groupScaleDomainMin && _d.groupIndex <= groupScaleDomainMax
|
451
|
+
})
|
452
|
+
})
|
453
|
+
// console.log('filteredData', filteredData)
|
454
|
+
|
455
|
+
if (!filteredData.flat().length) {
|
456
|
+
return 1
|
457
|
+
} else {
|
458
|
+
const yArr = filteredData.flat().map(d => d.axisYFromZero)
|
459
|
+
const barMaxY = Math.max(...yArr)
|
460
|
+
const stackYArr = filteredData.map(d => d.reduce((prev, current) => prev + current.axisYFromZero, 0))
|
461
|
+
const barStackMaxY = Math.max(...stackYArr)
|
462
|
+
|
463
|
+
return barMaxY / barStackMaxY
|
464
|
+
}
|
465
|
+
})
|
466
|
+
)
|
467
|
+
|
468
|
+
const graphicData$ = combineLatest({
|
469
|
+
transposedVisibleData: transposedVisibleData$,
|
470
|
+
yRatio: yRatio$,
|
471
|
+
zeroY: zeroY$
|
472
|
+
}).pipe(
|
473
|
+
takeUntil(destroy$),
|
474
|
+
map(data => {
|
475
|
+
console.log(data.transposedVisibleData)
|
476
|
+
return data.transposedVisibleData.map(d => {
|
477
|
+
let accY = data.zeroY
|
478
|
+
return d.map(_d => {
|
479
|
+
const _barStartY = accY
|
480
|
+
const _barHeight = _d.axisYFromZero * data.yRatio
|
481
|
+
accY = accY + _barHeight
|
482
|
+
return <GraphicDatum>{
|
483
|
+
..._d,
|
484
|
+
_barStartY,
|
485
|
+
_barHeight
|
486
|
+
}
|
487
|
+
})
|
488
|
+
})
|
489
|
+
})
|
490
|
+
)
|
491
|
+
|
492
|
+
observer.gridAxesSize$.pipe(
|
493
|
+
takeUntil(destroy$)
|
494
|
+
).subscribe(data => {
|
495
|
+
const clipPathData = [{
|
496
|
+
id: clipPathID,
|
497
|
+
width: data.width,
|
498
|
+
height: data.height
|
499
|
+
}]
|
500
|
+
renderClipPath({
|
501
|
+
defsSelection,
|
502
|
+
clipPathData
|
503
|
+
})
|
504
|
+
})
|
505
|
+
|
506
|
+
// const SeriesDataMap$ = visibleComputedData$.pipe(
|
507
|
+
// map(d => makeGridSeriesDataMap(d))
|
508
|
+
// )
|
509
|
+
|
510
|
+
// const GroupDataMap$ = visibleComputedData$.pipe(
|
511
|
+
// map(d => makeGridGroupDataMap(d))
|
512
|
+
// )
|
513
|
+
|
514
|
+
const highlightTarget$ = observer.fullChartParams$.pipe(
|
515
|
+
takeUntil(destroy$),
|
516
|
+
map(d => d.highlightTarget),
|
517
|
+
distinctUntilChanged()
|
518
|
+
)
|
519
|
+
|
520
|
+
combineLatest({
|
521
|
+
// renderBarsFn: renderBarsFn$,
|
522
|
+
graphicData: graphicData$,
|
523
|
+
zeroY: zeroY$,
|
524
|
+
groupLabels: groupLabels$,
|
525
|
+
// barScale: barScale$,
|
526
|
+
params: observer.fullParams$,
|
527
|
+
chartParams: observer.fullChartParams$,
|
528
|
+
highlightTarget: highlightTarget$,
|
529
|
+
barWidth: barWidth$,
|
530
|
+
transformedBarRadius: transformedBarRadius$,
|
531
|
+
delayGroup: delayGroup$,
|
532
|
+
transitionItem: transitionItem$,
|
533
|
+
SeriesDataMap: observer.SeriesDataMap$,
|
534
|
+
GroupDataMap: observer.GroupDataMap$
|
535
|
+
}).pipe(
|
536
|
+
takeUntil(destroy$),
|
537
|
+
// 轉換後會退訂前一個未完成的訂閱事件,因此可以取到「同時間」最後一次的訂閱事件
|
538
|
+
switchMap(async (d) => d),
|
539
|
+
).subscribe(data => {
|
540
|
+
const barSelection = renderRectBars({
|
541
|
+
selection: graphicGSelection,
|
542
|
+
data: data.graphicData,
|
543
|
+
zeroY: data.zeroY,
|
544
|
+
groupLabels: data.groupLabels,
|
545
|
+
// barScale: data.barScale,
|
546
|
+
params: data.params,
|
547
|
+
chartParams: data.chartParams,
|
548
|
+
barWidth: data.barWidth,
|
549
|
+
transformedBarRadius: data.transformedBarRadius,
|
550
|
+
delayGroup: data.delayGroup,
|
551
|
+
transitionItem: data.transitionItem
|
552
|
+
})
|
553
|
+
|
554
|
+
barSelection!
|
555
|
+
.on('mouseover', (event, datum) => {
|
556
|
+
event.stopPropagation()
|
557
|
+
|
558
|
+
subject.event$.next({
|
559
|
+
type: 'grid',
|
560
|
+
eventName: 'mouseover',
|
561
|
+
pluginName: name,
|
562
|
+
highlightTarget: data.highlightTarget,
|
563
|
+
datum,
|
564
|
+
series: data.SeriesDataMap.get(datum.seriesLabel)!,
|
565
|
+
seriesIndex: datum.seriesIndex,
|
566
|
+
seriesLabel: datum.seriesLabel,
|
567
|
+
groups: data.GroupDataMap.get(datum.groupLabel)!,
|
568
|
+
groupIndex: datum.groupIndex,
|
569
|
+
groupLabel: datum.groupLabel,
|
570
|
+
event,
|
571
|
+
data: data.graphicData
|
572
|
+
})
|
573
|
+
})
|
574
|
+
.on('mousemove', (event, datum) => {
|
575
|
+
event.stopPropagation()
|
576
|
+
|
577
|
+
subject.event$.next({
|
578
|
+
type: 'grid',
|
579
|
+
eventName: 'mousemove',
|
580
|
+
pluginName: name,
|
581
|
+
highlightTarget: data.highlightTarget,
|
582
|
+
datum,
|
583
|
+
series: data.SeriesDataMap.get(datum.seriesLabel)!,
|
584
|
+
seriesIndex: datum.seriesIndex,
|
585
|
+
seriesLabel: datum.seriesLabel,
|
586
|
+
groups: data.GroupDataMap.get(datum.groupLabel)!,
|
587
|
+
groupIndex: datum.groupIndex,
|
588
|
+
groupLabel: datum.groupLabel,
|
589
|
+
event,
|
590
|
+
data: data.graphicData
|
591
|
+
})
|
592
|
+
})
|
593
|
+
.on('mouseout', (event, datum) => {
|
594
|
+
event.stopPropagation()
|
595
|
+
|
596
|
+
subject.event$.next({
|
597
|
+
type: 'grid',
|
598
|
+
eventName: 'mouseout',
|
599
|
+
pluginName: name,
|
600
|
+
highlightTarget: data.highlightTarget,
|
601
|
+
datum,
|
602
|
+
series: data.SeriesDataMap.get(datum.seriesLabel)!,
|
603
|
+
seriesIndex: datum.seriesIndex,
|
604
|
+
seriesLabel: datum.seriesLabel,
|
605
|
+
groups: data.GroupDataMap.get(datum.groupLabel)!,
|
606
|
+
groupIndex: datum.groupIndex,
|
607
|
+
groupLabel: datum.groupLabel,
|
608
|
+
event,
|
609
|
+
data: data.graphicData
|
610
|
+
})
|
611
|
+
})
|
612
|
+
.on('click', (event, datum) => {
|
613
|
+
event.stopPropagation()
|
614
|
+
|
615
|
+
subject.event$.next({
|
616
|
+
type: 'grid',
|
617
|
+
eventName: 'click',
|
618
|
+
pluginName: name,
|
619
|
+
highlightTarget: data.highlightTarget,
|
620
|
+
datum,
|
621
|
+
series: data.SeriesDataMap.get(datum.seriesLabel)!,
|
622
|
+
seriesIndex: datum.seriesIndex,
|
623
|
+
seriesLabel: datum.seriesLabel,
|
624
|
+
groups: data.GroupDataMap.get(datum.groupLabel)!,
|
625
|
+
groupIndex: datum.groupIndex,
|
626
|
+
groupLabel: datum.groupLabel,
|
627
|
+
event,
|
628
|
+
data: data.graphicData
|
629
|
+
})
|
630
|
+
})
|
631
|
+
|
632
|
+
barSelection$.next(barSelection!)
|
633
|
+
})
|
634
|
+
|
635
|
+
// const datumList$ = observer.computedData$.pipe(
|
636
|
+
// takeUntil(destroy$),
|
637
|
+
// map(d => d.flat())
|
638
|
+
// )
|
639
|
+
// const highlight$ = highlightObservable({ datumList$, chartParams$, event$: store.event$ })
|
640
|
+
const highlightSubscription = observer.gridHighlight$.subscribe()
|
641
|
+
|
642
|
+
combineLatest({
|
643
|
+
barSelection: barSelection$,
|
644
|
+
highlight: observer.gridHighlight$,
|
645
|
+
fullChartParams: observer.fullChartParams$
|
646
|
+
}).pipe(
|
647
|
+
takeUntil(destroy$),
|
648
|
+
switchMap(async d => d)
|
649
|
+
).subscribe(data => {
|
650
|
+
highlight({
|
651
|
+
selection: data.barSelection,
|
652
|
+
ids: data.highlight,
|
653
|
+
fullChartParams: data.fullChartParams
|
654
|
+
})
|
655
|
+
})
|
656
|
+
|
657
|
+
return () => {
|
658
|
+
destroy$.next(undefined)
|
659
|
+
highlightSubscription.unsubscribe()
|
660
|
+
}
|
661
|
+
})
|