@orbcharts/core 3.0.0-alpha.21

Sign up to get free protection for your applications and to get access to all the features.
Files changed (166) hide show
  1. package/.gitignore +23 -0
  2. package/LICENSE +201 -0
  3. package/dist/orbcharts-core.es.js +5096 -0
  4. package/dist/orbcharts-core.umd.js +3 -0
  5. package/dist/src/AbstractChart.d.ts +17 -0
  6. package/dist/src/GridChart.d.ts +6 -0
  7. package/dist/src/MultiGridChart.d.ts +6 -0
  8. package/dist/src/MultiValueChart.d.ts +6 -0
  9. package/dist/src/RelationshipChart.d.ts +6 -0
  10. package/dist/src/SeriesChart.d.ts +6 -0
  11. package/dist/src/TreeChart.d.ts +6 -0
  12. package/dist/src/base/createBaseChart.d.ts +3 -0
  13. package/dist/src/base/createBasePlugin.d.ts +3 -0
  14. package/dist/src/defaults.d.ts +37 -0
  15. package/dist/src/defineGridPlugin.d.ts +1 -0
  16. package/dist/src/defineMultiGridPlugin.d.ts +1 -0
  17. package/dist/src/defineMultiValuePlugin.d.ts +1 -0
  18. package/dist/src/defineNoneDataPlugin.d.ts +1 -0
  19. package/dist/src/defineRelationshipPlugin.d.ts +1 -0
  20. package/dist/src/defineSeriesPlugin.d.ts +1 -0
  21. package/dist/src/defineTreePlugin.d.ts +1 -0
  22. package/dist/src/grid/computeGridData.d.ts +3 -0
  23. package/dist/src/grid/createGridContextObserver.d.ts +3 -0
  24. package/dist/src/grid/gridObservables.d.ts +25 -0
  25. package/dist/src/index.d.ts +15 -0
  26. package/dist/src/multiGrid/computeMultiGridData.d.ts +3 -0
  27. package/dist/src/multiGrid/createMultiGridContextObserver.d.ts +3 -0
  28. package/dist/src/multiGrid/multiGridObservables.d.ts +0 -0
  29. package/dist/src/multiValue/computeMultiValueData.d.ts +3 -0
  30. package/dist/src/multiValue/createMultiValueContextObserver.d.ts +3 -0
  31. package/dist/src/multiValue/multiValueObservables.d.ts +0 -0
  32. package/dist/src/relationship/computeRelationshipData.d.ts +3 -0
  33. package/dist/src/relationship/createRelationshipContextObserver.d.ts +3 -0
  34. package/dist/src/relationship/relationshipObservables.d.ts +0 -0
  35. package/dist/src/series/computeSeriesData.d.ts +3 -0
  36. package/dist/src/series/createSeriesContextObserver.d.ts +3 -0
  37. package/dist/src/series/seriesObservables.d.ts +8 -0
  38. package/dist/src/tree/computeTreeData.d.ts +3 -0
  39. package/dist/src/tree/createTreeContextObserver.d.ts +3 -0
  40. package/dist/src/tree/treeObservables.d.ts +0 -0
  41. package/dist/src/types/Axis.d.ts +1 -0
  42. package/dist/src/types/Chart.d.ts +41 -0
  43. package/dist/src/types/ChartParams.d.ts +36 -0
  44. package/dist/src/types/ComputedData.d.ts +28 -0
  45. package/dist/src/types/ComputedDataGrid.d.ts +10 -0
  46. package/dist/src/types/ComputedDataMultiGrid.d.ts +3 -0
  47. package/dist/src/types/ComputedDataMultiValue.d.ts +6 -0
  48. package/dist/src/types/ComputedDataRelationship.d.ts +18 -0
  49. package/dist/src/types/ComputedDataSeries.d.ts +6 -0
  50. package/dist/src/types/ComputedDataTree.d.ts +7 -0
  51. package/dist/src/types/ContextObserver.d.ts +28 -0
  52. package/dist/src/types/ContextObserverGrid.d.ts +18 -0
  53. package/dist/src/types/ContextObserverMultiGrid.d.ts +4 -0
  54. package/dist/src/types/ContextObserverMultiValue.d.ts +4 -0
  55. package/dist/src/types/ContextObserverRelationship.d.ts +4 -0
  56. package/dist/src/types/ContextObserverSeries.d.ts +8 -0
  57. package/dist/src/types/ContextObserverTree.d.ts +4 -0
  58. package/dist/src/types/ContextSubject.d.ts +15 -0
  59. package/dist/src/types/Data.d.ts +19 -0
  60. package/dist/src/types/DataFormatter.d.ts +40 -0
  61. package/dist/src/types/DataFormatterGrid.d.ts +20 -0
  62. package/dist/src/types/DataFormatterMultiGrid.d.ts +16 -0
  63. package/dist/src/types/DataFormatterMultiValue.d.ts +13 -0
  64. package/dist/src/types/DataFormatterRelationship.d.ts +5 -0
  65. package/dist/src/types/DataFormatterSeries.d.ts +10 -0
  66. package/dist/src/types/DataFormatterTree.d.ts +5 -0
  67. package/dist/src/types/DataGrid.d.ts +6 -0
  68. package/dist/src/types/DataMultiGrid.d.ts +6 -0
  69. package/dist/src/types/DataMultiValue.d.ts +6 -0
  70. package/dist/src/types/DataRelationship.d.ts +20 -0
  71. package/dist/src/types/DataSeries.d.ts +6 -0
  72. package/dist/src/types/DataTree.d.ts +13 -0
  73. package/dist/src/types/Event.d.ts +64 -0
  74. package/dist/src/types/Layout.d.ts +8 -0
  75. package/dist/src/types/Padding.d.ts +6 -0
  76. package/dist/src/types/Plugin.d.ts +37 -0
  77. package/dist/src/types/TransformData.d.ts +8 -0
  78. package/dist/src/types/index.d.ts +37 -0
  79. package/dist/src/utils/commonUtils.d.ts +8 -0
  80. package/dist/src/utils/d3Utils.d.ts +25 -0
  81. package/dist/src/utils/index.d.ts +4 -0
  82. package/dist/src/utils/observables.d.ts +14 -0
  83. package/dist/src/utils/orbchartsUtils.d.ts +20 -0
  84. package/dist/vite.config.d.ts +2 -0
  85. package/package.json +40 -0
  86. package/src/AbstractChart.ts +48 -0
  87. package/src/GridChart.ts +21 -0
  88. package/src/MultiGridChart.ts +21 -0
  89. package/src/MultiValueChart.ts +21 -0
  90. package/src/RelationshipChart.ts +21 -0
  91. package/src/SeriesChart.ts +21 -0
  92. package/src/TreeChart.ts +21 -0
  93. package/src/base/createBaseChart.ts +329 -0
  94. package/src/base/createBasePlugin.ts +89 -0
  95. package/src/defaults.ts +229 -0
  96. package/src/defineGridPlugin.ts +3 -0
  97. package/src/defineMultiGridPlugin.ts +3 -0
  98. package/src/defineMultiValuePlugin.ts +3 -0
  99. package/src/defineNoneDataPlugin.ts +4 -0
  100. package/src/defineRelationshipPlugin.ts +3 -0
  101. package/src/defineSeriesPlugin.ts +3 -0
  102. package/src/defineTreePlugin.ts +3 -0
  103. package/src/grid/computeGridData.ts +192 -0
  104. package/src/grid/createGridContextObserver.ts +91 -0
  105. package/src/grid/gridObservables.ts +359 -0
  106. package/src/index.ts +21 -0
  107. package/src/multiGrid/computeMultiGridData.ts +48 -0
  108. package/src/multiGrid/createMultiGridContextObserver.ts +12 -0
  109. package/src/multiGrid/multiGridObservables.ts +0 -0
  110. package/src/multiValue/computeMultiValueData.ts +127 -0
  111. package/src/multiValue/createMultiValueContextObserver.ts +12 -0
  112. package/src/multiValue/multiValueObservables.ts +0 -0
  113. package/src/relationship/computeRelationshipData.ts +101 -0
  114. package/src/relationship/createRelationshipContextObserver.ts +12 -0
  115. package/src/relationship/relationshipObservables.ts +0 -0
  116. package/src/series/computeSeriesData.ts +154 -0
  117. package/src/series/createSeriesContextObserver.ts +33 -0
  118. package/src/series/seriesObservables.ts +23 -0
  119. package/src/tree/computeTreeData.ts +104 -0
  120. package/src/tree/createTreeContextObserver.ts +12 -0
  121. package/src/tree/treeObservables.ts +0 -0
  122. package/src/types/Axis.ts +1 -0
  123. package/src/types/Chart.ts +46 -0
  124. package/src/types/ChartParams.ts +50 -0
  125. package/src/types/ComputedData.ts +66 -0
  126. package/src/types/ComputedDataGrid.ts +12 -0
  127. package/src/types/ComputedDataMultiGrid.ts +3 -0
  128. package/src/types/ComputedDataMultiValue.ts +10 -0
  129. package/src/types/ComputedDataRelationship.ts +20 -0
  130. package/src/types/ComputedDataSeries.ts +8 -0
  131. package/src/types/ComputedDataTree.ts +20 -0
  132. package/src/types/ContextObserver.ts +38 -0
  133. package/src/types/ContextObserverGrid.ts +16 -0
  134. package/src/types/ContextObserverMultiGrid.ts +5 -0
  135. package/src/types/ContextObserverMultiValue.ts +5 -0
  136. package/src/types/ContextObserverRelationship.ts +5 -0
  137. package/src/types/ContextObserverSeries.ts +8 -0
  138. package/src/types/ContextObserverTree.ts +5 -0
  139. package/src/types/ContextSubject.ts +18 -0
  140. package/src/types/Data.ts +45 -0
  141. package/src/types/DataFormatter.ts +99 -0
  142. package/src/types/DataFormatterGrid.ts +40 -0
  143. package/src/types/DataFormatterMultiGrid.ts +23 -0
  144. package/src/types/DataFormatterMultiValue.ts +19 -0
  145. package/src/types/DataFormatterRelationship.ts +23 -0
  146. package/src/types/DataFormatterSeries.ts +26 -0
  147. package/src/types/DataFormatterTree.ts +10 -0
  148. package/src/types/DataGrid.ts +11 -0
  149. package/src/types/DataMultiGrid.ts +7 -0
  150. package/src/types/DataMultiValue.ts +11 -0
  151. package/src/types/DataRelationship.ts +27 -0
  152. package/src/types/DataSeries.ts +11 -0
  153. package/src/types/DataTree.ts +18 -0
  154. package/src/types/Event.ts +114 -0
  155. package/src/types/Layout.ts +12 -0
  156. package/src/types/Padding.ts +6 -0
  157. package/src/types/Plugin.ts +60 -0
  158. package/src/types/TransformData.ts +8 -0
  159. package/src/types/index.ts +37 -0
  160. package/src/utils/commonUtils.ts +50 -0
  161. package/src/utils/d3Utils.ts +87 -0
  162. package/src/utils/index.ts +4 -0
  163. package/src/utils/observables.ts +198 -0
  164. package/src/utils/orbchartsUtils.ts +150 -0
  165. package/tsconfig.json +14 -0
  166. package/vite.config.js +45 -0
@@ -0,0 +1,20 @@
1
+ import { DatumValue } from '../types/Data';
2
+ import { DataSeries } from '../types/DataSeries';
3
+ import { DataGrid, DataGridDatum } from '../types/DataGrid';
4
+ import { DataMultiGrid } from '../types/DataMultiGrid';
5
+ import { DataMultiValue } from '../types/DataMultiValue';
6
+ import { SeriesType, DataFormatterGrid } from '../types/DataFormatterGrid';
7
+ import * as d3 from 'd3';
8
+ export declare function formatValueToLabel(value: any, valueFormatter: string | ((text: d3.NumberValue) => string)): string;
9
+ export declare function createDefaultDatumId(type: string, levelOneIndex: number, levelTwoIndex: number): string;
10
+ export declare function createDefaultSeriesLabel(type: string, seriesIndex: number): string;
11
+ export declare function createDefaultGroupLabel(type: string, groupIndex: number): string;
12
+ export declare function createGridSeriesLabels(transposedDataGrid: DataGridDatum[][], dataFormatter: DataFormatterGrid): string[];
13
+ export declare function createGridGroupLabels(transposedDataGrid: DataGridDatum[][], dataFormatter: DataFormatterGrid): string[];
14
+ export declare function getMinAndMax(data: number[]): [number, number];
15
+ export declare function getMinAndMaxValue(data: DatumValue[]): [number, number];
16
+ export declare function getMinAndMaxSeries(data: DataSeries): [number, number];
17
+ export declare function getMinAndMaxGrid(data: DataGrid): [number, number];
18
+ export declare function getMinAndMaxMultiGrid(data: DataMultiGrid): [number, number];
19
+ export declare function getMinAndMaxMultiValue(data: DataMultiValue, valueIndex?: number): [number, number];
20
+ export declare function transposeData<T>(seriesType: SeriesType, data: T[][]): T[][];
@@ -0,0 +1,2 @@
1
+ declare const _default: import('vite').UserConfig & Promise<import('vite').UserConfig> & (import('vite').UserConfigFnObject & import('vite').UserConfigExport);
2
+ export default _default;
package/package.json ADDED
@@ -0,0 +1,40 @@
1
+ {
2
+ "name": "@orbcharts/core",
3
+ "version": "3.0.0-alpha.21",
4
+ "description": "OrbCharts is an open source chart library based on d3.js and rx.js",
5
+ "author": "Blue Planet Inc.",
6
+ "license": "Apache-2.0",
7
+ "keywords": [
8
+ "d3",
9
+ "rxjs",
10
+ "svg",
11
+ "visualization",
12
+ "infographic",
13
+ "graph",
14
+ "chart"
15
+ ],
16
+ "private": false,
17
+ "publishConfig": {
18
+ "access": "public",
19
+ "registry": "https://registry.npmjs.org/"
20
+ },
21
+ "files": [
22
+ "*"
23
+ ],
24
+ "module": "./dist/orbcharts-core.es.js",
25
+ "types": "./dist/src/index.d.ts",
26
+ "scripts": {
27
+ "test": "echo \"Error: no test specified\" && exit 1",
28
+ "build": "vite build --mode release"
29
+ },
30
+ "devDependencies": {
31
+ "@types/d3": "^7.4.0",
32
+ "ts-loader": "^9.4.2",
33
+ "typescript": "^5.0.4",
34
+ "vite-plugin-dts": "^3.7.3"
35
+ },
36
+ "dependencies": {
37
+ "d3": "^7.8.5",
38
+ "rxjs": "^7.8.1"
39
+ }
40
+ }
@@ -0,0 +1,48 @@
1
+ import * as d3 from 'd3'
2
+ import {
3
+ Subject } from 'rxjs'
4
+ import type {
5
+ ComputedDataFn,
6
+ ChartEntity,
7
+ ChartType,
8
+ ChartParamsPartial,
9
+ ContextObserverFn,
10
+ ChartOptionsPartial,
11
+ DataTypeMap,
12
+ DataFormatterTypeMap,
13
+ DataFormatterPartialTypeMap,
14
+ EventTypeMap,
15
+ PluginEntity } from './types'
16
+ import { createBaseChart } from './base/createBaseChart'
17
+
18
+ export abstract class AbstractChart<T extends ChartType> implements ChartEntity<T> {
19
+ selection: d3.Selection<SVGGElement, unknown, HTMLElement, unknown>
20
+ destroy: () => void
21
+ data$: Subject<DataTypeMap<T>> = new Subject()
22
+ dataFormatter$: Subject<DataFormatterPartialTypeMap<T>> = new Subject()
23
+ plugins$: Subject<PluginEntity<T, any, any>[]> = new Subject()
24
+ chartParams$: Subject<ChartParamsPartial> = new Subject()
25
+ event$: Subject<EventTypeMap<T>> = new Subject()
26
+
27
+ constructor (
28
+ { defaultDataFormatter, computedDataFn, contextObserverFn }: {
29
+ defaultDataFormatter: DataFormatterTypeMap<T>
30
+ computedDataFn: ComputedDataFn<T>
31
+ contextObserverFn: ContextObserverFn<T>
32
+ },
33
+ element: HTMLElement | Element,
34
+ options?: ChartOptionsPartial<T>
35
+ ) {
36
+ const baseChart = createBaseChart({ defaultDataFormatter, computedDataFn, contextObserverFn })
37
+ const chartEntity = baseChart(element, options)
38
+
39
+ this.selection = chartEntity.selection
40
+ this.destroy = chartEntity.destroy
41
+ this.data$ = chartEntity.data$
42
+ this.dataFormatter$ = chartEntity.dataFormatter$
43
+ this.plugins$ = chartEntity.plugins$
44
+ this.chartParams$ = chartEntity.chartParams$
45
+ this.event$ = chartEntity.event$
46
+ }
47
+
48
+ }
@@ -0,0 +1,21 @@
1
+ import type {
2
+ ChartEntity,
3
+ ChartOptionsPartial } from './types'
4
+ import { DATA_FORMATTER_GRID_DEFAULT } from './defaults'
5
+ import { computeGridData } from './grid/computeGridData'
6
+ import { createGridContextObserver } from './grid/createGridContextObserver'
7
+ import { AbstractChart } from './AbstractChart'
8
+
9
+ export class GridChart extends AbstractChart<'grid'> implements ChartEntity<'grid'> {
10
+ constructor (element: HTMLElement | Element, options?: ChartOptionsPartial<'grid'>) {
11
+ super(
12
+ {
13
+ defaultDataFormatter: DATA_FORMATTER_GRID_DEFAULT,
14
+ computedDataFn: computeGridData,
15
+ contextObserverFn: createGridContextObserver
16
+ },
17
+ element,
18
+ options
19
+ )
20
+ }
21
+ }
@@ -0,0 +1,21 @@
1
+ import type {
2
+ ChartEntity,
3
+ ChartOptionsPartial } from './types'
4
+ import { DATA_FORMATTER_MULTI_GRID_DEFAULT } from './defaults'
5
+ import { computeMultiGridData } from './multiGrid/computeMultiGridData'
6
+ import { createMultiGridContextObserver } from './multiGrid/createMultiGridContextObserver'
7
+ import { AbstractChart } from './AbstractChart'
8
+
9
+ export class MultiGridChart extends AbstractChart<'multiGrid'> implements ChartEntity<'multiGrid'> {
10
+ constructor (element: HTMLElement | Element, options?: ChartOptionsPartial<'multiGrid'>) {
11
+ super(
12
+ {
13
+ defaultDataFormatter: DATA_FORMATTER_MULTI_GRID_DEFAULT,
14
+ computedDataFn: computeMultiGridData,
15
+ contextObserverFn: createMultiGridContextObserver
16
+ },
17
+ element,
18
+ options
19
+ )
20
+ }
21
+ }
@@ -0,0 +1,21 @@
1
+ import type {
2
+ ChartEntity,
3
+ ChartOptionsPartial } from './types'
4
+ import { DATA_FORMATTER_MULTI_VALUE_DEFAULT } from './defaults'
5
+ import { computeMultiValueData } from './multiValue/computeMultiValueData'
6
+ import { createMultiValueContextObserver } from './multiValue/createMultiValueContextObserver'
7
+ import { AbstractChart } from './AbstractChart'
8
+
9
+ export class MultiValueChart extends AbstractChart<'multiValue'> implements ChartEntity<'multiValue'> {
10
+ constructor (element: HTMLElement | Element, options?: ChartOptionsPartial<'multiValue'>) {
11
+ super(
12
+ {
13
+ defaultDataFormatter: DATA_FORMATTER_MULTI_VALUE_DEFAULT,
14
+ computedDataFn: computeMultiValueData,
15
+ contextObserverFn: createMultiValueContextObserver
16
+ },
17
+ element,
18
+ options
19
+ )
20
+ }
21
+ }
@@ -0,0 +1,21 @@
1
+ import type {
2
+ ChartEntity,
3
+ ChartOptionsPartial } from './types'
4
+ import { DATA_FORMATTER_RELATIONAL_DEFAULT} from './defaults'
5
+ import { computeRelationshipData } from './relationship/computeRelationshipData'
6
+ import { createRelationshipContextObserver } from './relationship/createRelationshipContextObserver'
7
+ import { AbstractChart } from './AbstractChart'
8
+
9
+ export class RelationshipChart extends AbstractChart<'relationship'> implements ChartEntity<'relationship'> {
10
+ constructor (element: HTMLElement | Element, options?: ChartOptionsPartial<'relationship'>) {
11
+ super(
12
+ {
13
+ defaultDataFormatter: DATA_FORMATTER_RELATIONAL_DEFAULT,
14
+ computedDataFn: computeRelationshipData,
15
+ contextObserverFn: createRelationshipContextObserver
16
+ },
17
+ element,
18
+ options
19
+ )
20
+ }
21
+ }
@@ -0,0 +1,21 @@
1
+ import type {
2
+ ChartEntity,
3
+ ChartOptionsPartial } from './types'
4
+ import { DATA_FORMATTER_SERIES_DEFAULT } from './defaults'
5
+ import { computeSeriesData } from './series/computeSeriesData'
6
+ import { createSeriesContextObserver } from './series/createSeriesContextObserver'
7
+ import { AbstractChart } from './AbstractChart'
8
+
9
+ export class SeriesChart extends AbstractChart<'series'> implements ChartEntity<'series'> {
10
+ constructor (element: HTMLElement | Element, options?: ChartOptionsPartial<'series'>) {
11
+ super(
12
+ {
13
+ defaultDataFormatter: DATA_FORMATTER_SERIES_DEFAULT,
14
+ computedDataFn: computeSeriesData,
15
+ contextObserverFn: createSeriesContextObserver
16
+ },
17
+ element,
18
+ options
19
+ )
20
+ }
21
+ }
@@ -0,0 +1,21 @@
1
+ import type {
2
+ ChartEntity,
3
+ ChartOptionsPartial } from './types'
4
+ import { DATA_FORMATTER_TREE_DEFAULT } from './defaults'
5
+ import { computeTreeData } from './tree/computeTreeData'
6
+ import { createTreeContextObserver } from './tree/createTreeContextObserver'
7
+ import { AbstractChart } from './AbstractChart'
8
+
9
+ export class TreeChart extends AbstractChart<'tree'> implements ChartEntity<'tree'> {
10
+ constructor (element: HTMLElement | Element, options?: ChartOptionsPartial<'tree'>) {
11
+ super(
12
+ {
13
+ defaultDataFormatter: DATA_FORMATTER_TREE_DEFAULT,
14
+ computedDataFn: computeTreeData,
15
+ contextObserverFn: createTreeContextObserver
16
+ },
17
+ element,
18
+ options
19
+ )
20
+ }
21
+ }
@@ -0,0 +1,329 @@
1
+ import * as d3 from 'd3'
2
+ import {
3
+ combineLatest,
4
+ iif,
5
+ of,
6
+ EMPTY,
7
+ Subject,
8
+ BehaviorSubject,
9
+ Observable,
10
+ first,
11
+ takeUntil,
12
+ catchError,
13
+ throwError } from 'rxjs'
14
+ import {
15
+ map,
16
+ mergeWith,
17
+ concatMap,
18
+ switchMap,
19
+ switchAll,
20
+ throttleTime,
21
+ debounceTime,
22
+ distinctUntilChanged,
23
+ share,
24
+ shareReplay,
25
+ filter,
26
+ take,
27
+ startWith,
28
+ scan,
29
+ } from 'rxjs/operators'
30
+ import type {
31
+ CreateBaseChart,
32
+ CreateChart,
33
+ ComputedDataFn,
34
+ ChartEntity,
35
+ ChartType,
36
+ ChartParams,
37
+ ContextSubject,
38
+ ComputedDataTypeMap,
39
+ ContextObserverFn,
40
+ ChartOptions,
41
+ DataTypeMap,
42
+ DataFormatterTypeMap,
43
+ DataFormatterBase,
44
+ DataFormatterContext,
45
+ Layout,
46
+ PluginEntity,
47
+ PluginContext,
48
+ Preset,
49
+ ContextObserverTypeMap } from '../types'
50
+ // import type { EventTypeMap } from './types/Event'
51
+ import { mergeOptionsWithDefault } from '../utils'
52
+ import {
53
+ CHART_OPTIONS_DEFAULT,
54
+ PADDING_DEFAULT,
55
+ CHART_PARAMS_DEFAULT,
56
+ CHART_WIDTH_DEFAULT,
57
+ CHART_HEIGHT_DEFAULT } from '../defaults'
58
+
59
+ // 判斷dataFormatter是否需要size參數
60
+ const isAxesTypeMap: {[key in ChartType]: Boolean} = {
61
+ series: false,
62
+ grid: true,
63
+ multiGrid: true,
64
+ multiValue: true,
65
+ tree: false,
66
+ relationship: false
67
+ }
68
+
69
+ function resizeObservable(elem: HTMLElement | Element): Observable<DOMRectReadOnly> {
70
+ return new Observable(subscriber => {
71
+ const ro = new ResizeObserver(entries => {
72
+ const entry = entries[0]
73
+ if (entry && entry.contentRect) {
74
+ subscriber.next(entry.contentRect)
75
+ }
76
+ })
77
+
78
+ ro.observe(elem)
79
+ return function unsubscribe() {
80
+ ro.unobserve(elem)
81
+ }
82
+ })
83
+ }
84
+
85
+ export const createBaseChart: CreateBaseChart = <T extends ChartType>({ defaultDataFormatter, computedDataFn, contextObserverFn }: {
86
+ defaultDataFormatter: DataFormatterTypeMap<T>
87
+ computedDataFn: ComputedDataFn<T>
88
+ contextObserverFn: ContextObserverFn<T>
89
+ }): CreateChart<T> => {
90
+ const destroy$ = new Subject()
91
+
92
+ const chartType: ChartType = (defaultDataFormatter as unknown as DataFormatterBase<any>).type
93
+
94
+ // 建立chart實例
95
+ return function createChart (element: HTMLElement | Element, options?: Partial<ChartOptions<T>>): ChartEntity<T> {
96
+
97
+ // -- selections --
98
+ // svg selection
99
+ d3.select(element).selectAll('svg').remove()
100
+ const svgSelection = d3.select(element).append('svg')
101
+ svgSelection
102
+ .attr('xmlns:xlink', 'http://www.w3.org/1999/xlink')
103
+ .attr('xmls', 'http://www.w3.org/2000/svg')
104
+ .attr('version', '1.1')
105
+ .style('position', 'absolute')
106
+ .style('width', '100%')
107
+ .style('height', '100%')
108
+ .classed('orbcharts__root', true)
109
+ // 傳入操作的 selection
110
+ const selectionLayout = svgSelection.append('g')
111
+ selectionLayout.classed('orbcharts__layout', true)
112
+ const selectionPlugins = selectionLayout.append('g')
113
+ selectionPlugins.classed('orbcharts__plugins', true)
114
+
115
+ // chartSubject
116
+ const chartSubject: ContextSubject<T> = {
117
+ data$: new Subject(),
118
+ dataFormatter$: new Subject(),
119
+ plugins$: new Subject(),
120
+ chartParams$: new Subject(),
121
+ event$: new Subject()
122
+ }
123
+
124
+ // options
125
+ const mergedPresetWithDefault: Preset<T> = ((options) => {
126
+ const _options = options ? options : CHART_OPTIONS_DEFAULT
127
+ const preset = _options.preset ? _options.preset : {}
128
+ return {
129
+ chartParams: preset.chartParams
130
+ ? mergeOptionsWithDefault(preset.chartParams, CHART_PARAMS_DEFAULT)
131
+ : CHART_PARAMS_DEFAULT,
132
+ dataFormatter: preset.dataFormatter
133
+ ? mergeOptionsWithDefault(preset.dataFormatter, defaultDataFormatter)
134
+ : defaultDataFormatter,
135
+ allPluginParams: preset.allPluginParams
136
+ ? preset.allPluginParams
137
+ : {}
138
+ }
139
+ })(options)
140
+
141
+
142
+ // console.log('mergedOptions', mergedOptions)
143
+
144
+ const sharedData$ = chartSubject.data$.pipe(shareReplay(1))
145
+ const shareAndMergedDataFormatter$ = chartSubject.dataFormatter$
146
+ .pipe(
147
+ takeUntil(destroy$),
148
+ startWith({}),
149
+ map((d) => mergeOptionsWithDefault(d, mergedPresetWithDefault.dataFormatter)),
150
+ shareReplay(1)
151
+ )
152
+ const shareAndMergedChartParams$ = chartSubject.chartParams$
153
+ .pipe(
154
+ takeUntil(destroy$),
155
+ startWith({}),
156
+ map((d) => mergeOptionsWithDefault(d, mergedPresetWithDefault.chartParams)),
157
+ shareReplay(1)
158
+ )
159
+
160
+ // -- size --
161
+ // padding
162
+ const mergedPadding$ = shareAndMergedChartParams$
163
+ .pipe(
164
+ takeUntil(destroy$),
165
+ startWith({}),
166
+ map((d: any) => mergeOptionsWithDefault(d.padding ?? {}, PADDING_DEFAULT))
167
+ )
168
+ mergedPadding$
169
+ .pipe(
170
+ takeUntil(destroy$),
171
+ first()
172
+ )
173
+ .subscribe(d => {
174
+ selectionLayout
175
+ .attr('transform', `translate(${d.left}, ${d.top})`)
176
+ })
177
+ mergedPadding$.subscribe(size => {
178
+ selectionLayout
179
+ .transition()
180
+ .attr('transform', `translate(${size.left}, ${size.top})`)
181
+ })
182
+
183
+ // 監聽外層的element尺寸
184
+ const rootSize$ = resizeObservable(element)
185
+ .pipe(
186
+ takeUntil(destroy$),
187
+ share()
188
+ )
189
+ const rootSizeFiltered$ = of().pipe(
190
+ mergeWith(
191
+ rootSize$.pipe(
192
+ debounceTime(250)
193
+ ),
194
+ rootSize$.pipe(
195
+ throttleTime(250)
196
+ )
197
+ ),
198
+ distinctUntilChanged((a, b) => JSON.stringify(a) === JSON.stringify(b)),
199
+ share()
200
+ )
201
+ const rootSizeSubscription = rootSizeFiltered$.subscribe()
202
+
203
+ // layout
204
+ const layout$: Observable<Layout> = combineLatest({
205
+ rootSize: rootSizeFiltered$,
206
+ mergedPadding: mergedPadding$
207
+ }).pipe(
208
+ takeUntil(destroy$),
209
+ switchMap(async (d) => {
210
+ const rootWidth = d.rootSize.width > 0
211
+ ? d.rootSize.width
212
+ : CHART_WIDTH_DEFAULT
213
+ const rootHeight = d.rootSize.height > 0
214
+ ? d.rootSize.height
215
+ : CHART_HEIGHT_DEFAULT
216
+ return {
217
+ width: rootWidth - d.mergedPadding.left - d.mergedPadding.right,
218
+ height: rootHeight - d.mergedPadding.top - d.mergedPadding.bottom,
219
+ top: d.mergedPadding.top,
220
+ right: d.mergedPadding.right,
221
+ bottom: d.mergedPadding.bottom,
222
+ left: d.mergedPadding.left,
223
+ rootWidth,
224
+ rootHeight
225
+ }
226
+ }),
227
+ shareReplay(1)
228
+ )
229
+
230
+ // -- computedData --
231
+ const computedData$: Observable<ComputedDataTypeMap<T>> = combineLatest({
232
+ data: sharedData$,
233
+ dataFormatter: shareAndMergedDataFormatter$,
234
+ chartParams: shareAndMergedChartParams$,
235
+ layout: iif(() => isAxesTypeMap[chartType] === true, layout$, of(undefined))
236
+ }).pipe(
237
+ takeUntil(destroy$),
238
+ switchMap(async d => d),
239
+ switchMap((d) => {
240
+ return of(d)
241
+ .pipe(
242
+ map(_d => {
243
+ try {
244
+ return computedDataFn({ data: _d.data, dataFormatter: _d.dataFormatter, chartParams: _d.chartParams, layout: _d.layout })
245
+ } catch (e) {
246
+ console.error(e)
247
+ throw new Error(e)
248
+ }
249
+ }),
250
+ catchError(() => EMPTY)
251
+ )
252
+ }),
253
+ shareReplay(1)
254
+ )
255
+
256
+ // -- plugins --
257
+ const pluginEntityMap: any = {} // 用於destroy
258
+ chartSubject.plugins$.subscribe(plugins => {
259
+ if (!plugins) {
260
+ return
261
+ }
262
+ // 建立<g>
263
+ const update = selectionPlugins
264
+ .selectAll<SVGGElement, PluginEntity<T, any, any>>('g.orbcharts__plugin')
265
+ .data(plugins, d => d.name as string)
266
+ const enter = update.enter()
267
+ .append('g')
268
+ .attr('class', plugin => {
269
+ return `orbcharts__plugin orbcharts__${plugin.name}`
270
+ })
271
+ const exit = update.exit()
272
+ .remove()
273
+
274
+ // destroy entity
275
+ exit.each((plugin: PluginEntity<T, unknown, unknown>, i, n) => {
276
+ if (pluginEntityMap[plugin.name as string]) {
277
+ pluginEntityMap[plugin.name as string].destroy()
278
+ }
279
+ })
280
+
281
+ enter.each((plugin, i, n) => {
282
+ const _pluginObserverBase = {
283
+ fullParams$: new Observable(),
284
+ fullChartParams$: shareAndMergedChartParams$,
285
+ fullDataFormatter$: shareAndMergedDataFormatter$,
286
+ computedData$,
287
+ layout$
288
+ }
289
+ const pluginObserver: ContextObserverTypeMap<T, typeof plugin.defaultParams> = contextObserverFn({
290
+ observer: _pluginObserverBase,
291
+ subject: chartSubject
292
+ })
293
+
294
+ // -- createPlugin(plugin) --
295
+ const pluginSelection = d3.select(n[i])
296
+ const pluginContext: PluginContext<T, typeof plugin.name, typeof plugin.defaultParams> = {
297
+ selection: pluginSelection,
298
+ rootSelection: svgSelection,
299
+ name: plugin.name,
300
+ chartType,
301
+ subject: chartSubject,
302
+ observer: pluginObserver
303
+ }
304
+
305
+ plugin.setPresetParams(mergedPresetWithDefault.allPluginParams[plugin.name] ?? {})
306
+ // 傳入context
307
+ plugin.setContext(pluginContext)
308
+
309
+ // 紀錄起來
310
+ pluginEntityMap[pluginContext.name as string] = plugin
311
+
312
+ // init plugin
313
+ plugin.init()
314
+
315
+ })
316
+
317
+ })
318
+
319
+ return {
320
+ ...chartSubject,
321
+ selection: svgSelection,
322
+ destroy () {
323
+ d3.select(element).selectAll('svg').remove()
324
+ destroy$.next(undefined)
325
+ rootSizeSubscription.unsubscribe()
326
+ }
327
+ }
328
+ }
329
+ }
@@ -0,0 +1,89 @@
1
+ import { takeUntil, map, shareReplay, startWith, Subject, Observable } from 'rxjs'
2
+ import type { ChartType, CreateBasePlugin, PluginInitFn, PluginContext } from '../types'
3
+ import { mergeOptionsWithDefault } from '../utils'
4
+
5
+ // 建立plugin實例
6
+ function createPlugin <T extends ChartType, PluginName, PluginParams>({ name, defaultParams, initFn }: {
7
+ name: PluginName
8
+ defaultParams: PluginParams
9
+ initFn: PluginInitFn<T, PluginName, PluginParams>
10
+ }) {
11
+
12
+ const destroy$ = new Subject()
13
+ const params$: Subject<Partial<typeof defaultParams>> = new Subject()
14
+ const StoreMap = new WeakMap() // 避免memory leak
15
+ let pluginDestroyFn = () => {}
16
+ let pluginContext: PluginContext<T, PluginName, PluginParams> | undefined
17
+ let mergedDefaultParams: PluginParams = defaultParams
18
+
19
+ // 建立plugin實例
20
+ return {
21
+ params$,
22
+ name,
23
+ defaultParams,
24
+ init () {
25
+ if (!pluginContext) {
26
+ return
27
+ }
28
+ // 執行
29
+ pluginDestroyFn = (initFn(pluginContext) ?? (() => {})) // plugin執行會回傳destroy函式
30
+ StoreMap.set(pluginContext.selection, pluginContext)
31
+ },
32
+ destroy () {
33
+ pluginDestroyFn()
34
+ if (pluginContext) {
35
+ pluginContext.selection.remove()
36
+ pluginContext = undefined
37
+ }
38
+ destroy$.next(undefined)
39
+ },
40
+ setPresetParams: (presetParams: Partial<PluginParams>) => {
41
+ mergedDefaultParams = mergeOptionsWithDefault(presetParams, defaultParams)
42
+ },
43
+ setContext: (_pluginContext: PluginContext<T, PluginName, PluginParams>) => {
44
+ pluginContext = _pluginContext
45
+ pluginContext.observer.fullParams$ = params$
46
+ .pipe(
47
+ takeUntil(destroy$),
48
+ startWith({}),
49
+ map(d => mergeOptionsWithDefault(d, mergedDefaultParams)),
50
+ shareReplay(1),
51
+ )
52
+ }
53
+ }
54
+ }
55
+
56
+ // 建立plugin類別
57
+ export const createBasePlugin: CreateBasePlugin = <T extends ChartType>() => {
58
+
59
+ // 定義plugin
60
+ return function definePlugin<PluginName, PluginParams>(name: PluginName, defaultParams: PluginParams) {
61
+
62
+ // 定義plugin的初始化function
63
+ return function definePluginInitFn (initFn: PluginInitFn<T, PluginName, PluginParams>) {
64
+
65
+ return class Plugin {
66
+ params$: Subject<Partial<PluginParams>>
67
+ name: PluginName
68
+ defaultParams: PluginParams
69
+ // presetParams: Partial<PluginParams>
70
+ init: () => void
71
+ destroy: () => void
72
+ setPresetParams: (presetParams: Partial<PluginParams>) => void
73
+ setContext: (pluginContext: PluginContext<T, PluginName, PluginParams>) => void
74
+ constructor () {
75
+ const pluginEntity = createPlugin<T, PluginName, PluginParams>({ name, defaultParams, initFn })
76
+
77
+ this.params$ = pluginEntity.params$
78
+ this.name = pluginEntity.name
79
+ this.defaultParams = pluginEntity.defaultParams
80
+ // this.presetParams = pluginEntity.presetParams
81
+ this.init = pluginEntity.init
82
+ this.destroy = pluginEntity.destroy
83
+ this.setPresetParams = pluginEntity.setPresetParams
84
+ this.setContext = pluginEntity.setContext
85
+ }
86
+ }
87
+ }
88
+ }
89
+ }