@opsnow-mcp/opsnow-mcp-common-ui-server 1.0.11 → 1.0.16
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/README.md +105 -0
- package/build/components/examples/opsnow-common-chart-examples-data.js +403 -1
- package/build/components/examples/opsnow-common-forms-examples-data.js +202 -0
- package/build/components/examples/opsnow-common-grid-examples-data.js +104 -0
- package/build/components/examples/opsnow-common-layout-examples-data.js +12 -0
- package/build/components/examples/opsnow-common-tab-examples-data.js +5 -0
- package/build/components/examples/opsnow-common-toast-popup-examples-data.js +1 -1
- package/build/components/opsnow-common-chart.js +85 -13
- package/build/components/opsnow-common-examples.js +5 -2
- package/build/components/opsnow-common-forms.js +148 -1
- package/build/components/opsnow-common-grid.js +4 -1
- package/build/components/opsnow-common-layout.js +70 -1
- package/package.json +4 -1
package/README.md
CHANGED
|
@@ -209,3 +209,108 @@ MCP 플랫폼의 설정 파일(예: `mcp.config.json` 또는 유사 파일)에
|
|
|
209
209
|
|
|
210
210
|
### 3. MCP 플랫폼에서 서버 인식 확인
|
|
211
211
|
MCP 플랫폼을 재시작하거나 서버 목록을 새로고침하면, `opsnow-mcp-common-ui-server`가 정상적으로 등록되어야 합니다.
|
|
212
|
+
|
|
213
|
+
---
|
|
214
|
+
|
|
215
|
+
## Claude Code Skills 생성
|
|
216
|
+
|
|
217
|
+
MCP 서버를 Claude Code에서 사용할 수 있는 **정적 Skills**로 변환할 수 있습니다.
|
|
218
|
+
|
|
219
|
+
### MCP vs Skills 비교
|
|
220
|
+
|
|
221
|
+
| 구분 | MCP Server | Claude Code Skills |
|
|
222
|
+
|------|------------|-------------------|
|
|
223
|
+
| 실행 방식 | 런타임 (Node.js 프로세스) | 정적 문서 (마크다운) |
|
|
224
|
+
| 호출 방식 | Tool 호출 | `/skill-name` 슬래시 커맨드 |
|
|
225
|
+
| 배포 | npm 패키지 | Plugin Marketplace 또는 로컬 |
|
|
226
|
+
| 오프라인 | ❌ | ✅ |
|
|
227
|
+
|
|
228
|
+
### Skills 빌드 명령어
|
|
229
|
+
|
|
230
|
+
```bash
|
|
231
|
+
# Skills 빌드 (기존 파일 유지)
|
|
232
|
+
npm run build:skill
|
|
233
|
+
|
|
234
|
+
# Skills 클린 빌드 (기존 파일 삭제 후 새로 생성)
|
|
235
|
+
npm run build:skill:clean
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
### 빌드 출력물
|
|
239
|
+
|
|
240
|
+
```
|
|
241
|
+
skills/plugins/opsnow-common-ui-skill/
|
|
242
|
+
├── .claude-plugin/
|
|
243
|
+
│ └── plugin.json # 플러그인 매니페스트
|
|
244
|
+
└── skills/opsnow-common-ui/
|
|
245
|
+
├── SKILL.md # 메인 스킬 정의 (컴포넌트 카탈로그)
|
|
246
|
+
├── references/ # Props 레퍼런스 (35개)
|
|
247
|
+
│ ├── button.md
|
|
248
|
+
│ ├── datagrid.md
|
|
249
|
+
│ └── ...
|
|
250
|
+
├── examples/ # 상세 예제 (40개 파일, 463개 예제)
|
|
251
|
+
│ ├── button.md
|
|
252
|
+
│ ├── datagrid.md
|
|
253
|
+
│ └── ...
|
|
254
|
+
└── components/ # Zod 스키마 복사본 (18개)
|
|
255
|
+
├── opsnow-common-button.ts
|
|
256
|
+
└── ...
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
### 문서 구조 (Progressive Disclosure)
|
|
260
|
+
|
|
261
|
+
| 깊이 | 경로 | 용도 | 언제 참조? |
|
|
262
|
+
|------|------|------|-----------|
|
|
263
|
+
| 1 | `SKILL.md` | 컴포넌트 카탈로그, 개요 | 뭐가 있는지 파악할 때 |
|
|
264
|
+
| 2 | `references/*.md` | Props 테이블, 기본 사용법 | 컴포넌트 처음 사용할 때 |
|
|
265
|
+
| 3 | `examples/*.md` | 케이스별 상세 예제 | 특정 패턴 구현할 때 |
|
|
266
|
+
| 4 | `components/*.ts` | Zod 스키마, 타입 정의 | 타입/옵션 상세 확인할 때 |
|
|
267
|
+
|
|
268
|
+
### 로컬 테스트
|
|
269
|
+
|
|
270
|
+
생성된 Skills를 로컬에서 테스트하려면:
|
|
271
|
+
|
|
272
|
+
```bash
|
|
273
|
+
# 프로젝트 루트에서
|
|
274
|
+
cd skills/plugins/opsnow-common-ui-skill
|
|
275
|
+
|
|
276
|
+
# Claude Code에서 직접 테스트
|
|
277
|
+
claude
|
|
278
|
+
|
|
279
|
+
# 또는 skills 폴더를 Claude Code 설정에 추가
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
### 새 컴포넌트 추가 시 수정 필요 사항
|
|
283
|
+
|
|
284
|
+
`scripts/build-skill.ts`에서 다음 5개 매핑을 업데이트해야 합니다:
|
|
285
|
+
|
|
286
|
+
1. **`CATEGORIES[]`** - 카탈로그 분류 (차트, 폼, 레이아웃 등)
|
|
287
|
+
2. **`COMPONENT_NAME_MAP{}`** - React 컴포넌트명 매핑
|
|
288
|
+
3. **`COMPONENT_PURPOSE{}`** - 용도 설명
|
|
289
|
+
4. **`SCHEMA_TO_COMPONENT{}`** - Zod 스키마 → 컴포넌트 매핑
|
|
290
|
+
5. **`INTERNAL_SCHEMAS`** - 제외할 내부 스키마
|
|
291
|
+
|
|
292
|
+
### MCP 소스 작성 규칙
|
|
293
|
+
|
|
294
|
+
Skills가 올바르게 생성되려면 MCP 소스 파일이 다음 규칙을 따라야 합니다:
|
|
295
|
+
|
|
296
|
+
**Zod 스키마** (`src/components/*.ts`):
|
|
297
|
+
```typescript
|
|
298
|
+
// .describe()로 Props 설명 필수
|
|
299
|
+
export const ButtonPropsSchema = z.object({
|
|
300
|
+
label: z.string().describe('버튼 라벨'),
|
|
301
|
+
size: z.enum(['large', 'medium', 'small']).describe('버튼 크기'),
|
|
302
|
+
}).describe('버튼 컴포넌트');
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
**예제 파일** (`src/components/examples/*-examples-data.ts`):
|
|
306
|
+
```typescript
|
|
307
|
+
// 파일명: opsnow-common-{component}-examples-data.ts
|
|
308
|
+
// Export 명명: {PascalCase}Examples
|
|
309
|
+
export const ButtonExamples: Example[] = [
|
|
310
|
+
{
|
|
311
|
+
title: '기본 버튼',
|
|
312
|
+
props: { label: '버튼', size: 'medium' },
|
|
313
|
+
code: `<OpsnowCommonButton label="버튼" size="medium" />`,
|
|
314
|
+
},
|
|
315
|
+
];
|
|
316
|
+
```
|
|
@@ -502,7 +502,7 @@ export const BarChartExamples = [
|
|
|
502
502
|
width: 'p50',
|
|
503
503
|
hover: {
|
|
504
504
|
enabled: true,
|
|
505
|
-
|
|
505
|
+
: true
|
|
506
506
|
}
|
|
507
507
|
},
|
|
508
508
|
tooltip: {
|
|
@@ -2109,6 +2109,81 @@ export const LineChartExamples = [
|
|
|
2109
2109
|
chartData={chartData}
|
|
2110
2110
|
/>`
|
|
2111
2111
|
},
|
|
2112
|
+
{
|
|
2113
|
+
title: '라인 차트 - Bullet Label (데이터 포인트에 값 표시)',
|
|
2114
|
+
description: '라인 차트의 각 데이터 포인트 위에 값을 라벨로 표시하는 bullet label 예제입니다. format, prefix, suffix를 사용하여 값 형식을 지정할 수 있습니다.',
|
|
2115
|
+
code_props_usage: `
|
|
2116
|
+
const chartId = 'line-chart-bullet-label-${generateUniqueGeneralId()}'
|
|
2117
|
+
const chartRef = useRef(null)
|
|
2118
|
+
const [chartProps, setChartProps] = useState({
|
|
2119
|
+
chart: {
|
|
2120
|
+
paddingTop: 30,
|
|
2121
|
+
paddingBottom: 30
|
|
2122
|
+
},
|
|
2123
|
+
xAxis: {
|
|
2124
|
+
type: 'date',
|
|
2125
|
+
dateFormats: [
|
|
2126
|
+
{ type: 'day', dateFormat: 'MM-dd' },
|
|
2127
|
+
{ type: 'month', dateFormat: 'yy-MM' }
|
|
2128
|
+
],
|
|
2129
|
+
baseInterval: { timeUnit: 'month', count: 1 },
|
|
2130
|
+
gridHidden: true
|
|
2131
|
+
},
|
|
2132
|
+
yAxis: {
|
|
2133
|
+
type: 'value',
|
|
2134
|
+
extraMax: 0.15,
|
|
2135
|
+
min: 0,
|
|
2136
|
+
numberFormat: '$#,###'
|
|
2137
|
+
},
|
|
2138
|
+
series: {
|
|
2139
|
+
valueXField: 'date',
|
|
2140
|
+
dataProcessor: {
|
|
2141
|
+
dateFields: ['date'],
|
|
2142
|
+
dateFormat: 'yyyy-MM-dd'
|
|
2143
|
+
},
|
|
2144
|
+
bullet: {
|
|
2145
|
+
type: 'label', // 'label' 타입으로 설정
|
|
2146
|
+
locationX: 0.5, // X축 위치 (0~1, 0.5 = 중앙)
|
|
2147
|
+
locationY: 1, // Y축 위치 (0~1, 1 = 상단)
|
|
2148
|
+
label: {
|
|
2149
|
+
dy: -15, // Y축 오프셋 (음수: 위로 이동)
|
|
2150
|
+
format: '#,###', // 숫자 포맷
|
|
2151
|
+
prefix: '$', // 접두사
|
|
2152
|
+
fontSize: 9
|
|
2153
|
+
}
|
|
2154
|
+
}
|
|
2155
|
+
},
|
|
2156
|
+
legend: { useExtension: false }
|
|
2157
|
+
})
|
|
2158
|
+
const [chartCategory, setChartCategory] = useState(['cost1', 'cost2'])
|
|
2159
|
+
const [chartData, setChartData] = useState([
|
|
2160
|
+
{ date: '2024-10-01', cost1: 70000, cost2: 8000 },
|
|
2161
|
+
{ date: '2024-11-01', cost1: 85000, cost2: 10000 },
|
|
2162
|
+
{ date: '2024-12-01', cost1: 170000, cost2: 15000 },
|
|
2163
|
+
{ date: '2025-01-01', cost1: 165000, cost2: 14000 },
|
|
2164
|
+
{ date: '2025-02-01', cost1: 95000, cost2: 10000 },
|
|
2165
|
+
{ date: '2025-03-01', cost1: 115000, cost2: 12000 },
|
|
2166
|
+
{ date: '2025-04-01', cost1: 140000, cost2: 13000 },
|
|
2167
|
+
{ date: '2025-05-01', cost1: 270000, cost2: 18000 },
|
|
2168
|
+
{ date: '2025-06-01', cost1: 135000, cost2: 13500 },
|
|
2169
|
+
{ date: '2025-07-01', cost1: 140000, cost2: 14000 },
|
|
2170
|
+
{ date: '2025-08-01', cost1: 135000, cost2: 13800 },
|
|
2171
|
+
{ date: '2025-09-01', cost1: 159857, cost2: 14334 }
|
|
2172
|
+
])
|
|
2173
|
+
const chartCategoryLocaleMapping = [
|
|
2174
|
+
{ name: 'cost1', value: '계정 1 비용' },
|
|
2175
|
+
{ name: 'cost2', value: '계정 2 비용' }
|
|
2176
|
+
]
|
|
2177
|
+
`,
|
|
2178
|
+
code: `<OpsnowCommonLineChart
|
|
2179
|
+
chartId={chartId}
|
|
2180
|
+
chartRef={chartRef}
|
|
2181
|
+
chartProps={chartProps}
|
|
2182
|
+
chartCategory={chartCategory}
|
|
2183
|
+
chartData={chartData}
|
|
2184
|
+
chartCategoryLocaleMapping={chartCategoryLocaleMapping}
|
|
2185
|
+
/>`
|
|
2186
|
+
},
|
|
2112
2187
|
];
|
|
2113
2188
|
export const StackChartExamples = [
|
|
2114
2189
|
{
|
|
@@ -5980,4 +6055,331 @@ export const XyMultiChartExamples = [
|
|
|
5980
6055
|
chartUserDefinedFunc={udf()}
|
|
5981
6056
|
/>`
|
|
5982
6057
|
},
|
|
6058
|
+
{
|
|
6059
|
+
title: 'XY 멀티 차트 - Bullet Label (Line + Stack)',
|
|
6060
|
+
description: 'XY 멀티 차트에서 Line과 Stack 시리즈 모두에 bullet label을 적용하여 데이터 포인트에 값을 표시하는 예제입니다.',
|
|
6061
|
+
code_props_usage: `
|
|
6062
|
+
const chartId = 'xy-multi-bullet-label-${generateUniqueGeneralId()}'
|
|
6063
|
+
const chartRef = useRef(null)
|
|
6064
|
+
const [chartProps, setChartProps] = useState({
|
|
6065
|
+
chart: {
|
|
6066
|
+
paddingTop: 30
|
|
6067
|
+
},
|
|
6068
|
+
xAxis: {
|
|
6069
|
+
type: 'date',
|
|
6070
|
+
dateFormats: [
|
|
6071
|
+
{ type: 'day', dateFormat: 'MM-dd' },
|
|
6072
|
+
{ type: 'month', dateFormat: 'yy-MM' }
|
|
6073
|
+
],
|
|
6074
|
+
baseInterval: { timeUnit: 'month', count: 1 },
|
|
6075
|
+
gridHidden: true
|
|
6076
|
+
},
|
|
6077
|
+
yAxis: {
|
|
6078
|
+
type: 'value',
|
|
6079
|
+
extraMax: 0.15,
|
|
6080
|
+
min: 0,
|
|
6081
|
+
numberFormat: '$#,###'
|
|
6082
|
+
},
|
|
6083
|
+
series: {
|
|
6084
|
+
valueXField: 'date',
|
|
6085
|
+
dataProcessor: {
|
|
6086
|
+
dateFields: ['date'],
|
|
6087
|
+
dateFormat: 'yyyy-MM-dd'
|
|
6088
|
+
},
|
|
6089
|
+
seriesTypes: [
|
|
6090
|
+
{
|
|
6091
|
+
type: 'line',
|
|
6092
|
+
order: 'front',
|
|
6093
|
+
categoryGroupName: 'cost_line',
|
|
6094
|
+
bullet: {
|
|
6095
|
+
type: 'label', // 라벨 타입 bullet
|
|
6096
|
+
locationX: 0.5,
|
|
6097
|
+
locationY: 1,
|
|
6098
|
+
label: {
|
|
6099
|
+
dy: -10, // 위로 이동
|
|
6100
|
+
format: '#,###', // 숫자 포맷
|
|
6101
|
+
prefix: '$', // 달러 기호 접두사
|
|
6102
|
+
fontSize: 9
|
|
6103
|
+
}
|
|
6104
|
+
}
|
|
6105
|
+
},
|
|
6106
|
+
{
|
|
6107
|
+
type: 'stack',
|
|
6108
|
+
categoryGroupName: 'cost_stack',
|
|
6109
|
+
bullet: {
|
|
6110
|
+
type: 'label',
|
|
6111
|
+
locationX: 0.5,
|
|
6112
|
+
locationY: 1,
|
|
6113
|
+
label: {
|
|
6114
|
+
dy: -10,
|
|
6115
|
+
format: '#,###',
|
|
6116
|
+
prefix: '$',
|
|
6117
|
+
fontSize: 9
|
|
6118
|
+
}
|
|
6119
|
+
}
|
|
6120
|
+
}
|
|
6121
|
+
],
|
|
6122
|
+
tooltip: {
|
|
6123
|
+
type: 'CG',
|
|
6124
|
+
header: { name: '{category}' },
|
|
6125
|
+
body: {
|
|
6126
|
+
name: '{name}',
|
|
6127
|
+
value: '\${valueY.formatNumber("#,###")}',
|
|
6128
|
+
useMarker: true
|
|
6129
|
+
}
|
|
6130
|
+
}
|
|
6131
|
+
},
|
|
6132
|
+
legend: { useExtension: false }
|
|
6133
|
+
})
|
|
6134
|
+
const [chartData, setChartData] = useState([
|
|
6135
|
+
{ date: '2024-10-01', totalCost: 79580, cloudCost: 50000, onpremCost: 29580 },
|
|
6136
|
+
{ date: '2024-11-01', totalCost: 95812, cloudCost: 60000, onpremCost: 35812 },
|
|
6137
|
+
{ date: '2024-12-01', totalCost: 182965, cloudCost: 120000, onpremCost: 62965 },
|
|
6138
|
+
{ date: '2025-01-01', totalCost: 178695, cloudCost: 115000, onpremCost: 63695 },
|
|
6139
|
+
{ date: '2025-02-01', totalCost: 103273, cloudCost: 70000, onpremCost: 33273 },
|
|
6140
|
+
{ date: '2025-03-01', totalCost: 122976, cloudCost: 82000, onpremCost: 40976 },
|
|
6141
|
+
{ date: '2025-04-01', totalCost: 151876, cloudCost: 100000, onpremCost: 51876 },
|
|
6142
|
+
{ date: '2025-05-01', totalCost: 288608, cloudCost: 190000, onpremCost: 98608 },
|
|
6143
|
+
{ date: '2025-06-01', totalCost: 146040, cloudCost: 95000, onpremCost: 51040 },
|
|
6144
|
+
{ date: '2025-07-01', totalCost: 151794, cloudCost: 100000, onpremCost: 51794 },
|
|
6145
|
+
{ date: '2025-08-01', totalCost: 147177, cloudCost: 97000, onpremCost: 50177 },
|
|
6146
|
+
{ date: '2025-09-01', totalCost: 196047, cloudCost: 130000, onpremCost: 66047 }
|
|
6147
|
+
])
|
|
6148
|
+
const [chartCategory, setChartCategory] = useState([
|
|
6149
|
+
{ name: 'cost_line', categories: ['totalCost'] },
|
|
6150
|
+
{ name: 'cost_stack', categories: ['cloudCost', 'onpremCost'] }
|
|
6151
|
+
])
|
|
6152
|
+
const chartCategoryLocaleMapping = [
|
|
6153
|
+
{ name: 'totalCost', value: '총 비용' },
|
|
6154
|
+
{ name: 'cloudCost', value: '클라우드 비용' },
|
|
6155
|
+
{ name: 'onpremCost', value: '온프레미스 비용' }
|
|
6156
|
+
]
|
|
6157
|
+
`,
|
|
6158
|
+
code: `<OpsnowCommonXyMultiChart
|
|
6159
|
+
chartId={chartId}
|
|
6160
|
+
chartRef={chartRef}
|
|
6161
|
+
chartProps={chartProps}
|
|
6162
|
+
chartCategory={chartCategory}
|
|
6163
|
+
chartData={chartData}
|
|
6164
|
+
chartCategoryLocaleMapping={chartCategoryLocaleMapping}
|
|
6165
|
+
/>`
|
|
6166
|
+
},
|
|
6167
|
+
{
|
|
6168
|
+
title: 'XY 멀티 차트 - Bullet Label (Dual Axis: Bar + Line)',
|
|
6169
|
+
description: 'Dual Axis(Y축 2개) 차트에서 Bar와 Line 시리즈에 각각 다른 bullet label을 적용하는 예제입니다. 비용(Bar)에는 달러 기호, 증감률(Line)에는 % 기호를 사용합니다.',
|
|
6170
|
+
code_props_usage: `
|
|
6171
|
+
const chartId = 'xy-multi-dual-axis-${generateUniqueGeneralId()}'
|
|
6172
|
+
const chartRef = useRef(null)
|
|
6173
|
+
const [chartProps, setChartProps] = useState({
|
|
6174
|
+
chart: {
|
|
6175
|
+
paddingTop: 30,
|
|
6176
|
+
paddingRight: 50
|
|
6177
|
+
},
|
|
6178
|
+
xAxis: {
|
|
6179
|
+
type: 'date',
|
|
6180
|
+
dateFormats: [
|
|
6181
|
+
{ type: 'day', dateFormat: 'MM-dd' },
|
|
6182
|
+
{ type: 'month', dateFormat: 'MMM\\nyyyy' }
|
|
6183
|
+
],
|
|
6184
|
+
baseInterval: { timeUnit: 'month', count: 1 },
|
|
6185
|
+
gridHidden: true
|
|
6186
|
+
},
|
|
6187
|
+
yAxis: {
|
|
6188
|
+
type: 'value',
|
|
6189
|
+
numberFormat: "'$'#,###",
|
|
6190
|
+
extraMax: 0.15,
|
|
6191
|
+
min: 0
|
|
6192
|
+
},
|
|
6193
|
+
yAxis2: {
|
|
6194
|
+
type: 'value',
|
|
6195
|
+
numberFormat: "#'%'",
|
|
6196
|
+
opposite: true,
|
|
6197
|
+
gridHidden: true
|
|
6198
|
+
},
|
|
6199
|
+
series: {
|
|
6200
|
+
valueXField: 'date',
|
|
6201
|
+
dataProcessor: {
|
|
6202
|
+
dateFields: ['date'],
|
|
6203
|
+
dateFormat: 'yyyy-MM-dd'
|
|
6204
|
+
},
|
|
6205
|
+
seriesTypes: [
|
|
6206
|
+
{
|
|
6207
|
+
type: 'bar',
|
|
6208
|
+
categoryGroupName: 'bar_group',
|
|
6209
|
+
bullet: {
|
|
6210
|
+
type: 'label',
|
|
6211
|
+
locationX: 0.5,
|
|
6212
|
+
locationY: 1,
|
|
6213
|
+
label: {
|
|
6214
|
+
dy: -5,
|
|
6215
|
+
format: '#,###',
|
|
6216
|
+
prefix: '$', // 비용에 달러 기호
|
|
6217
|
+
fontSize: 9
|
|
6218
|
+
}
|
|
6219
|
+
}
|
|
6220
|
+
},
|
|
6221
|
+
{
|
|
6222
|
+
type: 'line',
|
|
6223
|
+
order: 'front',
|
|
6224
|
+
categoryGroupName: 'line_group',
|
|
6225
|
+
yAxis: 'yAxis2', // 두 번째 Y축 사용
|
|
6226
|
+
bullet: {
|
|
6227
|
+
type: 'label',
|
|
6228
|
+
locationX: 0.5,
|
|
6229
|
+
locationY: 1,
|
|
6230
|
+
label: {
|
|
6231
|
+
dy: -10,
|
|
6232
|
+
format: '#.#',
|
|
6233
|
+
suffix: '%', // 증감률에 % 기호
|
|
6234
|
+
fontSize: 9
|
|
6235
|
+
}
|
|
6236
|
+
}
|
|
6237
|
+
}
|
|
6238
|
+
],
|
|
6239
|
+
tooltip: {
|
|
6240
|
+
type: 'CG',
|
|
6241
|
+
header: { name: '{valueX.formatDate("yyyy년 M월")}' },
|
|
6242
|
+
body: {
|
|
6243
|
+
name: '{name}',
|
|
6244
|
+
value: '{valueY}',
|
|
6245
|
+
useMarker: true
|
|
6246
|
+
}
|
|
6247
|
+
}
|
|
6248
|
+
},
|
|
6249
|
+
legend: { useExtension: false }
|
|
6250
|
+
})
|
|
6251
|
+
const [chartData, setChartData] = useState([
|
|
6252
|
+
{ date: '2024-10-01', cost: 11255, changeRate: null },
|
|
6253
|
+
{ date: '2024-11-01', cost: 18464, changeRate: 64.1 },
|
|
6254
|
+
{ date: '2024-12-01', cost: 17335, changeRate: -6.1 },
|
|
6255
|
+
{ date: '2025-01-01', cost: 18731, changeRate: 8.1 },
|
|
6256
|
+
{ date: '2025-02-01', cost: 20358, changeRate: 8.7 },
|
|
6257
|
+
{ date: '2025-03-01', cost: 27291, changeRate: 34.1 },
|
|
6258
|
+
{ date: '2025-04-01', cost: 40417, changeRate: 48.1 },
|
|
6259
|
+
{ date: '2025-05-01', cost: 39887, changeRate: -1.3 },
|
|
6260
|
+
{ date: '2025-06-01', cost: 41529, changeRate: 4.1 },
|
|
6261
|
+
{ date: '2025-07-01', cost: 49871, changeRate: 20.1 },
|
|
6262
|
+
{ date: '2025-08-01', cost: 50659, changeRate: 1.6 },
|
|
6263
|
+
{ date: '2025-09-01', cost: 58388, changeRate: 15.3 }
|
|
6264
|
+
])
|
|
6265
|
+
const [chartCategory, setChartCategory] = useState([
|
|
6266
|
+
{ name: 'bar_group', categories: ['cost'] },
|
|
6267
|
+
{ name: 'line_group', categories: ['changeRate'] }
|
|
6268
|
+
])
|
|
6269
|
+
const chartCategoryLocaleMapping = [
|
|
6270
|
+
{ name: 'cost', value: 'Cost' },
|
|
6271
|
+
{ name: 'changeRate', value: '증감률' }
|
|
6272
|
+
]
|
|
6273
|
+
const chartCustomCategory = [
|
|
6274
|
+
{ name: 'cost', color: '#C8A2C8' },
|
|
6275
|
+
{ name: 'changeRate', color: '#2E4A62' }
|
|
6276
|
+
]
|
|
6277
|
+
`,
|
|
6278
|
+
code: `<OpsnowCommonXyMultiChart
|
|
6279
|
+
chartId={chartId}
|
|
6280
|
+
chartRef={chartRef}
|
|
6281
|
+
chartProps={chartProps}
|
|
6282
|
+
chartCategory={chartCategory}
|
|
6283
|
+
chartData={chartData}
|
|
6284
|
+
chartCategoryLocaleMapping={chartCategoryLocaleMapping}
|
|
6285
|
+
chartCustomCategory={chartCustomCategory}
|
|
6286
|
+
/>`
|
|
6287
|
+
},
|
|
6288
|
+
{
|
|
6289
|
+
title: 'XY 멀티 차트 - Bullet Label (Grouped Bar)',
|
|
6290
|
+
description: 'Grouped Bar 차트에서 bullet label을 사용하여 각 바 위에 값을 표시하는 예제입니다. text 속성으로 amCharts5 포맷 문자열을 직접 사용할 수 있습니다.',
|
|
6291
|
+
code_props_usage: `
|
|
6292
|
+
const chartId = 'xy-multi-grouped-bar-${generateUniqueGeneralId()}'
|
|
6293
|
+
const chartRef = useRef(null)
|
|
6294
|
+
const [chartProps, setChartProps] = useState({
|
|
6295
|
+
chart: {
|
|
6296
|
+
paddingTop: 30
|
|
6297
|
+
},
|
|
6298
|
+
xAxis: {
|
|
6299
|
+
type: 'date',
|
|
6300
|
+
dateFormats: [
|
|
6301
|
+
{ type: 'day', dateFormat: 'MM-dd' },
|
|
6302
|
+
{ type: 'month', dateFormat: 'yy년 M월' }
|
|
6303
|
+
],
|
|
6304
|
+
baseInterval: { timeUnit: 'month', count: 1 },
|
|
6305
|
+
gridHidden: true,
|
|
6306
|
+
cellStartLocation: 0.1,
|
|
6307
|
+
cellEndLocation: 0.9
|
|
6308
|
+
},
|
|
6309
|
+
yAxis: {
|
|
6310
|
+
type: 'value',
|
|
6311
|
+
numberFormat: '$#,###',
|
|
6312
|
+
extraMax: 0.08
|
|
6313
|
+
},
|
|
6314
|
+
series: {
|
|
6315
|
+
valueXField: 'date',
|
|
6316
|
+
dataProcessor: {
|
|
6317
|
+
dateFields: ['date'],
|
|
6318
|
+
dateFormat: 'yyyy-MM-dd'
|
|
6319
|
+
},
|
|
6320
|
+
bullet: {
|
|
6321
|
+
type: 'label',
|
|
6322
|
+
locationX: 0.5,
|
|
6323
|
+
locationY: 1,
|
|
6324
|
+
label: {
|
|
6325
|
+
dy: -2,
|
|
6326
|
+
text: '\${valueY.formatNumber("#,###")}', // amCharts5 포맷 문자열 직접 사용
|
|
6327
|
+
fontSize: 9
|
|
6328
|
+
}
|
|
6329
|
+
},
|
|
6330
|
+
seriesTypes: [
|
|
6331
|
+
{
|
|
6332
|
+
type: 'bar',
|
|
6333
|
+
categoryGroupName: 'cost_group',
|
|
6334
|
+
grouped: true
|
|
6335
|
+
}
|
|
6336
|
+
],
|
|
6337
|
+
tooltip: {
|
|
6338
|
+
type: 'CG',
|
|
6339
|
+
header: { name: '{valueX.formatDate("yyyy년 M월")}' },
|
|
6340
|
+
body: {
|
|
6341
|
+
name: '{name}',
|
|
6342
|
+
value: '\${valueY.formatNumber("#,###")}',
|
|
6343
|
+
useMarker: true
|
|
6344
|
+
}
|
|
6345
|
+
}
|
|
6346
|
+
},
|
|
6347
|
+
legend: { useExtension: false }
|
|
6348
|
+
})
|
|
6349
|
+
const [chartData, setChartData] = useState([
|
|
6350
|
+
{ date: '2024-10-01', costUsd: 79580, cloudCost: 81530 },
|
|
6351
|
+
{ date: '2024-11-01', costUsd: 95812, cloudCost: 98903 },
|
|
6352
|
+
{ date: '2024-12-01', costUsd: 182965, cloudCost: 188854 },
|
|
6353
|
+
{ date: '2025-01-01', costUsd: 178695, cloudCost: 184359 },
|
|
6354
|
+
{ date: '2025-02-01', costUsd: 103273, cloudCost: 106587 },
|
|
6355
|
+
{ date: '2025-03-01', costUsd: 122976, cloudCost: 126556 },
|
|
6356
|
+
{ date: '2025-04-01', costUsd: 151876, cloudCost: 155737 },
|
|
6357
|
+
{ date: '2025-05-01', costUsd: 288608, cloudCost: 296687 },
|
|
6358
|
+
{ date: '2025-06-01', costUsd: 146040, cloudCost: 149912 },
|
|
6359
|
+
{ date: '2025-07-01', costUsd: 151794, cloudCost: 155419 },
|
|
6360
|
+
{ date: '2025-08-01', costUsd: 147177, cloudCost: 150342 },
|
|
6361
|
+
{ date: '2025-09-01', costUsd: 220261, cloudCost: 196047 }
|
|
6362
|
+
])
|
|
6363
|
+
const [chartCategory, setChartCategory] = useState([
|
|
6364
|
+
{ name: 'cost_group', categories: ['costUsd', 'cloudCost'] }
|
|
6365
|
+
])
|
|
6366
|
+
const chartCategoryLocaleMapping = [
|
|
6367
|
+
{ name: 'costUsd', value: 'Cost(USD, 청구)' },
|
|
6368
|
+
{ name: 'cloudCost', value: '클라우드 사용요금' }
|
|
6369
|
+
]
|
|
6370
|
+
const chartCustomCategory = [
|
|
6371
|
+
{ name: 'costUsd', color: '#6B8E23' },
|
|
6372
|
+
{ name: 'cloudCost', color: '#1976d2' }
|
|
6373
|
+
]
|
|
6374
|
+
`,
|
|
6375
|
+
code: `<OpsnowCommonXyMultiChart
|
|
6376
|
+
chartId={chartId}
|
|
6377
|
+
chartRef={chartRef}
|
|
6378
|
+
chartProps={chartProps}
|
|
6379
|
+
chartCategory={chartCategory}
|
|
6380
|
+
chartData={chartData}
|
|
6381
|
+
chartCategoryLocaleMapping={chartCategoryLocaleMapping}
|
|
6382
|
+
chartCustomCategory={chartCustomCategory}
|
|
6383
|
+
/>`
|
|
6384
|
+
},
|
|
5983
6385
|
];
|