@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,997 @@
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
+ // inject context into plugins
745
+ pluginsInstance$.subscribe(plugins => {
746
+ // -- 建立頂層 svg 和 canvas --
747
+ let hasSVGPlugin = false
748
+ let hasCanvasPlugin = false
749
+ plugins.forEach(plugin => {
750
+ if (plugin._elementType === 'svg') {
751
+ hasSVGPlugin = true
752
+ } else if (plugin._elementType === 'canvas') {
753
+ hasCanvasPlugin = true
754
+ }
755
+ })
756
+ if (hasSVGPlugin && !context.svg) {
757
+ context.svg = createSVG('orbcharts-root-svg')
758
+ context.root.appendChild(context.svg)
759
+ svgElement$.next(context.svg)
760
+ } else if (!hasSVGPlugin && context.svg) {
761
+ context.svg.remove()
762
+ context.svg = null
763
+ svgElement$.next(null)
764
+ }
765
+ if (hasCanvasPlugin && !context.canvas) {
766
+ context.canvas = createCanvas('orbcharts-root-canvas')
767
+ context.root.appendChild(context.canvas)
768
+ canvasElement$.next(context.canvas)
769
+ } else if (!hasCanvasPlugin && context.canvas) {
770
+ context.canvas.remove()
771
+ context.canvas = null
772
+ canvasElement$.next(null)
773
+ }
774
+
775
+ // inject context
776
+ plugins.forEach(plugin => {
777
+ plugin._injectContext(context)
778
+ })
779
+ })
780
+
781
+ combineLatest({
782
+ size: context.size$,
783
+ svg: svgElement$,
784
+ }).pipe(
785
+ debounceTime(0),
786
+ filter(({ svg }) => !!svg)
787
+ ).subscribe(({ size, svg }) => {
788
+ if (svg) {
789
+ svg.setAttribute('width', size.width.toString())
790
+ svg.setAttribute('height', size.height.toString())
791
+ }
792
+ })
793
+
794
+ combineLatest({
795
+ size: context.size$,
796
+ canvas: canvasElement$
797
+ }).pipe(
798
+ debounceTime(0),
799
+ filter(({ canvas }) => !!canvas)
800
+ ).subscribe(({ size, canvas }) => {
801
+ if (canvas) {
802
+ canvas.width = size.width
803
+ canvas.height = size.height
804
+ }
805
+ })
806
+
807
+ // context.size$.subscribe(size => {
808
+ // const svgGElement: SVGGElement | null = context.root.querySelector(`:scope > svg`)
809
+ // const canvasElement: HTMLCanvasElement | null = context.root.querySelector(`:scope > canvas`)
810
+ // if (svgGElement) {
811
+ // svgGElement.setAttribute('width', size.width.toString())
812
+ // svgGElement.setAttribute('height', size.height.toString())
813
+ // }
814
+ // if (canvasElement) {
815
+ // canvasElement.width = size.width
816
+ // canvasElement.height = size.height
817
+ // }
818
+ // })
819
+
820
+ // create chart instance
821
+ return (() => {
822
+ function resize (sizeConfig: SizeConfig) {
823
+ sizeConfig$.next(sizeConfig)
824
+ }
825
+ function setData (data: RawData) {
826
+ try {
827
+ const { status, columnName, expectToBe } = dataValidator(data)
828
+ if (status === 'error') {
829
+ throw new Error(createValidatorErrorMessage({
830
+ columnName,
831
+ expectToBe,
832
+ from: 'Chart.setData'
833
+ }))
834
+ } else if (status === 'warning') {
835
+ console.warn(createValidatorWarningMessage({
836
+ columnName,
837
+ expectToBe,
838
+ from: 'Chart.setData'
839
+ }))
840
+ }
841
+ } catch (e) {
842
+ // 不中斷資料流
843
+ console.error(createOrbChartsErrorMessage(e))
844
+ }
845
+ rawData$.next(data)
846
+ }
847
+ // function setEncoding (partial: DeepPartial<Encoding>) {
848
+ // // deep-merge with default
849
+ // const currentEncoding = deepOverwrite(partial, defaultEncoding$.getValue())
850
+ // currentEncoding$.next(currentEncoding)
851
+ // }
852
+ function updateEncoding (patch: DeepPartial<Encoding>) {
853
+ try {
854
+ const { status, columnName, expectToBe } = encodingOptionsValidator(patch)
855
+ if (status === 'error') {
856
+ throw new Error(createValidatorErrorMessage({
857
+ columnName,
858
+ expectToBe,
859
+ from: 'Chart.updateEncoding'
860
+ }))
861
+ } else if (status === 'warning') {
862
+ console.warn(createValidatorWarningMessage({
863
+ columnName,
864
+ expectToBe,
865
+ from: 'Chart.updateEncoding'
866
+ }))
867
+ }
868
+ } catch (e) {
869
+ // 不中斷資料流
870
+ console.error(createOrbChartsErrorMessage(e))
871
+ }
872
+ // deep-merge with previous
873
+ const newEncoding = deepOverwrite(currentEncoding$.getValue(), patch)
874
+ currentEncoding$.next(newEncoding)
875
+ }
876
+ function forceReplaceEncoding (full: Encoding) {
877
+ // replace
878
+ currentEncoding$.next(full)
879
+ }
880
+ function getEncoding () {
881
+ return currentEncoding$.getValue()
882
+ }
883
+ function setPlugins (plugins: PluginEntity<any, unknown, unknown>[]) {
884
+ try {
885
+ const { status, columnName, expectToBe } = pluginsValidator(plugins)
886
+ if (status === 'error') {
887
+ throw new Error(createValidatorErrorMessage({
888
+ columnName,
889
+ expectToBe,
890
+ from: 'Chart.setPlugins'
891
+ }))
892
+ } else if (status === 'warning') {
893
+ console.warn(createValidatorWarningMessage({
894
+ columnName,
895
+ expectToBe,
896
+ from: 'Chart.setPlugins'
897
+ }))
898
+ }
899
+ } catch (e) {
900
+ // 不中斷資料流
901
+ console.error(createOrbChartsErrorMessage(e))
902
+ }
903
+ // replace all
904
+ pluginsInstance$.next(plugins)
905
+ }
906
+ function addPlugin (plugin: PluginEntity<any, unknown, unknown>) {
907
+ try {
908
+ const { status, columnName, expectToBe } = pluginsValidator([plugin])
909
+ if (status === 'error') {
910
+ throw new Error(createValidatorErrorMessage({
911
+ columnName,
912
+ expectToBe,
913
+ from: 'Chart.addPlugin'
914
+ }))
915
+ } else if (status === 'warning') {
916
+ console.warn(createValidatorWarningMessage({
917
+ columnName,
918
+ expectToBe,
919
+ from: 'Chart.addPlugin'
920
+ }))
921
+ }
922
+ } catch (e) {
923
+ // 不中斷資料流
924
+ console.error(createOrbChartsErrorMessage(e))
925
+ }
926
+ // add one
927
+ pluginsInstance$.next([...pluginsInstance$.getValue(), plugin])
928
+ }
929
+ function removePlugin (id: string) {
930
+ // remove one by id
931
+ pluginsInstance$.next(pluginsInstance$.getValue().filter(plugin => plugin._getId() !== id))
932
+ }
933
+ // function setTheme (theme: DeepPartial<Theme>) {
934
+ // // replace all
935
+ // const currentTheme = deepOverwrite(defaultTheme$.getValue(), theme)
936
+ // previousTheme$.next(currentTheme)
937
+ // currentTheme$.next(currentTheme)
938
+ // }
939
+ function updateTheme (patch: DeepPartial<Theme>) {
940
+ try {
941
+ const { status, columnName, expectToBe } = themeOptionsValidator(patch)
942
+ if (status === 'error') {
943
+ throw new Error(createValidatorErrorMessage({
944
+ columnName,
945
+ expectToBe,
946
+ from: 'Chart.updateTheme'
947
+ }))
948
+ } else if (status === 'warning') {
949
+ console.warn(createValidatorWarningMessage({
950
+ columnName,
951
+ expectToBe,
952
+ from: 'Chart.updateTheme'
953
+ }))
954
+ }
955
+ } catch (e) {
956
+ // 不中斷資料流
957
+ console.error(createOrbChartsErrorMessage(e))
958
+ }
959
+ // deep-merge with previous
960
+ const newTheme = deepOverwrite(currentTheme$.getValue(), patch)
961
+ currentTheme$.next(newTheme)
962
+ }
963
+ function forceReplaceTheme (full: Theme) {
964
+ // replace all
965
+ // previousTheme$.next(full)
966
+ currentTheme$.next(full)
967
+ }
968
+ function getTheme () {
969
+ return currentTheme$.getValue()
970
+ }
971
+ function destroy() {
972
+ // context.svgSelection.remove()
973
+ // context.canvasSelection.remove()
974
+ destroy$.next(undefined)
975
+ // 清空 element 底下所有元素
976
+ removeElementChildren(element)
977
+ }
978
+
979
+ return {
980
+ resize,
981
+ setData,
982
+ // setEncoding,
983
+ updateEncoding,
984
+ forceReplaceEncoding,
985
+ getEncoding,
986
+ setPlugins,
987
+ addPlugin,
988
+ removePlugin,
989
+ // setTheme,
990
+ updateTheme,
991
+ forceReplaceTheme,
992
+ getTheme,
993
+ destroy,
994
+ context
995
+ }
996
+ })()
997
+ }