首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> 關於.NET

ZedGraph 自訂 X 軸標籤:解決跨年週數循環顯示問題

     編輯:關於.NET

ZedGraph 5.1.4 在 .NET 2.0/VS2008 環境下,預設 X 軸依數值大小排序。當以「週數」為 X 軸且跨年時(如第 50、51、52 週接著第 1、2 週),直接繫結週數會導致排序錯誤(1, 2, 3, 4, 50, 51, 52)。

解決方案:擴充 AxisType 列舉並實作 WeeklyScale

1. 修改 Type.cs - 新增 Weekly 列舉值

public enum AxisType {
    Linear, Log, Date, Text, Ordinal, DateAsOrdinal, LinearAsOrdinal, Exponent,
    Weekly  // 新增
}

2. 修改 Scale.cs - MakeNewScale 加入實例化分支

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");
    }
}

3. 新增 WeeklyScale.cs

[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);
    }
}

4. 使用方式

myPane.XAxis.Type = AxisType.Weekly;

替代方案:ScaleFormatEvent 事件

官方文件提及可透過 ScaleFormatEvent 自訂格式,但較新版本可能已移除此事件:

z1.GraphPane.XAxis.ScaleFormatEvent += XScaleFormatEvent;

public string XScaleFormatEvent(GraphPane pane, Axis axis, double val, int index) {
    return (val + 50).ToString(); // 範例:偏移顯示
}

若專案版本支援此事件,可嘗試此較簡單做法;否則採用擴充 AxisType 的方式更穩健。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved