@operato/chart 7.0.1 → 7.0.2
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.
- package/CHANGELOG.md +12 -0
- package/dist/src/chartjs/config-converter.js +7 -1
- package/dist/src/chartjs/config-converter.js.map +1 -1
- package/dist/src/editors/configurer.d.ts +2 -2
- package/dist/src/editors/configurer.js +0 -1
- package/dist/src/editors/configurer.js.map +1 -1
- package/dist/src/editors/input-chart-abstract.js +3 -2
- package/dist/src/editors/input-chart-abstract.js.map +1 -1
- package/dist/src/scichart/ox-scichart.d.ts +2 -0
- package/dist/src/scichart/ox-scichart.js +51 -3
- package/dist/src/scichart/ox-scichart.js.map +1 -1
- package/dist/src/scichart/scichart-builder.js +169 -29
- package/dist/src/scichart/scichart-builder.js.map +1 -1
- package/dist/stories/common.js +2 -2
- package/dist/stories/common.js.map +1 -1
- package/dist/stories/ox-input-chart-timeseries.stories.js +42 -8
- package/dist/stories/ox-input-chart-timeseries.stories.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +3 -2
- package/src/chartjs/config-converter.ts +12 -4
- package/src/editors/configurer.ts +0 -1
- package/src/editors/input-chart-abstract.ts +3 -2
- package/src/scichart/custom-point-markers.ts.xxx +178 -0
- package/src/scichart/ox-scichart.ts +50 -3
- package/src/scichart/scichart-builder.ts +214 -30
- package/src/types.d.ts +14 -2
- package/stories/common.ts +2 -2
- package/stories/ox-input-chart-timeseries.stories.ts +42 -8
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
import { BasePointMarker, TSciChart, IRenderableSeries, EPointMarkerType } from 'scichart'
|
|
2
|
+
|
|
3
|
+
interface PointMarkerOptions {
|
|
4
|
+
width?: number
|
|
5
|
+
height?: number
|
|
6
|
+
strokeThickness?: number
|
|
7
|
+
fill?: string
|
|
8
|
+
stroke?: string
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
abstract class CustomPointMarker extends BasePointMarker {
|
|
12
|
+
private _width: number
|
|
13
|
+
private _height: number
|
|
14
|
+
private _strokeThickness: number
|
|
15
|
+
private _fill: string
|
|
16
|
+
private _stroke: string
|
|
17
|
+
|
|
18
|
+
constructor(wasmContext: TSciChart, options: PointMarkerOptions = {}) {
|
|
19
|
+
super(wasmContext)
|
|
20
|
+
this._width = options.width ?? 10
|
|
21
|
+
this._height = options.height ?? 10
|
|
22
|
+
this._strokeThickness = options.strokeThickness ?? 2
|
|
23
|
+
this._fill = options.fill ?? '#FF6600'
|
|
24
|
+
this._stroke = options.stroke ?? '#000000'
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
get width(): number {
|
|
28
|
+
return this._width
|
|
29
|
+
}
|
|
30
|
+
set width(value: number) {
|
|
31
|
+
this._width = value
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
get height(): number {
|
|
35
|
+
return this._height
|
|
36
|
+
}
|
|
37
|
+
set height(value: number) {
|
|
38
|
+
this._height = value
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
get strokeThickness(): number {
|
|
42
|
+
return this._strokeThickness
|
|
43
|
+
}
|
|
44
|
+
set strokeThickness(value: number) {
|
|
45
|
+
this._strokeThickness = value
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
get fill(): string {
|
|
49
|
+
return this._fill
|
|
50
|
+
}
|
|
51
|
+
set fill(value: string) {
|
|
52
|
+
this._fill = value
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
get stroke(): string {
|
|
56
|
+
return this._stroke
|
|
57
|
+
}
|
|
58
|
+
set stroke(value: string) {
|
|
59
|
+
this._stroke = value
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
get type(): EPointMarkerType {
|
|
63
|
+
return EPointMarkerType.Custom
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
drawSprite(
|
|
67
|
+
context: CanvasRenderingContext2D,
|
|
68
|
+
x: number,
|
|
69
|
+
y: number,
|
|
70
|
+
stroke: string,
|
|
71
|
+
dpiAdjustedStrokeThickness: number,
|
|
72
|
+
fill: string
|
|
73
|
+
): void {
|
|
74
|
+
this.draw(context, null as any, x, y)
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
abstract draw(
|
|
78
|
+
context: CanvasRenderingContext2D,
|
|
79
|
+
renderableSeries: IRenderableSeries,
|
|
80
|
+
xCoord: number,
|
|
81
|
+
yCoord: number
|
|
82
|
+
): void
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// Rotated Square Point Marker
|
|
86
|
+
export class RotatedSquarePointMarker extends CustomPointMarker {
|
|
87
|
+
draw(context: CanvasRenderingContext2D, renderableSeries: IRenderableSeries, xCoord: number, yCoord: number): void {
|
|
88
|
+
context.save()
|
|
89
|
+
context.translate(xCoord, yCoord)
|
|
90
|
+
context.rotate(Math.PI / 4) // 45 degrees rotation
|
|
91
|
+
context.fillStyle = this.fill
|
|
92
|
+
context.strokeStyle = this.stroke
|
|
93
|
+
context.lineWidth = this.strokeThickness
|
|
94
|
+
context.beginPath()
|
|
95
|
+
context.rect(-this.width / 2, -this.height / 2, this.width, this.height)
|
|
96
|
+
context.fill()
|
|
97
|
+
context.stroke()
|
|
98
|
+
context.restore()
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// Cross Rot Point Marker
|
|
103
|
+
export class CrossRotPointMarker extends CustomPointMarker {
|
|
104
|
+
draw(context: CanvasRenderingContext2D, renderableSeries: IRenderableSeries, xCoord: number, yCoord: number): void {
|
|
105
|
+
context.save()
|
|
106
|
+
context.translate(xCoord, yCoord)
|
|
107
|
+
context.rotate(Math.PI / 4) // 45 degrees rotation
|
|
108
|
+
context.strokeStyle = this.stroke
|
|
109
|
+
context.lineWidth = this.strokeThickness
|
|
110
|
+
context.beginPath()
|
|
111
|
+
context.moveTo(-this.width / 2, 0)
|
|
112
|
+
context.lineTo(this.width / 2, 0)
|
|
113
|
+
context.moveTo(0, -this.height / 2)
|
|
114
|
+
context.lineTo(0, this.height / 2)
|
|
115
|
+
context.stroke()
|
|
116
|
+
context.restore()
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// Star Point Marker
|
|
121
|
+
export class StarPointMarker extends CustomPointMarker {
|
|
122
|
+
draw(context: CanvasRenderingContext2D, renderableSeries: IRenderableSeries, xCoord: number, yCoord: number): void {
|
|
123
|
+
const spikes = 5
|
|
124
|
+
const outerRadius = this.width / 2
|
|
125
|
+
const innerRadius = outerRadius / 2
|
|
126
|
+
context.save()
|
|
127
|
+
context.translate(xCoord, yCoord)
|
|
128
|
+
context.fillStyle = this.fill
|
|
129
|
+
context.strokeStyle = this.stroke
|
|
130
|
+
context.lineWidth = this.strokeThickness
|
|
131
|
+
context.beginPath()
|
|
132
|
+
for (let i = 0; i < spikes; i++) {
|
|
133
|
+
context.lineTo(
|
|
134
|
+
Math.cos((i * 2 * Math.PI) / spikes) * outerRadius,
|
|
135
|
+
Math.sin((i * 2 * Math.PI) / spikes) * outerRadius
|
|
136
|
+
)
|
|
137
|
+
context.lineTo(
|
|
138
|
+
Math.cos(((i * 2 + 1) * Math.PI) / spikes) * innerRadius,
|
|
139
|
+
Math.sin(((i * 2 + 1) * Math.PI) / spikes) * innerRadius
|
|
140
|
+
)
|
|
141
|
+
}
|
|
142
|
+
context.closePath()
|
|
143
|
+
context.fill()
|
|
144
|
+
context.stroke()
|
|
145
|
+
context.restore()
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// Line Point Marker
|
|
150
|
+
export class LinePointMarker extends CustomPointMarker {
|
|
151
|
+
draw(context: CanvasRenderingContext2D, renderableSeries: IRenderableSeries, xCoord: number, yCoord: number): void {
|
|
152
|
+
context.save()
|
|
153
|
+
context.translate(xCoord, yCoord)
|
|
154
|
+
context.strokeStyle = this.stroke
|
|
155
|
+
context.lineWidth = this.strokeThickness
|
|
156
|
+
context.beginPath()
|
|
157
|
+
context.moveTo(-this.width / 2, 0)
|
|
158
|
+
context.lineTo(this.width / 2, 0)
|
|
159
|
+
context.stroke()
|
|
160
|
+
context.restore()
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// Dash Point Marker
|
|
165
|
+
export class DashPointMarker extends CustomPointMarker {
|
|
166
|
+
draw(context: CanvasRenderingContext2D, renderableSeries: IRenderableSeries, xCoord: number, yCoord: number): void {
|
|
167
|
+
context.save()
|
|
168
|
+
context.translate(xCoord, yCoord)
|
|
169
|
+
context.strokeStyle = this.stroke
|
|
170
|
+
context.lineWidth = this.strokeThickness
|
|
171
|
+
context.setLineDash([this.width / 4, this.width / 4])
|
|
172
|
+
context.beginPath()
|
|
173
|
+
context.moveTo(-this.width / 2, 0)
|
|
174
|
+
context.lineTo(this.width / 2, 0)
|
|
175
|
+
context.stroke()
|
|
176
|
+
context.restore()
|
|
177
|
+
}
|
|
178
|
+
}
|
|
@@ -20,16 +20,43 @@ class OxSciChart extends LitElement {
|
|
|
20
20
|
private dataSeries: any[] = []
|
|
21
21
|
|
|
22
22
|
@query('div#container') container!: HTMLDivElement
|
|
23
|
+
@query('div#legend') legendContainer!: HTMLDivElement
|
|
23
24
|
|
|
24
25
|
static styles = css`
|
|
25
26
|
:host {
|
|
26
27
|
display: block;
|
|
28
|
+
width: 100%;
|
|
29
|
+
height: 100%;
|
|
27
30
|
}
|
|
28
31
|
|
|
29
|
-
|
|
32
|
+
.chart-container {
|
|
33
|
+
display: flex;
|
|
30
34
|
width: 100%;
|
|
31
35
|
height: 100%;
|
|
32
36
|
}
|
|
37
|
+
|
|
38
|
+
.chart-content {
|
|
39
|
+
flex: 1;
|
|
40
|
+
position: relative;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
.legend {
|
|
44
|
+
display: flex;
|
|
45
|
+
align-items: center;
|
|
46
|
+
justify-content: center;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
.legend-top,
|
|
50
|
+
.legend-bottom {
|
|
51
|
+
width: 100%;
|
|
52
|
+
height: 50px;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
.legend-right,
|
|
56
|
+
.legend-left {
|
|
57
|
+
width: 150px;
|
|
58
|
+
height: 100%;
|
|
59
|
+
}
|
|
33
60
|
`
|
|
34
61
|
|
|
35
62
|
firstUpdated() {
|
|
@@ -70,8 +97,9 @@ class OxSciChart extends LitElement {
|
|
|
70
97
|
}
|
|
71
98
|
|
|
72
99
|
async updated(changedProperties: Map<string | number | symbol, unknown>) {
|
|
73
|
-
if (changedProperties.has('config')) {
|
|
100
|
+
if (changedProperties.has('config') && this.config) {
|
|
74
101
|
await this.initializeSciChart()
|
|
102
|
+
this.updateLegend()
|
|
75
103
|
}
|
|
76
104
|
|
|
77
105
|
if (changedProperties.has('data')) {
|
|
@@ -127,8 +155,27 @@ class OxSciChart extends LitElement {
|
|
|
127
155
|
})
|
|
128
156
|
}
|
|
129
157
|
|
|
158
|
+
updateLegend() {
|
|
159
|
+
const legendPosition = this.config?.options?.legend?.position || 'right'
|
|
160
|
+
const legendElement = this.shadowRoot?.getElementById('legend')
|
|
161
|
+
if (legendElement) {
|
|
162
|
+
legendElement.className = `legend legend-${legendPosition}`
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
130
166
|
render() {
|
|
131
|
-
|
|
167
|
+
const legendPosition = this.config?.options?.legend?.position || 'right'
|
|
168
|
+
return html`
|
|
169
|
+
<div class="chart-container">
|
|
170
|
+
${legendPosition === 'left' ? html`<div id="legend" class="legend legend-left"></div>` : ''}
|
|
171
|
+
<div class="chart-content">
|
|
172
|
+
${legendPosition === 'top' ? html`<div id="legend" class="legend legend-top"></div>` : ''}
|
|
173
|
+
<div id="container"></div>
|
|
174
|
+
${legendPosition === 'bottom' ? html`<div id="legend" class="legend legend-bottom"></div>` : ''}
|
|
175
|
+
</div>
|
|
176
|
+
${legendPosition === 'right' ? html`<div id="legend" class="legend legend-right"></div>` : ''}
|
|
177
|
+
</div>
|
|
178
|
+
`
|
|
132
179
|
}
|
|
133
180
|
}
|
|
134
181
|
|
|
@@ -1,10 +1,18 @@
|
|
|
1
1
|
import { TinyColor } from '@ctrl/tinycolor'
|
|
2
2
|
import { format as formatText } from '../utils/text-formatter'
|
|
3
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
|
+
|
|
4
12
|
export async function buildSciChart(
|
|
5
13
|
config: OperatoChart.ChartConfig | undefined | null,
|
|
6
14
|
container: any,
|
|
7
|
-
{ fontSize, fontFamily, fontColor
|
|
15
|
+
{ fontSize, fontFamily, fontColor }: { fontSize?: number; fontFamily?: string; fontColor?: string }
|
|
8
16
|
): Promise<{ chart: any; dataSeries: any[] } | undefined> {
|
|
9
17
|
if (!config) {
|
|
10
18
|
return
|
|
@@ -12,10 +20,16 @@ export async function buildSciChart(
|
|
|
12
20
|
|
|
13
21
|
const {
|
|
14
22
|
SciChartSurface,
|
|
15
|
-
|
|
23
|
+
SciChartJSLightTheme,
|
|
24
|
+
SciChartJSDarkv2Theme,
|
|
16
25
|
XyDataSeries,
|
|
17
26
|
FastLineRenderableSeries,
|
|
27
|
+
SplineLineRenderableSeries,
|
|
18
28
|
FastColumnRenderableSeries,
|
|
29
|
+
StackedColumnRenderableSeries,
|
|
30
|
+
StackedMountainRenderableSeries,
|
|
31
|
+
StackedColumnCollection,
|
|
32
|
+
StackedMountainCollection,
|
|
19
33
|
NumericAxis,
|
|
20
34
|
DateTimeNumericAxis,
|
|
21
35
|
EAutoRange,
|
|
@@ -24,25 +38,60 @@ export async function buildSciChart(
|
|
|
24
38
|
MouseWheelZoomModifier,
|
|
25
39
|
RubberBandXyZoomModifier,
|
|
26
40
|
ZoomExtentsModifier,
|
|
27
|
-
RolloverModifier
|
|
41
|
+
RolloverModifier,
|
|
42
|
+
SmartDateLabelProvider,
|
|
43
|
+
EllipsePointMarker,
|
|
44
|
+
SquarePointMarker,
|
|
45
|
+
TrianglePointMarker,
|
|
46
|
+
CrossPointMarker,
|
|
47
|
+
XPointMarker,
|
|
48
|
+
WaveAnimation,
|
|
49
|
+
LegendModifier
|
|
28
50
|
} = SciChart
|
|
29
51
|
|
|
30
52
|
const { type: chartType, options, data: fromData } = config
|
|
31
|
-
const { theme, legend, scales: fromScales, xGridLine, yGridLine, y2ndGridLine } = options || {}
|
|
32
53
|
const { datasets = [] } = fromData || {}
|
|
54
|
+
var {
|
|
55
|
+
theme,
|
|
56
|
+
tooltip,
|
|
57
|
+
animation,
|
|
58
|
+
legend,
|
|
59
|
+
scales: fromScales,
|
|
60
|
+
xGridLine,
|
|
61
|
+
yGridLine,
|
|
62
|
+
y2ndGridLine,
|
|
63
|
+
stacked
|
|
64
|
+
} = options || {}
|
|
65
|
+
|
|
66
|
+
var baseColor = getBaseColorFromTheme(theme)
|
|
67
|
+
|
|
68
|
+
if (theme === 'auto') {
|
|
69
|
+
theme = getThemeFromBrowser()
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
fontColor = fontColor || baseColor.clone().toString()
|
|
33
73
|
|
|
34
74
|
const { xAxes = [], yAxes = [] } = fromScales || {}
|
|
35
75
|
|
|
36
76
|
const chart = await SciChartSurface.create(container, {
|
|
37
|
-
theme: new
|
|
77
|
+
theme: theme == 'dark' ? new SciChartJSDarkv2Theme() : new SciChartJSLightTheme()
|
|
38
78
|
})
|
|
39
79
|
const { sciChartSurface, wasmContext } = chart
|
|
40
80
|
|
|
41
81
|
// X 축 설정
|
|
42
82
|
xAxes.forEach((axis, index) => {
|
|
43
83
|
const { axisTitle, ticks } = axis
|
|
44
|
-
const {
|
|
45
|
-
|
|
84
|
+
const {
|
|
85
|
+
autoMax,
|
|
86
|
+
autoMin,
|
|
87
|
+
min,
|
|
88
|
+
max,
|
|
89
|
+
stepSize,
|
|
90
|
+
beginAtZero,
|
|
91
|
+
color = fontColor,
|
|
92
|
+
textStrokeColor = fontColor,
|
|
93
|
+
display = !!axisTitle
|
|
94
|
+
} = ticks || {}
|
|
46
95
|
|
|
47
96
|
const xAxis = new DateTimeNumericAxis(wasmContext, {
|
|
48
97
|
axisTitle,
|
|
@@ -54,13 +103,14 @@ export async function buildSciChart(
|
|
|
54
103
|
labelStyle: {
|
|
55
104
|
fontFamily,
|
|
56
105
|
fontSize,
|
|
57
|
-
color
|
|
106
|
+
color
|
|
58
107
|
},
|
|
59
108
|
axisTitleStyle: {
|
|
60
109
|
fontFamily,
|
|
61
110
|
fontSize,
|
|
62
|
-
color:
|
|
63
|
-
}
|
|
111
|
+
color: textStrokeColor
|
|
112
|
+
},
|
|
113
|
+
labelProvider: new SmartDateLabelProvider()
|
|
64
114
|
})
|
|
65
115
|
|
|
66
116
|
sciChartSurface.xAxes.add(xAxis)
|
|
@@ -70,12 +120,12 @@ export async function buildSciChart(
|
|
|
70
120
|
yAxes.forEach((axis, index) => {
|
|
71
121
|
const { axisTitle, ticks } = axis
|
|
72
122
|
const { autoMax, autoMin, min, max, stepSize, beginAtZero } = ticks || {}
|
|
73
|
-
const id = yAxes.length > 1 ? `right` : 'left'
|
|
74
123
|
|
|
75
124
|
const yAxis = new NumericAxis(wasmContext, {
|
|
125
|
+
id: `yAxis${index}`,
|
|
76
126
|
axisTitle,
|
|
77
127
|
autoRange: autoMin || autoMax ? EAutoRange.Always : undefined,
|
|
78
|
-
axisAlignment:
|
|
128
|
+
axisAlignment: index === 0 ? EAxisAlignment.Left : EAxisAlignment.Right,
|
|
79
129
|
visibleRange: min !== undefined && max !== undefined ? new NumberRange(min, max) : undefined,
|
|
80
130
|
majorDelta: stepSize,
|
|
81
131
|
growBy: beginAtZero ? new NumberRange(0.1, 0.1) : undefined,
|
|
@@ -90,6 +140,7 @@ export async function buildSciChart(
|
|
|
90
140
|
color: fontColor
|
|
91
141
|
}
|
|
92
142
|
})
|
|
143
|
+
|
|
93
144
|
sciChartSurface.yAxes.add(yAxis)
|
|
94
145
|
})
|
|
95
146
|
|
|
@@ -100,36 +151,158 @@ export async function buildSciChart(
|
|
|
100
151
|
containsNaN: false
|
|
101
152
|
})
|
|
102
153
|
|
|
154
|
+
const yAxisId = dataset.yAxisID || 'yAxis0'
|
|
155
|
+
const stackGroupId = dataset.stack || `__stack${index}__`
|
|
156
|
+
|
|
103
157
|
let series: any
|
|
104
158
|
if (dataset.type === 'bar') {
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
159
|
+
if (stacked) {
|
|
160
|
+
series = new StackedColumnRenderableSeries(wasmContext, {
|
|
161
|
+
dataSeries,
|
|
162
|
+
strokeThickness: dataset.borderWidth || 2,
|
|
163
|
+
fill: dataset.backgroundColor || '#FF6600',
|
|
164
|
+
yAxisId,
|
|
165
|
+
stackedGroupId: stackGroupId
|
|
166
|
+
})
|
|
167
|
+
} else {
|
|
168
|
+
series = new FastColumnRenderableSeries(wasmContext, {
|
|
169
|
+
dataSeries,
|
|
170
|
+
strokeThickness: dataset.borderWidth || 2,
|
|
171
|
+
fill: dataset.backgroundColor || '#FF6600',
|
|
172
|
+
animation: animation && new WaveAnimation({ duration: 1000, fadeEffect: true }),
|
|
173
|
+
yAxisId
|
|
174
|
+
})
|
|
175
|
+
}
|
|
110
176
|
} else {
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
177
|
+
const { pointStyle, lineTension } = dataset
|
|
178
|
+
let pointMarker
|
|
179
|
+
|
|
180
|
+
switch (pointStyle) {
|
|
181
|
+
case 'circle':
|
|
182
|
+
pointMarker = new EllipsePointMarker(wasmContext, {
|
|
183
|
+
width: 10,
|
|
184
|
+
height: 10,
|
|
185
|
+
strokeThickness: 2,
|
|
186
|
+
fill: dataset.color || '#FF6600',
|
|
187
|
+
stroke: '#000000'
|
|
188
|
+
})
|
|
189
|
+
break
|
|
190
|
+
case 'triangle':
|
|
191
|
+
pointMarker = new TrianglePointMarker(wasmContext, {
|
|
192
|
+
width: 10,
|
|
193
|
+
height: 10,
|
|
194
|
+
strokeThickness: 2,
|
|
195
|
+
fill: dataset.color || '#FF6600',
|
|
196
|
+
stroke: '#000000'
|
|
197
|
+
})
|
|
198
|
+
break
|
|
199
|
+
case 'rect':
|
|
200
|
+
pointMarker = new SquarePointMarker(wasmContext, {
|
|
201
|
+
width: 10,
|
|
202
|
+
height: 10,
|
|
203
|
+
strokeThickness: 2,
|
|
204
|
+
fill: dataset.color || '#FF6600',
|
|
205
|
+
stroke: '#000000'
|
|
206
|
+
})
|
|
207
|
+
break
|
|
208
|
+
case 'cross':
|
|
209
|
+
pointMarker = new CrossPointMarker(wasmContext, {
|
|
210
|
+
width: 10,
|
|
211
|
+
height: 10,
|
|
212
|
+
strokeThickness: 2,
|
|
213
|
+
fill: dataset.color || '#FF6600',
|
|
214
|
+
stroke: '#000000'
|
|
215
|
+
})
|
|
216
|
+
break
|
|
217
|
+
case 'crossRot':
|
|
218
|
+
pointMarker = new XPointMarker(wasmContext, {
|
|
219
|
+
width: 10,
|
|
220
|
+
height: 10,
|
|
221
|
+
strokeThickness: 2,
|
|
222
|
+
fill: dataset.color || '#FF6600',
|
|
223
|
+
stroke: '#000000'
|
|
224
|
+
})
|
|
225
|
+
break
|
|
226
|
+
default:
|
|
227
|
+
pointMarker = new EllipsePointMarker(wasmContext, {
|
|
228
|
+
width: 10,
|
|
229
|
+
height: 10,
|
|
230
|
+
strokeThickness: 2,
|
|
231
|
+
fill: dataset.color || '#FF6600',
|
|
232
|
+
stroke: '#000000'
|
|
233
|
+
})
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
if (stacked) {
|
|
237
|
+
series = new StackedMountainRenderableSeries(wasmContext, {
|
|
238
|
+
dataSeries,
|
|
239
|
+
strokeThickness: dataset.borderWidth || 2,
|
|
240
|
+
stroke: dataset.color || '#FF6600',
|
|
241
|
+
fill: dataset.backgroundColor || '#FF6600',
|
|
242
|
+
yAxisId,
|
|
243
|
+
stackedGroupId: stackGroupId
|
|
244
|
+
})
|
|
245
|
+
} else {
|
|
246
|
+
series =
|
|
247
|
+
!!lineTension && lineTension > 0
|
|
248
|
+
? new SplineLineRenderableSeries(wasmContext, {
|
|
249
|
+
dataSeries,
|
|
250
|
+
strokeThickness: dataset.borderWidth || 2,
|
|
251
|
+
stroke: dataset.color || '#FF6600',
|
|
252
|
+
pointMarker,
|
|
253
|
+
animation: animation && new WaveAnimation({ duration: 1000, fadeEffect: true }),
|
|
254
|
+
yAxisId
|
|
255
|
+
})
|
|
256
|
+
: new FastLineRenderableSeries(wasmContext, {
|
|
257
|
+
dataSeries,
|
|
258
|
+
strokeThickness: dataset.borderWidth || 2,
|
|
259
|
+
stroke: dataset.color || '#FF6600',
|
|
260
|
+
pointMarker,
|
|
261
|
+
animation: animation && new WaveAnimation({ duration: 1000, fadeEffect: true }),
|
|
262
|
+
yAxisId
|
|
263
|
+
})
|
|
264
|
+
}
|
|
116
265
|
}
|
|
117
266
|
|
|
118
267
|
sciChartSurface.renderableSeries.add(series)
|
|
119
268
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
269
|
+
if (tooltip) {
|
|
270
|
+
const rolloverModifier = new RolloverModifier({
|
|
271
|
+
showTooltip: true,
|
|
272
|
+
showAxisLabels: true,
|
|
273
|
+
tooltipColor: 'white',
|
|
274
|
+
tooltipBackgroundColor: 'rgba(0, 0, 0, 0.7)',
|
|
275
|
+
rollOverDataSeries: dataSeries
|
|
276
|
+
})
|
|
127
277
|
|
|
128
|
-
|
|
278
|
+
sciChartSurface.chartModifiers.add(rolloverModifier)
|
|
279
|
+
}
|
|
129
280
|
|
|
130
281
|
return dataSeries
|
|
131
282
|
})
|
|
132
283
|
|
|
284
|
+
// Stacked collections 추가
|
|
285
|
+
if (stacked) {
|
|
286
|
+
const stackedColumnCollection = new StackedColumnCollection(wasmContext)
|
|
287
|
+
const stackedMountainCollection = new StackedMountainCollection(wasmContext)
|
|
288
|
+
|
|
289
|
+
sciChartSurface.renderableSeries.asArray().forEach((series: any) => {
|
|
290
|
+
if (series instanceof StackedColumnRenderableSeries) {
|
|
291
|
+
stackedColumnCollection.add(series)
|
|
292
|
+
} else if (series instanceof StackedMountainRenderableSeries) {
|
|
293
|
+
stackedMountainCollection.add(series)
|
|
294
|
+
}
|
|
295
|
+
})
|
|
296
|
+
|
|
297
|
+
if (stackedColumnCollection.size() > 0) {
|
|
298
|
+
sciChartSurface.renderableSeries.add(stackedColumnCollection)
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
if (stackedMountainCollection.size() > 0) {
|
|
302
|
+
sciChartSurface.renderableSeries.add(stackedMountainCollection)
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
|
|
133
306
|
// 줌인/줌아웃 모디파이어 추가
|
|
134
307
|
sciChartSurface.chartModifiers.add(
|
|
135
308
|
new RubberBandXyZoomModifier(),
|
|
@@ -137,5 +310,16 @@ export async function buildSciChart(
|
|
|
137
310
|
new ZoomExtentsModifier()
|
|
138
311
|
)
|
|
139
312
|
|
|
313
|
+
// Legend 설정
|
|
314
|
+
if (legend?.display) {
|
|
315
|
+
const legendModifier = new LegendModifier({
|
|
316
|
+
showCheckboxes: true,
|
|
317
|
+
showSeriesMarkers: true,
|
|
318
|
+
showLegend: true,
|
|
319
|
+
placement: legend.position || 'bottom-right'
|
|
320
|
+
})
|
|
321
|
+
sciChartSurface.chartModifiers.add(legendModifier)
|
|
322
|
+
}
|
|
323
|
+
|
|
140
324
|
return { chart, dataSeries: dataSeriesArray }
|
|
141
325
|
}
|
package/src/types.d.ts
CHANGED
|
@@ -24,7 +24,17 @@ declare namespace OperatoChart {
|
|
|
24
24
|
stack?: string
|
|
25
25
|
fill?: boolean
|
|
26
26
|
lineTension?: number
|
|
27
|
-
pointStyle?:
|
|
27
|
+
pointStyle?:
|
|
28
|
+
| 'circle'
|
|
29
|
+
| 'triangle'
|
|
30
|
+
| 'rect'
|
|
31
|
+
| 'rectRot'
|
|
32
|
+
| 'cross'
|
|
33
|
+
| 'crossRot'
|
|
34
|
+
| 'star'
|
|
35
|
+
| 'line'
|
|
36
|
+
| 'dash'
|
|
37
|
+
| undefined
|
|
28
38
|
pointRadius?: number
|
|
29
39
|
valuePrefix?: string
|
|
30
40
|
valueSuffix?: string
|
|
@@ -34,7 +44,7 @@ declare namespace OperatoChart {
|
|
|
34
44
|
}
|
|
35
45
|
|
|
36
46
|
export interface ChartOptions {
|
|
37
|
-
theme?: 'dark' | 'light'
|
|
47
|
+
theme?: 'dark' | 'light' | 'auto'
|
|
38
48
|
tooltip?: boolean
|
|
39
49
|
animation?: boolean
|
|
40
50
|
legend?: LegendOptions
|
|
@@ -74,5 +84,7 @@ declare namespace OperatoChart {
|
|
|
74
84
|
max?: number
|
|
75
85
|
stepSize?: number
|
|
76
86
|
beginAtZero?: boolean
|
|
87
|
+
color?: string
|
|
88
|
+
textStrokeColor?: string
|
|
77
89
|
}
|
|
78
90
|
}
|
package/stories/common.ts
CHANGED
|
@@ -63,10 +63,10 @@ function getRandomInRange(min: number, max: number) {
|
|
|
63
63
|
// 랜덤 데이터를 생성하는 함수
|
|
64
64
|
function generateRandomData(count: number) {
|
|
65
65
|
const randomData = []
|
|
66
|
-
const startTimestamp = Math.floor(Date.now()
|
|
66
|
+
const startTimestamp = Math.floor(Date.now()) // 현재 시간을 Unix 타임스탬프로 설정
|
|
67
67
|
|
|
68
68
|
for (let i = 0; i < count; i++) {
|
|
69
|
-
const timestamp = startTimestamp + i *
|
|
69
|
+
const timestamp = startTimestamp + i * 360 * 30 * 1000 // 3초씩 증가하는 타임스탬프 설정
|
|
70
70
|
const randomCount = getRandomInRange(5, 35) // count 값을 5에서 35 사이로 랜덤 생성
|
|
71
71
|
const randomAverage = getRandomInRange(50, 150) // average 값을 50에서 150 사이로 랜덤 생성
|
|
72
72
|
|