@operato/chart 7.1.31 → 7.1.33

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 (41) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/dist/tsconfig.tsbuildinfo +1 -1
  3. package/package.json +9 -9
  4. package/.editorconfig +0 -29
  5. package/.storybook/main.js +0 -3
  6. package/.storybook/preview.js +0 -52
  7. package/.storybook/server.mjs +0 -8
  8. package/demo/index.html +0 -33
  9. package/src/chartjs/config-converter.ts +0 -341
  10. package/src/chartjs/ox-chart-js.ts +0 -207
  11. package/src/editors/configurer.ts +0 -336
  12. package/src/editors/index.ts +0 -8
  13. package/src/editors/input-chart-abstract.ts +0 -202
  14. package/src/editors/input-chart-styles.ts +0 -206
  15. package/src/editors/ox-input-chart-hbar.ts +0 -157
  16. package/src/editors/ox-input-chart-mixed.ts +0 -241
  17. package/src/editors/ox-input-chart-pie.ts +0 -69
  18. package/src/editors/ox-input-chart-radar.ts +0 -56
  19. package/src/editors/ox-input-chart-timeseries.ts +0 -279
  20. package/src/editors/ox-property-editor-chart.ts +0 -72
  21. package/src/editors/templates/annotations.ts +0 -295
  22. package/src/editors/templates/display-value.ts +0 -111
  23. package/src/editors/templates/series.ts +0 -316
  24. package/src/index.ts +0 -0
  25. package/src/progress/ox-progress-circle.ts +0 -133
  26. package/src/scichart/ox-scichart.ts +0 -151
  27. package/src/scichart/scichart-builder.ts +0 -490
  28. package/stories/common.ts +0 -87
  29. package/stories/ox-input-chart-bar.stories.ts +0 -188
  30. package/stories/ox-input-chart-doughnut.stories.ts +0 -130
  31. package/stories/ox-input-chart-hbar.stories.ts +0 -188
  32. package/stories/ox-input-chart-line.stories.ts +0 -198
  33. package/stories/ox-input-chart-pie.stories.ts +0 -130
  34. package/stories/ox-input-chart-polar-area.stories.ts +0 -130
  35. package/stories/ox-input-chart-radar.stories.ts +0 -141
  36. package/stories/ox-input-chart-timeseries.stories.ts +0 -268
  37. package/tsconfig.json +0 -25
  38. package/web-dev-server.config.mjs +0 -27
  39. package/web-test-runner.config.mjs +0 -41
  40. /package/{src → types}/global.d.ts +0 -0
  41. /package/{src → types}/types.d.ts +0 -0
@@ -1,52 +0,0 @@
1
- import { i18next } from '@operato/i18n'
2
-
3
- export const globalTypes = {
4
- locale: {
5
- name: 'Locale',
6
- description: 'Internationalization locale',
7
- toolbar: {
8
- icon: 'globe',
9
- items: [
10
- { value: 'en', right: '🇺🇸', title: 'English' },
11
- { value: 'ko', right: '🇰🇷', title: '한국어' },
12
- { value: 'zh', right: '🇨🇳', title: '中文' },
13
- { value: 'ja', right: '🇯🇵', title: '日本語' },
14
- { value: 'ms', right: '🇲🇾', title: 'Bahasa Melayu' }
15
- ],
16
- showName: true
17
- }
18
- },
19
- theme: {
20
- name: 'Theme',
21
- description: 'Global theme for components',
22
- toolbar: {
23
- icon: 'paintbrush',
24
- items: [
25
- { value: 'light', title: 'Light' },
26
- { value: 'dark', title: 'Dark' }
27
- ],
28
- showName: true
29
- }
30
- }
31
- }
32
-
33
- export const decorators = [
34
- (Story, context) => {
35
- const { locale, theme } = context.globals
36
-
37
- if (locale) {
38
- i18next.changeLanguage(locale)
39
- }
40
-
41
- // Set the theme class for the document
42
- if (theme === 'dark') {
43
- document.documentElement.classList.add('dark')
44
- document.documentElement.classList.remove('light')
45
- } else {
46
- document.documentElement.classList.add('light')
47
- document.documentElement.classList.remove('dark')
48
- }
49
-
50
- return Story()
51
- }
52
- ]
@@ -1,8 +0,0 @@
1
- import { storybookPlugin } from '@web/dev-server-storybook'
2
- import baseConfig from '../web-dev-server.config.mjs'
3
-
4
- export default /** @type {import('@web/dev-server').DevServerConfig} */ ({
5
- ...baseConfig,
6
- open: '/',
7
- plugins: [storybookPlugin({ type: 'web-components' }), ...baseConfig.plugins]
8
- })
package/demo/index.html DELETED
@@ -1,33 +0,0 @@
1
- <!doctype html>
2
- <html lang="en-GB">
3
- <head>
4
- <meta charset="utf-8" />
5
- <meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1" />
6
- <style>
7
- body {
8
- background: #fafafa;
9
- }
10
-
11
- a {
12
- display: block;
13
- }
14
- </style>
15
- <link href="/themes/app-theme.css" rel="stylesheet" />
16
- <link href="/themes/input-theme.css" rel="stylesheet" />
17
- <link
18
- href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL@20..48,100..700,0..1"
19
- rel="stylesheet"
20
- />
21
- <link
22
- href="https://fonts.googleapis.com/css2?family=Material+Symbols+Rounded:opsz,wght,FILL@20..48,100..700,0..1"
23
- rel="stylesheet"
24
- />
25
- <link
26
- href="https://fonts.googleapis.com/css2?family=Material+Symbols+Sharp:opsz,wght,FILL@20..48,100..700,0..1"
27
- rel="stylesheet"
28
- />
29
- </head>
30
- <body>
31
- <a href="./index-select.html">select</a>
32
- </body>
33
- </html>
@@ -1,341 +0,0 @@
1
- import { TinyColor } from '@ctrl/tinycolor'
2
- import { format as formatText } from '@operato/utils/format.js'
3
-
4
- function getBaseColorFromTheme(theme?: 'light' | 'dark' | 'auto') {
5
- return new TinyColor(theme == 'dark' ? '#fff' : '#000')
6
- }
7
-
8
- function getThemeFromBrowser() {
9
- return window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'
10
- }
11
-
12
- export function convertConfigure(
13
- config: OperatoChart.ChartConfig,
14
- { fontSize, fontFamily, fontColor }: { fontSize?: number; fontFamily?: string; fontColor?: string }
15
- ) {
16
- if (!config) {
17
- return
18
- }
19
-
20
- const { type: chartType, options, data: fromData } = config
21
- var {
22
- theme,
23
- animation,
24
- tooltip,
25
- stacked,
26
- legend,
27
- scales: fromScales,
28
- xGridLine,
29
- yGridLine,
30
- y2ndGridLine,
31
- multiAxis
32
- } = options || {}
33
- const { datasets = [] } = fromData || {}
34
-
35
- if (theme === 'auto') {
36
- theme = getThemeFromBrowser()
37
- }
38
-
39
- const { xAxes = [], yAxes = [] } = fromScales || {}
40
- const toScales = {} as any
41
-
42
- chartType != 'pie' &&
43
- xAxes.forEach((xAxis, index) => {
44
- const { axisTitle, barSpacing, categorySpacing, barPercentage, ticks } = xAxis
45
- const id = xAxes.length > 1 ? `x${index + 1}` : 'x'
46
-
47
- toScales[id] = setupScale(
48
- {
49
- axis: 'x',
50
- id,
51
- position: 'bottom',
52
- display: true,
53
- title: {
54
- display: !!axisTitle,
55
- text: axisTitle
56
- },
57
- grid: {
58
- display: xGridLine
59
- },
60
- beginAtZero: false,
61
- ticks
62
- },
63
- { fontSize, fontFamily, fontColor, theme }
64
- )
65
- })
66
-
67
- chartType != 'pie' &&
68
- yAxes.forEach((yAxis, index) => {
69
- const { axisTitle, barSpacing, categorySpacing, barPercentage, ticks } = yAxis
70
- const id = yAxes.length > 1 ? `right` : 'left'
71
-
72
- toScales[id] = setupScale(
73
- {
74
- axis: 'y',
75
- id,
76
- position: id,
77
- display: true,
78
- title: {
79
- display: !!axisTitle,
80
- text: axisTitle
81
- },
82
- grid: {
83
- display: index == 0 ? yGridLine : y2ndGridLine
84
- },
85
- ticks,
86
- stacked: stacked ? true : false
87
- },
88
- { fontSize, fontFamily, fontColor, theme }
89
- )
90
- })
91
-
92
- // setup series configure
93
- // for (let i in datasets) {
94
- // let series = datasets[i]
95
- //
96
- // /*
97
- // * TODO from chartjs 2.9, categoryPercentage, barPercentage properties move to dataset.
98
- // * so need to move related properties - categorySpacing, barSpacing should be moved to series.
99
- // */
100
- // if (chartType == 'bar') {
101
- // let categorySpacing = (xAxes && xAxes[0].categorySpacing) || 0
102
- // let barSpacing = (xAxes && xAxes[0].barSpacing) || 0
103
-
104
- // series.categoryPercentage = 1 - categorySpacing || 1
105
- // series.barPercentage = 1 - barSpacing || 0.8
106
- // } else if (chartType == 'horizontalBar') {
107
- // let categorySpacing = (yAxes && yAxes[0].categorySpacing) || 0
108
- // let barSpacing = (yAxes && yAxes[0].barSpacing) || 0
109
-
110
- // series.categoryPercentage = 1 - categorySpacing || 1
111
- // series.barPercentage = 1 - barSpacing || 0.8
112
- // }
113
- // }
114
-
115
- const converted = {
116
- type: chartType == 'horizontalBar' ? 'bar' : chartType,
117
- options: {
118
- animation,
119
- stacked,
120
- maintainAspectRatio: false,
121
- // parsing: false /* recommendations for performance */,
122
- // normalized: true /* recommendations for performance */,
123
- plugins: {
124
- legend: setupLegend(legend || {}, { fontSize, fontFamily, fontColor, theme }),
125
- tooltip: setupTooltip(
126
- {
127
- enabled: tooltip,
128
- mode: 'interpolate',
129
- intersect: false
130
- },
131
- { fontSize, fontFamily }
132
- ),
133
- title: {
134
- /* new option candidate - subtitle */
135
- display: false,
136
- text: 'Custom Chart Title'
137
- },
138
- subtitle: {
139
- /* new option candidate - subtitle */
140
- display: false,
141
- text: 'Custom Chart Subtitle'
142
- },
143
- crosshair: {
144
- line: {
145
- color: '#F66', // crosshair line color
146
- width: 1 // crosshair line width
147
- },
148
- sync: {
149
- enabled: true, // enable trace line syncing with other charts
150
- group: 1, // chart group
151
- suppressTooltips: false // suppress tooltips when showing a synced tracer
152
- },
153
- zoom: {
154
- enabled: true, // enable zooming
155
- zoomboxBackgroundColor: 'rgba(66,133,244,0.2)', // background color of zoom box
156
- zoomboxBorderColor: '#48F', // border color of zoom box
157
- zoomButtonText: 'Reset Zoom', // reset zoom button text
158
- zoomButtonClass: 'reset-zoom' // reset zoom button class
159
- },
160
- callbacks: {
161
- beforeZoom: () =>
162
- function (start: number, end: number) {
163
- // called before zoom, return false to prevent zoom
164
- return true
165
- },
166
- afterZoom: () =>
167
- function (start: number, end: number) {
168
- // called after zoom
169
- }
170
- }
171
- }
172
- },
173
- scales: toScales,
174
- indexAxis: chartType == 'horizontalBar' ? 'y' : chartType != 'pie' ? 'x' : ''
175
- },
176
- data: {
177
- datasets: datasets.map((dataset, index) => {
178
- return setupSeries(chartType!, {
179
- ...dataset,
180
- stack:
181
- chartType == 'pie' || chartType == 'doughnut'
182
- ? undefined
183
- : stacked && !dataset.stack
184
- ? '__all__'
185
- : `__${index}__`,
186
- type: dataset.type == 'horizontalBar' ? 'bar' : dataset.type
187
- })
188
- })
189
- }
190
- }
191
-
192
- console.error('converted', config, converted)
193
- return converted
194
- }
195
-
196
- function setupLegend(
197
- legend: any,
198
- {
199
- fontSize,
200
- fontFamily,
201
- fontColor,
202
- theme
203
- }: { fontSize?: number; fontFamily?: string; fontColor?: string; theme?: 'light' | 'dark' | 'auto' }
204
- ) {
205
- legend.labels = legend.labels ? legend.labels : {}
206
-
207
- if (fontSize) {
208
- legend.labels.fontSize = fontSize
209
- }
210
-
211
- if (fontFamily) {
212
- legend.labels.fontFamily = fontFamily
213
- }
214
-
215
- var baseColor = getBaseColorFromTheme(theme)
216
-
217
- legend.labels = legend.labels ? legend.labels : {}
218
- legend.labels.fontColor = fontColor ? fontColor : baseColor.clone().setAlpha(0.5).toString()
219
- // legend.labels.usePointStyle = true
220
-
221
- return legend
222
- }
223
-
224
- function setupTooltip(
225
- tooltip: any,
226
- {
227
- fontSize,
228
- fontFamily,
229
- fontColor,
230
- theme
231
- }: { fontSize?: number; fontFamily?: string; fontColor?: string; theme?: 'light' | 'dark' }
232
- ) {
233
- if (fontSize) {
234
- tooltip.titleFontSize = tooltip.bodyFontSize = tooltip.footerFontSize = fontSize
235
- }
236
-
237
- if (fontFamily) {
238
- tooltip.titleFontFamily = tooltip.bodyFontFamily = tooltip.footerFontFamily = fontFamily
239
- }
240
-
241
- tooltip.mode = 'index'
242
- tooltip.intersect = false
243
- tooltip.callbacks = {
244
- ...tooltip.callbacks,
245
- label: function ({ dataset, label }: { dataset: any; label: any }) {
246
- var prefix = dataset.valuePrefix || ''
247
- var suffix = dataset.valueSuffix || ''
248
- var format = dataset.valueFormat || ''
249
-
250
- var stringValue = format ? formatText(format, Number(label)) : Number(label).toLocaleString()
251
-
252
- return `${prefix + stringValue + suffix}`
253
- }
254
- }
255
-
256
- return tooltip
257
- }
258
-
259
- function setupScale(
260
- axis: any,
261
- {
262
- fontSize,
263
- fontFamily,
264
- fontColor,
265
- theme
266
- }: { fontSize?: number; fontFamily?: string; fontColor?: string; theme?: 'light' | 'dark' | 'auto' }
267
- ) {
268
- axis.ticks = axis.ticks ? axis.ticks : {}
269
-
270
- if (fontSize) {
271
- axis.ticks.fontSize = fontSize
272
- }
273
-
274
- if (fontFamily) {
275
- axis.ticks.fontFamily = fontFamily
276
- }
277
-
278
- axis.pointLabels = {
279
- fontSize,
280
- fontFamily
281
- }
282
-
283
- /* TODO move min, max, autoMin, autoMax from ticks to axis */
284
- const { min, max, autoMin, autoMax } = axis.ticks
285
-
286
- axis.min = min
287
- axis.max = max
288
-
289
- if (autoMin) {
290
- delete axis.min
291
- }
292
- if (autoMax) {
293
- delete axis.max
294
- }
295
-
296
- var baseColor = getBaseColorFromTheme(theme)
297
-
298
- axis.grid = axis.grid ? axis.grid : {}
299
- if (axis.grid) {
300
- axis.grid.tickColor = baseColor.clone().setAlpha(0.5).toString()
301
- axis.grid.color = baseColor.clone().setAlpha(0.1).toString()
302
- }
303
-
304
- axis.ticks = axis.ticks ? axis.ticks : {}
305
- axis.ticks.color = baseColor.clone().setAlpha(0.5).toString()
306
- axis.ticks.textStrokeColor = fontColor ? fontColor : baseColor.clone().setAlpha(0.5).toString()
307
-
308
- return axis
309
- }
310
-
311
- function setupSeries(chartType: string, series: OperatoChart.Dataset) {
312
- var type = series.type || chartType
313
-
314
- // series.parsing = {
315
- // yAxisKey: series.dataKey
316
- // } /* 이 형식의 data는 잘 안되었음. */
317
-
318
- var color = series.color ? series.color : series.backgroundColor
319
-
320
- switch (type) {
321
- case 'bar':
322
- case 'horizontalBar':
323
- series.borderColor = series.backgroundColor = color
324
- break
325
-
326
- case 'line':
327
- case 'radar':
328
- color = series.color ? series.color : series.borderColor
329
- series.pointBackgroundColor = series.pointBorderColor = series.borderColor = series.backgroundColor = color
330
- series.pointBorderWidth = (series.borderWidth as number) * 0.5
331
- series.pointHoverRadius = series.pointRadius
332
- if (series.fill == undefined) series.fill = false
333
- break
334
-
335
- default:
336
- series.borderColor = series.backgroundColor = color
337
- break
338
- }
339
-
340
- return series
341
- }
@@ -1,207 +0,0 @@
1
- import ChartDataLabels from 'chartjs-plugin-datalabels'
2
-
3
- import { LitElement, html, css } from 'lit'
4
- import { property, query, state, customElement } from 'lit/decorators.js'
5
- import { Chart, ChartConfiguration } from 'chart.js/auto'
6
- import { format as formatText } from '@operato/utils/format.js'
7
- import { convertConfigure } from './config-converter'
8
-
9
- Chart.register(ChartDataLabels)
10
-
11
- @customElement('ox-chart-js')
12
- export class OxChartJs extends LitElement {
13
- @property({ type: Object }) config: OperatoChart.ChartConfig | null = null
14
- @property({ type: Array }) data: { [key: string]: any }[] = []
15
- @property({ type: Number }) width!: number
16
- @property({ type: Number }) height!: number
17
-
18
- private chart: Chart | null = null
19
- private chartjsConfig: ChartConfiguration | null = null
20
-
21
- @query('canvas') canvas!: HTMLCanvasElement
22
-
23
- static styles = css`
24
- :host {
25
- display: block;
26
-
27
- background-color: var(--ox-chart-background-color, var(--md-sys-color-surface));
28
- color: var(--ox-chart-color, var(--md-sys-color-on-surface));
29
- }
30
-
31
- canvas {
32
- width: 100%;
33
- height: 100%;
34
- }
35
- `
36
-
37
- disconnectedCallback(): void {
38
- super.disconnectedCallback()
39
- if (this.chart) {
40
- this.chart.destroy()
41
- }
42
- }
43
-
44
- updated(changedProperties: Map<string | number | symbol, unknown>) {
45
- var needUpdateData = false
46
-
47
- if (changedProperties.has('width') || changedProperties.has('height')) {
48
- this.updateChartSize()
49
- }
50
-
51
- if (changedProperties.has('config') && this.config) {
52
- this.chartjsConfig = convertConfigure(this.config, {}) as any
53
-
54
- this.attachPluginOptions(this.chartjsConfig!.options as any)
55
-
56
- this.chart && this.chart.destroy()
57
- this.chart = new Chart(this.canvas, this.chartjsConfig!)
58
-
59
- needUpdateData = true
60
- }
61
-
62
- if (changedProperties.has('data')) {
63
- needUpdateData = true
64
- }
65
-
66
- if (needUpdateData) {
67
- this.updateData()
68
- }
69
- }
70
-
71
- updateData() {
72
- if (!this.chart) {
73
- return
74
- }
75
-
76
- var data = this.data
77
-
78
- if (this.data[0]?.hasOwnProperty('__field1')) {
79
- /* DEPRECATED 이 케이스는 앞으로 지원하지 않는 것이 좋다. 하위 호환성 때문에 제공함. 사용빈도 낮음. */
80
- data = toObjectArrayValue(this.data) as { [key: string]: any }[]
81
- }
82
-
83
- const labelDataKey = this.config!.data.labelDataKey || ''
84
-
85
- labelDataKey && (this.chart!.config.data!.labels = data.map((data: any) => data[labelDataKey]))
86
-
87
- const datasets = this.chart!.config.data.datasets
88
- for (let key in datasets) {
89
- const dataset = datasets[Number(key)]
90
- const dataKey = (dataset as any).dataKey
91
- dataKey && (dataset.data = data.map(d => d[dataKey]) as any)
92
- }
93
-
94
- this.chart.update()
95
- }
96
-
97
- updateChartSize() {
98
- const width = Math.floor(this.width)
99
- const height = Math.floor(this.height)
100
-
101
- this.canvas.style.width = `${width}px`
102
- this.canvas.style.height = `${height}px`
103
-
104
- const _ = () => {
105
- if (this.canvas.offsetWidth == 0 || this.canvas.offsetHeight == 0) {
106
- requestAnimationFrame(_)
107
- } else {
108
- /*
109
- 주의 : chart.resize() 내에서 pixel ratio를 감안해서, canvas 의 width, height를 설정하기때문에,
110
- 별도 처리가 필요하지 않다.
111
- */
112
- this.chart!.resize()
113
- }
114
- }
115
-
116
- requestAnimationFrame(_)
117
- }
118
-
119
- render() {
120
- return html`<canvas></canvas>`
121
- }
122
-
123
- attachPluginOptions(options: OperatoChart.ChartOptions) {
124
- if (!options.plugins) {
125
- options.plugins = {}
126
- }
127
-
128
- this.attachDatalabelPluginOptions(options.plugins)
129
- }
130
-
131
- attachDatalabelPluginOptions(pluginOptions: any) {
132
- pluginOptions.datalabels = {
133
- ...pluginOptions.datalabels,
134
- display: function (context: any) {
135
- return !!context.dataset.displayValue
136
- },
137
- anchor: function (context: any) {
138
- return context.dataset.dataLabelAnchor || 'center'
139
- },
140
- offset: function (context: any) {
141
- return context.dataset.dataLabelOffset || 0
142
- },
143
- align: function (context: any) {
144
- return context.dataset.dataLabelAnchor || 'center'
145
- },
146
- rotation: function (context: any) {
147
- return context.dataset.dataLabelRotation || 0
148
- },
149
- color: function (context: any) {
150
- return context.dataset?.defaultFontColor || '#000'
151
- },
152
- font: function (context: any) {
153
- return {
154
- size: context.dataset?.defaultFontSize,
155
- family: context.chart.options?.defaultFontFamily
156
- }
157
- },
158
- clamp: true,
159
- formatter: function (value: string, context: any) {
160
- var prefix = context.dataset.valuePrefix || ''
161
- var suffix = context.dataset.valueSuffix || ''
162
- var format = context.dataset.valueFormat || ''
163
-
164
- if (value === undefined) {
165
- return value
166
- }
167
-
168
- var stringValue = format ? formatText(format, Number(value)) : Number(value).toLocaleString()
169
- return prefix + stringValue + suffix
170
- }
171
- }
172
- }
173
- }
174
-
175
- function toObjectArrayValue(array: any[]): any[] | null {
176
- if (!array || array.length === 0) {
177
- return null
178
- }
179
-
180
- let indexKeyMap: any = {}
181
- let value = []
182
-
183
- for (let key in array[0]) {
184
- indexKeyMap[key] = array[0][key]
185
- }
186
-
187
- for (var i = 1; i < array.length; i++) {
188
- let object: any = {}
189
- let thisObject = array[i]
190
-
191
- for (let key in indexKeyMap) {
192
- let k = indexKeyMap[key]
193
- let v = thisObject[key]
194
- object[k] = v
195
- }
196
-
197
- value.push(object)
198
- }
199
-
200
- return value
201
- }
202
-
203
- declare global {
204
- interface HTMLElementTagNameMap {
205
- 'ox-chart-js': OxChartJs
206
- }
207
- }