using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Globalization;
using System.Linq;
using System.Text.Json.Nodes;
using Sim.Host;
namespace System.Windows.Forms.DataVisualization.Charting;
public enum SeriesChartType
{
Point, FastPoint, Bubble, Line, Spline, StepLine, FastLine, Bar, StackedBar, StackedBar100, Column, StackedColumn, StackedColumn100,
Area, SplineArea, StackedArea, StackedArea100, Pie, Doughnut, Stock, Candlestick, Range, SplineRange, RangeBar, RangeColumn,
Radar, Polar, ErrorBar, BoxPlot, Renko, ThreeLineBreak, Kagi, PointAndFigure, Funnel, Pyramid,
}
public enum ChartValueType { Auto, Double, Single, Int32, Int64, UInt32, UInt64, String, DateTime, Date, Time, DateTimeOffset }
public enum Docking { Top, Right, Bottom, Left }
public enum MarkerStyle { None, Square, Circle, Diamond, Triangle, Cross, Star4, Star5, Star6, Star10 }
public enum ChartColorPalette { None, Bright, Grayscale, Excel, Light, Pastel, EarthTones, SemiTransparent, Berry, Chocolate, Fire, SeaGreen, BrightPastel }
public enum StringAlignment { Near, Center, Far }
/// 图表里的元素(ChartArea、Legend、Series、Title):有名字,改动时通知所在的图表重画
public abstract class ChartNamedElement
{
private string _name = "";
internal Chart? Owner { get; set; }
public string Name
{
get => _name;
set
{
_name = value ?? "";
Changed();
}
}
public object? Tag { get; set; }
internal void Changed() => Owner?.Invalidated();
}
/// ChartAreas、Legends、Series、Titles 共用:按序号或名字取,Add 一个对象或一个名字
public class ChartNamedElementCollection : IEnumerable where T : ChartNamedElement, new()
{
private readonly List _items = new();
private readonly Chart _owner;
private readonly string _prefix;
internal ChartNamedElementCollection(Chart owner, string prefix)
{
_owner = owner;
_prefix = prefix;
}
public int Count => _items.Count;
public T this[int index] => _items[index];
public T this[string name] =>
FindByName(name) ?? throw new ArgumentException($"在集合中找不到名为“{name}”的图表元素。");
public T? FindByName(string name) => _items.FirstOrDefault(i => i.Name == name);
public void Add(T item)
{
if (string.IsNullOrEmpty(item.Name)) item.Name = NextName();
item.Owner = _owner;
_items.Add(item);
_owner.Invalidated();
}
public T Add(string name)
{
var item = new T { Name = name };
Add(item);
return item;
}
public int IndexOf(string name) => _items.FindIndex(i => i.Name == name);
public bool Remove(T item)
{
var removed = _items.Remove(item);
_owner.Invalidated();
return removed;
}
public void RemoveAt(int index)
{
_items.RemoveAt(index);
_owner.Invalidated();
}
public void Clear()
{
_items.Clear();
_owner.Invalidated();
}
private string NextName()
{
for (var i = 1; ; i++)
if (FindByName($"{_prefix}{i}") == null) return $"{_prefix}{i}";
}
public IEnumerator GetEnumerator() => _items.GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}
public class Axis
{
public string Title { get; set; } = "";
public double Minimum { get; set; } = double.NaN;
public double Maximum { get; set; } = double.NaN;
public double Interval { get; set; }
public Grid MajorGrid { get; } = new();
public LabelStyle LabelStyle { get; } = new();
public bool IsStartedFromZero { get; set; } = true;
}
public class Grid
{
public bool Enabled { get; set; } = true;
public Color LineColor { get; set; } = Color.Black;
}
public class LabelStyle
{
public string Format { get; set; } = "";
public int Angle { get; set; }
}
public class ChartArea : ChartNamedElement
{
public ChartArea() { }
public ChartArea(string name) => Name = name;
public Axis AxisX { get; } = new();
public Axis AxisY { get; } = new();
public Axis AxisX2 { get; } = new();
public Axis AxisY2 { get; } = new();
public Color BackColor { get; set; }
}
public class Legend : ChartNamedElement
{
public Legend() { }
public Legend(string name) => Name = name;
public bool Enabled { get; set; } = true;
public Docking Docking { get; set; } = Docking.Right;
public string Title { get; set; } = "";
public Color TitleForeColor { get; set; } = Color.Black;
public Color BackColor { get; set; }
public Color ForeColor { get; set; } = Color.Black;
public StringAlignment Alignment { get; set; }
}
public class Title : ChartNamedElement
{
private string _text = "";
public Title() { }
public Title(string text) => _text = text;
public string Text
{
get => _text;
set
{
_text = value ?? "";
Changed();
}
}
public Font? Font { get; set; }
public Color ForeColor { get; set; } = Color.Black;
public Docking Docking { get; set; } = Docking.Top;
}
public class DataPoint
{
public DataPoint() { }
public DataPoint(double xValue, double yValue)
{
XValue = xValue;
YValues = new[] { yValue };
}
public double XValue { get; set; }
public double[] YValues { get; set; } = { 0 };
/// X 值是文字(如日期字符串)时显示的标签
public string AxisLabel { get; set; } = "";
public string Label { get; set; } = "";
public Color Color { get; set; }
public bool IsEmpty { get; set; }
public string ToolTip { get; set; } = "";
}
public class DataPointCollection : IEnumerable
{
private readonly List _items = new();
private readonly Series _series;
internal DataPointCollection(Series series) => _series = series;
public int Count => _items.Count;
public DataPoint this[int index] => _items[index];
/// 加一个点:X 是数字或日期时按数值,否则(如字符串)当作分类标签,和 WinForms 一样
public int AddXY(object? xValue, params object?[] yValue)
{
var point = new DataPoint { YValues = yValue.Select(ToDouble).ToArray() };
switch (xValue)
{
case null or DBNull:
break;
case DateTime d:
point.XValue = d.ToOADate();
point.AxisLabel = d.ToString(CultureInfo.CurrentCulture);
break;
case IConvertible c when xValue is not string:
point.XValue = c.ToDouble(CultureInfo.InvariantCulture);
break;
default:
point.AxisLabel = Convert.ToString(xValue, CultureInfo.CurrentCulture) ?? "";
point.XValue = _items.Count + 1;
break;
}
_items.Add(point);
_series.Changed();
return _items.Count - 1;
}
public int AddY(params object?[] yValue) => AddXY(_items.Count + 1, yValue);
public void Add(DataPoint point)
{
_items.Add(point);
_series.Changed();
}
public void Clear()
{
_items.Clear();
_series.Changed();
}
public void RemoveAt(int index)
{
_items.RemoveAt(index);
_series.Changed();
}
/// 按两组值绑定:xValues 和 yValues 一一对应
public void DataBindXY(IEnumerable xValues, params IEnumerable[] yValues)
{
_items.Clear();
var xs = xValues.Cast