@orbcharts/core 3.0.7 → 4.0.0-alpha.0

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 (196) hide show
  1. package/dist/orbcharts-core.es.js +2826 -6582
  2. package/dist/orbcharts-core.umd.js +6 -6
  3. package/dist/src/OrbCharts.d.ts +18 -0
  4. package/dist/src/chart/createChart.d.ts +3 -0
  5. package/dist/src/chart/createGraphData.d.ts +3 -0
  6. package/dist/src/chart/createGridData.d.ts +3 -0
  7. package/dist/src/chart/createMultivariateData.d.ts +3 -0
  8. package/dist/src/chart/createSeriesData.d.ts +3 -0
  9. package/dist/src/chart/createTreeData.d.ts +3 -0
  10. package/dist/src/chart/defaults.d.ts +5 -0
  11. package/dist/src/defineCanvasLayer.d.ts +16 -0
  12. package/dist/src/defineCanvasPlugin.d.ts +22 -0
  13. package/dist/src/defineSVGLayer.d.ts +16 -0
  14. package/dist/src/defineSVGPlugin.d.ts +22 -0
  15. package/dist/src/index.d.ts +6 -14
  16. package/dist/src/layer/createLayer.d.ts +3 -0
  17. package/dist/src/plugin/createPlugin.d.ts +3 -0
  18. package/dist/src/test/createGraphData.test.d.ts +1 -0
  19. package/dist/src/test/createTreeData.test.d.ts +1 -0
  20. package/dist/src/test/simple-graph-test.d.ts +74 -0
  21. package/dist/src/test/simple-tree-test.d.ts +13 -0
  22. package/dist/src/types/Chart.d.ts +39 -0
  23. package/dist/src/types/ChartContext.d.ts +27 -0
  24. package/dist/src/types/Common.d.ts +3 -0
  25. package/dist/src/types/Encoding.d.ts +33 -0
  26. package/dist/src/types/Event.d.ts +12 -0
  27. package/dist/src/types/Layers.d.ts +55 -0
  28. package/dist/src/types/ModelData.d.ts +70 -0
  29. package/dist/src/types/Plugin.d.ts +39 -0
  30. package/dist/src/types/RawData.d.ts +18 -0
  31. package/dist/src/types/RenderData.d.ts +4 -0
  32. package/dist/src/types/Theme.d.ts +17 -0
  33. package/dist/src/types/Validator.d.ts +20 -0
  34. package/dist/src/types/index.d.ts +12 -0
  35. package/dist/src/utils/aggregateUtils.d.ts +37 -0
  36. package/dist/src/utils/colorUtils.d.ts +22 -0
  37. package/dist/src/utils/commonUtils.d.ts +3 -5
  38. package/dist/src/utils/dom-lifecycle.d.ts +37 -0
  39. package/dist/src/utils/dom.d.ts +6 -0
  40. package/dist/src/utils/index.d.ts +5 -1
  41. package/dist/src/utils/observables.d.ts +1 -25
  42. package/dist/src/utils/orbchartsUtils.d.ts +2 -53
  43. package/dist/src/utils/validator.d.ts +2 -2
  44. package/dist/test/aggregateTest.d.ts +1 -0
  45. package/package.json +24 -13
  46. package/src/OrbCharts.ts +35 -0
  47. package/src/chart/createChart.ts +997 -0
  48. package/src/chart/createGraphData.ts +391 -0
  49. package/src/chart/createGridData.ts +247 -0
  50. package/src/chart/createMultivariateData.ts +181 -0
  51. package/src/chart/createSeriesData.ts +297 -0
  52. package/src/chart/createTreeData.ts +344 -0
  53. package/src/chart/defaults.ts +120 -0
  54. package/src/defineCanvasLayer.ts +24 -0
  55. package/src/defineCanvasPlugin.ts +39 -0
  56. package/src/defineSVGLayer.ts +24 -0
  57. package/src/defineSVGPlugin.ts +39 -0
  58. package/src/index.ts +6 -18
  59. package/src/layer/createLayer.ts +138 -0
  60. package/src/plugin/createPlugin.ts +470 -0
  61. package/src/test/createGraphData.test.ts +103 -0
  62. package/src/test/createTreeData.test.ts +97 -0
  63. package/src/test/simple-graph-test.js +51 -0
  64. package/src/test/simple-tree-test.js +58 -0
  65. package/src/types/Chart.ts +62 -0
  66. package/src/types/ChartContext.ts +42 -0
  67. package/src/types/Common.ts +5 -0
  68. package/src/types/Encoding.ts +43 -0
  69. package/src/types/Event.ts +26 -0
  70. package/src/types/Layers.ts +93 -0
  71. package/src/types/ModelData.ts +95 -0
  72. package/src/types/Plugin.ts +98 -0
  73. package/src/types/RawData.ts +67 -0
  74. package/src/types/RenderData.ts +16 -0
  75. package/src/types/Theme.ts +21 -0
  76. package/src/types/Validator.ts +36 -0
  77. package/src/types/index.ts +12 -0
  78. package/src/utils/aggregateUtils.ts +99 -0
  79. package/src/utils/colorUtils.ts +63 -0
  80. package/src/utils/commonUtils.ts +12 -11
  81. package/src/utils/dom-lifecycle.ts +164 -0
  82. package/src/utils/dom.ts +55 -0
  83. package/src/utils/index.ts +6 -2
  84. package/src/utils/observables.ts +1 -292
  85. package/src/utils/orbchartsUtils.ts +6 -393
  86. package/src/utils/validator.ts +15 -14
  87. package/dist/lib/core-types.d.ts +0 -1
  88. package/dist/src/AbstractChart.d.ts +0 -19
  89. package/dist/src/GridChart.d.ts +0 -6
  90. package/dist/src/MultiGridChart.d.ts +0 -6
  91. package/dist/src/MultiValueChart.d.ts +0 -6
  92. package/dist/src/RelationshipChart.d.ts +0 -6
  93. package/dist/src/SeriesChart.d.ts +0 -6
  94. package/dist/src/TreeChart.d.ts +0 -6
  95. package/dist/src/base/createBaseChart.d.ts +0 -3
  96. package/dist/src/base/createBasePlugin.d.ts +0 -3
  97. package/dist/src/base/validators/chartOptionsValidator.d.ts +0 -3
  98. package/dist/src/base/validators/chartParamsValidator.d.ts +0 -3
  99. package/dist/src/base/validators/elementValidator.d.ts +0 -3
  100. package/dist/src/base/validators/pluginsValidator.d.ts +0 -3
  101. package/dist/src/defaults.d.ts +0 -25
  102. package/dist/src/defineGridPlugin.d.ts +0 -1
  103. package/dist/src/defineMultiGridPlugin.d.ts +0 -1
  104. package/dist/src/defineMultiValuePlugin.d.ts +0 -1
  105. package/dist/src/defineNoneDataPlugin.d.ts +0 -1
  106. package/dist/src/defineRelationshipPlugin.d.ts +0 -1
  107. package/dist/src/defineSeriesPlugin.d.ts +0 -1
  108. package/dist/src/defineTreePlugin.d.ts +0 -1
  109. package/dist/src/grid/computedDataFn.d.ts +0 -4
  110. package/dist/src/grid/contextObserverCallback.d.ts +0 -3
  111. package/dist/src/grid/dataFormatterValidator.d.ts +0 -3
  112. package/dist/src/grid/dataValidator.d.ts +0 -3
  113. package/dist/src/grid/gridObservables.d.ts +0 -64
  114. package/dist/src/multiGrid/computedDataFn.d.ts +0 -3
  115. package/dist/src/multiGrid/contextObserverCallback.d.ts +0 -3
  116. package/dist/src/multiGrid/dataFormatterValidator.d.ts +0 -3
  117. package/dist/src/multiGrid/dataValidator.d.ts +0 -3
  118. package/dist/src/multiGrid/multiGridObservables.d.ts +0 -16
  119. package/dist/src/multiValue/computedDataFn.d.ts +0 -3
  120. package/dist/src/multiValue/contextObserverCallback.d.ts +0 -3
  121. package/dist/src/multiValue/dataFormatterValidator.d.ts +0 -3
  122. package/dist/src/multiValue/dataValidator.d.ts +0 -3
  123. package/dist/src/multiValue/multiValueObservables.d.ts +0 -130
  124. package/dist/src/relationship/computedDataFn.d.ts +0 -3
  125. package/dist/src/relationship/contextObserverCallback.d.ts +0 -3
  126. package/dist/src/relationship/dataFormatterValidator.d.ts +0 -3
  127. package/dist/src/relationship/dataValidator.d.ts +0 -3
  128. package/dist/src/relationship/relationshipObservables.d.ts +0 -13
  129. package/dist/src/series/computedDataFn.d.ts +0 -3
  130. package/dist/src/series/contextObserverCallback.d.ts +0 -3
  131. package/dist/src/series/dataFormatterValidator.d.ts +0 -3
  132. package/dist/src/series/dataValidator.d.ts +0 -3
  133. package/dist/src/series/seriesObservables.d.ts +0 -37
  134. package/dist/src/tree/computedDataFn.d.ts +0 -3
  135. package/dist/src/tree/contextObserverCallback.d.ts +0 -3
  136. package/dist/src/tree/dataFormatterValidator.d.ts +0 -3
  137. package/dist/src/tree/dataValidator.d.ts +0 -3
  138. package/dist/src/tree/treeObservables.d.ts +0 -10
  139. package/dist/src/utils/d3Scale.d.ts +0 -28
  140. package/lib/core-types.ts +0 -7
  141. package/src/AbstractChart.ts +0 -57
  142. package/src/GridChart.ts +0 -25
  143. package/src/MultiGridChart.ts +0 -25
  144. package/src/MultiValueChart.ts +0 -25
  145. package/src/RelationshipChart.ts +0 -25
  146. package/src/SeriesChart.ts +0 -25
  147. package/src/TreeChart.ts +0 -25
  148. package/src/base/createBaseChart.ts +0 -524
  149. package/src/base/createBasePlugin.ts +0 -154
  150. package/src/base/validators/chartOptionsValidator.ts +0 -24
  151. package/src/base/validators/chartParamsValidator.ts +0 -134
  152. package/src/base/validators/elementValidator.ts +0 -14
  153. package/src/base/validators/pluginsValidator.ts +0 -15
  154. package/src/defaults.ts +0 -284
  155. package/src/defineGridPlugin.ts +0 -3
  156. package/src/defineMultiGridPlugin.ts +0 -3
  157. package/src/defineMultiValuePlugin.ts +0 -3
  158. package/src/defineNoneDataPlugin.ts +0 -4
  159. package/src/defineRelationshipPlugin.ts +0 -3
  160. package/src/defineSeriesPlugin.ts +0 -3
  161. package/src/defineTreePlugin.ts +0 -3
  162. package/src/grid/computedDataFn.ts +0 -129
  163. package/src/grid/contextObserverCallback.ts +0 -209
  164. package/src/grid/dataFormatterValidator.ts +0 -126
  165. package/src/grid/dataValidator.ts +0 -13
  166. package/src/grid/gridObservables.ts +0 -699
  167. package/src/multiGrid/computedDataFn.ts +0 -123
  168. package/src/multiGrid/contextObserverCallback.ts +0 -109
  169. package/src/multiGrid/dataFormatterValidator.ts +0 -121
  170. package/src/multiGrid/dataValidator.ts +0 -13
  171. package/src/multiGrid/multiGridObservables.ts +0 -367
  172. package/src/multiValue/computedDataFn.ts +0 -113
  173. package/src/multiValue/contextObserverCallback.ts +0 -328
  174. package/src/multiValue/dataFormatterValidator.ts +0 -95
  175. package/src/multiValue/dataValidator.ts +0 -13
  176. package/src/multiValue/multiValueObservables.ts +0 -865
  177. package/src/relationship/computedDataFn.ts +0 -159
  178. package/src/relationship/contextObserverCallback.ts +0 -80
  179. package/src/relationship/dataFormatterValidator.ts +0 -14
  180. package/src/relationship/dataValidator.ts +0 -14
  181. package/src/relationship/relationshipObservables.ts +0 -85
  182. package/src/series/computedDataFn.ts +0 -88
  183. package/src/series/contextObserverCallback.ts +0 -132
  184. package/src/series/dataFormatterValidator.ts +0 -47
  185. package/src/series/dataValidator.ts +0 -13
  186. package/src/series/seriesObservables.ts +0 -210
  187. package/src/tree/computedDataFn.ts +0 -129
  188. package/src/tree/contextObserverCallback.ts +0 -58
  189. package/src/tree/dataFormatterValidator.ts +0 -14
  190. package/src/tree/dataValidator.ts +0 -14
  191. package/src/tree/treeObservables.ts +0 -106
  192. package/src/utils/d3Scale.ts +0 -198
  193. package/tsconfig.base.json +0 -14
  194. package/tsconfig.json +0 -3
  195. package/vite-env.d.ts +0 -7
  196. package/vite.config.js +0 -23
@@ -0,0 +1,138 @@
1
+ import {
2
+ Subject,
3
+ BehaviorSubject,
4
+ filter,
5
+ takeUntil,
6
+ switchMap,
7
+ combineLatest,
8
+ of,
9
+ map,
10
+ shareReplay,
11
+ debounceTime,
12
+ } from "rxjs"
13
+ import type {
14
+ DefineLayerConfig,
15
+ LayerEntity,
16
+ ExtendableContext,
17
+ LayerEnableProps
18
+ } from "../types"
19
+ import { deepOverwrite } from "../utils/commonUtils"
20
+ import { createOrbChartsErrorMessage, createValidatorErrorMessage, createValidatorWarningMessage } from "../utils"
21
+
22
+ export const createLayer = <
23
+ ExtendContext extends ExtendableContext,
24
+ PluginParams extends Record<string, any>,
25
+ LayerParams extends Record<string, any>
26
+ >(elementType: 'canvas' | 'svg', config: DefineLayerConfig<'svg' | 'canvas', ExtendContext, PluginParams, LayerParams>): LayerEntity<ExtendContext, PluginParams, LayerParams> => {
27
+
28
+ // let svgElement: SVGSVGElement | null = null
29
+ // let canvasElement: HTMLCanvasElement | null = null
30
+
31
+ const layerParams$ = new BehaviorSubject<LayerParams>(Object.assign({}, config.defaultParams))
32
+
33
+ // let _context: ChartContext<ExtendContext> = {} as ChartContext<ExtendContext>
34
+ let destroySetup = () => {}
35
+
36
+ const enableProps$ = new BehaviorSubject<LayerEnableProps<'svg' | 'canvas', ExtendContext, PluginParams, LayerParams> | null>(null)
37
+
38
+ const enabledProps$ = enableProps$.pipe(
39
+ filter(enableProps => enableProps !== null)
40
+ )
41
+
42
+ // show
43
+ combineLatest({
44
+ layerParams: layerParams$,
45
+ enabledProps: enabledProps$
46
+ }).pipe(
47
+ debounceTime(0)
48
+ ).subscribe(({ layerParams, enabledProps }) => {
49
+ destroySetup()
50
+ destroySetup = elementType === 'svg' ?
51
+ config.setup({
52
+ svgG: (enabledProps as LayerEnableProps<'svg', ExtendContext, PluginParams, LayerParams>).svgG,
53
+ // canvas: enabledProps.canvas,
54
+ // context: Object.assign({}, enabledProps.context),
55
+ context: enabledProps.context,
56
+ pluginParams$: enabledProps.pluginParams$,
57
+ layerParams$: layerParams$.pipe(
58
+ map(params => {
59
+ return deepOverwrite(params, enabledProps.initLayerParams ?? {})
60
+ }),
61
+ )
62
+ })
63
+ : config.setup({
64
+ // svgG: enabledProps.svgG,
65
+ canvas: (enabledProps as LayerEnableProps<'canvas', ExtendContext, PluginParams, LayerParams>).canvas,
66
+ // context: Object.assign({}, enabledProps.context),
67
+ context: enabledProps.context,
68
+ pluginParams$: enabledProps.pluginParams$,
69
+ layerParams$: layerParams$.pipe(
70
+ map(params => {
71
+ return deepOverwrite(params, enabledProps.initLayerParams ?? {})
72
+ }),
73
+ )
74
+ })
75
+ })
76
+
77
+ // hide
78
+ enableProps$.pipe(filter(enableProps => enableProps === null)).subscribe(() => {
79
+ destroySetup()
80
+ })
81
+
82
+ return {
83
+ _name: config.name,
84
+ _defaultParams: config.defaultParams,
85
+ _layerIndex: config.layerIndex,
86
+ _initShow: config.initShow,
87
+ _enable: (enableProps) => {
88
+ enableProps$.next(enableProps)
89
+ },
90
+ _disable: () => {
91
+ enableProps$.next(null)
92
+ },
93
+ // setParams: (partial) => {
94
+ // previousParams$.next(deepOverwrite(defaultParams$.getValue(), partial))
95
+ // },
96
+ _updateParams: (patch) => {
97
+ try {
98
+ // 檢查 data$ 資料格式是否正確
99
+ const { status, columnName, expectToBe } = config.validator(patch)
100
+ if (status === 'error') {
101
+ throw new Error(createValidatorErrorMessage({
102
+ columnName,
103
+ expectToBe,
104
+ from: `${config.name}.params$`
105
+ }))
106
+ } else if (status === 'warning') {
107
+ console.warn(createValidatorWarningMessage({
108
+ columnName,
109
+ expectToBe,
110
+ from: `${config.name}.params$`
111
+ }))
112
+ }
113
+ } catch (e) {
114
+ // throw new Error(e.message)
115
+ // 驗證失敗仍繼續執行,才不會把 Observable 資料流給中斷掉
116
+ console.error(createOrbChartsErrorMessage(e))
117
+ }
118
+ const layerParams = deepOverwrite(layerParams$.getValue(), patch)
119
+ layerParams$.next(layerParams)
120
+ },
121
+ _forceReplaceParams: (full) => {
122
+ layerParams$.next(full)
123
+ },
124
+ _getParams: () => {
125
+ return layerParams$.getValue()
126
+ },
127
+ // injectContext: (context) => {
128
+ // _context = Object.assign({}, context)
129
+ // // re-setup layer with new context
130
+ // enableProps$.next(true)
131
+ // },
132
+ _destroy: () => {
133
+ enableProps$.next(null)
134
+ enableProps$.complete()
135
+ layerParams$.complete()
136
+ }
137
+ }
138
+ }
@@ -0,0 +1,470 @@
1
+ import type { ChartContext, DeepPartial, DefinePluginConfig, ExtendableContext, PluginEntity } from '../types'
2
+ import {
3
+ BehaviorSubject,
4
+ combineLatest,
5
+ switchMap,
6
+ map,
7
+ filter,
8
+ of,
9
+ shareReplay,
10
+ debounceTime,
11
+ first,
12
+ Observable,
13
+ Subject,
14
+ } from 'rxjs'
15
+ import type { PluginSetupProps, LayerEnableProps } from '../types'
16
+ // import { handleElementLifecycle } from '../utils/dom-lifecycle'
17
+ // import { createSVG, createCanvasElement, createSVGGroup, createCanvas } from '../utils/dom'
18
+ // import { createPluginClassName, createLayerClassName } from '../utils/orbchartsUtils'
19
+ import { deepOverwrite } from '../utils/commonUtils'
20
+ import { createOrbChartsErrorMessage, createValidatorErrorMessage, createValidatorWarningMessage } from '../utils/errorMessage'
21
+
22
+ export const createPlugin = <
23
+ ElementType extends 'svg' | 'canvas',
24
+ ExtendContext extends ExtendableContext,
25
+ PluginParams,
26
+ AllLayerParams
27
+ >(elementType: ElementType, config: DefinePluginConfig<ExtendContext, PluginParams, AllLayerParams>, initPluginParams?: DeepPartial<PluginParams | AllLayerParams>): PluginEntity<ElementType, PluginParams, AllLayerParams> => {
28
+ // const svgClassName = `${createPluginClassName(config.name)}__svg`
29
+ // const svgGClassName = `${createPluginClassName(config.name)}__g`
30
+ // const canvasClassName = `${createPluginClassName(config.name)}__canvas`
31
+
32
+ // 內部保存起來的 id
33
+ let _id = config.name
34
+
35
+ let destroySetup = () => {}
36
+
37
+ const context$ = new BehaviorSubject<ChartContext<ExtendContext> | null>(null)
38
+ const injectedContext$ = context$.pipe(
39
+ filter((context): context is ChartContext<ExtendContext> => context !== null)
40
+ )
41
+
42
+ // element 全部保存起來避免重複創建
43
+ // const layerSVGElementsRef: Record<string, SVGElement> = {}
44
+ // const layerCanvasElementsRef: Record<string, HTMLCanvasElement> = {}
45
+
46
+ // 全部的layers
47
+ const allLayerInstances = {
48
+ // 將陣列轉成字典
49
+ ...config.layers.reduce((acc, layer) => {
50
+ acc[layer._name as keyof AllLayerParams] = layer
51
+ return acc
52
+ }, {} as Record<keyof AllLayerParams, typeof config.layers[number]>)
53
+ }
54
+ const getAllLayerNamesSet = () => new Set(config.layers.map(l => l._name as keyof AllLayerParams))
55
+ // const getParamsKeySet = (params: DeepPartial<PluginParams | AllLayerParams>): Set<keyof AllLayerParams> => {
56
+ // // 取得有設定 params 的 layer name
57
+ // if (params) {
58
+ // const AllLayerNamesSet = getAllLayerNamesSet()
59
+ // const keysOfParams = Object.keys(params) as (keyof AllLayerParams)[]
60
+ // return new Set(keysOfParams.filter(key => AllLayerNamesSet.has(key)))
61
+ // }
62
+ // return new Set()
63
+ // }
64
+ const getParamsKeys = (params: DeepPartial<PluginParams | AllLayerParams>): (keyof AllLayerParams)[] => {
65
+ // 取得有設定 params 的 layer name
66
+ if (params) {
67
+ const AllLayerNamesSet = getAllLayerNamesSet()
68
+ const keysOfParams = Object.keys(params) as (keyof AllLayerParams)[]
69
+ return keysOfParams.filter(key => AllLayerNamesSet.has(key))
70
+ }
71
+ return []
72
+ }
73
+
74
+ // config 設定顯示的 layers
75
+ const systemInitLayerNames = config.layers.reduce((prev, current) => {
76
+ if (current._initShow) {
77
+ prev.push(current._name as keyof AllLayerParams)
78
+ }
79
+ return prev
80
+ }, [] as (keyof AllLayerParams)[])
81
+ // 有設定 params 對應的 layers 名稱
82
+ const initLayerNames = getParamsKeys(initPluginParams)
83
+ // const InitLayerNameSet$ = new BehaviorSubject<Set<keyof AllLayerParams>>(getParamsKeySet(initPluginParams))
84
+ // 有設定 show/showOnly 等的 layers 名稱
85
+ const ShownLayerNameSet$ = new BehaviorSubject<Set<keyof AllLayerParams>>(
86
+ new Set(initLayerNames.length > 0 ? initLayerNames : systemInitLayerNames)
87
+ )
88
+ // 顯示的 layers 名稱
89
+ // const getShownLayerNames = ({ InitLayerNameSet, IsShowLayerNameSet }: { InitLayerNameSet: Set<keyof AllLayerParams>, IsShowLayerNameSet: Set<keyof AllLayerParams> | null }) => {
90
+ // const ShownLayerNameSet = IsShowLayerNameSet == null ? InitLayerNameSet : IsShowLayerNameSet // IsShowLayerNameSet 預設為 null
91
+ // return ShownLayerNameSet
92
+ // }
93
+ // const ShownLayerNameSet$ = combineLatest({
94
+ // InitLayerNameSet: InitLayerNameSet$,
95
+ // IsShowLayerNameSet: IsShowLayerNameSet$
96
+ // }).pipe(
97
+ // debounceTime(0),
98
+ // // filter(({ context }) => context !== null),
99
+ // map(({ InitLayerNameSet, IsShowLayerNameSet }) => {
100
+ // return getShownLayerNames({ InitLayerNameSet, IsShowLayerNameSet })
101
+ // })
102
+ // )
103
+ // 顯示的 layers 名稱依照 layerIndex 排序
104
+ const shownLayerNamesSeq$ = ShownLayerNameSet$.pipe(
105
+ map(ShownLayerNameSet => {
106
+ // 依照 layerIndex 排序
107
+ const shownLayerNamesSeq: string[] = Array.from(ShownLayerNameSet)
108
+ .map(name => [
109
+ name,
110
+ config.layers.find(l => l._name === name)?._layerIndex ?? -1
111
+ ])
112
+ .filter(([, index]) => index !== -1)
113
+ .sort((a, b) => (a[1] as number) - (b[1] as number))
114
+ .map(([name]) => name as string)
115
+ return shownLayerNamesSeq
116
+ })
117
+ )
118
+
119
+ // plugin 的根元素
120
+ // const pluginElement$: Observable<SVGGElement | HTMLCanvasElement> = injectedContext$.pipe(
121
+ // map(context => {
122
+ // // -- 在 svg 或 canvas 元素底下建立 plugin 的元素 --
123
+ // if (elementType === 'svg') {
124
+ // let svgGElement: SVGGElement | null = context.svg.querySelector(`.${svgGClassName}`)
125
+ // if (!svgGElement) {
126
+ // svgGElement = createSVGGroup(svgGClassName)
127
+ // context.svg.appendChild(svgGElement)
128
+ // }
129
+ // return svgGElement
130
+ // } else if (elementType === 'canvas') {
131
+ // let canvasElement: HTMLCanvasElement | null = context.canvas.querySelector(`.${canvasClassName}`)
132
+ // if (!canvasElement) {
133
+ // canvasElement = createCanvasElement(canvasClassName)
134
+ // context.canvas.appendChild(canvasElement)
135
+ // }
136
+ // return canvasElement
137
+ // }
138
+ // })
139
+ // )
140
+
141
+ // update plugin params
142
+ const patchPluginParams$ = new BehaviorSubject<DeepPartial<AllLayerParams | PluginParams> | undefined>(
143
+ initPluginParams ?? {}
144
+ )
145
+
146
+ // force replace plugin params
147
+ const forceReplacePluginParams$ = new Subject<DeepPartial<AllLayerParams | PluginParams> | undefined>()
148
+
149
+ const pluginParams$ = new Observable<PluginParams>(subscriber => {
150
+ // -- update --
151
+ patchPluginParams$.subscribe(patch => {
152
+ try {
153
+ // 檢查 data$ 資料格式是否正確
154
+ const { status, columnName, expectToBe } = config.validator(patch)
155
+ if (status === 'error') {
156
+ throw new Error(createValidatorErrorMessage({
157
+ columnName,
158
+ expectToBe,
159
+ from: `${config.name}.params$`
160
+ }))
161
+ } else if (status === 'warning') {
162
+ console.warn(createValidatorWarningMessage({
163
+ columnName,
164
+ expectToBe,
165
+ from: `${config.name}.params$`
166
+ }))
167
+ }
168
+ } catch (e) {
169
+ // throw new Error(e.message)
170
+ // 驗證失敗仍繼續執行,才不會把 Observable 資料流給中斷掉
171
+ console.error(createOrbChartsErrorMessage(e))
172
+ }
173
+
174
+ const newParams = deepOverwrite(config.defaultParams, patch as DeepPartial<PluginParams> ?? {})
175
+ // console.log('newParams', newParams)
176
+ subscriber.next(newParams)
177
+ })
178
+
179
+ // -- force replace --
180
+ forceReplacePluginParams$.subscribe(full => {
181
+ subscriber.next(full as PluginParams)
182
+ })
183
+ })
184
+
185
+ // patchPluginParams$.pipe(
186
+ // map(patch => {
187
+ // try {
188
+ // // 檢查 data$ 資料格式是否正確
189
+ // const { status, columnName, expectToBe } = config.validator(patch)
190
+ // if (status === 'error') {
191
+ // throw new Error(createValidatorErrorMessage({
192
+ // columnName,
193
+ // expectToBe,
194
+ // from: `${config.name}.params$`
195
+ // }))
196
+ // } else if (status === 'warning') {
197
+ // console.warn(createValidatorWarningMessage({
198
+ // columnName,
199
+ // expectToBe,
200
+ // from: `${config.name}.params$`
201
+ // }))
202
+ // }
203
+ // } catch (e) {
204
+ // // throw new Error(e.message)
205
+ // // 驗證失敗仍繼續執行,才不會把 Observable 資料流給中斷掉
206
+ // console.error(createOrbChartsErrorMessage(e))
207
+ // }
208
+
209
+ // return deepOverwrite(config.defaultParams, patch as DeepPartial<PluginParams> ?? {})
210
+ // }),
211
+ // shareReplay(1)
212
+ // )
213
+
214
+ const pluginSetupProps$: Observable<PluginSetupProps<ExtendContext, PluginParams>> = injectedContext$.pipe(
215
+ map((context) => {
216
+ // const pluginSetupProps: PluginSetupProps<ExtendContext, PluginParams> =
217
+ // elementType === 'svg' ? {
218
+ // context: context as ChartContext<ExtendContext>, // 初始化時 context 有可能被 in place 擴展
219
+ // svgG: pluginElement as SVGSVGElement,
220
+ // pluginParams$
221
+ // } : {
222
+ // context: context as ChartContext<ExtendContext>,
223
+ // canvas: pluginElement as HTMLCanvasElement,
224
+ // pluginParams$
225
+ // }
226
+ return {
227
+ context, // 初始化時 context 有可能被 in place 擴展
228
+ pluginParams$
229
+ }
230
+ }),
231
+ first() // 只做初始化
232
+ )
233
+
234
+ combineLatest({
235
+ pluginSetupProps: pluginSetupProps$,
236
+ ShownLayerNameSet: ShownLayerNameSet$,
237
+ shownLayerNamesSeq: shownLayerNamesSeq$
238
+ }).pipe(
239
+ debounceTime(0)
240
+ ).subscribe(({ pluginSetupProps, ShownLayerNameSet, shownLayerNamesSeq }) => {
241
+
242
+ // 更新 layer elements
243
+ const layerElements = pluginSetupProps.context._updateLayerElements(
244
+ elementType,
245
+ _id,
246
+ shownLayerNamesSeq.map(layer => ({
247
+ pluginId: _id,
248
+ pluginName: config.name,
249
+ layerName: layer,
250
+ layerIndex: allLayerInstances[layer as keyof AllLayerParams]._layerIndex
251
+ }))
252
+ )
253
+
254
+ // init plugin
255
+ if (config.setup) {
256
+ destroySetup = config.setup(pluginSetupProps)
257
+ }
258
+
259
+ // // layer element - 處理 SVG 元素的 enter/update/exit
260
+ // if (elementType === 'svg') {
261
+ // handleElementLifecycle(
262
+ // // (pluginSetupProps as PluginSetupProps<ExtendContext, PluginParams>).svgG,
263
+ // pluginSetupProps.context.svg,
264
+ // shownLayerNamesSeq, // 依照 shownLayerNamesSeq
265
+ // layerSVGElementsRef,
266
+ // (layerName) => createSVGGroup(createLayerClassName(config.name, layerName))
267
+ // )
268
+ // }
269
+
270
+ // // layer element - 處理 Canvas 元素的 enter/update/exit
271
+ // if (elementType === 'canvas') {
272
+ // handleElementLifecycle(
273
+ // // (pluginSetupProps as PluginSetupProps<ExtendContext, PluginParams>).canvas,
274
+ // pluginSetupProps.context.canvas,
275
+ // shownLayerNamesSeq, // 依照 shownLayerNamesSeq
276
+ // layerCanvasElementsRef,
277
+ // (layerName) => createCanvas(createLayerClassName(config.name, layerName))
278
+ // )
279
+ // }
280
+
281
+ // init layers
282
+ config.layers.forEach((layer) => {
283
+ if (ShownLayerNameSet.has(layer._name as keyof AllLayerParams)) {
284
+ const layerEnableProps: LayerEnableProps<'svg' | 'canvas', ExtendContext, PluginParams, unknown> =
285
+ elementType === 'svg' ?
286
+ {
287
+ // svgG: (pluginSetupProps as PluginSetupProps<'svg', ExtendContext, PluginParams>).svgG.querySelector(`.${createLayerClassName(config.name, layer.name)}`),
288
+ svgG: layerElements[layer._name as keyof AllLayerParams] as SVGGElement,
289
+ // canvas: context.root.querySelector(`.${createLayerClassName(config.name, layer.name)}`),
290
+ // context: Object.assign({}, context) as ChartContext<ExtendContext>,
291
+ context: pluginSetupProps.context,
292
+ pluginParams$,
293
+ initLayerParams: patchPluginParams$.getValue()?.[layer._name as keyof AllLayerParams] as unknown || {}
294
+ }
295
+ : {
296
+ // svgG: context.root.querySelector(`.${createLayerClassName(config.name, layer.name)}`),
297
+ // canvas: (pluginSetupProps as PluginSetupProps<'canvas', ExtendContext, PluginParams>).canvas.querySelector(`.${createLayerClassName(config.name, layer.name)}`),
298
+ canvas: layerElements[layer._name as keyof AllLayerParams] as HTMLCanvasElement,
299
+ // context: Object.assign({}, context) as ChartContext<ExtendContext>,
300
+ context: pluginSetupProps.context,
301
+ pluginParams$,
302
+ initLayerParams: patchPluginParams$.getValue()?.[layer._name as keyof AllLayerParams] as unknown || {}
303
+ }
304
+
305
+ layer._enable(layerEnableProps)
306
+ } else {
307
+ layer._disable()
308
+ }
309
+ })
310
+ })
311
+
312
+ return {
313
+ // name: `${config.name}-${Math.random().toString(36).substr(2, 9)}`,
314
+ _name: config.name,
315
+ _elementType: elementType,
316
+ // info: {
317
+ // name: config.name,
318
+ // layers: [config.name]
319
+ // } as PluginInfo,
320
+ // layerIndex: config.layerIndex,
321
+ // contextExtension,
322
+ // layer visibility controls
323
+ _getId: () => _id,
324
+ _setId: (id: string) => {
325
+ _id = id
326
+ },
327
+ // 由 chart 注入 context
328
+ _injectContext: (context) => {
329
+
330
+ context$.next(Object.assign({}, context) as ChartContext<ExtendContext>)
331
+
332
+ // context.size$.subscribe(size => {
333
+ // const svgGElement: SVGGElement | null = context.root.querySelector(`.${svgGClassName}`)
334
+ // const canvasElement: HTMLCanvasElement | null = context.root.querySelector(`.${canvasClassName}`)
335
+ // if (svgGElement) {
336
+ // svgGElement.setAttribute('width', size.width.toString())
337
+ // svgGElement.setAttribute('height', size.height.toString())
338
+ // }
339
+ // if (canvasElement) {
340
+ // canvasElement.width = size.width
341
+ // canvasElement.height = size.height
342
+ // }
343
+ // })
344
+
345
+ // if (config.setup) {
346
+ // // const extension: ExtendContext = config.setup(context)
347
+ // // Object.assign(context, extension)
348
+ // config.setup({
349
+ // context: context as ChartContext<ExtendContext>,
350
+ // svg: mainSvgElement!,
351
+ // canvas: mainCanvasElement!,
352
+ // pluginParams$
353
+ // })
354
+ // }
355
+
356
+ // 顯示全部 layers
357
+ // IsShowLayerNameSet$.next(getAllLayerNamesSet())
358
+ },
359
+ show: (names: (keyof AllLayerParams) | (keyof AllLayerParams)[]) => {
360
+ names = Array.isArray(names) ? names : [names]
361
+ ShownLayerNameSet$.next(new Set([...Array.from(ShownLayerNameSet$.getValue()), ...names]))
362
+ },
363
+ showOnly: (names: (keyof AllLayerParams) | (keyof AllLayerParams)[]) => {
364
+ names = Array.isArray(names) ? names : [names]
365
+ ShownLayerNameSet$.next(new Set([...names]))
366
+ },
367
+ showAll: () => {
368
+ ShownLayerNameSet$.next(getAllLayerNamesSet())
369
+ },
370
+ hide: (names: (keyof AllLayerParams) | (keyof AllLayerParams)[]) => {
371
+ names = Array.isArray(names) ? names : [names]
372
+ ShownLayerNameSet$.next(new Set([...Array.from(ShownLayerNameSet$.getValue()).filter(name => !names.includes(name))]))
373
+ },
374
+ hideAll: () => {
375
+ ShownLayerNameSet$.next(new Set())
376
+ },
377
+ toggle: (names: (keyof AllLayerParams) | (keyof AllLayerParams)[]) => {
378
+ names = Array.isArray(names) ? names : [names]
379
+ Array.from(ShownLayerNameSet$.getValue()).forEach(shown => {
380
+ if (names.includes(shown)) {
381
+ names.splice(names.indexOf(shown), 1)
382
+ } else {
383
+ names.push(shown)
384
+ }
385
+ })
386
+ ShownLayerNameSet$.next(new Set(names))
387
+ },
388
+ getShownLayerNames: () => {
389
+ // const ShownLayerNameSet = getShownLayerNames({
390
+ // InitLayerNameSet: InitLayerNameSet$.getValue(),
391
+ // IsShowLayerNameSet: IsShowLayerNameSet$.getValue()
392
+ // })
393
+ return Array.from(ShownLayerNameSet$.getValue())
394
+ },
395
+ // layer params
396
+ // setLayers: (partial: DeepPartial<PluginParams>) => {
397
+ // params = { ...params, ...partial }
398
+ // },
399
+ updateParams: (patch: DeepPartial<PluginParams | AllLayerParams>) => {
400
+ // plugin params
401
+ patchPluginParams$.next(patch)
402
+ // layer params
403
+ Object.keys(patch).forEach((key) => {
404
+ const layer = allLayerInstances[key as keyof AllLayerParams]
405
+ if (layer) {
406
+ layer._updateParams((patch as Record<string, any>)[key])
407
+ }
408
+ })
409
+
410
+ // InitLayerNameSet$.next(getParamsKeySet(patch))
411
+ },
412
+ forceReplaceParams: (full: PluginParams | AllLayerParams) => {
413
+ // plugin params
414
+ forceReplacePluginParams$.next(full)
415
+ // layer params
416
+ Object.keys(full).forEach((key) => {
417
+ const layer = allLayerInstances[key as keyof AllLayerParams]
418
+ if (layer) {
419
+ layer._forceReplaceParams((full as Record<string, any>)[key])
420
+ }
421
+ })
422
+ // InitLayerNameSet$.next(getParamsKeySet(full))
423
+ },
424
+ getParams: () => {
425
+ return config.layers.reduce((acc, layer) => {
426
+ acc[layer._name] = layer._getParams()
427
+ return acc
428
+ }, {} as Record<string, any>) as PluginParams | AllLayerParams
429
+ },
430
+ // layer: <LayerName extends keyof PluginParams>(name: LayerName) => ({
431
+ // // set: (partial: DeepPartial<PluginParams[LayerName]>) => {
432
+ // // if (params[name]) {
433
+ // // params[name] = { ...params[name], ...partial }
434
+ // // }
435
+ // // },
436
+ // update: (patch: DeepPartial<PluginParams[LayerName]>) => {
437
+ // if (params[name]) {
438
+ // params[name] = { ...params[name], ...patch }
439
+ // }
440
+ // },
441
+ // replace: (full: PluginParams[LayerName]) => {
442
+ // params[name] = full
443
+ // },
444
+ // show: () => {
445
+ // // implementation for showing this layer
446
+ // },
447
+ // hide: () => {
448
+ // // implementation for hiding this layer
449
+ // },
450
+ // toggle: () => {
451
+ // // implementation for toggling this layer
452
+ // }
453
+ // }),
454
+ destroy: () => {
455
+ destroySetup()
456
+ // subscription.unsubscribe()
457
+ context$.complete()
458
+ // IsShowLayerNameSet$.complete()
459
+ ShownLayerNameSet$.complete()
460
+
461
+ config.layers.forEach((layer) => {
462
+ layer._destroy()
463
+ })
464
+ },
465
+ // // outputs
466
+ // layers$: new Observable<Record<string, PluginParams>>(subscriber => {
467
+ // subscriber.next(params)
468
+ // })
469
+ }
470
+ }