@orbcharts/core 3.0.7 → 4.0.0-beta.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 (198) hide show
  1. package/LICENSE +200 -200
  2. package/dist/orbcharts-core.es.js +2849 -6594
  3. package/dist/orbcharts-core.umd.js +6 -6
  4. package/dist/src/OrbCharts.d.ts +18 -0
  5. package/dist/src/chart/createChart.d.ts +3 -0
  6. package/dist/src/chart/createGraphData.d.ts +3 -0
  7. package/dist/src/chart/createGridData.d.ts +3 -0
  8. package/dist/src/chart/createMultivariateData.d.ts +3 -0
  9. package/dist/src/chart/createSeriesData.d.ts +3 -0
  10. package/dist/src/chart/createTreeData.d.ts +3 -0
  11. package/dist/src/chart/defaults.d.ts +5 -0
  12. package/dist/src/defineCanvasLayer.d.ts +16 -0
  13. package/dist/src/defineCanvasPlugin.d.ts +22 -0
  14. package/dist/src/defineSVGLayer.d.ts +16 -0
  15. package/dist/src/defineSVGPlugin.d.ts +22 -0
  16. package/dist/src/index.d.ts +6 -14
  17. package/dist/src/layer/createLayer.d.ts +3 -0
  18. package/dist/src/plugin/createPlugin.d.ts +3 -0
  19. package/dist/src/test/createGraphData.test.d.ts +1 -0
  20. package/dist/src/test/createTreeData.test.d.ts +1 -0
  21. package/dist/src/test/simple-graph-test.d.ts +74 -0
  22. package/dist/src/test/simple-tree-test.d.ts +13 -0
  23. package/dist/src/types/Chart.d.ts +39 -0
  24. package/dist/src/types/ChartContext.d.ts +27 -0
  25. package/dist/src/types/Common.d.ts +3 -0
  26. package/dist/src/types/Encoding.d.ts +33 -0
  27. package/dist/src/types/Event.d.ts +12 -0
  28. package/dist/src/types/Layers.d.ts +55 -0
  29. package/dist/src/types/ModelData.d.ts +70 -0
  30. package/dist/src/types/Plugin.d.ts +39 -0
  31. package/dist/src/types/RawData.d.ts +18 -0
  32. package/dist/src/types/RenderData.d.ts +4 -0
  33. package/dist/src/types/Theme.d.ts +17 -0
  34. package/dist/src/types/Validator.d.ts +20 -0
  35. package/dist/src/types/index.d.ts +12 -0
  36. package/dist/src/utils/aggregateUtils.d.ts +37 -0
  37. package/dist/src/utils/colorUtils.d.ts +22 -0
  38. package/dist/src/utils/commonUtils.d.ts +3 -5
  39. package/dist/src/utils/dom-lifecycle.d.ts +37 -0
  40. package/dist/src/utils/dom.d.ts +6 -0
  41. package/dist/src/utils/index.d.ts +5 -1
  42. package/dist/src/utils/observables.d.ts +1 -25
  43. package/dist/src/utils/orbchartsUtils.d.ts +2 -53
  44. package/dist/src/utils/validator.d.ts +2 -2
  45. package/dist/test/aggregateTest.d.ts +1 -0
  46. package/package.json +24 -13
  47. package/src/OrbCharts.ts +35 -0
  48. package/src/chart/createChart.ts +1014 -0
  49. package/src/chart/createGraphData.ts +391 -0
  50. package/src/chart/createGridData.ts +247 -0
  51. package/src/chart/createMultivariateData.ts +181 -0
  52. package/src/chart/createSeriesData.ts +297 -0
  53. package/src/chart/createTreeData.ts +344 -0
  54. package/src/chart/defaults.ts +120 -0
  55. package/src/defineCanvasLayer.ts +24 -0
  56. package/src/defineCanvasPlugin.ts +39 -0
  57. package/src/defineSVGLayer.ts +24 -0
  58. package/src/defineSVGPlugin.ts +39 -0
  59. package/src/index.ts +8 -20
  60. package/src/layer/createLayer.ts +138 -0
  61. package/src/plugin/createPlugin.ts +488 -0
  62. package/src/test/createGraphData.test.ts +103 -0
  63. package/src/test/createTreeData.test.ts +97 -0
  64. package/src/test/simple-graph-test.js +51 -0
  65. package/src/test/simple-tree-test.js +58 -0
  66. package/src/types/Chart.ts +62 -0
  67. package/src/types/ChartContext.ts +42 -0
  68. package/src/types/Common.ts +5 -0
  69. package/src/types/Encoding.ts +43 -0
  70. package/src/types/Event.ts +26 -0
  71. package/src/types/Layers.ts +93 -0
  72. package/src/types/ModelData.ts +95 -0
  73. package/src/types/Plugin.ts +101 -0
  74. package/src/types/RawData.ts +67 -0
  75. package/src/types/RenderData.ts +16 -0
  76. package/src/types/Theme.ts +21 -0
  77. package/src/types/Validator.ts +36 -0
  78. package/src/types/index.ts +12 -0
  79. package/src/utils/aggregateUtils.ts +99 -0
  80. package/src/utils/colorUtils.ts +63 -0
  81. package/src/utils/commonUtils.ts +56 -55
  82. package/src/utils/dom-lifecycle.ts +164 -0
  83. package/src/utils/dom.ts +55 -0
  84. package/src/utils/errorMessage.ts +40 -40
  85. package/src/utils/index.ts +8 -4
  86. package/src/utils/observables.ts +16 -307
  87. package/src/utils/orbchartsUtils.ts +9 -396
  88. package/src/utils/validator.ts +127 -126
  89. package/dist/lib/core-types.d.ts +0 -1
  90. package/dist/src/AbstractChart.d.ts +0 -19
  91. package/dist/src/GridChart.d.ts +0 -6
  92. package/dist/src/MultiGridChart.d.ts +0 -6
  93. package/dist/src/MultiValueChart.d.ts +0 -6
  94. package/dist/src/RelationshipChart.d.ts +0 -6
  95. package/dist/src/SeriesChart.d.ts +0 -6
  96. package/dist/src/TreeChart.d.ts +0 -6
  97. package/dist/src/base/createBaseChart.d.ts +0 -3
  98. package/dist/src/base/createBasePlugin.d.ts +0 -3
  99. package/dist/src/base/validators/chartOptionsValidator.d.ts +0 -3
  100. package/dist/src/base/validators/chartParamsValidator.d.ts +0 -3
  101. package/dist/src/base/validators/elementValidator.d.ts +0 -3
  102. package/dist/src/base/validators/pluginsValidator.d.ts +0 -3
  103. package/dist/src/defaults.d.ts +0 -25
  104. package/dist/src/defineGridPlugin.d.ts +0 -1
  105. package/dist/src/defineMultiGridPlugin.d.ts +0 -1
  106. package/dist/src/defineMultiValuePlugin.d.ts +0 -1
  107. package/dist/src/defineNoneDataPlugin.d.ts +0 -1
  108. package/dist/src/defineRelationshipPlugin.d.ts +0 -1
  109. package/dist/src/defineSeriesPlugin.d.ts +0 -1
  110. package/dist/src/defineTreePlugin.d.ts +0 -1
  111. package/dist/src/grid/computedDataFn.d.ts +0 -4
  112. package/dist/src/grid/contextObserverCallback.d.ts +0 -3
  113. package/dist/src/grid/dataFormatterValidator.d.ts +0 -3
  114. package/dist/src/grid/dataValidator.d.ts +0 -3
  115. package/dist/src/grid/gridObservables.d.ts +0 -64
  116. package/dist/src/multiGrid/computedDataFn.d.ts +0 -3
  117. package/dist/src/multiGrid/contextObserverCallback.d.ts +0 -3
  118. package/dist/src/multiGrid/dataFormatterValidator.d.ts +0 -3
  119. package/dist/src/multiGrid/dataValidator.d.ts +0 -3
  120. package/dist/src/multiGrid/multiGridObservables.d.ts +0 -16
  121. package/dist/src/multiValue/computedDataFn.d.ts +0 -3
  122. package/dist/src/multiValue/contextObserverCallback.d.ts +0 -3
  123. package/dist/src/multiValue/dataFormatterValidator.d.ts +0 -3
  124. package/dist/src/multiValue/dataValidator.d.ts +0 -3
  125. package/dist/src/multiValue/multiValueObservables.d.ts +0 -130
  126. package/dist/src/relationship/computedDataFn.d.ts +0 -3
  127. package/dist/src/relationship/contextObserverCallback.d.ts +0 -3
  128. package/dist/src/relationship/dataFormatterValidator.d.ts +0 -3
  129. package/dist/src/relationship/dataValidator.d.ts +0 -3
  130. package/dist/src/relationship/relationshipObservables.d.ts +0 -13
  131. package/dist/src/series/computedDataFn.d.ts +0 -3
  132. package/dist/src/series/contextObserverCallback.d.ts +0 -3
  133. package/dist/src/series/dataFormatterValidator.d.ts +0 -3
  134. package/dist/src/series/dataValidator.d.ts +0 -3
  135. package/dist/src/series/seriesObservables.d.ts +0 -37
  136. package/dist/src/tree/computedDataFn.d.ts +0 -3
  137. package/dist/src/tree/contextObserverCallback.d.ts +0 -3
  138. package/dist/src/tree/dataFormatterValidator.d.ts +0 -3
  139. package/dist/src/tree/dataValidator.d.ts +0 -3
  140. package/dist/src/tree/treeObservables.d.ts +0 -10
  141. package/dist/src/utils/d3Scale.d.ts +0 -28
  142. package/lib/core-types.ts +0 -7
  143. package/src/AbstractChart.ts +0 -57
  144. package/src/GridChart.ts +0 -25
  145. package/src/MultiGridChart.ts +0 -25
  146. package/src/MultiValueChart.ts +0 -25
  147. package/src/RelationshipChart.ts +0 -25
  148. package/src/SeriesChart.ts +0 -25
  149. package/src/TreeChart.ts +0 -25
  150. package/src/base/createBaseChart.ts +0 -524
  151. package/src/base/createBasePlugin.ts +0 -154
  152. package/src/base/validators/chartOptionsValidator.ts +0 -24
  153. package/src/base/validators/chartParamsValidator.ts +0 -134
  154. package/src/base/validators/elementValidator.ts +0 -14
  155. package/src/base/validators/pluginsValidator.ts +0 -15
  156. package/src/defaults.ts +0 -284
  157. package/src/defineGridPlugin.ts +0 -3
  158. package/src/defineMultiGridPlugin.ts +0 -3
  159. package/src/defineMultiValuePlugin.ts +0 -3
  160. package/src/defineNoneDataPlugin.ts +0 -4
  161. package/src/defineRelationshipPlugin.ts +0 -3
  162. package/src/defineSeriesPlugin.ts +0 -3
  163. package/src/defineTreePlugin.ts +0 -3
  164. package/src/grid/computedDataFn.ts +0 -129
  165. package/src/grid/contextObserverCallback.ts +0 -209
  166. package/src/grid/dataFormatterValidator.ts +0 -126
  167. package/src/grid/dataValidator.ts +0 -13
  168. package/src/grid/gridObservables.ts +0 -699
  169. package/src/multiGrid/computedDataFn.ts +0 -123
  170. package/src/multiGrid/contextObserverCallback.ts +0 -109
  171. package/src/multiGrid/dataFormatterValidator.ts +0 -121
  172. package/src/multiGrid/dataValidator.ts +0 -13
  173. package/src/multiGrid/multiGridObservables.ts +0 -367
  174. package/src/multiValue/computedDataFn.ts +0 -113
  175. package/src/multiValue/contextObserverCallback.ts +0 -328
  176. package/src/multiValue/dataFormatterValidator.ts +0 -95
  177. package/src/multiValue/dataValidator.ts +0 -13
  178. package/src/multiValue/multiValueObservables.ts +0 -865
  179. package/src/relationship/computedDataFn.ts +0 -159
  180. package/src/relationship/contextObserverCallback.ts +0 -80
  181. package/src/relationship/dataFormatterValidator.ts +0 -14
  182. package/src/relationship/dataValidator.ts +0 -14
  183. package/src/relationship/relationshipObservables.ts +0 -85
  184. package/src/series/computedDataFn.ts +0 -88
  185. package/src/series/contextObserverCallback.ts +0 -132
  186. package/src/series/dataFormatterValidator.ts +0 -47
  187. package/src/series/dataValidator.ts +0 -13
  188. package/src/series/seriesObservables.ts +0 -210
  189. package/src/tree/computedDataFn.ts +0 -129
  190. package/src/tree/contextObserverCallback.ts +0 -58
  191. package/src/tree/dataFormatterValidator.ts +0 -14
  192. package/src/tree/dataValidator.ts +0 -14
  193. package/src/tree/treeObservables.ts +0 -106
  194. package/src/utils/d3Scale.ts +0 -198
  195. package/tsconfig.base.json +0 -14
  196. package/tsconfig.json +0 -3
  197. package/vite-env.d.ts +0 -7
  198. package/vite.config.js +0 -23
@@ -0,0 +1,1014 @@
1
+ import {
2
+ Subject,
3
+ BehaviorSubject,
4
+ Observable,
5
+ EMPTY,
6
+ shareReplay,
7
+ takeUntil,
8
+ filter,
9
+ switchMap,
10
+ of,
11
+ iif,
12
+ map,
13
+ debounceTime,
14
+ throttleTime,
15
+ distinctUntilChanged,
16
+ mergeWith,
17
+ share,
18
+ combineLatest,
19
+ catchError
20
+ } from 'rxjs'
21
+ import type {
22
+ DeepPartial,
23
+ CreateChart,
24
+ PartialChartOptions,
25
+ ChartContext,
26
+ RawData,
27
+ Encoding,
28
+ ModelData,
29
+ PluginInfo,
30
+ PluginEntity,
31
+ Theme,
32
+ EventData,
33
+ Size,
34
+ SizeConfig,
35
+ ValidatorResult,
36
+ LayerInfo,
37
+ } from '../types'
38
+ import {
39
+ isDom,
40
+ isPlainObject,
41
+ removeElementChildren,
42
+ deepOverwrite,
43
+ validateObject,
44
+ createValidatorErrorMessage,
45
+ createValidatorWarningMessage,
46
+ createOrbChartsErrorMessage,
47
+ resizeObservable,
48
+ createUnexpectedErrorMessage,
49
+ createSVG,
50
+ createSVGGroup,
51
+ createCanvas
52
+ } from '../utils'
53
+ import { DEFAULT_DATA_ENCODING, DEFAULT_THEME, DEFAULT_SIZE_CONFIG } from './defaults'
54
+ import { createSeriesData } from './createSeriesData'
55
+ import { createGridData } from './createGridData'
56
+ import { createMultivariateData } from './createMultivariateData'
57
+ import { createGraphData } from './createGraphData'
58
+ import { createTreeData } from './createTreeData'
59
+ import { handleElementLifecycle } from '../utils/dom-lifecycle'
60
+ import { createLayerClassName } from '../utils/orbchartsUtils'
61
+
62
+ interface LayerMakerInfo extends LayerInfo {
63
+ pluginSeq: number
64
+ }
65
+
66
+ function elementValidator (element: HTMLElement | Element): ValidatorResult {
67
+ const result = validateObject({ element }, {
68
+ element: {
69
+ toBe: 'Dom',
70
+ test: (value: any) => isDom(value)
71
+ },
72
+ })
73
+
74
+ return result
75
+ }
76
+
77
+ function sizeOptionsValidator (sizeConfig: DeepPartial<SizeConfig>): ValidatorResult {
78
+ const result = validateObject(sizeConfig, {
79
+ width: {
80
+ toBe: '"auto" | number',
81
+ test: (value: any) => value === 'auto' || typeof value === 'number'
82
+ },
83
+ height: {
84
+ toBe: '"auto" | number',
85
+ test: (value: any) => value === 'auto' || typeof value === 'number'
86
+ },
87
+ resizeDebounce: {
88
+ toBe: 'number',
89
+ test: (value: any) => typeof value === 'number'
90
+ }
91
+ })
92
+ return result
93
+ }
94
+
95
+ function themeOptionsValidator (themeConfig: DeepPartial<Theme>): ValidatorResult {
96
+ const result = validateObject(themeConfig, {
97
+ colorScheme: {
98
+ toBe: '"dark" | "light" | "auto"',
99
+ test: (value: any) => value === 'dark' || value === 'light' || value === 'auto'
100
+ },
101
+ colors: {
102
+ toBeTypes: ['object'],
103
+ test: (value: any) => {
104
+ return value.light && value.dark
105
+ }
106
+ },
107
+ fontSize: {
108
+ toBeTypes: ['string'],
109
+ },
110
+ })
111
+ if (themeConfig.colors) {
112
+ const colorsResult = validateObject(themeConfig.colors, {
113
+ light: {
114
+ toBeTypes: ['object'],
115
+ test: (value: any) => {
116
+ return value.data && value.primary && value.secondary && value.dataContrast && value.background
117
+ }
118
+ },
119
+ dark: {
120
+ toBeTypes: ['object'],
121
+ test: (value: any) => {
122
+ return value.data && value.primary && value.secondary && value.dataContrast && value.background
123
+ }
124
+ }
125
+ })
126
+ if (colorsResult.status === 'error') {
127
+ return colorsResult
128
+ }
129
+ if (themeConfig.colors.light) {
130
+ const lightColorsResult = validateObject(themeConfig.colors.light, {
131
+ data: {
132
+ toBeTypes: ['string[]']
133
+ },
134
+ primary: {
135
+ toBeTypes: ['string']
136
+ },
137
+ secondary: {
138
+ toBeTypes: ['string']
139
+ },
140
+ dataContrast: {
141
+ toBeTypes: ['string[]']
142
+ },
143
+ background: {
144
+ toBeTypes: ['string']
145
+ }
146
+ })
147
+ if (lightColorsResult.status === 'error') {
148
+ return lightColorsResult
149
+ }
150
+ }
151
+ if (themeConfig.colors.dark) {
152
+ const darkColorsResult = validateObject(themeConfig.colors.dark, {
153
+ data: {
154
+ toBeTypes: ['string[]']
155
+ },
156
+ primary: {
157
+ toBeTypes: ['string']
158
+ },
159
+ secondary: {
160
+ toBeTypes: ['string']
161
+ },
162
+ dataContrast: {
163
+ toBeTypes: ['string[]']
164
+ },
165
+ background: {
166
+ toBeTypes: ['string']
167
+ }
168
+ })
169
+ if (darkColorsResult.status === 'error') {
170
+ return darkColorsResult
171
+ }
172
+ }
173
+ }
174
+ return result
175
+ }
176
+
177
+ function encodingOptionsValidator (encodingConfig: DeepPartial<Encoding>): ValidatorResult {
178
+ const result = validateObject(encodingConfig, {
179
+ dataset: {
180
+ toBeTypes: ['object']
181
+ },
182
+ series: {
183
+ toBeTypes: ['object']
184
+ },
185
+ category: {
186
+ toBeTypes: ['object']
187
+ },
188
+ value: {
189
+ toBeTypes: ['object']
190
+ },
191
+ multivariate: {
192
+ toBeTypes: ['object']
193
+ },
194
+ color: {
195
+ toBeTypes: ['object']
196
+ }
197
+ })
198
+ if (encodingConfig.dataset) {
199
+ const datasetResult = validateObject(encodingConfig.dataset, {
200
+ from: {
201
+ toBeTypes: ['string']
202
+ },
203
+ sort: {
204
+ toBe: '"original" | "alphabetical" | string[]',
205
+ test: (value: any) => value === 'original' || value === 'alphabetical' || (Array.isArray(value) && value.every((v) => typeof v === 'string'))
206
+ }
207
+ })
208
+ if (datasetResult.status === 'error') {
209
+ return datasetResult
210
+ }
211
+ }
212
+ if (encodingConfig.series) {
213
+ const seriesResult = validateObject(encodingConfig.series, {
214
+ from: {
215
+ toBeTypes: ['string']
216
+ },
217
+ sort: {
218
+ toBe: '"original" | "alphabetical" | string[]',
219
+ test: (value: any) => value === 'original' || value === 'alphabetical' || (Array.isArray(value) && value.every((v) => typeof v === 'string'))
220
+ }
221
+ })
222
+ if (seriesResult.status === 'error') {
223
+ return seriesResult
224
+ }
225
+ }
226
+ if (encodingConfig.category) {
227
+ const categoryResult = validateObject(encodingConfig.category, {
228
+ from: {
229
+ toBeTypes: ['string']
230
+ },
231
+ sort: {
232
+ toBe: '"original" | "alphabetical" | string[]',
233
+ test: (value: any) => value === 'original' || value === 'alphabetical' || (Array.isArray(value) && value.every((v) => typeof v === 'string'))
234
+ }
235
+ })
236
+ if (categoryResult.status === 'error') {
237
+ return categoryResult
238
+ }
239
+ }
240
+ if (encodingConfig.value) {
241
+ const valueResult = validateObject(encodingConfig.value, {
242
+ from: {
243
+ toBeTypes: ['string']
244
+ },
245
+ sort: {
246
+ toBe: '"original" | "asc" | "desc"',
247
+ test: (value: any) => value === 'original' || value === 'asc' || value === 'desc'
248
+ },
249
+ aggregate: {
250
+ toBe: '"sum" | "mean" | "median" | "min" | "max" | "count" | "none"',
251
+ test: (value: any) => ['sum', 'mean', 'median', 'min', 'max', 'count', 'none'].includes(value)
252
+ }
253
+ })
254
+ if (valueResult.status === 'error') {
255
+ return valueResult
256
+ }
257
+ }
258
+ if (encodingConfig.multivariate) {
259
+ const multivariateResult = validateObject({ multivariate: encodingConfig.multivariate}, {
260
+ multivariate: {
261
+ toBe: 'EncodingMultivariateItem[]',
262
+ test: (value: any) => Array.isArray(value)
263
+ && value.every((v) => typeof v.from === 'string' && typeof v.label === 'string')
264
+ }
265
+ })
266
+ if (multivariateResult.status === 'error') {
267
+ return multivariateResult
268
+ }
269
+ }
270
+ if (encodingConfig.color) {
271
+ const colorResult = validateObject(encodingConfig.color, {
272
+ from: {
273
+ toBe: '"index" | "series" | "category" | "dataset"',
274
+ test: (value: any) => ['index', 'series', 'category', 'dataset'].includes(value)
275
+ }
276
+ })
277
+ if (colorResult.status === 'error') {
278
+ return colorResult
279
+ }
280
+ }
281
+ return result
282
+ }
283
+
284
+ function dataValidator (data: RawData): ValidatorResult {
285
+ // 先檢查 data 的基本格式
286
+ const result = validateObject({ data }, {
287
+ data: {
288
+ toBe: 'RawDataColumn[] | RawDataColumn[][]',
289
+ // 畢免資料量過大檢查不完,不深度檢查
290
+ test: (value) => Array.isArray(value) && value.every((d) => Array.isArray(d) || isPlainObject(d))
291
+ }
292
+ })
293
+ return result
294
+ }
295
+
296
+ function pluginsValidator (plugins: PluginEntity<any, any, any>[]): ValidatorResult {
297
+ const result = validateObject({ plugins }, {
298
+ plugins: {
299
+ toBe: `PluginEntity[]`,
300
+ test: (value: PluginEntity<any, any, any>[]) => {
301
+ return Array.isArray(value)
302
+ && value.every((v) => isPlainObject(v) && typeof v._name === 'string' && typeof v._injectContext === 'function')
303
+ }
304
+ }
305
+ })
306
+ return result
307
+ }
308
+
309
+ function chartOptionsValidator (chartOptionsPartial: PartialChartOptions): ValidatorResult {
310
+ if (!chartOptionsPartial) {
311
+ // chartOptions 可為空值
312
+ return { status: 'success', columnName: '', expectToBe: '' }
313
+ }
314
+ const result = validateObject(chartOptionsPartial, {
315
+ size: {
316
+ toBeTypes: ['object']
317
+ },
318
+ theme: {
319
+ toBeTypes: ['object']
320
+ },
321
+ data: {
322
+ toBe: 'RawDataColumn[] | RawDataColumn[][]',
323
+ // 畢免資料量過大檢查不完,不深度檢查
324
+ test: (value) => Array.isArray(value)
325
+ },
326
+ encoding: {
327
+ toBeTypes: ['object']
328
+ },
329
+ plugins: {
330
+ toBe: `PluginEntity[]`,
331
+ test: (value: PluginEntity<any, any, any>[]) => {
332
+ return Array.isArray(value)
333
+ && value.every((v) => isPlainObject(v) && typeof v._name === 'string' && typeof v._injectContext === 'function')
334
+ }
335
+ }
336
+ })
337
+ if (result.status === 'error') {
338
+ return result
339
+ }
340
+ if (chartOptionsPartial.size) {
341
+ const sizeResult = sizeOptionsValidator(chartOptionsPartial.size)
342
+ if (sizeResult.status === 'error') {
343
+ return sizeResult
344
+ }
345
+ }
346
+ if (chartOptionsPartial.theme) {
347
+ const themeResult = themeOptionsValidator(chartOptionsPartial.theme)
348
+ if (themeResult.status === 'error') {
349
+ return themeResult
350
+ }
351
+ }
352
+ if (chartOptionsPartial.encoding) {
353
+ const encodingResult = encodingOptionsValidator(chartOptionsPartial.encoding)
354
+ if (encodingResult.status === 'error') {
355
+ return encodingResult
356
+ }
357
+ }
358
+ if (chartOptionsPartial.data) {
359
+ const dataResult = dataValidator(chartOptionsPartial.data)
360
+ if (dataResult.status === 'error') {
361
+ return dataResult
362
+ }
363
+ }
364
+ if (chartOptionsPartial.plugins) {
365
+ const pluginsResult = pluginsValidator(chartOptionsPartial.plugins)
366
+ if (pluginsResult.status === 'error') {
367
+ return pluginsResult
368
+ }
369
+ }
370
+ return result
371
+ }
372
+
373
+ function createLayerElementsUpdater ({ svgElement$, canvasElement$, pluginsInstance$ }:{
374
+ svgElement$: BehaviorSubject<SVGElement | null>
375
+ canvasElement$: BehaviorSubject<HTMLCanvasElement | null>
376
+ pluginsInstance$: BehaviorSubject<PluginEntity<any, unknown, unknown>[]>
377
+ }) {
378
+ // 紀錄 layer 陣列的資訊
379
+ let svgLayerInfo: LayerMakerInfo[] = []
380
+ let canvasLayerInfo: LayerMakerInfo[] = []
381
+ // 產生新的 layer 資訊
382
+ const createLayerInfo = (elementType: 'svg' | 'canvas', fromPluginId: string, fetchLayerInfo: LayerInfo[]) => {
383
+ const pluginSeq = pluginsInstance$.getValue().reduce((acc, plugin, index) => {
384
+ acc[plugin._getId()] = index
385
+ return acc
386
+ }, {} as Record<string, number>)
387
+ const addedLayerInfo: LayerMakerInfo[] = fetchLayerInfo.map(layerInfo => ({
388
+ ...layerInfo,
389
+ pluginSeq: pluginSeq[layerInfo.pluginId]
390
+ }))
391
+ const newLayerInfo = (elementType === 'svg' ? svgLayerInfo : canvasLayerInfo)
392
+ .filter((layerInfo) => layerInfo.pluginId !== fromPluginId)
393
+ .map(layerInfo => {
394
+ return {
395
+ ...layerInfo,
396
+ pluginSeq: pluginSeq[layerInfo.pluginId]
397
+ }
398
+ })
399
+ .concat(addedLayerInfo)
400
+ .sort((a, b) => {
401
+ // 優先排layerIndex再排pluginSeq
402
+ return a.layerIndex - b.layerIndex || a.pluginSeq - b.pluginSeq
403
+ })
404
+ return newLayerInfo
405
+ }
406
+ // layer elements
407
+ const layerSVGElementsRef: Record<string, SVGGElement> = {}
408
+ const layerCanvasElementsRef: Record<string, HTMLCanvasElement> = {}
409
+
410
+ return <ElementType extends 'svg' | 'canvas'>(elementType: ElementType, fromPluginId: string, fetchLayerInfo: LayerInfo[])
411
+ : Record<string, ElementType extends 'svg' ? SVGGElement : HTMLCanvasElement> => {
412
+
413
+ const element = elementType === 'svg' ? svgElement$.getValue() : canvasElement$.getValue()
414
+
415
+ if (!element) {
416
+ return {}
417
+ }
418
+
419
+ const layerElementsRef = elementType === 'svg' ? layerSVGElementsRef : layerCanvasElementsRef
420
+ const newLayerInfo = createLayerInfo(elementType, fromPluginId, fetchLayerInfo)
421
+ const sortedLayerClassNames = newLayerInfo.map(info => createLayerClassName(info.pluginId, info.layerName))
422
+
423
+ // 根據新的 layerInfo 來更新 DOM 結構
424
+ if (elementType === 'svg') {
425
+ handleElementLifecycle(
426
+ element,
427
+ sortedLayerClassNames,
428
+ layerElementsRef as Record<string, SVGGElement>,
429
+ (elementClassName) => createSVGGroup(elementClassName)
430
+ )
431
+ svgLayerInfo = newLayerInfo
432
+ } else {
433
+ handleElementLifecycle(
434
+ element,
435
+ sortedLayerClassNames,
436
+ layerElementsRef as Record<string, HTMLCanvasElement>,
437
+ (elementClassName) => createCanvas(elementClassName)
438
+ )
439
+ canvasLayerInfo = newLayerInfo
440
+ }
441
+
442
+ // 回傳目前pluginId的elements (Record<layerName, element>)
443
+ const currentLayerElementsRef = Object.entries(layerElementsRef as Record<string, ElementType extends 'svg' ? SVGGElement : HTMLCanvasElement>)
444
+ .reduce((prev, [key, layerElement]) => {
445
+ const [orbchartsPrefix, pluginId, layerName] = key.split('-')
446
+ if (pluginId === fromPluginId) {
447
+ prev[layerName] = layerElement
448
+ }
449
+ return prev
450
+ }, {} as Record<string, ElementType extends 'svg' ? SVGGElement : HTMLCanvasElement>)
451
+
452
+ return currentLayerElementsRef
453
+ }
454
+ }
455
+
456
+ export const createChart: CreateChart = (element, options) => {
457
+ try {
458
+ const { status, columnName, expectToBe } = chartOptionsValidator(options)
459
+ if (status === 'error') {
460
+ throw new Error(createValidatorErrorMessage({
461
+ columnName,
462
+ expectToBe,
463
+ from: 'Chart.constructor'
464
+ }))
465
+ } else if (status === 'warning') {
466
+ console.warn(createValidatorWarningMessage({
467
+ columnName,
468
+ expectToBe,
469
+ from: 'Chart.constructor'
470
+ }))
471
+ } else {
472
+ const { status, columnName, expectToBe } = elementValidator(element)
473
+ if (status === 'error') {
474
+ throw new Error(createValidatorErrorMessage({
475
+ columnName,
476
+ expectToBe,
477
+ from: 'Chart.constructor'
478
+ }))
479
+ } else if (status === 'warning') {
480
+ console.warn(createValidatorWarningMessage({
481
+ columnName,
482
+ expectToBe,
483
+ from: 'Chart.constructor'
484
+ }))
485
+ }
486
+ }
487
+ } catch (e) {
488
+ throw new Error(e)
489
+ }
490
+
491
+ const destroy$ = new Subject()
492
+
493
+ // data
494
+ const rawData$ = new BehaviorSubject<RawData>(options?.data || [])
495
+ // data encoding
496
+ const defaultEncoding = options && options.encoding
497
+ ? deepOverwrite(DEFAULT_DATA_ENCODING, options.encoding)
498
+ : DEFAULT_DATA_ENCODING
499
+ const currentEncoding$ = new BehaviorSubject<Encoding>(defaultEncoding)
500
+ // theme
501
+ const defaultTheme = options && options.theme
502
+ ? deepOverwrite(DEFAULT_THEME, options.theme)
503
+ : DEFAULT_THEME
504
+ // const defaultTheme$ = new BehaviorSubject<Theme>(defaultTheme)
505
+ // const previousTheme$ = new BehaviorSubject<Theme>(defaultTheme)
506
+ const currentTheme$ = new BehaviorSubject<Theme>(defaultTheme)
507
+ // plugins
508
+ const pluginsInstance$ = new BehaviorSubject<PluginEntity<'svg' | 'canvas', unknown, unknown>[]>(options?.plugins || [])
509
+ // size
510
+ const defaultSizeConfig = options && options.size
511
+ ? deepOverwrite(DEFAULT_SIZE_CONFIG, options.size)
512
+ : DEFAULT_SIZE_CONFIG
513
+ const sizeConfig$ = new BehaviorSubject<SizeConfig>(defaultSizeConfig)
514
+ // elements
515
+ const svgElement$ = new BehaviorSubject<SVGElement | null>(null)
516
+ const canvasElement$ = new BehaviorSubject<HTMLCanvasElement | null>(null)
517
+
518
+
519
+ // chart context
520
+ const context: ChartContext<{}> = (() => {
521
+ // 監聽外層的element尺寸
522
+ const size$: Observable<Size> = sizeConfig$.pipe(
523
+ switchMap(sizeConfig => {
524
+ return iif(
525
+ () =>
526
+ sizeConfig.width === 'auto' || sizeConfig.height === 'auto',
527
+ // 有 'auto' 的話就監聽element的尺寸
528
+ resizeObservable(element).pipe(
529
+ map((d) => {
530
+ return {
531
+ width: sizeConfig.width === 'auto' ? d.width : sizeConfig.width,
532
+ height: sizeConfig.height === 'auto'
533
+ ? (d.height <= 0 ? d.width : d.height) // html高度很容易出現0的狀況,為避免顯示不出來這種情況就和width相等
534
+ : sizeConfig.height
535
+ }
536
+ }),
537
+ debounceTime(sizeConfig.resizeDebounce),
538
+ distinctUntilChanged((a, b) => JSON.stringify(a) === JSON.stringify(b))
539
+ ),
540
+ of({
541
+ width: sizeConfig.width as number,
542
+ height: sizeConfig.height as number
543
+ })
544
+ )
545
+ }),
546
+ takeUntil(destroy$),
547
+ shareReplay(1)
548
+ )
549
+ // const encoding$ = new Observable<Encoding>(subscriber => {
550
+ // currentEncoding$.subscribe(data => {
551
+ // subscriber.next(data)
552
+ // })
553
+ // }).pipe(
554
+ // shareReplay(1)
555
+ // )
556
+ const encoding$ = currentEncoding$
557
+ .asObservable()
558
+ .pipe(
559
+ shareReplay(1)
560
+ )
561
+ const seriesData$ = combineLatest([
562
+ rawData$,
563
+ currentEncoding$,
564
+ currentTheme$
565
+ ]).pipe(
566
+ debounceTime(0),
567
+ map(([rawData, encoding, theme]) => {
568
+ try {
569
+ return createSeriesData(rawData, encoding, theme)
570
+ } catch (e) {
571
+ throw new Error(createUnexpectedErrorMessage({
572
+ from: 'Chart.seriesData$',
573
+ systemMessage: e
574
+ }))
575
+ }
576
+ }),
577
+ catchError((e) => {
578
+ console.error(createOrbChartsErrorMessage(e))
579
+ return EMPTY
580
+ }),
581
+ shareReplay(1)
582
+ )
583
+ const gridData$ = combineLatest([
584
+ rawData$,
585
+ currentEncoding$,
586
+ currentTheme$
587
+ ]).pipe(
588
+ debounceTime(0),
589
+ map(([rawData, encoding, theme]) => {
590
+ try {
591
+ return createGridData(rawData, encoding, theme)
592
+ } catch (e) {
593
+ throw new Error(createUnexpectedErrorMessage({
594
+ from: 'Chart.gridData$',
595
+ systemMessage: e
596
+ }))
597
+ }
598
+ }),
599
+ catchError((e) => {
600
+ console.error(createOrbChartsErrorMessage(e))
601
+ return EMPTY
602
+ }),
603
+ shareReplay(1)
604
+ )
605
+ const multivariateData$ = combineLatest([
606
+ rawData$,
607
+ currentEncoding$,
608
+ currentTheme$
609
+ ]).pipe(
610
+ debounceTime(0),
611
+ map(([rawData, encoding, theme]) => {
612
+ try {
613
+ return createMultivariateData(rawData, encoding, theme)
614
+ } catch (e) {
615
+ throw new Error(createUnexpectedErrorMessage({
616
+ from: 'Chart.multivariateData$',
617
+ systemMessage: e
618
+ }))
619
+ }
620
+ }),
621
+ catchError((e) => {
622
+ console.error(createOrbChartsErrorMessage(e))
623
+ return EMPTY
624
+ }),
625
+ shareReplay(1)
626
+ )
627
+ const graphData$ = combineLatest([
628
+ rawData$,
629
+ currentEncoding$,
630
+ currentTheme$
631
+ ]).pipe(
632
+ debounceTime(0),
633
+ map(([rawData, encoding, theme]) => {
634
+ try {
635
+ return createGraphData(rawData, encoding, theme)
636
+ } catch (e) {
637
+ throw new Error(createUnexpectedErrorMessage({
638
+ from: 'Chart.graphData$',
639
+ systemMessage: e
640
+ }))
641
+ }
642
+ }),
643
+ catchError((e) => {
644
+ console.error(createOrbChartsErrorMessage(e))
645
+ return EMPTY
646
+ }),
647
+ shareReplay(1)
648
+ )
649
+ const treeData$ = combineLatest([
650
+ rawData$,
651
+ currentEncoding$,
652
+ currentTheme$
653
+ ]).pipe(
654
+ debounceTime(0),
655
+ map(([rawData, encoding, theme]) => {
656
+ try {
657
+ return createTreeData(rawData, encoding, theme)
658
+ } catch (e) {
659
+ throw new Error(createUnexpectedErrorMessage({
660
+ from: 'Chart.treeData$',
661
+ systemMessage: e
662
+ }))
663
+ }
664
+ }),
665
+ catchError((e) => {
666
+ console.error(createOrbChartsErrorMessage(e))
667
+ return EMPTY
668
+ }),
669
+ shareReplay(1)
670
+ )
671
+ const plugins$ = new BehaviorSubject<PluginInfo[]>([])
672
+ pluginsInstance$.subscribe(plugins => {
673
+ const pluginIdRecord: Record<string, string> = {}
674
+ const pluginIds = plugins.map(plugin => {
675
+ let id = plugin._getId()
676
+ if (pluginIdRecord[id]) {
677
+ // 原本id加上序號
678
+ const prevNo = pluginIdRecord[id].split('[')[1]?.split(']')[0] || '0'
679
+ const newNo = parseInt(prevNo) + 1
680
+ id = `${id.split('[')[0]}[${newNo}]`
681
+ }
682
+ pluginIdRecord[id] = plugin._getId()
683
+ return id
684
+ })
685
+ // 更新 plugin 實例的 id(確保唯一性)
686
+ plugins.forEach((plugin, index) => plugin._setId(pluginIds[index]))
687
+
688
+ const pluginInfos = plugins.map(plugin => {
689
+ return {
690
+ id: plugin._getId(),
691
+ name: plugin._name,
692
+ elementType: plugin._elementType,
693
+ shownLayers: plugin.getShownLayerNames()
694
+ }
695
+ })
696
+ plugins$.next(pluginInfos)
697
+ })
698
+ // const theme$ = new Observable<Theme>(subscriber => {
699
+ // currentTheme$.subscribe(data => {
700
+ // subscriber.next(data)
701
+ // })
702
+ // })
703
+ const theme$ = currentTheme$
704
+ .asObservable()
705
+ .pipe(
706
+ shareReplay(1)
707
+ )
708
+ const eventTrigger$ = new Subject<EventData>()
709
+
710
+ // const event$ = new Observable<EventData>(subscriber => {
711
+ // eventTrigger$.subscribe((data) => {
712
+ // subscriber.next(data)
713
+ // })
714
+ // })
715
+ const event$ = eventTrigger$
716
+ .asObservable()
717
+ .pipe(
718
+ share()
719
+ )
720
+ const _context: ChartContext<{}> = {
721
+ root: element,
722
+ svg: null,
723
+ canvas: null,
724
+ size$: size$,
725
+ encoding$,
726
+ seriesData$,
727
+ gridData$,
728
+ multivariateData$,
729
+ graphData$,
730
+ treeData$,
731
+ plugins$,
732
+ theme$,
733
+ event$,
734
+ eventTrigger$,
735
+ _updateLayerElements: createLayerElementsUpdater({
736
+ svgElement$,
737
+ canvasElement$,
738
+ pluginsInstance$
739
+ })
740
+ }
741
+ return _context
742
+ })()
743
+
744
+ // OrbCharts 自有的 container(root 的直接子元素,由 OrbCharts 建立及擁有):
745
+ // svg/canvas 為 position:absolute,需要一個 positioned ancestor 作為錨點,
746
+ // 但 root 是使用者傳入的元素、不應修改它的樣式——
747
+ // 因此在 root 底下建立 position:relative 的 container 來掛載 svg/canvas。
748
+ // (container 本身高度為 0、不影響 root 的尺寸量測;destroy 時隨 root 清空一併移除)
749
+ let orbContainer: HTMLDivElement | null = null
750
+ const getOrbContainer = (): HTMLDivElement => {
751
+ if (!orbContainer) {
752
+ orbContainer = document.createElement('div')
753
+ orbContainer.classList.add('orbcharts-container')
754
+ orbContainer.style.position = 'relative'
755
+ element.appendChild(orbContainer)
756
+ }
757
+ return orbContainer
758
+ }
759
+
760
+ // inject context into plugins
761
+ pluginsInstance$.subscribe(plugins => {
762
+ // -- 建立頂層 svg 和 canvas --
763
+ let hasSVGPlugin = false
764
+ let hasCanvasPlugin = false
765
+ plugins.forEach(plugin => {
766
+ if (plugin._elementType === 'svg') {
767
+ hasSVGPlugin = true
768
+ } else if (plugin._elementType === 'canvas') {
769
+ hasCanvasPlugin = true
770
+ }
771
+ })
772
+ if (hasSVGPlugin && !context.svg) {
773
+ context.svg = createSVG('orbcharts-root-svg')
774
+ getOrbContainer().appendChild(context.svg)
775
+ svgElement$.next(context.svg)
776
+ } else if (!hasSVGPlugin && context.svg) {
777
+ context.svg.remove()
778
+ context.svg = null
779
+ svgElement$.next(null)
780
+ }
781
+ if (hasCanvasPlugin && !context.canvas) {
782
+ context.canvas = createCanvas('orbcharts-root-canvas')
783
+ getOrbContainer().appendChild(context.canvas)
784
+ canvasElement$.next(context.canvas)
785
+ } else if (!hasCanvasPlugin && context.canvas) {
786
+ context.canvas.remove()
787
+ context.canvas = null
788
+ canvasElement$.next(null)
789
+ }
790
+
791
+ // inject context
792
+ plugins.forEach(plugin => {
793
+ plugin._injectContext(context)
794
+ })
795
+ })
796
+
797
+ combineLatest({
798
+ size: context.size$,
799
+ svg: svgElement$,
800
+ }).pipe(
801
+ debounceTime(0),
802
+ filter(({ svg }) => !!svg)
803
+ ).subscribe(({ size, svg }) => {
804
+ if (svg) {
805
+ svg.setAttribute('width', size.width.toString())
806
+ svg.setAttribute('height', size.height.toString())
807
+ }
808
+ })
809
+
810
+ combineLatest({
811
+ size: context.size$,
812
+ canvas: canvasElement$
813
+ }).pipe(
814
+ debounceTime(0),
815
+ filter(({ canvas }) => !!canvas)
816
+ ).subscribe(({ size, canvas }) => {
817
+ if (canvas) {
818
+ canvas.width = size.width
819
+ canvas.height = size.height
820
+ }
821
+ })
822
+
823
+ // context.size$.subscribe(size => {
824
+ // const svgGElement: SVGGElement | null = context.root.querySelector(`:scope > svg`)
825
+ // const canvasElement: HTMLCanvasElement | null = context.root.querySelector(`:scope > canvas`)
826
+ // if (svgGElement) {
827
+ // svgGElement.setAttribute('width', size.width.toString())
828
+ // svgGElement.setAttribute('height', size.height.toString())
829
+ // }
830
+ // if (canvasElement) {
831
+ // canvasElement.width = size.width
832
+ // canvasElement.height = size.height
833
+ // }
834
+ // })
835
+
836
+ // create chart instance
837
+ return (() => {
838
+ function resize (sizeConfig: SizeConfig) {
839
+ sizeConfig$.next(sizeConfig)
840
+ }
841
+ function setData (data: RawData) {
842
+ try {
843
+ const { status, columnName, expectToBe } = dataValidator(data)
844
+ if (status === 'error') {
845
+ throw new Error(createValidatorErrorMessage({
846
+ columnName,
847
+ expectToBe,
848
+ from: 'Chart.setData'
849
+ }))
850
+ } else if (status === 'warning') {
851
+ console.warn(createValidatorWarningMessage({
852
+ columnName,
853
+ expectToBe,
854
+ from: 'Chart.setData'
855
+ }))
856
+ }
857
+ } catch (e) {
858
+ // 不中斷資料流
859
+ console.error(createOrbChartsErrorMessage(e))
860
+ }
861
+ rawData$.next(data)
862
+ }
863
+ // function setEncoding (partial: DeepPartial<Encoding>) {
864
+ // // deep-merge with default
865
+ // const currentEncoding = deepOverwrite(partial, defaultEncoding$.getValue())
866
+ // currentEncoding$.next(currentEncoding)
867
+ // }
868
+ function updateEncoding (patch: DeepPartial<Encoding>) {
869
+ try {
870
+ const { status, columnName, expectToBe } = encodingOptionsValidator(patch)
871
+ if (status === 'error') {
872
+ throw new Error(createValidatorErrorMessage({
873
+ columnName,
874
+ expectToBe,
875
+ from: 'Chart.updateEncoding'
876
+ }))
877
+ } else if (status === 'warning') {
878
+ console.warn(createValidatorWarningMessage({
879
+ columnName,
880
+ expectToBe,
881
+ from: 'Chart.updateEncoding'
882
+ }))
883
+ }
884
+ } catch (e) {
885
+ // 不中斷資料流
886
+ console.error(createOrbChartsErrorMessage(e))
887
+ }
888
+ // deep-merge with previous
889
+ const newEncoding = deepOverwrite(currentEncoding$.getValue(), patch)
890
+ currentEncoding$.next(newEncoding)
891
+ }
892
+ function forceReplaceEncoding (full: Encoding) {
893
+ // replace
894
+ currentEncoding$.next(full)
895
+ }
896
+ function getEncoding () {
897
+ return currentEncoding$.getValue()
898
+ }
899
+ function setPlugins (plugins: PluginEntity<any, unknown, unknown>[]) {
900
+ try {
901
+ const { status, columnName, expectToBe } = pluginsValidator(plugins)
902
+ if (status === 'error') {
903
+ throw new Error(createValidatorErrorMessage({
904
+ columnName,
905
+ expectToBe,
906
+ from: 'Chart.setPlugins'
907
+ }))
908
+ } else if (status === 'warning') {
909
+ console.warn(createValidatorWarningMessage({
910
+ columnName,
911
+ expectToBe,
912
+ from: 'Chart.setPlugins'
913
+ }))
914
+ }
915
+ } catch (e) {
916
+ // 不中斷資料流
917
+ console.error(createOrbChartsErrorMessage(e))
918
+ }
919
+ // replace all
920
+ pluginsInstance$.next(plugins)
921
+ }
922
+ function addPlugin (plugin: PluginEntity<any, unknown, unknown>) {
923
+ try {
924
+ const { status, columnName, expectToBe } = pluginsValidator([plugin])
925
+ if (status === 'error') {
926
+ throw new Error(createValidatorErrorMessage({
927
+ columnName,
928
+ expectToBe,
929
+ from: 'Chart.addPlugin'
930
+ }))
931
+ } else if (status === 'warning') {
932
+ console.warn(createValidatorWarningMessage({
933
+ columnName,
934
+ expectToBe,
935
+ from: 'Chart.addPlugin'
936
+ }))
937
+ }
938
+ } catch (e) {
939
+ // 不中斷資料流
940
+ console.error(createOrbChartsErrorMessage(e))
941
+ }
942
+ // add one
943
+ pluginsInstance$.next([...pluginsInstance$.getValue(), plugin])
944
+ }
945
+ function removePlugin (id: string) {
946
+ // remove one by id
947
+ pluginsInstance$.next(pluginsInstance$.getValue().filter(plugin => plugin._getId() !== id))
948
+ }
949
+ // function setTheme (theme: DeepPartial<Theme>) {
950
+ // // replace all
951
+ // const currentTheme = deepOverwrite(defaultTheme$.getValue(), theme)
952
+ // previousTheme$.next(currentTheme)
953
+ // currentTheme$.next(currentTheme)
954
+ // }
955
+ function updateTheme (patch: DeepPartial<Theme>) {
956
+ try {
957
+ const { status, columnName, expectToBe } = themeOptionsValidator(patch)
958
+ if (status === 'error') {
959
+ throw new Error(createValidatorErrorMessage({
960
+ columnName,
961
+ expectToBe,
962
+ from: 'Chart.updateTheme'
963
+ }))
964
+ } else if (status === 'warning') {
965
+ console.warn(createValidatorWarningMessage({
966
+ columnName,
967
+ expectToBe,
968
+ from: 'Chart.updateTheme'
969
+ }))
970
+ }
971
+ } catch (e) {
972
+ // 不中斷資料流
973
+ console.error(createOrbChartsErrorMessage(e))
974
+ }
975
+ // deep-merge with previous
976
+ const newTheme = deepOverwrite(currentTheme$.getValue(), patch)
977
+ currentTheme$.next(newTheme)
978
+ }
979
+ function forceReplaceTheme (full: Theme) {
980
+ // replace all
981
+ // previousTheme$.next(full)
982
+ currentTheme$.next(full)
983
+ }
984
+ function getTheme () {
985
+ return currentTheme$.getValue()
986
+ }
987
+ function destroy() {
988
+ // context.svgSelection.remove()
989
+ // context.canvasSelection.remove()
990
+ destroy$.next(undefined)
991
+ // 清空 element 底下所有元素(含 OrbCharts 自有的 container)
992
+ removeElementChildren(element)
993
+ orbContainer = null
994
+ }
995
+
996
+ return {
997
+ resize,
998
+ setData,
999
+ // setEncoding,
1000
+ updateEncoding,
1001
+ forceReplaceEncoding,
1002
+ getEncoding,
1003
+ setPlugins,
1004
+ addPlugin,
1005
+ removePlugin,
1006
+ // setTheme,
1007
+ updateTheme,
1008
+ forceReplaceTheme,
1009
+ getTheme,
1010
+ destroy,
1011
+ context
1012
+ }
1013
+ })()
1014
+ }