@orbcharts/core 3.0.0-alpha.21
Sign up to get free protection for your applications and to get access to all the features.
- package/.gitignore +23 -0
- package/LICENSE +201 -0
- package/dist/orbcharts-core.es.js +5096 -0
- package/dist/orbcharts-core.umd.js +3 -0
- package/dist/src/AbstractChart.d.ts +17 -0
- package/dist/src/GridChart.d.ts +6 -0
- package/dist/src/MultiGridChart.d.ts +6 -0
- package/dist/src/MultiValueChart.d.ts +6 -0
- package/dist/src/RelationshipChart.d.ts +6 -0
- package/dist/src/SeriesChart.d.ts +6 -0
- package/dist/src/TreeChart.d.ts +6 -0
- package/dist/src/base/createBaseChart.d.ts +3 -0
- package/dist/src/base/createBasePlugin.d.ts +3 -0
- package/dist/src/defaults.d.ts +37 -0
- package/dist/src/defineGridPlugin.d.ts +1 -0
- package/dist/src/defineMultiGridPlugin.d.ts +1 -0
- package/dist/src/defineMultiValuePlugin.d.ts +1 -0
- package/dist/src/defineNoneDataPlugin.d.ts +1 -0
- package/dist/src/defineRelationshipPlugin.d.ts +1 -0
- package/dist/src/defineSeriesPlugin.d.ts +1 -0
- package/dist/src/defineTreePlugin.d.ts +1 -0
- package/dist/src/grid/computeGridData.d.ts +3 -0
- package/dist/src/grid/createGridContextObserver.d.ts +3 -0
- package/dist/src/grid/gridObservables.d.ts +25 -0
- package/dist/src/index.d.ts +15 -0
- package/dist/src/multiGrid/computeMultiGridData.d.ts +3 -0
- package/dist/src/multiGrid/createMultiGridContextObserver.d.ts +3 -0
- package/dist/src/multiGrid/multiGridObservables.d.ts +0 -0
- package/dist/src/multiValue/computeMultiValueData.d.ts +3 -0
- package/dist/src/multiValue/createMultiValueContextObserver.d.ts +3 -0
- package/dist/src/multiValue/multiValueObservables.d.ts +0 -0
- package/dist/src/relationship/computeRelationshipData.d.ts +3 -0
- package/dist/src/relationship/createRelationshipContextObserver.d.ts +3 -0
- package/dist/src/relationship/relationshipObservables.d.ts +0 -0
- package/dist/src/series/computeSeriesData.d.ts +3 -0
- package/dist/src/series/createSeriesContextObserver.d.ts +3 -0
- package/dist/src/series/seriesObservables.d.ts +8 -0
- package/dist/src/tree/computeTreeData.d.ts +3 -0
- package/dist/src/tree/createTreeContextObserver.d.ts +3 -0
- package/dist/src/tree/treeObservables.d.ts +0 -0
- package/dist/src/types/Axis.d.ts +1 -0
- package/dist/src/types/Chart.d.ts +41 -0
- package/dist/src/types/ChartParams.d.ts +36 -0
- package/dist/src/types/ComputedData.d.ts +28 -0
- package/dist/src/types/ComputedDataGrid.d.ts +10 -0
- package/dist/src/types/ComputedDataMultiGrid.d.ts +3 -0
- package/dist/src/types/ComputedDataMultiValue.d.ts +6 -0
- package/dist/src/types/ComputedDataRelationship.d.ts +18 -0
- package/dist/src/types/ComputedDataSeries.d.ts +6 -0
- package/dist/src/types/ComputedDataTree.d.ts +7 -0
- package/dist/src/types/ContextObserver.d.ts +28 -0
- package/dist/src/types/ContextObserverGrid.d.ts +18 -0
- package/dist/src/types/ContextObserverMultiGrid.d.ts +4 -0
- package/dist/src/types/ContextObserverMultiValue.d.ts +4 -0
- package/dist/src/types/ContextObserverRelationship.d.ts +4 -0
- package/dist/src/types/ContextObserverSeries.d.ts +8 -0
- package/dist/src/types/ContextObserverTree.d.ts +4 -0
- package/dist/src/types/ContextSubject.d.ts +15 -0
- package/dist/src/types/Data.d.ts +19 -0
- package/dist/src/types/DataFormatter.d.ts +40 -0
- package/dist/src/types/DataFormatterGrid.d.ts +20 -0
- package/dist/src/types/DataFormatterMultiGrid.d.ts +16 -0
- package/dist/src/types/DataFormatterMultiValue.d.ts +13 -0
- package/dist/src/types/DataFormatterRelationship.d.ts +5 -0
- package/dist/src/types/DataFormatterSeries.d.ts +10 -0
- package/dist/src/types/DataFormatterTree.d.ts +5 -0
- package/dist/src/types/DataGrid.d.ts +6 -0
- package/dist/src/types/DataMultiGrid.d.ts +6 -0
- package/dist/src/types/DataMultiValue.d.ts +6 -0
- package/dist/src/types/DataRelationship.d.ts +20 -0
- package/dist/src/types/DataSeries.d.ts +6 -0
- package/dist/src/types/DataTree.d.ts +13 -0
- package/dist/src/types/Event.d.ts +64 -0
- package/dist/src/types/Layout.d.ts +8 -0
- package/dist/src/types/Padding.d.ts +6 -0
- package/dist/src/types/Plugin.d.ts +37 -0
- package/dist/src/types/TransformData.d.ts +8 -0
- package/dist/src/types/index.d.ts +37 -0
- package/dist/src/utils/commonUtils.d.ts +8 -0
- package/dist/src/utils/d3Utils.d.ts +25 -0
- package/dist/src/utils/index.d.ts +4 -0
- package/dist/src/utils/observables.d.ts +14 -0
- package/dist/src/utils/orbchartsUtils.d.ts +20 -0
- package/dist/vite.config.d.ts +2 -0
- package/package.json +40 -0
- package/src/AbstractChart.ts +48 -0
- package/src/GridChart.ts +21 -0
- package/src/MultiGridChart.ts +21 -0
- package/src/MultiValueChart.ts +21 -0
- package/src/RelationshipChart.ts +21 -0
- package/src/SeriesChart.ts +21 -0
- package/src/TreeChart.ts +21 -0
- package/src/base/createBaseChart.ts +329 -0
- package/src/base/createBasePlugin.ts +89 -0
- package/src/defaults.ts +229 -0
- package/src/defineGridPlugin.ts +3 -0
- package/src/defineMultiGridPlugin.ts +3 -0
- package/src/defineMultiValuePlugin.ts +3 -0
- package/src/defineNoneDataPlugin.ts +4 -0
- package/src/defineRelationshipPlugin.ts +3 -0
- package/src/defineSeriesPlugin.ts +3 -0
- package/src/defineTreePlugin.ts +3 -0
- package/src/grid/computeGridData.ts +192 -0
- package/src/grid/createGridContextObserver.ts +91 -0
- package/src/grid/gridObservables.ts +359 -0
- package/src/index.ts +21 -0
- package/src/multiGrid/computeMultiGridData.ts +48 -0
- package/src/multiGrid/createMultiGridContextObserver.ts +12 -0
- package/src/multiGrid/multiGridObservables.ts +0 -0
- package/src/multiValue/computeMultiValueData.ts +127 -0
- package/src/multiValue/createMultiValueContextObserver.ts +12 -0
- package/src/multiValue/multiValueObservables.ts +0 -0
- package/src/relationship/computeRelationshipData.ts +101 -0
- package/src/relationship/createRelationshipContextObserver.ts +12 -0
- package/src/relationship/relationshipObservables.ts +0 -0
- package/src/series/computeSeriesData.ts +154 -0
- package/src/series/createSeriesContextObserver.ts +33 -0
- package/src/series/seriesObservables.ts +23 -0
- package/src/tree/computeTreeData.ts +104 -0
- package/src/tree/createTreeContextObserver.ts +12 -0
- package/src/tree/treeObservables.ts +0 -0
- package/src/types/Axis.ts +1 -0
- package/src/types/Chart.ts +46 -0
- package/src/types/ChartParams.ts +50 -0
- package/src/types/ComputedData.ts +66 -0
- package/src/types/ComputedDataGrid.ts +12 -0
- package/src/types/ComputedDataMultiGrid.ts +3 -0
- package/src/types/ComputedDataMultiValue.ts +10 -0
- package/src/types/ComputedDataRelationship.ts +20 -0
- package/src/types/ComputedDataSeries.ts +8 -0
- package/src/types/ComputedDataTree.ts +20 -0
- package/src/types/ContextObserver.ts +38 -0
- package/src/types/ContextObserverGrid.ts +16 -0
- package/src/types/ContextObserverMultiGrid.ts +5 -0
- package/src/types/ContextObserverMultiValue.ts +5 -0
- package/src/types/ContextObserverRelationship.ts +5 -0
- package/src/types/ContextObserverSeries.ts +8 -0
- package/src/types/ContextObserverTree.ts +5 -0
- package/src/types/ContextSubject.ts +18 -0
- package/src/types/Data.ts +45 -0
- package/src/types/DataFormatter.ts +99 -0
- package/src/types/DataFormatterGrid.ts +40 -0
- package/src/types/DataFormatterMultiGrid.ts +23 -0
- package/src/types/DataFormatterMultiValue.ts +19 -0
- package/src/types/DataFormatterRelationship.ts +23 -0
- package/src/types/DataFormatterSeries.ts +26 -0
- package/src/types/DataFormatterTree.ts +10 -0
- package/src/types/DataGrid.ts +11 -0
- package/src/types/DataMultiGrid.ts +7 -0
- package/src/types/DataMultiValue.ts +11 -0
- package/src/types/DataRelationship.ts +27 -0
- package/src/types/DataSeries.ts +11 -0
- package/src/types/DataTree.ts +18 -0
- package/src/types/Event.ts +114 -0
- package/src/types/Layout.ts +12 -0
- package/src/types/Padding.ts +6 -0
- package/src/types/Plugin.ts +60 -0
- package/src/types/TransformData.ts +8 -0
- package/src/types/index.ts +37 -0
- package/src/utils/commonUtils.ts +50 -0
- package/src/utils/d3Utils.ts +87 -0
- package/src/utils/index.ts +4 -0
- package/src/utils/observables.ts +198 -0
- package/src/utils/orbchartsUtils.ts +150 -0
- package/tsconfig.json +14 -0
- 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[][];
|
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
|
+
}
|
package/src/GridChart.ts
ADDED
@@ -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
|
+
}
|
package/src/TreeChart.ts
ADDED
@@ -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
|
+
}
|