choiminyeong 5e5ef8c36f 플랫폼 최초 커밋 + 자동 업데이트 배포 폴더(dist)
소스(Core/Shell/Launcher)와 실행 PC가 받아갈 업데이트 파일(dist)을 함께 올린다.
Launcher가 켤 때 이 저장소의 dist와 D:\UbisamPlatform\bin을 비교해 새 버전이면 받아간다.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-21 21:56:35 +09:00

121 lines
4.9 KiB
C#

using System;
using System.Windows;
using System.Windows.Media;
using LiveChartsCore;
using LiveChartsCore.SkiaSharpView;
using LiveChartsCore.SkiaSharpView.Painting;
using LiveChartsCore.SkiaSharpView.Painting.Effects;
using SkiaSharp;
namespace UbisamBase.Core.Charting;
/// <summary>
/// 차트(축·시리즈)를 만들어주는 정적 팩토리 — 색을 코드에 박지 않고 현재 테마의 브러시 리소스에서
/// 매번 읽는다. 화면마다 색을 다시 지정하지 말고 이 클래스만 써야 라이트/다크 전환에도 톤이 유지된다.
/// 테마가 바뀐 뒤에는 이미 만들어진 시리즈의 색은 그대로이므로, <see cref="NotifyThemeChanged"/>를
/// 구독해 시리즈를 다시 만들어야 한다.
/// </summary>
public static class ChartTheme
{
private static readonly TimeSpan AnimationSpeed = TimeSpan.FromMilliseconds(260);
public static event Action? ThemeChanged;
public static void NotifyThemeChanged() => ThemeChanged?.Invoke();
public static SKColor Accent => ReadColor("Ubisam.Brush.Accent");
public static SKColor AccentFill => ReadColor("Ubisam.Brush.Accent.Fill");
public static SKColor GridLine => ReadColor("Ubisam.Brush.Table.GridLine");
public static SKColor Muted => ReadColor("Ubisam.Brush.Muted");
public static SKColor Surface => ReadColor("Ubisam.Brush.Sidebar.Background");
public static SKColor Text => ReadColor("Ubisam.Brush.ContentForeground");
private static SKColor ReadColor(string resourceKey)
{
var color = ((SolidColorBrush)Application.Current.Resources[resourceKey]).Color;
return new SKColor(color.R, color.G, color.B, color.A);
}
private static SKTypeface BodyTypeface => SKTypeface.FromFamilyName("Barlow") ?? SKTypeface.Default;
private static SKTypeface HeadingTypeface => SKTypeface.FromFamilyName("Barlow Condensed") ?? SKTypeface.Default;
/// <summary>측정값 선 — accent 밝은 단계, 두께 2, 보간 없음(LineSmoothness=0), 점 표시 없음, 면적 12%.</summary>
public static ISeries Line(double[] values, string name) => new LineSeries<double>
{
Values = values,
Name = name,
Stroke = new SolidColorPaint(Accent, 2),
Fill = new SolidColorPaint(Accent.WithAlpha(0x1F)),
GeometrySize = 0,
LineSmoothness = 0,
AnimationsSpeed = AnimationSpeed
};
/// <summary>기준·목표선 — 회색 파선, 면적 없음, hover 비활성. 측정선보다 먼저 시리즈에 넣어야 아래에 깔린다.</summary>
public static ISeries ReferenceLine(double[] values, string name) => new LineSeries<double>
{
Values = values,
Name = name,
Stroke = new SolidColorPaint(Muted, 1) { PathEffect = new DashEffect(new float[] { 5, 4 }) },
Fill = null,
GeometrySize = 0,
LineSmoothness = 0,
IsHoverable = false,
AnimationsSpeed = AnimationSpeed
};
/// <summary>막대 — accent 깊은 단계 채움 85%, 각진 모서리.</summary>
public static ISeries Column(double[] values, string name) => new ColumnSeries<double>
{
Values = values,
Name = name,
Fill = new SolidColorPaint(AccentFill.WithAlpha(217)),
Rx = 0,
Ry = 0,
AnimationsSpeed = AnimationSpeed
};
/// <summary>0~100 가동률 도넛 게이지 — 값 조각(accent 채움) + 잔여 조각(격자선 색).</summary>
public static ISeries[] Gauge(double value) => new ISeries[]
{
new PieSeries<double>
{
Values = new[] { value },
Fill = new SolidColorPaint(AccentFill),
InnerRadius = 40,
MaxRadialColumnWidth = 46,
AnimationsSpeed = AnimationSpeed
},
new PieSeries<double>
{
Values = new[] { 100 - value },
Fill = new SolidColorPaint(GridLine),
InnerRadius = 40,
MaxRadialColumnWidth = 46,
IsHoverable = false,
AnimationsSpeed = AnimationSpeed
}
};
/// <summary>가로축 — 세로 격자선 없음(SeparatorsPaint 미지정), 라벨 11pt Muted Barlow.</summary>
public static Axis XAxis(Func<double, string>? labeler = null) => new Axis
{
Labeler = labeler != null ? new Func<double, string>(v => labeler(v)) : null!,
TextSize = 11,
LabelsPaint = new SolidColorPaint(Muted) { SKTypeface = BodyTypeface },
SeparatorsPaint = null!
};
/// <summary>세로축 — 가로 격자선(GridLine, 헤어라인), 라벨 11pt Muted Barlow, 자릿수 고정 포맷.</summary>
public static Axis YAxis(string format = "0", double? min = null, double? max = null) => new Axis
{
Labeler = v => v.ToString(format),
MinLimit = min,
MaxLimit = max,
TextSize = 11,
LabelsPaint = new SolidColorPaint(Muted) { SKTypeface = BodyTypeface },
SeparatorsPaint = new SolidColorPaint(GridLine, 1)
};
}