ZedGraph 5.1.4 在 .NET 2.0/VS2008 環境下,預設 X 軸依數值大小排序。當以「週數」為 X 軸且跨年時(如第 50、51、52 週接著第 1、2 週),直接繫結週數會導致排序錯誤(1, 2, 3, 4, 50, 51, 52)。
public enum AxisType {
Linear, Log, Date, Text, Ordinal, DateAsOrdinal, LinearAsOrdinal, Exponent,
Weekly // 新增
}
public Scale MakeNewScale(Scale oldScale, AxisType type) {
switch (type) {
// ... 既有 case ...
case AxisType.Weekly:
return new WeeklyScale(oldScale, _ownerAxis);
default:
throw new Exception("Implementation Error: Invalid AxisType");
}
}
[Serializable]
class WeeklyScale : Scale, ISerializable {
public WeeklyScale(Axis owner) : base(owner) { }
public WeeklyScale(Scale rhs, Axis owner) : base(rhs, owner) { }
public override Scale Clone(Axis owner) => new WeeklyScale(this, owner);
public override AxisType Type => AxisType.Weekly;
// 核心:決定刻度範圍與間距
override public void PickScale(GraphPane pane, Graphics g, float scaleFactor) {
base.PickScale(pane, g, scaleFactor);
// 取得第一條曲線的 X 值範圍
double tMin = 0, tMax = 1;
foreach (CurveItem curve in pane.CurveList) {
if (IsXAxis(curve)) {
curve.GetRange(out double xMin, out double xMax, out _, out _, false, false, pane);
tMin = xMin; tMax = xMax;
}
}
double range = Math.Abs(tMax - tMin);
base.PickScale(pane, g, scaleFactor);
OrdinalScale.PickScale(pane, g, scaleFactor, this);
SetScaleMag(tMin, tMax, range / Default.TargetXSteps);
}
// 核心:自訂標籤文字(將絕對週數轉為「YY年第N週」)
override internal string MakeLabel(GraphPane pane, int index, double dVal) {
if (_format == null) _format = Scale.Default.Format;
double scaleMult = Math.Pow(10.0, _mag);
double weekNum = dVal / scaleMult;
int baseWeeks = (DateTime.Now.Year - 2007) * 52;
if (weekNum - baseWeeks > 0) {
return string.Format("{0:yy}年第{1}周", DateTime.Now,
(weekNum - baseWeeks).ToString(_format));
} else {
return string.Format("{0:yy}年第{1}周", DateTime.Now.AddYears(-1),
weekNum.ToString(_format));
}
}
// 序列化支援
public const int schema2 = 10;
protected WeeklyScale(SerializationInfo info, StreamingContext context) : base(info, context) {
info.GetInt32("schema2");
}
[SecurityPermission(SecurityAction.Demand, SerializationFormatter = true)]
public override void GetObjectData(SerializationInfo info, StreamingContext context) {
base.GetObjectData(info, context);
info.AddValue("schema2", schema2);
}
}
myPane.XAxis.Type = AxisType.Weekly;
官方文件提及可透過 ScaleFormatEvent 自訂格式,但較新版本可能已移除此事件:
z1.GraphPane.XAxis.ScaleFormatEvent += XScaleFormatEvent;
public string XScaleFormatEvent(GraphPane pane, Axis axis, double val, int index) {
return (val + 50).ToString(); // 範例:偏移顯示
}
若專案版本支援此事件,可嘗試此較簡單做法;否則採用擴充 AxisType 的方式更穩健。