@nethru/kit 1.0.7 → 1.1.1
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/dist/components/charts/Chart.js +379 -0
- package/dist/components/charts/ChartColors.js +11 -0
- package/dist/components/charts/ColumnChart.js +118 -0
- package/dist/components/charts/Number.js +48 -0
- package/dist/components/charts/PieChart.js +168 -0
- package/dist/components/charts/StackedAreaTrendChart.js +52 -0
- package/dist/components/charts/TrendChart.js +30 -0
- package/dist/components/chat/AiChat.js +46 -0
- package/dist/components/chat/ChatInput.js +112 -0
- package/dist/components/chat/ChatMessage.js +76 -0
- package/dist/components/chat/ChatMessages.js +34 -0
- package/dist/components/chat/LoadingIndicator.js +48 -0
- package/dist/components/chat/content/MarkdownContent.css +151 -0
- package/dist/components/chat/content/MarkdownContent.js +14 -0
- package/dist/components/chat/content/ToolContent.js +86 -0
- package/dist/components/chat/content/wisecollector/ColumnChartContent.js +65 -0
- package/dist/components/chat/content/wisecollector/PieChartContent.js +89 -0
- package/dist/components/chat/content/wisecollector/StackedAreaChartContent.js +98 -0
- package/dist/components/chat/contexts/ToolContext.js +31 -0
- package/dist/components/chat/hooks/useChatApi.js +90 -0
- package/dist/components/chat/mock.js +737 -0
- package/dist/index.js +5 -22324
- package/dist/js/config.js +12 -0
- package/dist/js/dateHelper.js +78 -0
- package/package.json +17 -23
- package/dist/index.esm.js +0 -22317
|
@@ -0,0 +1,379 @@
|
|
|
1
|
+
import React, { useCallback, useEffect, useState } from "react";
|
|
2
|
+
import Highcharts from 'highcharts';
|
|
3
|
+
import HighchartsReactModule from 'highcharts-react-official';
|
|
4
|
+
import highchartsAccessibility from 'highcharts/modules/accessibility.js';
|
|
5
|
+
import highchartsAnnotations from 'highcharts/modules/annotations.js';
|
|
6
|
+
import { format, formatToPercent } from "./Number";
|
|
7
|
+
import * as ChartColors from "./ChartColors";
|
|
8
|
+
import { grey } from "@nethru/ui/base/colors";
|
|
9
|
+
|
|
10
|
+
// Handle both ES module and CommonJS exports
|
|
11
|
+
import { jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
|
|
12
|
+
const HighchartsReact = HighchartsReactModule.default || HighchartsReactModule;
|
|
13
|
+
highchartsAccessibility(Highcharts);
|
|
14
|
+
highchartsAnnotations(Highcharts);
|
|
15
|
+
export default function Chart(props) {
|
|
16
|
+
const [legendLimitEnabled, setLegendLimitEnabled] = useState(props.legendLimit > 0);
|
|
17
|
+
const [options, setOptions] = useState(toOptions(props, legendLimitEnabled));
|
|
18
|
+
useEffect(() => {
|
|
19
|
+
if (props.delay) setTimeout(() => setOptions(toOptions(props, legendLimitEnabled, handleLegendItemClick)), props.delay);else setOptions(toOptions(props, legendLimitEnabled, handleLegendItemClick));
|
|
20
|
+
// eslint-disable-next-line
|
|
21
|
+
}, [props]);
|
|
22
|
+
const handleLegendItemClick = useCallback(() => setLegendLimitEnabled(false), []);
|
|
23
|
+
return /*#__PURE__*/_jsx(_Fragment, {
|
|
24
|
+
children: options && /*#__PURE__*/_jsx(HighchartsReact, {
|
|
25
|
+
highcharts: Highcharts,
|
|
26
|
+
options: options
|
|
27
|
+
})
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
function toOptions(props, legendLimitEnabled, handleLegendItemClick) {
|
|
31
|
+
const {
|
|
32
|
+
title = '',
|
|
33
|
+
type,
|
|
34
|
+
categorize,
|
|
35
|
+
stacking,
|
|
36
|
+
showLegend = true,
|
|
37
|
+
showDataLabel,
|
|
38
|
+
xAxisType,
|
|
39
|
+
xAxisLabel = true,
|
|
40
|
+
xAxisLabelFormat,
|
|
41
|
+
xAxisTickInterval,
|
|
42
|
+
yAxisLabelEnabled = true,
|
|
43
|
+
yAxisLabelFormat,
|
|
44
|
+
yAxisTickInterval = null,
|
|
45
|
+
yAxisPlotLines = [],
|
|
46
|
+
opacity = 1,
|
|
47
|
+
innerSize = 0,
|
|
48
|
+
colors: customColors,
|
|
49
|
+
backgroundColor = undefined,
|
|
50
|
+
xPlotIndex,
|
|
51
|
+
dimension,
|
|
52
|
+
metrics,
|
|
53
|
+
records = [],
|
|
54
|
+
metas,
|
|
55
|
+
height = 200,
|
|
56
|
+
legendLimit,
|
|
57
|
+
legendAlign = 'center',
|
|
58
|
+
tooltip = {},
|
|
59
|
+
secondaryXAxis = []
|
|
60
|
+
} = props;
|
|
61
|
+
const {
|
|
62
|
+
outside
|
|
63
|
+
} = tooltip;
|
|
64
|
+
const pie = type === 'pie';
|
|
65
|
+
const centers = pieCenters(metrics.length);
|
|
66
|
+
const size = pieSize(metrics.length);
|
|
67
|
+
const colors = customColors ? customColors : ChartColors.preset;
|
|
68
|
+
const categories = records.map(record => record[dimension]);
|
|
69
|
+
const mainXAxis = records.map(r => r.time);
|
|
70
|
+
const chartColorHandlers = {
|
|
71
|
+
line: (colors, index) => ({
|
|
72
|
+
color: colors[index],
|
|
73
|
+
mainColor: colors[index]
|
|
74
|
+
}),
|
|
75
|
+
area: (colors, index) => ({
|
|
76
|
+
color: colors[index][0],
|
|
77
|
+
mainColor: colors[index][1]
|
|
78
|
+
}),
|
|
79
|
+
gradient: (colors, index) => ({
|
|
80
|
+
color: {
|
|
81
|
+
linearGradient: {
|
|
82
|
+
x1: 0,
|
|
83
|
+
y1: 0,
|
|
84
|
+
x2: 0,
|
|
85
|
+
y2: 1
|
|
86
|
+
},
|
|
87
|
+
stops: [[0, `${colors[index][0]}`], [0.95, `${colors[index][1]}`]]
|
|
88
|
+
},
|
|
89
|
+
mainColor: colors[index][2]
|
|
90
|
+
})
|
|
91
|
+
};
|
|
92
|
+
const series = metrics.map(({
|
|
93
|
+
chartType,
|
|
94
|
+
metric
|
|
95
|
+
}, index) => {
|
|
96
|
+
const type = chartType === 'gradient' ? 'area' : chartType;
|
|
97
|
+
const {
|
|
98
|
+
color,
|
|
99
|
+
mainColor
|
|
100
|
+
} = chartColorHandlers[chartType](colors, index);
|
|
101
|
+
const meta = metas[metric];
|
|
102
|
+
let option = {
|
|
103
|
+
type: type,
|
|
104
|
+
name: meta ? meta.name : '',
|
|
105
|
+
data: records.map(record => {
|
|
106
|
+
const data = record.metric[metric] ?? null;
|
|
107
|
+
return pie ? {
|
|
108
|
+
name: record[dimension],
|
|
109
|
+
y: data
|
|
110
|
+
} : data;
|
|
111
|
+
}),
|
|
112
|
+
custom: {
|
|
113
|
+
type: meta ? meta.type : '',
|
|
114
|
+
pointerNames: meta?.pointerNames ?? null
|
|
115
|
+
},
|
|
116
|
+
center: centers[index] || [null, null],
|
|
117
|
+
size: size,
|
|
118
|
+
point: {
|
|
119
|
+
events: {
|
|
120
|
+
render: function () {
|
|
121
|
+
this.graphic.attr({
|
|
122
|
+
zIndex: this.y === 0 ? -1 : ZIndex.COMPARE_CHART_BASE - index
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
},
|
|
127
|
+
showInLegend: pie && index > 0 ? false : true,
|
|
128
|
+
color: color,
|
|
129
|
+
lineColor: mainColor,
|
|
130
|
+
lineWidth: 2,
|
|
131
|
+
marker: {
|
|
132
|
+
fillColor: mainColor
|
|
133
|
+
},
|
|
134
|
+
metric: metric
|
|
135
|
+
};
|
|
136
|
+
if (legendLimitEnabled) option = {
|
|
137
|
+
...option,
|
|
138
|
+
visible: index < legendLimit
|
|
139
|
+
};
|
|
140
|
+
return option;
|
|
141
|
+
});
|
|
142
|
+
const yPlotLines = yAxisPlotLines.map((line, index) => {
|
|
143
|
+
return {
|
|
144
|
+
value: line.value,
|
|
145
|
+
width: 1,
|
|
146
|
+
color: line.color,
|
|
147
|
+
dashStyle: "Dash",
|
|
148
|
+
zIndex: ZIndex.AVERAGE_LINE_BASE + index,
|
|
149
|
+
label: {
|
|
150
|
+
text: line.label,
|
|
151
|
+
align: line.labelAlign,
|
|
152
|
+
style: {
|
|
153
|
+
color: line.labelColor,
|
|
154
|
+
opacity: 0.7,
|
|
155
|
+
fontSize: "12px",
|
|
156
|
+
padding: '1px 5px'
|
|
157
|
+
},
|
|
158
|
+
y: -8,
|
|
159
|
+
useHTML: true
|
|
160
|
+
}
|
|
161
|
+
};
|
|
162
|
+
});
|
|
163
|
+
const xPlotBands = [{
|
|
164
|
+
from: xPlotIndex,
|
|
165
|
+
to: categories.length - 1,
|
|
166
|
+
color: 'rgba(0, 0, 0, 0.03)',
|
|
167
|
+
zIndex: ZIndex.NOW_BAND
|
|
168
|
+
}];
|
|
169
|
+
const xPlotLines = [{
|
|
170
|
+
color: "#aaa",
|
|
171
|
+
width: 1,
|
|
172
|
+
value: xPlotIndex,
|
|
173
|
+
zIndex: ZIndex.NOW_BORDER,
|
|
174
|
+
label: {
|
|
175
|
+
text: "현재",
|
|
176
|
+
rotation: 0,
|
|
177
|
+
x: 5,
|
|
178
|
+
y: 13,
|
|
179
|
+
style: {
|
|
180
|
+
fontWeight: 500,
|
|
181
|
+
lineHeight: "16.8px",
|
|
182
|
+
color: "#333",
|
|
183
|
+
fontSize: "12px"
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
}];
|
|
187
|
+
return {
|
|
188
|
+
chart: {
|
|
189
|
+
type: type.toLowerCase(),
|
|
190
|
+
height: height,
|
|
191
|
+
backgroundColor,
|
|
192
|
+
events: {
|
|
193
|
+
render: secondaryXAxis.length === 0 ? undefined : function () {
|
|
194
|
+
const chart = this;
|
|
195
|
+
const visibleSeries = chart.series.filter(s => s.visible);
|
|
196
|
+
let newCategories = null;
|
|
197
|
+
if (visibleSeries.length === 1 && visibleSeries[0].options.metric === 'prev') {
|
|
198
|
+
newCategories = secondaryXAxis;
|
|
199
|
+
} else {
|
|
200
|
+
newCategories = mainXAxis;
|
|
201
|
+
}
|
|
202
|
+
const isSame = JSON.stringify(chart.xAxis[0].categories) === JSON.stringify(newCategories);
|
|
203
|
+
if (!isSame) {
|
|
204
|
+
chart.xAxis[0].setCategories(newCategories);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
},
|
|
209
|
+
title: {
|
|
210
|
+
text: ''
|
|
211
|
+
},
|
|
212
|
+
subtitle: {
|
|
213
|
+
text: title
|
|
214
|
+
},
|
|
215
|
+
colors: colors,
|
|
216
|
+
xAxis: {
|
|
217
|
+
type: xAxisType,
|
|
218
|
+
labels: {
|
|
219
|
+
enabled: xAxisLabel,
|
|
220
|
+
autoRotation: false,
|
|
221
|
+
format: xAxisLabelFormat ? `{value:${xAxisLabelFormat}}` : undefined,
|
|
222
|
+
style: {
|
|
223
|
+
color: grey[600]
|
|
224
|
+
}
|
|
225
|
+
},
|
|
226
|
+
categories: categorize ? categories : undefined,
|
|
227
|
+
tickWidth: 1,
|
|
228
|
+
tickInterval: xAxisTickInterval ?? (xAxisType === 'datetime' ? records.length / 20 : 1),
|
|
229
|
+
lineColor: grey[900],
|
|
230
|
+
tickColor: grey[900],
|
|
231
|
+
crosshair: true,
|
|
232
|
+
startOnTick: true,
|
|
233
|
+
plotBands: xPlotIndex !== undefined ? xPlotBands : undefined,
|
|
234
|
+
plotLines: xPlotIndex !== undefined ? xPlotLines : undefined
|
|
235
|
+
},
|
|
236
|
+
yAxis: {
|
|
237
|
+
title: {
|
|
238
|
+
text: ''
|
|
239
|
+
},
|
|
240
|
+
labels: {
|
|
241
|
+
enabled: yAxisLabelEnabled,
|
|
242
|
+
formatter: yAxisLabelFormat,
|
|
243
|
+
style: {
|
|
244
|
+
color: grey[600]
|
|
245
|
+
}
|
|
246
|
+
},
|
|
247
|
+
tickInterval: yAxisTickInterval,
|
|
248
|
+
gridLineColor: '#f8f8f8',
|
|
249
|
+
plotLines: yPlotLines
|
|
250
|
+
},
|
|
251
|
+
plotOptions: {
|
|
252
|
+
series: {
|
|
253
|
+
opacity: opacity,
|
|
254
|
+
stacking: stackingType(stacking),
|
|
255
|
+
showInLegend: showLegend,
|
|
256
|
+
dataLabels: {
|
|
257
|
+
enabled: showDataLabel
|
|
258
|
+
},
|
|
259
|
+
colorByPoint: pie,
|
|
260
|
+
lineWidth: 2,
|
|
261
|
+
marker: {
|
|
262
|
+
enabled: false,
|
|
263
|
+
symbol: 'circle'
|
|
264
|
+
},
|
|
265
|
+
cursor: 'pointer',
|
|
266
|
+
point: {
|
|
267
|
+
events: {}
|
|
268
|
+
},
|
|
269
|
+
events: {
|
|
270
|
+
legendItemClick: handleLegendItemClick
|
|
271
|
+
}
|
|
272
|
+
},
|
|
273
|
+
pie: {
|
|
274
|
+
allowPointSelect: true,
|
|
275
|
+
innerSize: `${innerSize}%`
|
|
276
|
+
}
|
|
277
|
+
},
|
|
278
|
+
legend: {
|
|
279
|
+
align: legendAlign,
|
|
280
|
+
verticalAlign: 'top',
|
|
281
|
+
enabled: showLegend
|
|
282
|
+
},
|
|
283
|
+
tooltip: {
|
|
284
|
+
followPointer: false,
|
|
285
|
+
shared: true,
|
|
286
|
+
shadow: false,
|
|
287
|
+
useHTML: true,
|
|
288
|
+
formatter: function () {
|
|
289
|
+
return tooltipFormatter(this, tooltip);
|
|
290
|
+
},
|
|
291
|
+
outside: outside,
|
|
292
|
+
style: {
|
|
293
|
+
zIndex: 2000
|
|
294
|
+
}
|
|
295
|
+
},
|
|
296
|
+
series: series,
|
|
297
|
+
time: {
|
|
298
|
+
useUTC: false,
|
|
299
|
+
getTimezoneOffset: function () {
|
|
300
|
+
return new Date().getTimezoneOffset();
|
|
301
|
+
}
|
|
302
|
+
},
|
|
303
|
+
credits: {
|
|
304
|
+
enabled: false
|
|
305
|
+
}
|
|
306
|
+
};
|
|
307
|
+
}
|
|
308
|
+
const tooltipFormatter = (_this, props) => {
|
|
309
|
+
const {
|
|
310
|
+
headerVisible = true,
|
|
311
|
+
dateFormat,
|
|
312
|
+
headerTime,
|
|
313
|
+
legendColors = []
|
|
314
|
+
} = props;
|
|
315
|
+
let tooltip = '<div style="font-size: 14px;padding: 12px; min-width: 200px;">';
|
|
316
|
+
if (headerVisible) {
|
|
317
|
+
const xDate = new Date(_this.x);
|
|
318
|
+
const date = formatDate(xDate, dateFormat);
|
|
319
|
+
tooltip += `<div style="display: flex; justify-content: space-between; font-weight: bold; font-size: 12px;">
|
|
320
|
+
<span style="font-size: 12px; color: #333;">${date}</span>`;
|
|
321
|
+
if (headerTime) {
|
|
322
|
+
const time = formatDate(xDate, '%H:%M');
|
|
323
|
+
tooltip += `<span style="font-size: 12px; color: #333;">${time}</span>`;
|
|
324
|
+
}
|
|
325
|
+
tooltip += '</div>';
|
|
326
|
+
}
|
|
327
|
+
_this.points.forEach(point => {
|
|
328
|
+
const type = point.series.options.custom.type;
|
|
329
|
+
const value = type !== 'TO_PERCENT' ? format(point.y, type) : formatToPercent(_this.percentage / 100);
|
|
330
|
+
const name = point.series.name;
|
|
331
|
+
let color = type !== 'TO_PERCENT' ? point.series.color : point.color;
|
|
332
|
+
if (legendColors.length !== 0) {
|
|
333
|
+
color = legendColors[point.series.index];
|
|
334
|
+
}
|
|
335
|
+
tooltip += `<div style="display: flex; flex-direction: column; gap: 8px;">
|
|
336
|
+
<div style="display: flex; justify-content: space-between; align-items: center; margin-top: 15px;">
|
|
337
|
+
<span style="width: 10px; height: 10px; border-radius: 2px; margin-right: 8px; background-color: ${color}"></span>
|
|
338
|
+
<span style="flex-grow: 1; font-size: 14px; padding-right: 20px;">${name}</span>
|
|
339
|
+
<span style="font-weight: bold; font-size: 14px;">${value}</span>
|
|
340
|
+
</div>
|
|
341
|
+
</div>`;
|
|
342
|
+
});
|
|
343
|
+
tooltip += '</div>';
|
|
344
|
+
return tooltip;
|
|
345
|
+
};
|
|
346
|
+
function formatDate(data, format) {
|
|
347
|
+
return Highcharts.dateFormat(format, data.getTime() - data.getTimezoneOffset() * 60000);
|
|
348
|
+
}
|
|
349
|
+
const ZIndex = {
|
|
350
|
+
AVERAGE_LINE_BASE: 10,
|
|
351
|
+
COMPARE_CHART_BASE: 5,
|
|
352
|
+
NOW_BORDER: 2,
|
|
353
|
+
NOW_BAND: 1
|
|
354
|
+
};
|
|
355
|
+
function stackingType(stacking) {
|
|
356
|
+
return stacking ? stacking.toLowerCase() : '';
|
|
357
|
+
}
|
|
358
|
+
function pieCenters(count) {
|
|
359
|
+
switch (count) {
|
|
360
|
+
case 2:
|
|
361
|
+
return [['25%', '50%'], ['75%', '50%']];
|
|
362
|
+
case 3:
|
|
363
|
+
return [['25%', '25%'], ['75%', '25%'], ['50%', '75%']];
|
|
364
|
+
case 4:
|
|
365
|
+
return [['25%', '25%'], ['75%', '25%'], ['25%', '75%'], ['75%', '75%']];
|
|
366
|
+
default:
|
|
367
|
+
return [];
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
function pieSize(count) {
|
|
371
|
+
switch (count) {
|
|
372
|
+
case 3:
|
|
373
|
+
return '50%';
|
|
374
|
+
case 4:
|
|
375
|
+
return '25%';
|
|
376
|
+
default:
|
|
377
|
+
return null;
|
|
378
|
+
}
|
|
379
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { blue, green, lime, orange, purple, red, yellow } from "@nethru/ui/base/colors";
|
|
2
|
+
import { alpha } from "@mui/material";
|
|
3
|
+
export const all = [[blue[500]], [purple[500], '#4168a6', '#81a7e1'], [green[500], '#debb7f', '#ecdbbe'], [yellow[500], '#1b8286', '#4ab3b6'], [red[500]], [orange[500]], [lime[500]], ['#54AAF9'], ['#BB4ECD'], ['#6DDBBA'], ['#FFE81C'], ['#FA7EBA'], ['#F55713'], ['#51B304'], ['#1559B2'], ['#733FAB'], ['#1C7B5F'], ['#D87500'], ['#C91E48'], ['#2F862F']];
|
|
4
|
+
export const colors = [[blue[400], blue[500]], [purple[400], purple[500]], [green[400], green[500]], [yellow[400], yellow[500]], [red[400], red[500]], [orange[400], orange[500]], [lime[400], lime[500]]];
|
|
5
|
+
export const gradient = [[alpha(blue[500], 0.2), 'transparent', blue[300]], [alpha(purple[500], 0.2), 'transparent', purple[500]], [alpha(green[500], 0.2), 'transparent', green[500]], [alpha(yellow[500], 0.2), 'transparent', yellow[500]], [alpha(red[500], 0.2), 'transparent', red[500]], [alpha(orange[500], 0.2), 'transparent', orange[500]], [alpha(lime[500], 0.2), 'transparent', lime[500]]];
|
|
6
|
+
export const grey = ['#333', '#666', '#999'];
|
|
7
|
+
export const preset = ['#003f5c', '#a05195', '#665191', '#2f4b7c', '#d45087', '#f95d6a', '#ff7c43', '#ffa600'];
|
|
8
|
+
export const perRatio = ['#df5645', '#9fcc2e', '#333'];
|
|
9
|
+
export const compare = '#fa9f1b';
|
|
10
|
+
export const backgroundColor = '#fff';
|
|
11
|
+
export const main = all.map(color => color[0]);
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import React, { useMemo } from 'react';
|
|
2
|
+
import Highcharts from 'highcharts';
|
|
3
|
+
import HighchartsReactModule from 'highcharts-react-official';
|
|
4
|
+
import 'highcharts/modules/pattern-fill.js';
|
|
5
|
+
|
|
6
|
+
// Handle both ES module and CommonJS exports
|
|
7
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
8
|
+
const HighchartsReact = HighchartsReactModule.default || HighchartsReactModule;
|
|
9
|
+
const ColumnChart = ({
|
|
10
|
+
data,
|
|
11
|
+
width,
|
|
12
|
+
height = 230
|
|
13
|
+
}) => {
|
|
14
|
+
const series = useMemo(() => {
|
|
15
|
+
return data.series.map((item, sindex) => ({
|
|
16
|
+
...item,
|
|
17
|
+
data: item.data.map((value, index) => ({
|
|
18
|
+
y: value,
|
|
19
|
+
color: data.colors[index % data.colors.length] + alphas[sindex % alphas.length]
|
|
20
|
+
}))
|
|
21
|
+
}));
|
|
22
|
+
}, [data]);
|
|
23
|
+
const colors = useMemo(() => {
|
|
24
|
+
return data.series.map((_, index) => data.colors[0] + alphas[index % alphas.length]);
|
|
25
|
+
}, [data]);
|
|
26
|
+
const options = useMemo(() => {
|
|
27
|
+
return {
|
|
28
|
+
chart: {
|
|
29
|
+
type: 'column',
|
|
30
|
+
backgroundColor: 'transparent',
|
|
31
|
+
width: width,
|
|
32
|
+
height: height,
|
|
33
|
+
style: {
|
|
34
|
+
fontFamily: fontFamily
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
title: {
|
|
38
|
+
text: undefined
|
|
39
|
+
},
|
|
40
|
+
tooltip: {
|
|
41
|
+
pointFormat: '<span><b>{point.y}</b></span>',
|
|
42
|
+
style: {
|
|
43
|
+
fontFamily: fontFamily,
|
|
44
|
+
fontSize: '13px',
|
|
45
|
+
fontWeight: '100'
|
|
46
|
+
},
|
|
47
|
+
useHTML: true
|
|
48
|
+
},
|
|
49
|
+
plotOptions: {
|
|
50
|
+
column: {
|
|
51
|
+
//size: size
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
xAxis: {
|
|
55
|
+
categories: data.categories,
|
|
56
|
+
crosshair: true,
|
|
57
|
+
labels: {
|
|
58
|
+
style: {
|
|
59
|
+
color: '#777',
|
|
60
|
+
fontFamily: fontFamily,
|
|
61
|
+
fontWeight: '400'
|
|
62
|
+
}
|
|
63
|
+
},
|
|
64
|
+
lineColor: '#aaa'
|
|
65
|
+
},
|
|
66
|
+
yAxis: {
|
|
67
|
+
title: {
|
|
68
|
+
text: undefined
|
|
69
|
+
},
|
|
70
|
+
labels: {
|
|
71
|
+
style: {
|
|
72
|
+
fontFamily: fontFamily,
|
|
73
|
+
fontSize: '12px',
|
|
74
|
+
fontWeight: '100'
|
|
75
|
+
}
|
|
76
|
+
},
|
|
77
|
+
gridLineColor: '#f9f9f9'
|
|
78
|
+
},
|
|
79
|
+
legend: {
|
|
80
|
+
layout: 'vertical',
|
|
81
|
+
itemStyle: {
|
|
82
|
+
fontFamily: fontFamily,
|
|
83
|
+
fontSize: '12px',
|
|
84
|
+
fontWeight: '100'
|
|
85
|
+
},
|
|
86
|
+
useHTML: true
|
|
87
|
+
},
|
|
88
|
+
series: series,
|
|
89
|
+
colors: colors,
|
|
90
|
+
credits: {
|
|
91
|
+
enabled: false
|
|
92
|
+
},
|
|
93
|
+
accessibility: {
|
|
94
|
+
enabled: false
|
|
95
|
+
}
|
|
96
|
+
};
|
|
97
|
+
}, [data, width, height, series, colors]);
|
|
98
|
+
return /*#__PURE__*/_jsx("div", {
|
|
99
|
+
style: styles.chartWrapper,
|
|
100
|
+
children: /*#__PURE__*/_jsx(HighchartsReact, {
|
|
101
|
+
highcharts: Highcharts,
|
|
102
|
+
options: options
|
|
103
|
+
})
|
|
104
|
+
});
|
|
105
|
+
};
|
|
106
|
+
export default ColumnChart;
|
|
107
|
+
const fontFamily = 'Pretendard, -apple-system, BlinkMacSystemFont, sans-serif';
|
|
108
|
+
const styles = {
|
|
109
|
+
chartWrapper: {
|
|
110
|
+
background: 'transparent',
|
|
111
|
+
textAlign: 'center',
|
|
112
|
+
display: 'flex',
|
|
113
|
+
flexDirection: 'column',
|
|
114
|
+
justifyContent: 'center',
|
|
115
|
+
alignItems: 'center'
|
|
116
|
+
}
|
|
117
|
+
};
|
|
118
|
+
const alphas = ['ff', 'bb', '77', '33'];
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
export function toValue(value) {
|
|
2
|
+
return value && typeof value === 'object' ? value.value : value;
|
|
3
|
+
}
|
|
4
|
+
export function toPercent(value) {
|
|
5
|
+
return Math.round(value * 100 * 100) / 100;
|
|
6
|
+
}
|
|
7
|
+
export function formatNumber(value) {
|
|
8
|
+
return value !== undefined ? value.toLocaleString() : '-';
|
|
9
|
+
}
|
|
10
|
+
export function formatToPercent(value) {
|
|
11
|
+
return formatPercent(toPercent(value));
|
|
12
|
+
}
|
|
13
|
+
export function formatPercent(value) {
|
|
14
|
+
return value !== undefined ? `${value.toLocaleString()}%` : '-';
|
|
15
|
+
}
|
|
16
|
+
export function formatDiffPercent(value) {
|
|
17
|
+
return value !== undefined ? `${value > 0 ? '+' : ''}${formatToPercent(value)}` : '-';
|
|
18
|
+
}
|
|
19
|
+
export function formatDuration(value) {
|
|
20
|
+
value = toValue(value);
|
|
21
|
+
if (!value) return '-';
|
|
22
|
+
let day = Math.floor(value / (60 * 60 * 24));
|
|
23
|
+
let hour = Math.floor(value / (60 * 60)) - day * 24;
|
|
24
|
+
let minute = Math.floor(value / 60) - (day * 24 + hour) * 60;
|
|
25
|
+
let second = Math.round(value % 60);
|
|
26
|
+
day = day > 0 ? `${day.toLocaleString()}일 ` : '';
|
|
27
|
+
hour = hour > 0 ? `${hour >= 10 ? hour : '0' + hour}시간 ` : '';
|
|
28
|
+
minute = `${minute >= 10 ? minute : '0' + minute}분 `;
|
|
29
|
+
second = `${second >= 10 ? second : '0' + second}초`;
|
|
30
|
+
return `${day}${hour}${minute}${second}`;
|
|
31
|
+
}
|
|
32
|
+
export function formatBytes(value) {
|
|
33
|
+
return value !== undefined ? `${value.toLocaleString()} bytes` : '-';
|
|
34
|
+
}
|
|
35
|
+
export function format(value, type) {
|
|
36
|
+
switch (type) {
|
|
37
|
+
case 'TO_PERCENT':
|
|
38
|
+
return formatToPercent(value);
|
|
39
|
+
case 'DURATION':
|
|
40
|
+
return formatDuration(value);
|
|
41
|
+
case 'BYTES':
|
|
42
|
+
return formatBytes(value);
|
|
43
|
+
case 'PERCENT':
|
|
44
|
+
return formatPercent(value);
|
|
45
|
+
default:
|
|
46
|
+
return formatNumber(value);
|
|
47
|
+
}
|
|
48
|
+
}
|