차트 종류별 디자인 정리 - 팔레트·면적·계단선·누적/가로 막대·원형·도넛·산점
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
7dbac78c6e
commit
83d207462f
2
dist/README.txt
vendored
2
dist/README.txt
vendored
@ -1,5 +1,5 @@
|
||||
UbisamBase 플랫폼 배포 폴더 (빌드할 때 자동 생성 - 직접 고치지 마세요)
|
||||
갱신 시각 : 2026-09-21 22:13:45
|
||||
갱신 시각 : 2026-09-21 22:17:54
|
||||
빌드 구성 : Release
|
||||
원본 소스 : D:\업무\03_개발\Source\용접기\08_UbisamPlatform\
|
||||
----
|
||||
|
||||
BIN
dist/UbisamBase.Core.dll
vendored
BIN
dist/UbisamBase.Core.dll
vendored
Binary file not shown.
BIN
dist/UbisamBase.Launcher.exe
vendored
BIN
dist/UbisamBase.Launcher.exe
vendored
Binary file not shown.
BIN
dist/UbisamBase.Shell.exe
vendored
BIN
dist/UbisamBase.Shell.exe
vendored
Binary file not shown.
2
dist/platform-version.json
vendored
2
dist/platform-version.json
vendored
@ -1,4 +1,4 @@
|
||||
{
|
||||
"version": "2026-09-21 22:13:45",
|
||||
"version": "2026-09-21 22:17:54",
|
||||
"configuration": "Release"
|
||||
}
|
||||
|
||||
@ -15,3 +15,4 @@
|
||||
| 2026-09-21 | 플랫폼 자동 업데이트 추가 — Launcher가 켤 때 깃 저장소의 `dist`와 비교해 새 버전이면 받아서 실행(UI Setting에서 사용/자동 여부 선택) |
|
||||
| 2026-09-21 | 업데이트 안내창을 플랫폼 디자인으로 교체(Launcher 자체 XAML, 시스템 테마 따름) |
|
||||
| 2026-09-21 | `ApiService` 추가 — 사내 API를 앱이 대신 호출(토큰은 설정 파일에만, 호출 간격 제한·타임아웃 포함) |
|
||||
| 2026-09-21 | 차트 종류별 디자인 정리 — 면적·계단선·누적/가로 막대·원형·도넛·산점 추가, 계열 팔레트(Chart.Series1~6)와 툴팁·범례 테마 적용 |
|
||||
|
||||
@ -299,7 +299,32 @@ private void Rebuild()
|
||||
```
|
||||
|
||||
- **`Background="Transparent"`를 꼭 지정** — 기본값은 흰 배경이라 다크 테마에서 튐.
|
||||
- `ChartTheme.Column(values, name)`, `ChartTheme.Gauge(percent)`(도넛 게이지, `ISeries[]` 반환)도 있음.
|
||||
- **툴팁·범례는 따로 입혀야 한다** — 지정하지 않으면 LiveCharts 기본(밝은 바탕 + 검은 글자)이 나와
|
||||
다크 테마에서 튄다. 차트를 만든 뒤와 테마가 바뀐 뒤에 `ChartTheme.Apply(chart)`를 한 번 부른다
|
||||
(`CartesianChart` / `PieChart` 둘 다 있음).
|
||||
|
||||
### 4-1. 차트 종류별 — 무엇을 언제 쓰나
|
||||
|
||||
| 만들기 | 생김새 | 쓰는 자리 |
|
||||
| --- | --- | --- |
|
||||
| `Line(values, name)` | accent 선 2px, 보간 없음, 면적 12% | 단일 측정값 추이(기본) |
|
||||
| `Line(values, name, i)` | 팔레트 i번 선, 면적 없음 | 여러 계열을 한 그래프에 겹칠 때 |
|
||||
| `ReferenceLine(values, name)` | 회색 파선, hover 없음 | 기준·목표·규격 상하한. **측정선보다 먼저** 넣어야 아래에 깔린다 |
|
||||
| `SmoothLine(values, name, i)` | 곡선 보간(0.65) | 추세만 보여줄 때. **공정 측정값에는 쓰지 말 것** — 없던 중간값을 지어낸다 |
|
||||
| `Area(values, name, i)` | 선 + 채움 24% | 누적량·점유량처럼 "쌓인 양" |
|
||||
| `StepLine(values, name, i)` | 계단선 | ON/OFF·단계값처럼 다음 값까지 유지되는 신호 |
|
||||
| `Column(values, name[, i])` | 각진 세로 막대, 채움 85% | 항목별 비교(수량·횟수) |
|
||||
| `StackedColumn(values, name, i)` | 누적 세로 막대 | 전체 대비 구성비를 시간축으로 |
|
||||
| `Bar(values, name[, i])` | 가로 막대 | 항목 이름이 길어 세로 막대 라벨이 겹칠 때(설비명·불량 유형) |
|
||||
| `Pie(values[, names])` | 원형, 조각 사이 판 색 경계 | 구성비. 조각 6개 이하일 때만 |
|
||||
| `Donut(values[, names])` | 가운데 빈 원형 | 구성비 + 가운데에 총계 표시 |
|
||||
| `Gauge(percent)` | 0~100 도넛 게이지 | 가동률·달성률 한 값 |
|
||||
| `Scatter(points, name, i)` | 점 9px, 판 색 테두리 | 두 값의 상관 |
|
||||
|
||||
- **색은 직접 고르지 않는다.** 단일 계열은 accent 하나, 여러 계열은 `seriesIndex`를 0,1,2…로 넘기면
|
||||
`Ubisam.Brush.Chart.Series1~6` 팔레트를 순서대로 쓴다(라이트/다크 각각 따로 정의돼 있다).
|
||||
7개째부터는 색이 처음으로 돌아가므로, 계열이 그보다 많으면 차트를 나누는 편이 낫다.
|
||||
- 팔레트 색이 필요하면 `ChartTheme.SeriesColor(i)`로 꺼내 쓴다(범례 표식 등).
|
||||
- 소비 프로젝트에서 차트를 직접 쓰려면 `LiveChartsCore`, `LiveChartsCore.SkiaSharpView`,
|
||||
`LiveChartsCore.SkiaSharpView.WPF`, `SkiaSharp` — 4개를 `$(UbisamPlatformDir)`에서
|
||||
HintPath로 참조 추가해야 함(TestApp.csproj 예시 참고).
|
||||
|
||||
@ -2,7 +2,9 @@ using System;
|
||||
using System.Windows;
|
||||
using System.Windows.Media;
|
||||
using LiveChartsCore;
|
||||
using LiveChartsCore.Defaults;
|
||||
using LiveChartsCore.SkiaSharpView;
|
||||
using LiveChartsCore.SkiaSharpView.WPF;
|
||||
using LiveChartsCore.SkiaSharpView.Painting;
|
||||
using LiveChartsCore.SkiaSharpView.Painting.Effects;
|
||||
using SkiaSharp;
|
||||
@ -117,4 +119,204 @@ public static class ChartTheme
|
||||
LabelsPaint = new SolidColorPaint(Muted) { SKTypeface = BodyTypeface },
|
||||
SeparatorsPaint = new SolidColorPaint(GridLine, 1)
|
||||
};
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────
|
||||
// 시리즈 색
|
||||
// 단일 계열 차트는 지금까지처럼 accent 하나만 쓴다. 여러 계열을 한 그래프에 그릴 때만
|
||||
// 아래 팔레트를 순서대로 쓴다 — 색을 화면마다 고르면 프로그램마다 톤이 달라진다.
|
||||
// ─────────────────────────────────────────────────────────────────────────
|
||||
|
||||
/// <summary>계열 순번(0부터)에 해당하는 색. 6개를 넘어가면 처음으로 돌아간다.</summary>
|
||||
public static SKColor SeriesColor(int index)
|
||||
=> ReadColor("Ubisam.Brush.Chart.Series" + ((Math.Abs(index) % 6) + 1));
|
||||
|
||||
/// <summary>꺾은선 — 여러 계열용. 색만 팔레트에서 가져오고 나머지는 단일 계열과 같다(두께 2, 보간 없음).</summary>
|
||||
public static ISeries Line(double[] values, string name, int seriesIndex)
|
||||
{
|
||||
var color = SeriesColor(seriesIndex);
|
||||
return new LineSeries<double>
|
||||
{
|
||||
Values = values,
|
||||
Name = name,
|
||||
Stroke = new SolidColorPaint(color, 2),
|
||||
Fill = null,
|
||||
GeometrySize = 0,
|
||||
LineSmoothness = 0,
|
||||
AnimationsSpeed = AnimationSpeed
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>부드러운 꺾은선 — 추세용. 공정 측정값처럼 "튄 지점"이 중요한 데이터에는 쓰지 말 것
|
||||
/// (보간이 실제로 없던 중간값을 지어낸다).</summary>
|
||||
public static ISeries SmoothLine(double[] values, string name, int seriesIndex = 0)
|
||||
{
|
||||
var color = SeriesColor(seriesIndex);
|
||||
return new LineSeries<double>
|
||||
{
|
||||
Values = values,
|
||||
Name = name,
|
||||
Stroke = new SolidColorPaint(color, 2),
|
||||
Fill = null,
|
||||
GeometrySize = 0,
|
||||
LineSmoothness = 0.65,
|
||||
AnimationsSpeed = AnimationSpeed
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>면적 — 누적량·점유량처럼 "쌓인 양"을 보여줄 때. 겹쳐 그릴 수 있도록 채움을 24%로 둔다.</summary>
|
||||
public static ISeries Area(double[] values, string name, int seriesIndex = 0)
|
||||
{
|
||||
var color = SeriesColor(seriesIndex);
|
||||
return new LineSeries<double>
|
||||
{
|
||||
Values = values,
|
||||
Name = name,
|
||||
Stroke = new SolidColorPaint(color, 2),
|
||||
Fill = new SolidColorPaint(color.WithAlpha(0x3D)),
|
||||
GeometrySize = 0,
|
||||
LineSmoothness = 0,
|
||||
AnimationsSpeed = AnimationSpeed
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>계단선 — ON/OFF나 단계값처럼 "다음 값까지 그 상태가 유지되는" 신호용.
|
||||
/// 이런 데이터를 꺾은선으로 그리면 없는 중간값이 있는 것처럼 보인다.</summary>
|
||||
public static ISeries StepLine(double[] values, string name, int seriesIndex = 0)
|
||||
{
|
||||
var color = SeriesColor(seriesIndex);
|
||||
return new StepLineSeries<double>
|
||||
{
|
||||
Values = values,
|
||||
Name = name,
|
||||
Stroke = new SolidColorPaint(color, 2),
|
||||
Fill = null,
|
||||
GeometrySize = 0,
|
||||
AnimationsSpeed = AnimationSpeed
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>세로 막대 — 여러 계열용. 각진 모서리는 단일 계열과 같다.</summary>
|
||||
public static ISeries Column(double[] values, string name, int seriesIndex)
|
||||
=> new ColumnSeries<double>
|
||||
{
|
||||
Values = values,
|
||||
Name = name,
|
||||
Fill = new SolidColorPaint(SeriesColor(seriesIndex).WithAlpha(217)),
|
||||
Rx = 0,
|
||||
Ry = 0,
|
||||
AnimationsSpeed = AnimationSpeed
|
||||
};
|
||||
|
||||
/// <summary>누적 막대 — 전체 대비 구성비를 볼 때. 같은 차트에 넣은 누적 막대끼리 쌓인다.</summary>
|
||||
public static ISeries StackedColumn(double[] values, string name, int seriesIndex)
|
||||
=> new StackedColumnSeries<double>
|
||||
{
|
||||
Values = values,
|
||||
Name = name,
|
||||
Fill = new SolidColorPaint(SeriesColor(seriesIndex).WithAlpha(217)),
|
||||
Rx = 0,
|
||||
Ry = 0,
|
||||
AnimationsSpeed = AnimationSpeed
|
||||
};
|
||||
|
||||
/// <summary>가로 막대 — 항목 이름이 길어 세로 막대에서 라벨이 겹칠 때(설비명·불량 유형 등).</summary>
|
||||
public static ISeries Bar(double[] values, string name, int seriesIndex = 0)
|
||||
=> new RowSeries<double>
|
||||
{
|
||||
Values = values,
|
||||
Name = name,
|
||||
Fill = new SolidColorPaint(SeriesColor(seriesIndex).WithAlpha(217)),
|
||||
Rx = 0,
|
||||
Ry = 0,
|
||||
AnimationsSpeed = AnimationSpeed
|
||||
};
|
||||
|
||||
/// <summary>원형 — 구성비. 조각은 팔레트 순서대로, 경계는 판 색으로 얇게 갈라 서로 붙어 보이지 않게 한다.
|
||||
/// 조각이 6개를 넘으면 색이 돌아오므로 그때는 가로 막대(Bar)가 낫다.</summary>
|
||||
public static ISeries[] Pie(double[] values, string[] names = null)
|
||||
=> BuildPie(values, names, innerRadius: 0);
|
||||
|
||||
/// <summary>도넛 — 원형과 같되 가운데를 비워 총계·제목을 얹을 수 있다.</summary>
|
||||
public static ISeries[] Donut(double[] values, string[] names = null)
|
||||
=> BuildPie(values, names, innerRadius: 52);
|
||||
|
||||
private static ISeries[] BuildPie(double[] values, string[] names, double innerRadius)
|
||||
{
|
||||
var series = new ISeries[values.Length];
|
||||
|
||||
for (var i = 0; i < values.Length; i++)
|
||||
{
|
||||
series[i] = new PieSeries<double>
|
||||
{
|
||||
Values = new[] { values[i] },
|
||||
Name = names != null && i < names.Length ? names[i] : string.Empty,
|
||||
Fill = new SolidColorPaint(SeriesColor(i)),
|
||||
Stroke = new SolidColorPaint(Surface, 2),
|
||||
InnerRadius = innerRadius,
|
||||
AnimationsSpeed = AnimationSpeed
|
||||
};
|
||||
}
|
||||
|
||||
return series;
|
||||
}
|
||||
|
||||
/// <summary>산점 — 두 값의 상관을 볼 때. 점이 겹쳐도 개수를 셀 수 있도록 판 색 테두리를 두른다.</summary>
|
||||
public static ISeries Scatter(ObservablePoint[] points, string name, int seriesIndex = 0)
|
||||
{
|
||||
var color = SeriesColor(seriesIndex);
|
||||
return new ScatterSeries<ObservablePoint>
|
||||
{
|
||||
Values = points,
|
||||
Name = name,
|
||||
Fill = new SolidColorPaint(color.WithAlpha(0xC8)),
|
||||
Stroke = new SolidColorPaint(Surface, 1),
|
||||
GeometrySize = 9,
|
||||
AnimationsSpeed = AnimationSpeed
|
||||
};
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────
|
||||
// 툴팁 · 범례 — 차트 컨트롤에 직접 넣어야 하는 값들.
|
||||
// 지정하지 않으면 LiveCharts 기본(밝은 바탕 + 검은 글자)이 나와서 다크 테마에서 튄다.
|
||||
// ─────────────────────────────────────────────────────────────────────────
|
||||
|
||||
public static SolidColorPaint TooltipTextPaint => new SolidColorPaint(Text) { SKTypeface = BodyTypeface };
|
||||
|
||||
public static SolidColorPaint TooltipBackgroundPaint => new SolidColorPaint(Surface);
|
||||
|
||||
public static SolidColorPaint LegendTextPaint => new SolidColorPaint(Muted) { SKTypeface = BodyTypeface };
|
||||
|
||||
public static SolidColorPaint LegendBackgroundPaint => new SolidColorPaint(Surface);
|
||||
|
||||
/// <summary>툴팁·범례 색을 이 차트에 입힌다. 차트를 만든 뒤와 테마가 바뀐 뒤에 한 번씩 불러주면 된다.</summary>
|
||||
public static void Apply(CartesianChart chart)
|
||||
{
|
||||
if (chart == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
chart.TooltipTextPaint = TooltipTextPaint;
|
||||
chart.TooltipBackgroundPaint = TooltipBackgroundPaint;
|
||||
chart.TooltipTextSize = 12;
|
||||
chart.LegendTextPaint = LegendTextPaint;
|
||||
chart.LegendBackgroundPaint = LegendBackgroundPaint;
|
||||
chart.LegendTextSize = 12;
|
||||
}
|
||||
|
||||
/// <summary>원형·도넛 차트에도 같은 처리.</summary>
|
||||
public static void Apply(PieChart chart)
|
||||
{
|
||||
if (chart == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
chart.TooltipTextPaint = TooltipTextPaint;
|
||||
chart.TooltipBackgroundPaint = TooltipBackgroundPaint;
|
||||
chart.TooltipTextSize = 12;
|
||||
chart.LegendTextPaint = LegendTextPaint;
|
||||
chart.LegendBackgroundPaint = LegendBackgroundPaint;
|
||||
chart.LegendTextSize = 12;
|
||||
}
|
||||
}
|
||||
|
||||
@ -65,4 +65,14 @@
|
||||
<SolidColorBrush x:Key="Ubisam.Brush.Toast.Border" Color="#FF535B67"/>
|
||||
<DropShadowEffect x:Key="Ubisam.Effect.Toast" BlurRadius="18" ShadowDepth="4" Direction="270" Opacity="0.55" Color="#000000"/>
|
||||
|
||||
<!-- 차트 시리즈 색 — 여러 계열을 한 그래프에 그릴 때 쓰는 순서 고정 팔레트.
|
||||
1번은 회사 하늘색(단일 계열 차트는 이 색 하나만 쓴다), 2~6번은 색상환에서 충분히 떨어뜨려
|
||||
겹쳐 그려도 구분되게 골랐다. 다크에서는 채도를 낮추고 밝기를 올려 어두운 판 위에서 뜨게 한다. -->
|
||||
<SolidColorBrush x:Key="Ubisam.Brush.Chart.Series1" Color="#FF4DA6F5"/>
|
||||
<SolidColorBrush x:Key="Ubisam.Brush.Chart.Series2" Color="#FF4ECDC4"/>
|
||||
<SolidColorBrush x:Key="Ubisam.Brush.Chart.Series3" Color="#FFE0A63C"/>
|
||||
<SolidColorBrush x:Key="Ubisam.Brush.Chart.Series4" Color="#FFA98BE8"/>
|
||||
<SolidColorBrush x:Key="Ubisam.Brush.Chart.Series5" Color="#FF5FC97E"/>
|
||||
<SolidColorBrush x:Key="Ubisam.Brush.Chart.Series6" Color="#FFF07070"/>
|
||||
|
||||
</ResourceDictionary>
|
||||
|
||||
@ -60,4 +60,12 @@
|
||||
<SolidColorBrush x:Key="Ubisam.Brush.Toast.Border" Color="#FFD6D6D9"/>
|
||||
<DropShadowEffect x:Key="Ubisam.Effect.Toast" BlurRadius="12" ShadowDepth="3" Direction="270" Opacity="0.22" Color="#000000"/>
|
||||
|
||||
<!-- 차트 시리즈 색 — 다크와 같은 순서·같은 계열이되, 밝은 바탕에서 읽히도록 한 단계 진하다. -->
|
||||
<SolidColorBrush x:Key="Ubisam.Brush.Chart.Series1" Color="#FF1D82E8"/>
|
||||
<SolidColorBrush x:Key="Ubisam.Brush.Chart.Series2" Color="#FF16A79C"/>
|
||||
<SolidColorBrush x:Key="Ubisam.Brush.Chart.Series3" Color="#FFB8791A"/>
|
||||
<SolidColorBrush x:Key="Ubisam.Brush.Chart.Series4" Color="#FF7B5BC7"/>
|
||||
<SolidColorBrush x:Key="Ubisam.Brush.Chart.Series5" Color="#FF2E8B4F"/>
|
||||
<SolidColorBrush x:Key="Ubisam.Brush.Chart.Series6" Color="#FFC93B3B"/>
|
||||
|
||||
</ResourceDictionary>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user