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

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.
@@ -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$,