- using System;
- using System.Collections;
- using System.Drawing;
- using System.Text;
- using Zanetti.Data;
- using Travis.Storage;
- namespace Zanetti.UI
- {
- /// <summary>
- /// Fibonacci の概要の説明です。
- /// </summary>
- internal class Fibonacci
- {
- private PointF _pivot;
- private PointF _destination;
- private int _id; //SolidFibonacciからの作成時のみセット、それ以外は-1
- private LineDrawMode _mode;
- public enum LineDrawMode
- {
- Normal,
- Hilight,//☆Fibonacci 20180816 カンマ「,」追加
- Move//☆Fibonacci 20180816 追加
- }
- public Fibonacci(PointF p)
- {
- _pivot = p;
- _destination = p;
- _id = -1;
- }
- public Fibonacci(PointF p1, PointF p2)
- {
- _pivot = p1;
- _destination = p2;
- _id = -1;
- }
- //リサイズしたときなどの再計算
- public Fibonacci(DataFarm farm, int firstdateindex, SolidFibonacci fl, Trans value_to_y)
- {
- int p = Env.Layout.DatePitch;
- _pivot = new PointF((farm.DateToIndex(fl._date1) - firstdateindex) * p + p / 2, (float)value_to_y.TransValue(fl._value1));
- _destination = new PointF((farm.DateToIndex(fl._date2) - firstdateindex) * p + p / 2, (float)value_to_y.TransValue(fl._value2));
- _id = fl._id;
- }
- public PointF Pivot
- {
- get
- {
- return _pivot;
- }
- //☆Fibonacci 20180816 setは不要
- }
- public PointF Destination
- {
- get
- {
- return _destination;
- }
- set
- {
- _destination = value;
- }
- }
- public LineDrawMode DrawMode
- {
- get
- {
- return _mode;
- }
- set
- {
- _mode = value;
- }
- }
- public int ID
- {
- get
- {
- return _id;
- }
- }
- public void SetHighPriceAndLowPrice(DataFarm farm, Trans pricetrans, float x1, float x2, int FirstDateIndex)
- {
- var range_max = double.MinValue;//☆Fibonacci 20180816 新規追加
- var range_min = double.MaxValue;//☆Fibonacci 20180816 新規追加
- var y1 = double.MinValue;//☆Fibonacci 20180816 新規追加
- var y2 = double.MinValue;//☆Fibonacci 20180816 新規追加
- if (x1 > Env.Layout.ChartAreaWidth || x2 > Env.Layout.ChartAreaWidth)
- return;
- int ind1 = FirstDateIndex + (int)Math.Floor((double)Math.Min(x1, x2) / Env.Layout.DatePitch);
- int ind2 = FirstDateIndex + (int)Math.Floor((double)Math.Max(x1, x2) / Env.Layout.DatePitch);
- if (ind1 < 0) ind1 = 0;
- if (ind2 < 0) ind2 = 0;
- if (ind1 >= farm.FilledLength) ind1 = farm.FilledLength - 1;//☆Fibonacci 20180816 修正
- if (ind2 >= farm.FilledLength) ind2 = farm.FilledLength - 1;//☆Fibonacci 20180816 修正
- //最高値と最安値の株価
- range_max = Max(farm, ind1, ind2);//☆Fibonacci 20180816 修正
- range_min = Min(farm, ind1, ind2);//☆Fibonacci 20180816 修正
- //最高値と最安値の画面上の位置
- //var y1 = pricetrans.TransValue(_pivot.Y > _destination.Y ? Env.Preference.InverseChart ? range_max : range_min : Env.Preference.InverseChart ? range_min : range_max);//☆Fibonacci 20180816 コメントアウト
- //var y2 = pricetrans.TransValue(_pivot.Y > _destination.Y ? Env.Preference.InverseChart ? range_min : range_max : Env.Preference.InverseChart ? range_max : range_min);//☆Fibonacci 20180816 コメントアウト
- //☆Fibonacci 20180816 新規追加ここから
- if (_mode != Fibonacci.LineDrawMode.Move && _id < 0)//モードが移動モード、かつ引いたばかりのフィボナッチラインではない
- {
- //_pivot.Y > _destination.Y は下から上に引いた線の意味
- y1 = pricetrans.TransValue(_pivot.Y > _destination.Y ? Env.Preference.InverseChart ? range_max : range_min : Env.Preference.InverseChart ? range_min : range_max);//☆Fibonacci 20180816 変更
- y2 = pricetrans.TransValue(_pivot.Y > _destination.Y ? Env.Preference.InverseChart ? range_min : range_max : Env.Preference.InverseChart ? range_max : range_min);//☆Fibonacci 20180816 変更
- }
- else
- {
- y1 = _pivot.Y < _destination.Y ? Env.Preference.InverseChart ? _pivot.Y : _destination.Y : Env.Preference.InverseChart ? _destination.Y : _pivot.Y;
- y2 = _pivot.Y < _destination.Y ? Env.Preference.InverseChart ? _destination.Y : _pivot.Y : Env.Preference.InverseChart ? _pivot.Y : _destination.Y;
- }
- //ここまで
- //_pivot = new PointF(x1, (float)y1);//☆Fibonacci 20180816 コメントアウト
- //_destination = new PointF(x2, (float)y2);//☆Fibonacci 20180816 コメントアウト
- _pivot = new PointF(_pivot.X < _destination.X ? Math.Min(x1, x2) : Math.Max(x1, x2), _pivot.Y < _destination.Y ? (float)Math.Min(y1, y2) : (float)Math.Max(y1, y2));//☆Fibonacci 20180816 新規追加
- _destination = new PointF(_pivot.X < _destination.X ? Math.Max(x1, x2) : Math.Min(x1, x2), _pivot.Y < _destination.Y ? (float)Math.Max(y1, y2) : (float)Math.Min(y1, y2));//☆Fibonacci 20180816 新規追加
- }
- private double Max(DataFarm farm, int ind1, int ind2)
- {
- var pos = ind1;
- var max = double.MinValue;
- var last = ind2 > farm.FilledLength ? farm.FilledLength - 1 : ind2;
- try
- {
- while (pos <= last)
- {
- var a = BitConverter.ToInt32(farm.RawDataImage, pos * 32 + 4 * 2) * farm.Brand.PriceScale / (Env.Preference.AdjustSplit ? farm.CalcSplitRatio(BitConverter.ToInt32(farm.RawDataImage, pos * 32)) : 1);
- //Console.WriteLine(pos);
- if (max < a) max = a;
- pos++;
- }
- }
- catch (Exception ex)
- {
- Console.WriteLine(ex.Message);
- }
- return max;
- }
- private double Min(DataFarm farm, int ind1, int ind2)
- {
- var pos = ind1;
- var min = double.MaxValue;
- var last = ind2 > farm.FilledLength ? farm.FilledLength - 1 : ind2;
- while (pos <= last)
- {
- var a = BitConverter.ToInt32(farm.RawDataImage, pos * 32 + 4 * 3) * farm.Brand.PriceScale / (Env.Preference.AdjustSplit ? farm.CalcSplitRatio(BitConverter.ToInt32(farm.RawDataImage, pos * 32)) : 1);
- if (min > a) min = a;
- pos++;
- }
- return min;
- }
- public Rectangle GetInclusion(Rectangle rect)
- {
- if (_pivot == _destination)
- return new Rectangle(new Point((int)_pivot.X, (int)_pivot.Y), new Size(0, 0));
- Point[] es = GetEdge(rect, new Point((int)_pivot.X, (int)_pivot.Y), new Point((int)_destination.X, (int)_destination.Y));
- return new Rectangle(Math.Min(es[0].X, es[1].X), Math.Min(es[0].Y, es[1].Y), Math.Abs(es[0].X - es[1].X), Math.Abs(es[0].Y - es[1].Y));
- }
- //十分に離した位置でないと線を確定させないようにする
- public bool PivotHasEnoughDistanceTo(PointF pt)
- {
- return Math.Abs(_pivot.X - pt.X) > 10 || Math.Abs(_pivot.Y - pt.Y) > 10;
- }
- //☆Fibonacci 20180816 Drawはまるまる書き直し ここから
- public void Draw(Trans pricetrans, Rectangle rect, IntPtr hdc)
- {
- Win32.POINT pt = new Win32.POINT();
- //Win32.SelectObject(hdc, _mode == LineDrawMode.Normal ? Env.Preference.FibonacciPen.Handle : Env.Preference.FibonacciBoldPen.Handle);//☆Fibonacci 20180816 コメントアウト
- var fibo = new double[] { -2.618, -1.618, 0, .236, .382, .5, .618, .764, 1, 1.618, 2.618 };
- //var fibo = new double[] { -2.618, 0, .236, .5, .618, 1, 1.618 };
- //var fibo = new double[] { 0, .236, .382, .5, .618, .764, 1 };
- //var fibo = new double[] { 0, .382, .5, .618, 1 };
- foreach (var f in fibo)
- {
- Win32.SelectObject(hdc, f == 0 ? Env.Preference.FibonacciBoldPen.Handle : f == 1 ? Env.Preference.FibonacciPen.Handle : f == .5 ? Env.Preference.FibonacciPen.Handle : Env.Preference.FibonacciDottedPen.Handle);//☆Fibonacci 20180816 追加
- FibonacciDrawLines fdl = new FibonacciDrawLines(_pivot, _destination, f, fibo);
- fdl.Draw(pricetrans, rect, hdc, out pt);
- }
- }//ここまで
- //☆Fibonacci 20180816 追加
- private void DrawTheLine(IntPtr hdc, float px1, float px2, float py, double kabuka, string text, out Win32.POINT pt)
- {
- Win32.MoveToEx(hdc, (int)px1, (int)py, out pt);
- Win32.LineTo(hdc, (int)px2, (int)py);
- DrawText(hdc, (int)px2, (int)py, kabuka);
- DrawText(hdc, (int)px1 - 30, (int)py, text);
- }
- private void DrawText(IntPtr hdc, int x, int y, string s)
- {
- //☆Fibonacci 20190207
- //Win32.SetTextColor(hdc, Util.ToCOLORREF(Color.White));
- Win32.SetTextColor(hdc, Util.ToCOLORREF(Env.Preference.TextColor));
- ChartUtil.DrawText(hdc, x + 3, y - 6, s);
- }
- private void DrawTheLine(IntPtr hdc, float px1, float px2, float py, double kabuka, out Win32.POINT pt)
- {
- Win32.MoveToEx(hdc, (int)px1, (int)py, out pt);
- Win32.LineTo(hdc, (int)px2, (int)py);
- DrawText(hdc, (int)px2, (int)py, kabuka);
- }
- private void DrawText(IntPtr hdc, int x, int y, double d)
- {
- //☆Fibonacci 20190207
- //Win32.SetTextColor(hdc, Util.ToCOLORREF(Color.White));
- Win32.SetTextColor(hdc, Util.ToCOLORREF(Env.Preference.TextColor));
- ChartUtil.DrawText(hdc, x + 3, y - 6, string.Format("{0:N}", d));
- }
- //p1,p2がrectに入っているとき、p1からp2に伸ばした線とp2からp1に伸ばした線がそれぞれrectと交差するところを返す
- private static Point[] GetEdge(Rectangle rect, Point p1, Point p2)
- {
- Point[] result = new Point[2];
- ArrayList ar = GetAllEdges(rect, p1, p2);
- if (ar.Count == 2) return (Point[])ar.ToArray(typeof(Point));
- result[0] = (Point)(p1.X > p2.X ? ar[1] : ar[2]);
- result[1] = (Point)(p1.X > p2.X ? ar[2] : ar[1]);
- return result;
- }
- //p1とp2を結ぶ線がrectを構成する4直線と交差する点を返す。水平・垂直のときは2個になる
- private static ArrayList GetAllEdges(Rectangle rect, Point p1, Point p2)
- {
- ArrayList ar = new ArrayList();
- if (p1.X == p2.X)
- {
- ar.Add(new Point(p1.X, p1.Y < p2.Y ? rect.Bottom : rect.Top));
- ar.Add(new Point(p1.X, p1.Y > p2.Y ? rect.Bottom : rect.Top));
- return ar;
- }
- else if (p1.Y == p2.Y)
- {
- ar.Add(new Point(p1.X < p2.X ? rect.Right : rect.Left, p1.Y));
- ar.Add(new Point(p1.X > p2.X ? rect.Right : rect.Left, p1.Y));
- return ar;
- }
- LinearTrans lt = LinearTrans.Solve(p1.X, p1.Y, p2.X, p2.Y);
- ar.Add(new Point(rect.Left, (int)lt.TransValue(rect.Left)));
- ar.Add(new Point(rect.Right, (int)lt.TransValue(rect.Right)));
- ar.Add(new Point((int)lt.Inverse(rect.Top), rect.Top));
- ar.Add(new Point((int)lt.Inverse(rect.Bottom), rect.Bottom));
- //この4点をX座標の順に並べ、2番目と3番目が答え
- ar.Sort(new PointComparer());
- return ar;
- }
- private class PointComparer : IComparer
- {
- public int Compare(object x, object y)
- {
- return ((Point)x).X - ((Point)y).X;
- }
- }
- public SolidFibonacci ToSolid(DataFarm farm, int firstdateindex, Trans value_to_y)
- {
- SolidFibonacci fl = new SolidFibonacci();
- int ind1 = firstdateindex + (int)Math.Floor((double)_pivot.X / Env.Layout.DatePitch);
- int ind2 = firstdateindex + (int)Math.Floor((double)_destination.X / Env.Layout.DatePitch);
- LinearTrans tr = LinearTrans.Solve(ind1, _pivot.Y, ind2, _destination.Y);
- double y1 = _pivot.Y;
- if (ind1 >= farm.FilledLength)
- {
- ind1 = farm.FilledLength - 1;
- //y1 = tr.TransValue(ind1);//☆Fibonacci 20180816 コメントアウト freelineと違ってy軸、つまり株価は移動しなくていい
- }
- else if (ind1 < 0)
- {
- ind1 = 0;
- y1 = tr.TransValue(ind1);
- }
- fl._date1 = farm.GetByIndex(ind1).Date;
- fl._value1 = value_to_y.Inverse(y1);
- double y2 = _destination.Y;
- if (ind2 >= farm.FilledLength)
- {
- ind2 = farm.FilledLength - 1;
- //y2 = tr.TransValue(ind2);//☆Fibonacci 20180816 コメントアウト freelineと違ってy軸、つまり株価は移動しなくていい
- }
- else if (ind2 < 0)
- {
- ind2 = 0;
- y2 = tr.TransValue(0);
- }
- fl._date2 = farm.GetByIndex(ind2).Date;
- fl._value2 = value_to_y.Inverse(y2);
- //_id==-1は作ったばかりのフィボナッチで、0以上は既存フィボナッチ
- if (_id == -1)
- {
- fl._id = SolidFibonacci.NextID++;
- _id = fl._id;
- }
- else
- {
- fl._id = _id;
- }
- return fl;
- }
- //☆Fibonacci 20180816 変更 GetDistanceは全面的に書き直し
- public double GetDistance(Point p)
- {
- return Math.Min(GetDistanceUpside(p), GetDistanceDownside(p));
- }
- //☆Fibonacci 20180816 新規
- //最上部のフィボナッチラインとマウスカーソルとの直線距離
- //マウスカーソルがフィボナッチラインの幅内にあった場合のみ、マウスカーソルと最上部フィボナッチラインの縦幅を計測して返す
- public double GetDistanceUpside(Point p)
- {
- var y = Math.Min(_pivot.Y, _destination.Y);
- var xl = Math.Min(_pivot.X, _destination.X);
- var xr = Math.Max(_pivot.X, _destination.X);
- return (p.X < xl || xr < p.X) ? double.MaxValue : Math.Abs(y - p.Y);
- }
- //☆Fibonacci 20180816 新規
- //最下部のフィボナッチラインとマウスカーソルとの直線距離
- //マウスカーソルがフィボナッチラインの幅内にあった場合のみ、マウスカーソルと最下部フィボナッチラインの縦幅を計測して返す
- public double GetDistanceDownside(Point p)
- {
- var y = Math.Max(_pivot.Y, _destination.Y);
- var xl = Math.Min(_pivot.X, _destination.X);
- var xr = Math.Max(_pivot.X, _destination.X);
- return (p.X < xl || xr < p.X) ? double.MaxValue : Math.Abs(y - p.Y);
- }
- //両端を通る直線を ax+by+c=0, a^2+b^2=1 となる形式でa,b,cの配列で返す
- private double[] GetNormalizedParam()
- {
- double a, b, c;
- if (_pivot.X == _destination.X)
- {
- a = 1;
- b = 0;
- }
- else
- {
- double d = -(_pivot.Y - _destination.Y) / (double)(_pivot.X - _destination.X);
- b = Math.Sqrt(1 / (1 + d * d));
- a = b * d;
- }
- c = -(a * _pivot.X + b * _pivot.Y);
- return new double[] { a, b, c };
- }
- }
- internal class SolidFibonacci
- {
- public int _id;
- public int _code;
- public ChartFormat _targetFormat;
- public bool _logScale;
- public int _date1;
- public double _value1;
- public int _date2;
- public double _value2;
- private static int _nextID;
- public static int NextID
- {
- get
- {
- return _nextID;
- }
- set
- {
- _nextID = value;
- }
- }
- }
- internal class FibonacciCollection
- {
- private ArrayList _data;
- public FibonacciCollection()
- {
- _data = new ArrayList();
- }
- public int Count
- {
- get
- {
- return _data.Count;
- }
- }
- public void Add(AbstractBrand br, ChartFormat format, bool logScale, SolidFibonacci fl)
- {
- fl._code = br.Code;
- fl._targetFormat = format;
- fl._logScale = logScale;
- _data.Add(fl);
- }
- public SolidFibonacci[] Find(AbstractBrand br, ChartFormat format, bool logScale)
- {
- ArrayList t = new ArrayList();
- foreach (SolidFibonacci fl in _data)
- {
- if (fl._code == br.Code && fl._targetFormat == format && fl._logScale == logScale)
- t.Add(fl);
- }
- return (SolidFibonacci[])t.ToArray(typeof(SolidFibonacci));
- }
- public void ClearAll()
- {
- _data.Clear();
- }
- public void Clear(AbstractBrand br, ChartFormat format, bool logScale)
- {
- ArrayList temp = new ArrayList();
- IEnumerator ie = _data.GetEnumerator();
- while (ie.MoveNext())
- {
- SolidFibonacci fl = (SolidFibonacci)ie.Current;
- if (!(fl._code == br.Code && fl._targetFormat == format && fl._logScale == logScale))
- temp.Add(fl);
- }
- _data = temp;
- }
- public void Remove(int id)
- {
- for (int i = 0; i < _data.Count; i++)
- {
- SolidFibonacci l = (SolidFibonacci)_data[i];
- if (l._id == id)
- {
- _data.RemoveAt(i);
- break;
- }
- }
- }
- public void Load(StorageNode parent)
- {
- string t = parent["fibonacci-lines"];
- if (t == null) return;
- foreach (string ee in t.Split(','))
- {
- if (ee == null) continue;
- if (ee.Trim() == string.Empty) continue;
- SolidFibonacci fl = new SolidFibonacci();
- string[] e = ee.Split(':');
- fl._code = Int32.Parse(e[0]);
- switch (e[1])
- {
- case "D":
- fl._targetFormat = ChartFormat.Daily;
- fl._logScale = false;
- break;
- case "W":
- fl._targetFormat = ChartFormat.Weekly;
- fl._logScale = false;
- break;
- case "M":
- fl._targetFormat = ChartFormat.Monthly;
- fl._logScale = false;
- break;
- case "Y":
- fl._targetFormat = ChartFormat.Yearly;
- fl._logScale = false;
- break;
- case "DL":
- fl._targetFormat = ChartFormat.Daily;
- fl._logScale = true;
- break;
- case "WL":
- fl._targetFormat = ChartFormat.Weekly;
- fl._logScale = true;
- break;
- case "ML":
- fl._targetFormat = ChartFormat.Monthly;
- fl._logScale = true;
- break;
- case "YL":
- fl._targetFormat = ChartFormat.Yearly;
- fl._logScale = true;
- break;
- }
- fl._date1 = Int32.Parse(e[2]);
- fl._value1 = Double.Parse(e[3]);
- fl._date2 = Int32.Parse(e[4]);
- fl._value2 = Double.Parse(e[5]);
- fl._id = SolidFibonacci.NextID++;
- _data.Add(fl);
- }
- }
- public void SaveTo(StorageNode parent)
- {
- StringBuilder bld = new StringBuilder();
- foreach (SolidFibonacci sl in _data)
- {
- if (bld.Length > 0) bld.Append(",");
- String format;
- switch (sl._targetFormat)
- {
- case ChartFormat.Daily:
- default:
- format = "D";
- break;
- case ChartFormat.Weekly:
- format = "W";
- break;
- case ChartFormat.Monthly:
- format = "M";
- break;
- case ChartFormat.Yearly:
- format = "Y";
- break;
- }
- if (sl._logScale)
- {
- format += "L";
- }
- bld.Append(String.Format("{0}:{1}:{2}:{3:F2}:{4}:{5:F2}", sl._code, format, sl._date1, sl._value1, sl._date2, sl._value2));
- }
- parent["fibonacci-lines"] = bld.ToString();
- }
- }
- //☆Fibonacci 20180816 新規追加
- internal class FibonacciDrawLines
- {
- //☆Fibonacci 20190207
- const bool SORTING = true;//起点ラインを100%終点ラインを0%と表示⇒true、起点ラインを0%終点ラインを100%と表示⇒false
- PointF _pivot;
- PointF _dest;
- double _fibopos = .0;
- double[] _fibonacci;
- string _text = string.Empty;
- public FibonacciDrawLines(PointF pivot, PointF dest, double fibopos, double[] fibonacci)
- {
- _pivot = pivot;
- _dest = dest;
- _fibopos = fibopos;
- _fibonacci = fibonacci;
- }
- public void Draw(Trans pricetrans, Rectangle rect, IntPtr hdc, out Win32.POINT pt)
- {
- var k = retKabuka(pricetrans);
- var y = (int)pricetrans.TransValue(k);//☆Fibonacci 20190207
- Win32.MoveToEx(hdc, (int)Math.Min(_pivot.X, _dest.X), y, out pt);
- Win32.LineTo(hdc, (int)Math.Max(_pivot.X, _dest.X), y);
- DrawText(hdc, (int)Math.Max(_pivot.X, _dest.X), y, k);
- DrawText(hdc, (int)Math.Min(_pivot.X, _dest.X) - 30, y, retText());
- }
- //☆Fibonacci 20190207 丸々書き換え
- private string retText()
- {
- //var per = "%";//%を付けたい人はここに書き込む
- var per = "";//%を付けたい人はここに書き込む
- return
- SORTING ?//起点ラインが100%終点ラインが0%表示
- _fibopos == 0 ?
- _pivot.Y < _dest.Y ?
- "100" + per : "0" + per
- : _fibopos == 1 ?
- _pivot.Y < _dest.Y ?
- "0" + per : "100" + per
- : string.Format("{0:00.0}{1}", _fibopos * 100, per)//天底以外の数値(0.618とか)はretKabukaでハンドリングするのでここでは逆転させない
- //起点ラインが0%終点ラインが100%表示
- : _fibopos == 0 ?
- _pivot.Y < _dest.Y ?
- "0" + per : "100" + per
- : _fibopos == 1 ?
- _pivot.Y < _dest.Y ?
- "100" + per : "0" + per
- : string.Format("{0:00.0}", _fibopos * 100);//天底以外の数値(0.618とか)はretKabukaでハンドリングするのでここでは逆転させない
- }
- //☆Fibonacci 20190207 丸々書き換え
- private double retKabuka(Trans pricetrans)
- {
- if (_fibopos == 0)
- return pricetrans.Inverse(Math.Min(_pivot.Y, _dest.Y));
- else if (_fibopos == 1)
- return pricetrans.Inverse(Math.Max(_pivot.Y, _dest.Y));
- else if (_fibopos < 0)
- return pricetrans.Inverse(Math.Max(_pivot.Y, _dest.Y) + Math.Abs(_pivot.Y - _dest.Y) * _fibopos);
- else
- return pricetrans.Inverse(Math.Min(_pivot.Y, _dest.Y) + Math.Abs(_pivot.Y - _dest.Y) * _fibopos);
- }
- private void DrawText(IntPtr hdc, int x, int y, string s)
- {
- //☆Fibonacci 20190207
- //Win32.SetTextColor(hdc, Util.ToCOLORREF(Color.White));
- Win32.SetTextColor(hdc, Util.ToCOLORREF(Env.Preference.TextColor));
- ChartUtil.DrawText(hdc, x + 3, y - 6, s);
- }
- private void DrawText(IntPtr hdc, int x, int y, double d)
- {
- //☆Fibonacci 20190207
- //Win32.SetTextColor(hdc, Util.ToCOLORREF(Color.White));
- Win32.SetTextColor(hdc, Util.ToCOLORREF(Env.Preference.TextColor));
- ChartUtil.DrawText(hdc, x + 3, y - 6, string.Format("{0:N}", d));
- }
- }
- }