@orbcharts/plugins-basic 3.0.0-alpha.32 → 3.0.0-alpha.34

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,427 +1,33 @@
1
- import * as d3 from 'd3'
2
1
  import {
3
- Observable,
4
- combineLatest,
5
- switchMap,
6
- distinctUntilChanged,
7
- filter,
8
- first,
9
- map,
10
- takeUntil,
11
2
  Subject } from 'rxjs'
12
3
  import {
13
4
  defineGridPlugin } from '@orbcharts/core'
14
- import type {
15
- ChartParams,
16
- ComputedDatumGrid,
17
- Layout } from '@orbcharts/core'
18
- import type { DotsParams } from '../types'
19
5
  import { DEFAULT_DOTS_PARAMS } from '../defaults'
20
- import { getDatumColor, getClassName, getUniID } from '../../utils/orbchartsUtils'
21
-
22
- type ClipPathDatum = {
23
- id: string;
24
- // x: number;
25
- // y: number;
26
- width: number;
27
- height: number;
28
- }
6
+ import { createBaseDots } from '../../base/BaseDots'
29
7
 
30
8
  const pluginName = 'Dots'
31
- const gClassName = getClassName(pluginName, 'g')
32
- const circleClassName = getClassName(pluginName, 'circle')
33
-
34
- function renderDots ({ selection, data, fullParams, fullChartParams, graphicOppositeScale }: {
35
- selection: d3.Selection<SVGGElement, any, any, any>
36
- data: ComputedDatumGrid[]
37
- fullParams: DotsParams
38
- fullChartParams: ChartParams
39
- graphicOppositeScale: [number, number]
40
- }) {
41
- const createEnterDuration = (enter: d3.Selection<d3.EnterElement, ComputedDatumGrid, SVGGElement, any>) => {
42
- const enterSize = enter.size()
43
- const eachDuration = fullChartParams.transitionDuration / enterSize
44
- return eachDuration
45
- }
46
- // enterDuration
47
- let enterDuration = 0
48
-
49
- const dots = selection
50
- .selectAll<SVGGElement, ComputedDatumGrid>('g')
51
- .data(data, d => d.id)
52
- .join(
53
- enter => {
54
- // enterDuration
55
- enterDuration = createEnterDuration(enter)
56
-
57
- return enter
58
- .append('g')
59
- .classed(gClassName, true)
60
- },
61
- update => update,
62
- exit => exit.remove()
63
- )
64
- .attr('transform', d => `translate(${d.axisX}, ${d.axisY})`)
65
- .each((d, i, g) => {
66
- const circle = d3.select(g[i])
67
- .selectAll('circle')
68
- .data([d])
69
- .join(
70
- enter => {
71
- return enter
72
- .append('circle')
73
- .style('cursor', 'pointer')
74
- .style('vector-effect', 'non-scaling-stroke')
75
- .classed(circleClassName, true)
76
- .attr('opacity', 0)
77
- .transition()
78
- .delay((_d, _i) => {
79
- return i * enterDuration
80
- })
81
- .attr('opacity', 1)
82
- },
83
- update => {
84
- return update
85
- .transition()
86
- .duration(50)
87
- // .attr('cx', d => d.axisX)
88
- // .attr('cy', d => d.axisY)
89
- .attr('opacity', 1)
90
- },
91
- exit => exit.remove()
92
- )
93
- .attr('r', fullParams.radius)
94
- .attr('fill', (d, i) => getDatumColor({ datum: d, colorType: fullParams.fillColorType, fullChartParams }))
95
- .attr('stroke', (d, i) => getDatumColor({ datum: d, colorType: fullParams.strokeColorType, fullChartParams }))
96
- .attr('stroke-width', fullParams.strokeWidth)
97
- .attr('transform', `scale(${graphicOppositeScale[0]}, ${graphicOppositeScale[1]})`)
98
- })
99
-
100
- return dots
101
- }
102
-
103
-
104
- function highlightDots ({ selection, ids, onlyShowHighlighted, fullChartParams }: {
105
- selection: d3.Selection<SVGGElement, ComputedDatumGrid, any, any>
106
- ids: string[]
107
- onlyShowHighlighted: boolean
108
- fullChartParams: ChartParams
109
- }) {
110
- selection.interrupt('highlight')
111
- if (!ids.length) {
112
- // remove highlight
113
- selection
114
- .transition('highlight')
115
- .duration(200)
116
- .style('opacity', onlyShowHighlighted === true ? 0 : 1)
117
- return
118
- }
119
-
120
- selection
121
- .each((d, i, n) => {
122
- if (ids.includes(d.id)) {
123
- d3.select(n[i])
124
- .style('opacity', 1)
125
- .transition('highlight')
126
- .duration(200)
127
- } else {
128
- d3.select(n[i])
129
- .style('opacity', onlyShowHighlighted === true ? 0 : fullChartParams.styles.unhighlightedOpacity)
130
- .transition('highlight')
131
- .duration(200)
132
- }
133
- })
134
- }
135
-
136
- function renderClipPath ({ defsSelection, clipPathData }: {
137
- defsSelection: d3.Selection<SVGDefsElement, any, any, any>
138
- clipPathData: ClipPathDatum[]
139
- }) {
140
- const clipPath = defsSelection
141
- .selectAll<SVGClipPathElement, Layout>('clipPath')
142
- .data(clipPathData)
143
- .join(
144
- enter => {
145
- return enter
146
- .append('clipPath')
147
- },
148
- update => update,
149
- exit => exit.remove()
150
- )
151
- .attr('id', d => d.id)
152
- .each((d, i, g) => {
153
- const rect = d3.select(g[i])
154
- .selectAll<SVGRectElement, typeof d>('rect')
155
- .data([d])
156
- .join('rect')
157
- .attr('x', 0)
158
- .attr('y', 0)
159
- .attr('width', _d => _d.width)
160
- .attr('height', _d => _d.height)
161
- })
162
-
163
- }
164
9
 
165
10
  export const Dots = defineGridPlugin(pluginName, DEFAULT_DOTS_PARAMS)(({ selection, name, subject, observer }) => {
166
- // const axisGUpdate = selection
167
- // .selectAll('g')
168
- // .data()
169
- const destroy$ = new Subject()
170
-
171
- const clipPathID = getUniID(pluginName, 'clipPath-box')
172
-
173
- // const rectSelection: d3.Selection<SVGRectElement, any, any, any> = selection
174
- // .append('rect')
175
- // .attr('pointer-events', 'none')
176
- const axisSelection: d3.Selection<SVGGElement, any, any, any> = selection
177
- .append('g')
178
- .attr('clip-path', `url(#${clipPathID})`)
179
- const defsSelection: d3.Selection<SVGDefsElement, any, any, any> = axisSelection.append('defs')
180
- const dataAreaSelection: d3.Selection<SVGGElement, any, any, any> = axisSelection.append('g')
181
- const graphicSelection$: Subject<d3.Selection<SVGGElement, ComputedDatumGrid, any, any>> = new Subject()
182
- // const dotSelection$: Subject<d3.Selection<SVGCircleElement, ComputedDatumGrid, SVGGElement, any>> = new Subject()
183
-
184
- observer.gridAxesTransform$
185
- .pipe(
186
- takeUntil(destroy$),
187
- map(d => d.value),
188
- distinctUntilChanged()
189
- ).subscribe(d => {
190
- axisSelection
191
- .style('transform', d)
192
- })
193
-
194
- observer.gridGraphicTransform$
195
- .pipe(
196
- takeUntil(destroy$),
197
- switchMap(async d => d.value),
198
- distinctUntilChanged()
199
- ).subscribe(d => {
200
- dataAreaSelection
201
- .transition()
202
- .duration(50)
203
- .style('transform', d)
204
- })
205
-
206
- const graphicOppositeScale$: Observable<[number, number]> = observer.gridGraphicTransform$.pipe(
207
- takeUntil(destroy$),
208
- map(d => [1 / d.scale[0], 1 / d.scale[1]])
209
- )
210
-
211
- // const axisSize$ = gridAxisSizeObservable({
212
- // dataFormatter$,
213
- // observer.layout$
214
- // })
215
-
216
- // combineLatest({
217
- // axisSized: axisSize$,
218
- // computedLayout: observer.layout$
219
- // }).pipe(
220
- // takeUntil(destroy$),
221
- // // 轉換後會退訂前一個未完成的訂閱事件,因此可以取到「同時間」最後一次的訂閱事件
222
- // switchMap(async (d) => d),
223
- // ).subscribe(d => {
224
- // rectSelection
225
- // .style('transform', d.computedLayout.content.axesTransform)
226
- // .attr('opacity', 0)
227
- // .attr('width', d.axisSized.width)
228
- // .attr('height', d.axisSized.height)
229
- // // .transition()
230
- // // .attr('opacity', 1)
231
- // })
232
- // selection.on('mouseover', (event, datum) => {
233
-
234
- // console.log('selection mouseover', event, datum)
235
- // })
236
-
237
- const clipPathSubscription = observer.gridAxesSize$.pipe(
238
- takeUntil(destroy$),
239
- // 轉換後會退訂前一個未完成的訂閱事件,因此可以取到「同時間」最後一次的訂閱事件
240
- switchMap(async (d) => d),
241
- ).subscribe(data => {
242
- // 外層的遮罩
243
- const clipPathData = [{
244
- id: clipPathID,
245
- width: data.width,
246
- height: data.height
247
- }]
248
- renderClipPath({
249
- defsSelection,
250
- clipPathData,
251
- })
252
- })
253
-
254
- // const visibleComputedData$ = observer.computedData$.pipe(
255
- // map(computedData => {
256
- // return computedData
257
- // .map(d => {
258
- // return d.filter(_d => _d.visible == true)
259
- // })
260
- // })
261
- // )
262
-
263
- // const SeriesDataMap$ = visibleComputedData$.pipe(
264
- // map(d => makeGridSeriesDataMap(d))
265
- // )
266
-
267
- // const GroupDataMap$ = visibleComputedData$.pipe(
268
- // map(d => makeGridGroupDataMap(d))
269
- // )
270
-
271
- // const DataMap$ = computedData$.pipe(
272
- // map(d => {
273
- // const DataMap: Map<string, ComputedDatumGrid> = new Map()
274
- // d.flat().forEach(_d => DataMap.set(_d.id, _d))
275
- // return DataMap
276
- // })
277
- // )
278
-
279
- const highlightTarget$ = observer.fullChartParams$.pipe(
280
- takeUntil(destroy$),
281
- map(d => d.highlightTarget),
282
- distinctUntilChanged()
283
- )
284
-
285
- combineLatest({
286
- computedData: observer.computedData$,
287
- visibleComputedData: observer.visibleComputedData$,
288
- SeriesDataMap: observer.SeriesDataMap$,
289
- GroupDataMap: observer.GroupDataMap$,
290
- graphicOppositeScale: graphicOppositeScale$,
291
- fullChartParams: observer.fullChartParams$,
292
- fullParams: observer.fullParams$,
293
- highlightTarget: highlightTarget$
294
- }).pipe(
295
- takeUntil(destroy$),
296
- // 轉換後會退訂前一個未完成的訂閱事件,因此可以取到「同時間」最後一次的訂閱事件
297
- switchMap(async (d) => d),
298
- ).subscribe(data => {
299
-
300
- const graphicSelection = renderDots({
301
- selection: dataAreaSelection,
302
- data: data.visibleComputedData.flat(),
303
- fullParams: data.fullParams,
304
- fullChartParams: data.fullChartParams,
305
- graphicOppositeScale: data.graphicOppositeScale
306
- })
307
-
308
- graphicSelection
309
- .on('mouseover', (event, datum) => {
310
- event.stopPropagation()
311
11
 
312
- subject.event$.next({
313
- type: 'grid',
314
- eventName: 'mouseover',
315
- pluginName: name,
316
- highlightTarget: data.highlightTarget,
317
- datum,
318
- series: data.SeriesDataMap.get(datum.seriesLabel)!,
319
- seriesIndex: datum.seriesIndex,
320
- seriesLabel: datum.seriesLabel,
321
- groups: data.GroupDataMap.get(datum.groupLabel)!,
322
- groupIndex: datum.groupIndex,
323
- groupLabel: datum.groupLabel,
324
- event,
325
- data: data.computedData
326
- })
327
- })
328
- .on('mousemove', (event, datum) => {
329
- event.stopPropagation()
330
-
331
- subject.event$.next({
332
- type: 'grid',
333
- eventName: 'mousemove',
334
- pluginName: name,
335
- highlightTarget: data.highlightTarget,
336
- data: data.computedData,
337
- datum,
338
- series: data.SeriesDataMap.get(datum.seriesLabel)!,
339
- seriesIndex: datum.seriesIndex,
340
- seriesLabel: datum.seriesLabel,
341
- groups: data.GroupDataMap.get(datum.groupLabel)!,
342
- groupIndex: datum.groupIndex,
343
- groupLabel: datum.groupLabel,
344
- event
345
- })
346
- })
347
- .on('mouseout', (event, datum) => {
348
- event.stopPropagation()
349
-
350
- subject.event$.next({
351
- type: 'grid',
352
- eventName: 'mouseout',
353
- pluginName: name,
354
- highlightTarget: data.highlightTarget,
355
- datum,
356
- series: data.SeriesDataMap.get(datum.seriesLabel)!,
357
- seriesIndex: datum.seriesIndex,
358
- seriesLabel: datum.seriesLabel,
359
- groups: data.GroupDataMap.get(datum.groupLabel)!,
360
- groupIndex: datum.groupIndex,
361
- groupLabel: datum.groupLabel,
362
- event,
363
- data: data.computedData
364
- })
365
- })
366
- .on('click', (event, datum) => {
367
- event.stopPropagation()
368
-
369
- subject.event$.next({
370
- type: 'grid',
371
- eventName: 'click',
372
- pluginName: name,
373
- highlightTarget: data.highlightTarget,
374
- datum,
375
- series: data.SeriesDataMap.get(datum.seriesLabel)!,
376
- seriesIndex: datum.seriesIndex,
377
- seriesLabel: datum.seriesLabel,
378
- groups: data.GroupDataMap.get(datum.groupLabel)!,
379
- groupIndex: datum.groupIndex,
380
- groupLabel: datum.groupLabel,
381
- event,
382
- data: data.computedData
383
- })
384
- })
385
-
386
- graphicSelection$.next(graphicSelection)
387
-
388
- })
12
+ const destroy$ = new Subject()
389
13
 
390
- // const datumList$ = observer.computedData$.pipe(
391
- // takeUntil(destroy$),
392
- // map(d => d.flat())
393
- // )
394
- // const highlight$ = highlightObservable({ datumList$, fullChartParams$, event$: store.event$ })
395
- const highlightSubscription = observer.gridHighlight$.subscribe()
396
- const onlyShowHighlighted$ = observer.fullParams$.pipe(
397
- takeUntil(destroy$),
398
- map(d => d.onlyShowHighlighted),
399
- distinctUntilChanged()
400
- )
401
-
402
- observer.fullChartParams$.pipe(
403
- takeUntil(destroy$),
404
- switchMap(d => combineLatest({
405
- graphicSelection: graphicSelection$,
406
- highlight: observer.gridHighlight$,
407
- onlyShowHighlighted: onlyShowHighlighted$,
408
- fullChartParams: observer.fullChartParams$
409
- }).pipe(
410
- takeUntil(destroy$),
411
- switchMap(async d => d)
412
- ))
413
- ).subscribe(data => {
414
- highlightDots({
415
- selection: data.graphicSelection,
416
- ids: data.highlight,
417
- onlyShowHighlighted: data.onlyShowHighlighted,
418
- fullChartParams: data.fullChartParams
419
- })
14
+ const unsubscribeBaseBars = createBaseDots(pluginName, {
15
+ selection,
16
+ computedData$: observer.computedData$,
17
+ visibleComputedData$: observer.visibleComputedData$,
18
+ SeriesDataMap$: observer.SeriesDataMap$,
19
+ GroupDataMap$: observer.GroupDataMap$,
20
+ fullParams$: observer.fullParams$,
21
+ fullChartParams$: observer.fullChartParams$,
22
+ gridAxesTransform$: observer.gridAxesTransform$,
23
+ gridGraphicTransform$: observer.gridGraphicTransform$,
24
+ gridAxesSize$: observer.gridAxesSize$,
25
+ gridHighlight$: observer.gridHighlight$,
26
+ event$: subject.event$,
420
27
  })
421
28
 
422
-
423
29
  return () => {
424
- highlightSubscription.unsubscribe()
425
30
  destroy$.next(undefined)
31
+ unsubscribeBaseBars()
426
32
  }
427
33
  })
@@ -7,6 +7,7 @@ import {
7
7
  Observable } from 'rxjs'
8
8
  import {
9
9
  defineMultiGridPlugin } from '@orbcharts/core'
10
+ import { DATA_FORMATTER_MULTI_GRID_DEFAULT } from '@orbcharts/core/src/defaults'
10
11
  // import { defineMultiGridPlugin } from '../../../../orbcharts-core/src'
11
12
  import { getClassName, getUniID } from '../../utils/orbchartsUtils'
12
13
  import { DEFAULT_BARS_AND_LINES_PARAMS } from '../defaults'
@@ -40,23 +41,38 @@ export const BarsAndLines = defineMultiGridPlugin(pluginName, DEFAULT_BARS_AND_L
40
41
  // })
41
42
 
42
43
  const barsComputedData$ = observer.computedData$.pipe(
44
+ takeUntil(destroy$),
43
45
  map((computedData) => computedData[0] || [])
44
46
  )
45
47
 
46
48
  const linesComputedData$ = observer.computedData$.pipe(
49
+ takeUntil(destroy$),
47
50
  map((computedData) => computedData[1] || [])
48
51
  )
49
52
 
50
53
  const barsFullParams$ = observer.fullParams$.pipe(
54
+ takeUntil(destroy$),
51
55
  map((fullParams) => fullParams.bars)
52
56
  )
53
57
 
54
58
  const linesFullParams$ = observer.fullParams$.pipe(
59
+ takeUntil(destroy$),
55
60
  map((fullParams) => fullParams.lines)
56
61
  )
57
62
 
58
- const linesFullDataFormatter$ = observer.fullDataFormatter$.pipe(
59
- map((fullDataFormatter) => fullDataFormatter.multiGrid[1])
63
+ const defaultFullDataFormatter$ = observer.fullDataFormatter$.pipe(
64
+ takeUntil(destroy$),
65
+ map((fullDataFormatter) => fullDataFormatter.multiGrid[0] || DATA_FORMATTER_MULTI_GRID_DEFAULT.multiGrid[0])
66
+ )
67
+
68
+ const linesFullDataFormatter$ = combineLatest({
69
+ fullDataFormatter: observer.fullDataFormatter$,
70
+ defaultFullDataFormatter: defaultFullDataFormatter$,
71
+ }).pipe(
72
+ takeUntil(destroy$),
73
+ map((data) => {
74
+ return data.fullDataFormatter.multiGrid[1] ?? data.defaultFullDataFormatter
75
+ })
60
76
  )
61
77
 
62
78
  observer.multiGrid$.subscribe((multiGrid) => {
@@ -7,7 +7,7 @@ import {
7
7
  Observable,
8
8
  Subject } from 'rxjs'
9
9
  import {
10
- defineMultiGridPlugin } from '@orbcharts/core'
10
+ defineMultiGridPlugin, mergeOptionsWithDefault } from '@orbcharts/core'
11
11
  import { DEFAULT_MULTI_GRID_LEGEND_PARAMS } from '../defaults'
12
12
  import { createBaseLegend } from '../../base/BaseLegend'
13
13
  import type { BaseLegendParams } from '../../base/BaseLegend'
@@ -45,13 +45,11 @@ export const MultiGridLegend = defineMultiGridPlugin(pluginName, DEFAULT_MULTI_G
45
45
  return data.computedData
46
46
  .map((gridData, gridIndex) => {
47
47
  // 這個grid全部series要套用的圖例列點樣式
48
- const gridListStyle = data.fullParams.gridList[gridIndex]
49
- ? data.fullParams.gridList[gridIndex]
50
- : {
51
- listRectWidth: data.fullParams.listRectWidth,
52
- listRectHeight: data.fullParams.listRectHeight,
53
- listRectRadius: data.fullParams.listRectRadius,
54
- }
48
+ const gridListStyle = mergeOptionsWithDefault(data.fullParams.gridList[gridIndex] ?? {}, {
49
+ listRectWidth: data.fullParams.listRectWidth,
50
+ listRectHeight: data.fullParams.listRectHeight,
51
+ listRectRadius: data.fullParams.listRectRadius,
52
+ })
55
53
  // series
56
54
  return gridData.map(d => gridListStyle)
57
55
  })
@@ -65,7 +63,9 @@ export const MultiGridLegend = defineMultiGridPlugin(pluginName, DEFAULT_MULTI_G
65
63
  seriesList: seriesList$
66
64
  }).pipe(
67
65
  takeUntil(destroy$),
66
+ switchMap(async d => d),
68
67
  map(d => {
68
+ console.log('fullParams', d)
69
69
  return {
70
70
  ...d.fullParams,
71
71
  seriesList: d.seriesList
@@ -73,6 +73,10 @@ export const MultiGridLegend = defineMultiGridPlugin(pluginName, DEFAULT_MULTI_G
73
73
  })
74
74
  )
75
75
 
76
+ fullParams$.subscribe(d => {
77
+ console.log('subscription')
78
+ })
79
+
76
80
  const unsubscribeBaseLegend = createBaseLegend(pluginName, {
77
81
  rootSelection,
78
82
  seriesLabels$,