using MarketData.Utils; using SkiaSharp; using System; using System.Collections.Generic; using System.Diagnostics; using System.Text; namespace DataDisplay.Common { public class GridLines { public delegate Type GetXDataType(); public delegate Type GetYDataType(); public delegate String XDataFormatter(Object data); // custom formatter for XData public delegate String YDataFormatter(Object data); // custom formatter for YData private SKPaint paintGrid=new SKPaint{Style=SKPaintStyle.Stroke,Color=new SKColor((uint)SKColors.LightGray),StrokeWidth=1f}; private SKPaint paintAxis=new SKPaint{Style=SKPaintStyle.Stroke,Color=new SKColor((uint)SKColors.Black),StrokeWidth=3f}; private SKPaint paintHorizontalLabelText=new SKPaint{TextSize=24f,IsAntialias=true,Color=new SKColor((uint)SKColors.Black),IsStroke=false,Typeface=SKTypeface.FromFamilyName("Calibri",SKFontStyleWeight.Bold,SKFontStyleWidth.Normal,SKFontStyleSlant.Upright)}; // dates private SKPaint paintVerticalLabelText=new SKPaint{TextSize=24f,IsAntialias=true,Color=new SKColor((uint)SKColors.Black),IsStroke=false,Typeface=SKTypeface.FromFamilyName("Calibri",SKFontStyleWeight.Bold,SKFontStyleWidth.Normal,SKFontStyleSlant.Upright)}; // values private GetXDataType getXDataType=null; private GetYDataType getYDataType=null; private XDataFormatter xDataFormatter; private YDataFormatter yDataFormatter; private Dictionary uniqueVerticalLabels; private Dictionary uniqueHorizontalLabels; public GridLines(double xGridLines,double yGridLines) { XGridLines=xGridLines; YGridLines=yGridLines; uniqueVerticalLabels=new Dictionary(); uniqueHorizontalLabels=new Dictionary(); } public double XGridLines{get;private set;} public double YGridLines{get;private set;} public GetXDataType AssignXDataType { get{return getXDataType;} set{getXDataType=value;} } public GetYDataType AssignGetYDataType { get{return getYDataType;} set{getYDataType=value;} } public XDataFormatter AssignXDataFormatter { get{return xDataFormatter;} set{xDataFormatter=value;} } public YDataFormatter AssignYDataFormatter { get{return yDataFormatter;} set{yDataFormatter=value;} } public void Render(SKCanvas canvas,PointMapping pointMapping,SKPaint axisPaint=null,SKPaint gridPaint=null) { if(null==axisPaint)axisPaint=paintAxis; if(null==gridPaint)gridPaint=paintGrid; SKPoint p1; SKPoint p2; double xLineFactor = pointMapping.XRange/XGridLines; double yLineFactor = pointMapping.YRange/YGridLines; if(0==xLineFactor)xLineFactor=.01; if(0==yLineFactor)yLineFactor=.01; // Draw horizontal line grid - the labels go along the left for (double yIndex = pointMapping.YDataExtentMin; yIndex <= pointMapping.YDataExtent+.05; yIndex += yLineFactor) { p1 = pointMapping.MapPoint(new SKPoint((float)pointMapping.XDataExtentMin, (float)yIndex)); p2 = pointMapping.MapPoint(new SKPoint((float)pointMapping.XDataExtent, (float)yIndex)); if(yIndex==pointMapping.YDataExtentMin)canvas.DrawPoints(SKPointMode.Polygon, new SKPoint[] { p1, p2 }, axisPaint); else canvas.DrawPoints(SKPointMode.Polygon, new SKPoint[] { p1, p2 }, gridPaint); p1.X=0f; DisplayXAxisLabel(canvas,pointMapping,p1,yIndex); } // Draw vertical line grid - the labels go along the bottom for (double xIndex = pointMapping.XDataExtentMin; xIndex <= pointMapping.XDataExtent+.05; xIndex += xLineFactor) { p1 = pointMapping.MapPoint(new SKPoint((float)xIndex,(float)pointMapping.YDataExtentMin)); p2 = pointMapping.MapPoint(new SKPoint((float)xIndex, (float)pointMapping.YDataExtent)); if(xIndex==pointMapping.XDataExtentMin)canvas.DrawPoints(SKPointMode.Polygon, new SKPoint[] { p1, p2 }, axisPaint); else canvas.DrawPoints(SKPointMode.Polygon, new SKPoint[] { p1, p2 }, gridPaint); p1.Y=(float)pointMapping.Height; DisplayYAxisLabel(canvas,pointMapping,p1,xIndex); } } // The labels along the left of the chart private void DisplayXAxisLabel(SKCanvas canvas,PointMapping pointMapping,SKPoint p1,double yIndex) { String strLabel; double percentage=(yIndex - pointMapping.YDataExtentMin) / pointMapping.YRange; Type dataType=typeof(double); if(null!=getYDataType)dataType=getYDataType(); if(dataType.Equals(typeof(DateTime))) { DateTime axisDate=new DateTime((long)((pointMapping.YDataExtentMin+(pointMapping.YRange*percentage))*10000000000.0)); if(null!=yDataFormatter)strLabel=yDataFormatter(axisDate); else strLabel=Utility.DateTimeToStringMMSYY(axisDate); } else if(dataType.Equals(typeof(double))) { double value=pointMapping.YDataExtentMin+(pointMapping.YRange*percentage); if(null!=yDataFormatter)strLabel=yDataFormatter(value); else { if(value>=1000)strLabel=Utility.FormatNumber(value,0,true); else strLabel=Utility.FormatNumber(value,2,true); } } else { double value=pointMapping.YDataExtentMin+(pointMapping.YRange*percentage); strLabel=Utility.FormatNumber(value,0,true); } if(uniqueVerticalLabels.ContainsKey(strLabel))return; uniqueVerticalLabels.Add(strLabel,strLabel); if(null!=strLabel)canvas.DrawText(strLabel, p1, paintVerticalLabelText); } // The labels along the bottom of the chart private void DisplayYAxisLabel(SKCanvas canvas,PointMapping pointMapping,SKPoint p1,double xIndex) { String strLabel=null; double percentage=(xIndex-pointMapping.XDataExtentMin)/pointMapping.XRange; Type dataType=typeof(double); if(null!=getXDataType())dataType=getXDataType(); if (dataType.Equals(typeof(DateTime))) { DateTime axisDate=new DateTime((long)((pointMapping.XDataExtentMin+(pointMapping.XRange*percentage))*10000000000.0)); if(null!=xDataFormatter)strLabel=xDataFormatter(axisDate); else strLabel=Utility.DateTimeToStringMMSYY(axisDate); } else if(dataType.Equals(typeof(double))) { double value=pointMapping.XDataExtentMin+(pointMapping.XRange*percentage); if(null!=xDataFormatter)strLabel=xDataFormatter(value); else { if(value>=1000)strLabel=Utility.FormatNumber(value,0,true); else strLabel=Utility.FormatNumber(value,2,true); } } else { double value=pointMapping.XDataExtentMin+(pointMapping.XRange*percentage); strLabel=Utility.FormatNumber(value,0,true); } if(uniqueHorizontalLabels.ContainsKey(strLabel))return; uniqueHorizontalLabels.Add(strLabel,strLabel); if(null!=strLabel)canvas.DrawText(strLabel, p1, paintHorizontalLabelText); } } }