@orbcharts/plugins-basic 3.0.0-alpha.64 → 3.0.0-alpha.66

Sign up to get free protection for your applications and to get access to all the features.
@@ -31,6 +31,7 @@ interface BaseGroupAxisContext {
31
31
  }>;
32
32
  gridContainerPosition$: Observable<GridContainerPosition[]>;
33
33
  isSeriesSeprate$: Observable<boolean>;
34
+ textSizePx$: Observable<number>;
34
35
  }
35
36
  export declare const createBaseGroupAxis: BasePluginFn<BaseGroupAxisContext>;
36
37
  export {};
@@ -1,4 +1,3 @@
1
1
  export * from './defaults';
2
2
  export * from './types';
3
- export { Container } from './plugins/Container';
4
3
  export { Tooltip } from './plugins/Tooltip';
@@ -19,6 +19,6 @@ export type TooltipParams = {
19
19
  textColorType: ColorType;
20
20
  offset: [number, number];
21
21
  padding: number;
22
- textRenderFn: <T extends ChartType>(eventData: EventTypeMap<T>) => string[];
22
+ textRenderFn: <T extends ChartType>(eventData: EventTypeMap<T>) => string[] | string | null;
23
23
  svgRenderFn: (<T extends ChartType>(eventData: EventTypeMap<T>) => string) | null;
24
24
  };
@@ -21,6 +21,8 @@ export interface PieParams {
21
21
  startAngle: number;
22
22
  endAngle: number;
23
23
  padAngle: number;
24
+ strokeColorType: ColorType;
25
+ strokeWidth: number;
24
26
  cornerRadius: number;
25
27
  }
26
28
  export interface PieEventTextsParams {
@@ -43,9 +45,12 @@ export interface PieLabelsParams {
43
45
  }
44
46
  export interface RoseParams {
45
47
  outerRadius: number;
48
+ padAngle: number;
49
+ strokeColorType: ColorType;
50
+ strokeWidth: number;
46
51
  cornerRadius: number;
47
52
  arcScaleType: ArcScaleType;
48
- mouseoverAngleIncrease: number;
53
+ angleIncreaseWhileHighlight: number;
49
54
  }
50
55
  export interface RoseLabelsParams {
51
56
  outerRadius: number;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@orbcharts/plugins-basic",
3
- "version": "3.0.0-alpha.64",
3
+ "version": "3.0.0-alpha.66",
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.58",
38
+ "@orbcharts/core": "^3.0.0-alpha.59",
39
39
  "d3": "^7.8.5",
40
40
  "rxjs": "^7.8.1"
41
41
  }
@@ -55,6 +55,7 @@ interface BaseGroupAxisContext {
55
55
  }>
56
56
  gridContainerPosition$: Observable<GridContainerPosition[]>
57
57
  isSeriesSeprate$: Observable<boolean>
58
+ textSizePx$: Observable<number>
58
59
  }
59
60
 
60
61
  interface TextAlign {
@@ -147,7 +148,7 @@ function renderAxisLabel ({ selection, groupingLabelClassName, fullParams, axisL
147
148
 
148
149
  }
149
150
 
150
- function renderAxis ({ selection, xAxisClassName, fullParams, tickTextAlign, gridAxesSize, fullDataFormatter, chartParams, groupScale, groupScaleDomain, groupLabels, textReverseTransformWithRotate }: {
151
+ function renderAxis ({ selection, xAxisClassName, fullParams, tickTextAlign, gridAxesSize, fullDataFormatter, chartParams, groupScale, groupScaleDomain, groupLabels, textReverseTransformWithRotate, textSizePx }: {
151
152
  selection: d3.Selection<SVGGElement, any, any, any>,
152
153
  xAxisClassName: string
153
154
  fullParams: BaseGroupAxisParams
@@ -159,6 +160,7 @@ function renderAxis ({ selection, xAxisClassName, fullParams, tickTextAlign, gri
159
160
  groupScaleDomain: number[]
160
161
  groupLabels: string[]
161
162
  textReverseTransformWithRotate: string
163
+ textSizePx: number
162
164
  }) {
163
165
 
164
166
  const xAxisSelection = selection
@@ -209,9 +211,34 @@ function renderAxis ({ selection, xAxisClassName, fullParams, tickTextAlign, gri
209
211
  const xAxisEl = xAxisSelection
210
212
  .transition()
211
213
  .duration(100)
212
- .call(xAxis)
213
- // .attr('text-anchor', () => params.tickTextRotate !== false ? 'end' : 'middle')
214
- // .attr('text-anchor', () => 'middle')
214
+ .call(xAxis)
215
+ .on('end', (self, t) => {
216
+ // 先等transition結束再處理文字,否則會被原本的文字覆蓋
217
+ xAxisEl
218
+ .selectAll('.tick text')
219
+ .each((d, groupIndex, n) => {
220
+ // -- 將原本單行文字改為多行文字 --
221
+ const groupLabel = groupLabels[groupIndex] ?? '' // 非整數index不顯示
222
+ const groupLabelTspans = groupLabel.split('\n')
223
+ const textSelection = d3.select(n[groupIndex])
224
+ .text(null) // 先清空原本的 text
225
+
226
+ const textX = Number(textSelection.attr('x'))
227
+ let textY = Number(textSelection.attr('y'))
228
+ if (fullDataFormatter.grid.groupAxis.position === 'top') {
229
+ // 當文字在上方時,要往上偏移第一行的高度
230
+ textY -= (groupLabelTspans.length - 1) * textSizePx
231
+ }
232
+
233
+ textSelection
234
+ .selectAll('tspan')
235
+ .data(groupLabelTspans)
236
+ .join('tspan')
237
+ .attr('x', textX)
238
+ .attr('y', (_d, _i) => textY + _i * textSizePx)
239
+ .text(d => d)
240
+ })
241
+ })
215
242
 
216
243
  xAxisEl.selectAll('line')
217
244
  .style('fill', 'none')
@@ -224,22 +251,7 @@ function renderAxis ({ selection, xAxisClassName, fullParams, tickTextAlign, gri
224
251
  .style('stroke', fullParams.axisLineVisible == true ? getColor(fullParams.axisLineColorType, chartParams) : 'none')
225
252
  .style('shape-rendering', 'crispEdges')
226
253
 
227
- // const xText = xAxisEl.selectAll('text')
228
- // xAxisSelection.each((d, i, g) => {
229
- // d3.select(g[i])
230
- // .selectAll('text')
231
- // .data([d])
232
- // .join('text')
233
- // .style('font-family', 'sans-serif')
234
- // .style('font-size', `${chartParams.styles.textSize}px`)
235
- // // .style('font-weight', 'bold')
236
- // .style('color', getColor(params.tickTextColorType, chartParams))
237
- // .attr('text-anchor', tickTextAlign.textAnchor)
238
- // .attr('dominant-baseline', tickTextAlign.dominantBaseline)
239
- // .attr('transform-origin', `0 -${params.tickPadding + defaultTickSize}`)
240
- // .style('transform', textReverseTransform)
241
- // })
242
- const xText = xAxisSelection.selectAll('text')
254
+ const xText = xAxisSelection.selectAll<SVGTextElement, BaseGroupAxisParams>('text')
243
255
  // .style('font-family', 'sans-serif')
244
256
  .attr('font-size', chartParams.styles.textSize)
245
257
  // .style('font-weight', 'bold')
@@ -269,6 +281,7 @@ export const createBaseGroupAxis: BasePluginFn<BaseGroupAxisContext> = ((pluginN
269
281
  gridAxesSize$,
270
282
  gridContainerPosition$,
271
283
  isSeriesSeprate$,
284
+ textSizePx$,
272
285
  }) => {
273
286
 
274
287
  const destroy$ = new Subject()
@@ -600,6 +613,7 @@ export const createBaseGroupAxis: BasePluginFn<BaseGroupAxisContext> = ((pluginN
600
613
  groupLabels: groupLabels$,
601
614
  textReverseTransform: textReverseTransform$,
602
615
  textReverseTransformWithRotate: textReverseTransformWithRotate$,
616
+ textSizePx: textSizePx$
603
617
  // tickTextFormatter: tickTextFormatter$
604
618
  }).pipe(
605
619
  takeUntil(destroy$),
@@ -618,6 +632,7 @@ export const createBaseGroupAxis: BasePluginFn<BaseGroupAxisContext> = ((pluginN
618
632
  groupScaleDomain: data.groupScaleDomain,
619
633
  groupLabels: data.groupLabels,
620
634
  textReverseTransformWithRotate: data.textReverseTransformWithRotate,
635
+ textSizePx: data.textSizePx
621
636
  })
622
637
 
623
638
  renderAxisLabel({
@@ -27,6 +27,7 @@ export const GroupAxis = defineGridPlugin(pluginName, DEFAULT_GROUP_AXIS_PARAMS)
27
27
  gridAxesSize$: observer.gridAxesSize$,
28
28
  gridContainerPosition$: observer.gridContainerPosition$,
29
29
  isSeriesSeprate$: observer.isSeriesSeprate$,
30
+ textSizePx$: observer.textSizePx$,
30
31
  })
31
32
 
32
33
  return () => {
@@ -58,6 +58,7 @@ export const MultiGroupAxis = defineMultiGridPlugin(pluginName, DEFAULT_MULTI_GR
58
58
  gridAxesSize$: d.gridAxesSize$,
59
59
  gridContainerPosition$: d.gridContainerPosition$,
60
60
  isSeriesSeprate$,
61
+ textSizePx$: observer.textSizePx$,
61
62
  })
62
63
  })
63
64
  })
@@ -47,7 +47,7 @@ export const OverlappingValueAxes = defineMultiGridPlugin(pluginName, DEFAULT_OV
47
47
  takeUntil(destroy$),
48
48
  switchMap(async (d) => d),
49
49
  map(data => {
50
- console.log('data', data)
50
+ // console.log('data', data)
51
51
  if (!data.fullDataFormatter.gridList[data.secondGridIndex]) {
52
52
  data.fullDataFormatter.gridList[data.secondGridIndex] = Object.assign({}, data.fullDataFormatter.gridList[data.firstGridIndex])
53
53
  }
@@ -1,4 +1,4 @@
1
1
  export * from './defaults'
2
2
  export * from './types'
3
- export { Container } from './plugins/Container'
3
+ // export { Container } from './plugins/Container'
4
4
  export { Tooltip } from './plugins/Tooltip'
@@ -34,15 +34,32 @@ const pluginName = 'Tooltip'
34
34
  const gClassName = getClassName(pluginName, 'g')
35
35
  const boxClassName = getClassName(pluginName, 'box')
36
36
 
37
- function textToSvg (textArr: string[], textStyle: TooltipStyle) {
37
+ function textToSvg (_textArr: string[] | string | null | undefined, textStyle: TooltipStyle) {
38
38
  const lineHeight = textStyle.textSizePx * 1.5
39
- return textArr
39
+
40
+ const textArr = _textArr == null
41
+ ? []
42
+ : Array.isArray(_textArr)
43
+ ? _textArr
44
+ : typeof _textArr === 'string'
45
+ ? _textArr.split('\n')
46
+ : [_textArr]
47
+
48
+ const tspan = textArr
40
49
  .filter(d => d != '')
41
50
  .map((text, i) => {
42
51
  const top = i * lineHeight
43
- return `<text font-size="${textStyle.textSize}" fill="${textStyle.textColor}" x="0" y="${top}" style="dominant-baseline:text-before-edge">${text}</text>`
52
+ return `<tspan x="0" y="${top}">${text}</tspan>`
44
53
  })
45
- .join()
54
+ .join('')
55
+
56
+ if (tspan) {
57
+ return `<text font-size="${textStyle.textSize}" fill="${textStyle.textColor}" x="0" y="0" style="dominant-baseline:text-before-edge">
58
+ ${tspan}
59
+ </text>`
60
+ } else {
61
+ return ''
62
+ }
46
63
  }
47
64
 
48
65
  function renderTooltip ({ rootSelection, pluginName, rootWidth, rootHeight, svgString, tooltipStyle, event }: {
@@ -234,14 +251,14 @@ export const Tooltip: PluginConstructor<any, string, any> = defineNoneDataPlugin
234
251
  }).pipe(
235
252
  takeUntil(destroy$),
236
253
  switchMap(async d => d),
237
- map(d => {
238
- if (d.fullParams.svgRenderFn) {
239
- return d.fullParams.svgRenderFn
254
+ map(data => {
255
+ if (data.fullParams.svgRenderFn) {
256
+ return data.fullParams.svgRenderFn
240
257
  }
241
258
  // 將textRenderFn回傳的資料使用<text>包裝起來
242
259
  return (eventData: EventTypeMap<any>) => {
243
- const textArr = d.fullParams.textRenderFn(eventData as any)
244
- return textToSvg(textArr, d.tooltipStyle)
260
+ const textArr = data.fullParams.textRenderFn(eventData as any)
261
+ return textToSvg(textArr, data.tooltipStyle)
245
262
  }
246
263
  })
247
264
  )
@@ -20,7 +20,7 @@ export type TooltipParams = {
20
20
  textColorType: ColorType
21
21
  offset: [number, number]
22
22
  padding: number
23
- textRenderFn: <T extends ChartType> (eventData: EventTypeMap<T>) => string[]
23
+ textRenderFn: <T extends ChartType> (eventData: EventTypeMap<T>) => string[] | string | null
24
24
  svgRenderFn: (<T extends ChartType> (eventData: EventTypeMap<T>) => string) | null
25
25
  }
26
26
 
@@ -31,14 +31,16 @@ export const DEFAULT_PIE_PARAMS: PieParams = {
31
31
  // bottom: 50,
32
32
  // left: 70
33
33
  // },
34
- outerRadius: 0.95,
34
+ outerRadius: 0.85,
35
35
  innerRadius: 0,
36
- outerRadiusWhileHighlight: 1,
36
+ outerRadiusWhileHighlight: 0.9,
37
37
  // label?: LabelStyle
38
38
  // enterDuration: 800,
39
39
  startAngle: 0,
40
40
  endAngle: Math.PI * 2,
41
- padAngle: 0.02,
41
+ padAngle: 0,
42
+ strokeColorType: 'background',
43
+ strokeWidth: 1,
42
44
  // padRadius: 100,
43
45
  cornerRadius: 0,
44
46
  // highlightTarget: 'datum',
@@ -99,13 +101,13 @@ DEFAULT_PIE_EVENT_TEXTS_PARAMS.eventFn.toString = () => `(eventData: EventSeries
99
101
  export const DEFAULT_PIE_LABELS_PARAMS: PieLabelsParams = {
100
102
  // solidColor: undefined,
101
103
  // colors: DEFAULT_COLORS,
102
- outerRadius: 0.95,
103
- outerRadiusWhileHighlight: 1,
104
+ outerRadius: 0.85,
105
+ outerRadiusWhileHighlight: 0.9,
104
106
  // innerRadius: 0,
105
107
  // enterDuration: 800,
106
108
  startAngle: 0,
107
109
  endAngle: Math.PI * 2,
108
- labelCentroid: 2.3,
110
+ labelCentroid: 2.1,
109
111
  // fontSize: 12,
110
112
  labelColorType: 'primary',
111
113
  labelFn: d => String(d.label),
@@ -113,15 +115,18 @@ export const DEFAULT_PIE_LABELS_PARAMS: PieLabelsParams = {
113
115
  DEFAULT_PIE_LABELS_PARAMS.labelFn.toString = () => `d => String(d.label)`
114
116
 
115
117
  export const DEFAULT_ROSE_PARAMS: RoseParams = {
116
- outerRadius: 0.95,
118
+ outerRadius: 0.85,
119
+ padAngle: 0,
120
+ strokeColorType: 'background',
121
+ strokeWidth: 0,
117
122
  cornerRadius: 0,
118
123
  arcScaleType: 'area',
119
- mouseoverAngleIncrease: 0.05
124
+ angleIncreaseWhileHighlight: 0.05
120
125
  }
121
126
 
122
127
  export const DEFAULT_ROSE_LABELS_PARAMS: RoseLabelsParams = {
123
- outerRadius: 0.95,
124
- labelCentroid: 2.5,
128
+ outerRadius: 0.85,
129
+ labelCentroid: 2.1,
125
130
  labelFn: d => String(d.label),
126
131
  labelColorType: 'primary',
127
132
  arcScaleType: 'area'
@@ -22,7 +22,7 @@ import {
22
22
  import { DEFAULT_PIE_PARAMS } from '../defaults'
23
23
  import { makePieData } from '../seriesUtils'
24
24
  import { getD3TransitionEase, makeD3Arc } from '../../utils/d3Utils'
25
- import { getClassName } from '../../utils/orbchartsUtils'
25
+ import { getDatumColor, getClassName } from '../../utils/orbchartsUtils'
26
26
  import { seriesCenterSelectionObservable } from '../seriesObservables'
27
27
 
28
28
 
@@ -87,11 +87,13 @@ function makePieRenderData (data: PieDatum[], startAngle: number, endAngle: numb
87
87
  })
88
88
  }
89
89
 
90
- function renderPie ({ selection, data, arc, pathClassName }: {
90
+ function renderPie ({ selection, data, arc, pathClassName, fullParams, fullChartParams }: {
91
91
  selection: d3.Selection<SVGGElement, unknown, any, unknown>
92
92
  data: PieDatum[]
93
93
  arc: d3.Arc<any, d3.DefaultArcObject>
94
94
  pathClassName: string
95
+ fullParams: PieParams
96
+ fullChartParams: ChartParams
95
97
  }): d3.Selection<SVGPathElement, PieDatum, any, any> {
96
98
  // console.log('data', data)
97
99
  const pathSelection: d3.Selection<SVGPathElement, PieDatum, any, any> = selection
@@ -101,6 +103,8 @@ function renderPie ({ selection, data, arc, pathClassName }: {
101
103
  .classed(pathClassName, true)
102
104
  .style('cursor', 'pointer')
103
105
  .attr('fill', (d, i) => d.data.color)
106
+ .attr('stroke', (d, i) => getDatumColor({ datum: d.data, colorType: fullParams.strokeColorType, fullChartParams }))
107
+ .attr('stroke-width', fullParams.strokeWidth)
104
108
  .attr('d', (d, i) => {
105
109
  return arc!(d as any)
106
110
  })
@@ -312,7 +316,9 @@ function createEachPie (pluginName: string, context: {
312
316
  selection: context.containerSelection,
313
317
  data: tweenData,
314
318
  arc: data.arc,
315
- pathClassName
319
+ pathClassName,
320
+ fullParams: data.fullParams,
321
+ fullChartParams: data.fullChartParams,
316
322
  })
317
323
 
318
324
  // @Q@ 想盡量減清效能負擔所以取消掉
@@ -345,7 +351,9 @@ function createEachPie (pluginName: string, context: {
345
351
  selection: context.containerSelection,
346
352
  data: tweenData,
347
353
  arc: data.arc,
348
- pathClassName
354
+ pathClassName,
355
+ fullParams: data.fullParams,
356
+ fullChartParams: data.fullChartParams,
349
357
  })
350
358
 
351
359
  // if (data.fullParams.highlightTarget && data.fullParams.highlightTarget != 'none') {