@orbcharts/core 3.0.0-alpha.21

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.
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
+ }