/// <summary> /// Translates a point from the chart dimension to the drawing canvas pixel dimension /// </summary> /// <param name="canvasInfo">Information about the canvas and its transformations</param> /// <param name="valuePoint">A point in the chart with real plot values</param> /// <returns>A point in the drawing canvas with pixel values</returns> public static Point ToPixel(CanvasTransformInfo canvasInfo, Point valuePoint) { Canvas canvas = canvasInfo.Canvas; Point scaledMaxPoint = canvasInfo.ScaledMaxPoint; Point scaledMinPoint = canvasInfo.ScaledMinPoint; double scaleX = 0.0; double scaleY = 0.0; var canvasSize = new Size(canvas.ActualWidth, canvas.ActualHeight); if (scaledMaxPoint.X != scaledMinPoint.X) { scaleX = canvasSize.Width / (scaledMaxPoint.X - scaledMinPoint.X); } if (scaledMaxPoint.Y != scaledMinPoint.Y) { scaleY = canvasSize.Height / (scaledMaxPoint.Y - scaledMinPoint.Y); } double xPos = (valuePoint.X - scaledMinPoint.X) * scaleX; double yPos = (valuePoint.Y - scaledMinPoint.Y) * scaleY; return(new Point(xPos, yPos)); }
///// <summary> ///// Convert a DataStream of values into a ChartData object which can be fed into the charts and displayed. ///// The default behaviour is to create a smoothed copy and add along with the original data. ///// The original data is colored Gray and the smoothed data Red by default.7 ///// </summary> ///// <param name="stream"></param> ///// <param name="streamName"></param> ///// <returns></returns> //public static ChartData ToChartData(DataVector stream, string streamName) //{ // if (stream == null) // throw new ArgumentNullException(); // if (stream.Count == 0) // throw new ArgumentException("Stream must contain at least one element"); // var data = stream; // var smoothedData = Numerics.SmoothBySavitzkyGolay(data, 11); // // We know there is at least one element, so Get(0) is safe! // return new ChartData( // stream.Get(0).Unit, // CreateDataItem(data, streamName, Colors.Gray, 1), // CreateDataItem(smoothedData, streamName, Colors.Red, 1)); //} ///// <summary> ///// Loads a set of DataInfo elements into a ChartPrimitive, using the Value and Time.Ticks ///// properties as values for each element. ///// </summary> ///// <param name="source"></param> ///// <param name="name"></param> ///// <param name="color"></param> ///// <param name="lineWidth"></param> ///// <returns></returns> //private static ChartPrimitive CreateDataItem(IEnumerable<DataInfo> source, String name, Color color, int lineWidth) //{ // var cp = new ChartPrimitive // { // Color = color, // Dashed = false, // Filled = false, // Label = name, // LineThickness = lineWidth, // ShowInLegend = false // }; // foreach (DataInfo info in source) // cp.AddPoint(info.Time.TotalMilliseconds, info.Value); // return cp; //} public static void RenderTextToChartPosition(DrawingContext drawingContext, CanvasTransformInfo canvasInfo, string text, Color textColor, Point chartPosition, Point pixelOffset, bool flipY, bool centreAligned) { var typeFace = new Typeface("Arial"); // Render the marker label beneath or above the marker according // to if the Y value is positive or negative Point textPos = ToPixel(canvasInfo, chartPosition); textPos.Offset(pixelOffset.X, pixelOffset.Y); var formattedText = new FormattedText( text, CultureInfo.CurrentCulture, FlowDirection.LeftToRight, typeFace, 10, new SolidColorBrush(textColor)); if (centreAligned) { formattedText.TextAlignment = TextAlignment.Center; } // Adjust position and transformation for inverted Y axis. // Default behaviour is flipY == false, in case we need to // flip the font rendering transform. The drawing canvas // has inverted its Y-axis causing the text to render upside-down. int transformY = flipY ? 1 : -1; textPos.Y *= transformY; // Push flip transformation drawingContext.PushTransform(new ScaleTransform(1, transformY)); // Render text drawingContext.DrawText(formattedText, textPos); // Pop flip transformation drawingContext.Pop(); }
///// <summary> ///// Convert a DataStream of values into a ChartData object which can be fed into the charts and displayed. ///// The default behaviour is to create a smoothed copy and add along with the original data. ///// The original data is colored Gray and the smoothed data Red by default.7 ///// </summary> ///// <param name="stream"></param> ///// <param name="streamName"></param> ///// <returns></returns> //public static ChartData ToChartData(DataVector stream, string streamName) //{ // if (stream == null) // throw new ArgumentNullException(); // if (stream.Count == 0) // throw new ArgumentException("Stream must contain at least one element"); // var data = stream; // var smoothedData = Numerics.SmoothBySavitzkyGolay(data, 11); // // We know there is at least one element, so Get(0) is safe! // return new ChartData( // stream.Get(0).Unit, // CreateDataItem(data, streamName, Colors.Gray, 1), // CreateDataItem(smoothedData, streamName, Colors.Red, 1)); //} ///// <summary> ///// Loads a set of DataInfo elements into a ChartPrimitive, using the Value and Time.Ticks ///// properties as values for each element. ///// </summary> ///// <param name="source"></param> ///// <param name="name"></param> ///// <param name="color"></param> ///// <param name="lineWidth"></param> ///// <returns></returns> //private static ChartPrimitive CreateDataItem(IEnumerable<DataInfo> source, String name, Color color, int lineWidth) //{ // var cp = new ChartPrimitive // { // Color = color, // Dashed = false, // Filled = false, // Label = name, // LineThickness = lineWidth, // ShowInLegend = false // }; // foreach (DataInfo info in source) // cp.AddPoint(info.Time.TotalMilliseconds, info.Value); // return cp; //} public static void RenderTextToChartPosition(DrawingContext drawingContext, CanvasTransformInfo canvasInfo, string text, Color textColor, Point chartPosition, Point pixelOffset, bool flipY, bool centreAligned) { var typeFace = new Typeface("Arial"); // Render the marker label beneath or above the marker according // to if the Y value is positive or negative Point textPos = ToPixel(canvasInfo, chartPosition); textPos.Offset(pixelOffset.X, pixelOffset.Y); var formattedText = new FormattedText( text, CultureInfo.CurrentCulture, FlowDirection.LeftToRight, typeFace, 10, new SolidColorBrush(textColor)); if (centreAligned) formattedText.TextAlignment = TextAlignment.Center; // Adjust position and transformation for inverted Y axis. // Default behaviour is flipY == false, in case we need to // flip the font rendering transform. The drawing canvas // has inverted its Y-axis causing the text to render upside-down. int transformY = flipY ? 1 : -1; textPos.Y *= transformY; // Push flip transformation drawingContext.PushTransform(new ScaleTransform(1, transformY)); // Render text drawingContext.DrawText(formattedText, textPos); // Pop flip transformation drawingContext.Pop(); }
/// <summary> /// Translates a point from the chart dimension to the drawing canvas pixel dimension /// </summary> /// <param name="canvasInfo">Information about the canvas and its transformations</param> /// <param name="valuePoint">A point in the chart with real plot values</param> /// <returns>A point in the drawing canvas with pixel values</returns> public static Point ToPixel(CanvasTransformInfo canvasInfo, Point valuePoint) { Canvas canvas = canvasInfo.Canvas; Point scaledMaxPoint = canvasInfo.ScaledMaxPoint; Point scaledMinPoint = canvasInfo.ScaledMinPoint; double scaleX = 0.0; double scaleY = 0.0; var canvasSize = new Size(canvas.ActualWidth, canvas.ActualHeight); if (scaledMaxPoint.X != scaledMinPoint.X) scaleX = canvasSize.Width/(scaledMaxPoint.X - scaledMinPoint.X); if (scaledMaxPoint.Y != scaledMinPoint.Y) scaleY = canvasSize.Height/(scaledMaxPoint.Y - scaledMinPoint.Y); double xPos = (valuePoint.X - scaledMinPoint.X)*scaleX; double yPos = (valuePoint.Y - scaledMinPoint.Y)*scaleY; return new Point(xPos, yPos); }
// Keep this line for you BSD License obligations #endregion Private Fields #region Public Methods /// <summary> /// Constructor. Initializes all the class fields. /// </summary> public XYLineChart() { // This assumes that you are navigating to this scene. // If you will normally instantiate it via code and display it // manually, you either have to call InitializeComponent by hand or // uncomment the following line. InitializeComponent(); TextCanvasInfo = new CanvasTransformInfo(); primitiveList = new List<ChartPrimitive>(); markerList = new List<ChartMarkerSet>(); intervalList = new List<Interval>(); // Set the Chart Geometry Clip region chartClip = new PathGeometry(); chartClip.AddGeometry( new RectangleGeometry(new Rect(0, 0, clippedPlotCanvas.ActualWidth, clippedPlotCanvas.ActualHeight))); shapeTransform = new MatrixTransform(); adornerMarkers = new AdornerChartMarkers(clippedPlotCanvas, shapeTransform, MarkerSets, this); adorner = new AdornerCursorCoordinateDrawer(clippedPlotCanvas, shapeTransform); optimalGridLineSpacing = new Point(100, 75); panZoomCalculator = new PanZoomCalculator(new Rect(0, 0, clippedPlotCanvas.ActualWidth, clippedPlotCanvas.ActualHeight)); panZoomCalculator.Window = new Rect(0, 0, clippedPlotCanvas.ActualWidth, clippedPlotCanvas.ActualHeight); panZoomCalculator.PanZoomChanged += panZoomCalculator_PanZoomChanged; closestPointPicker = new ClosestPointPicker(new Size(13, 13)); closestPointPicker.ClosestPointChanged += closestPointPicker_ClosestPointChanged; Cursor = Cursors.None; TextCanvasInfo.Canvas = textCanvas; // UniformScaling = true; // Set up all the message handlers for the clipped plot canvas AttachEventsToCanvas(this); //clippedPlotCanvas.Clip = chartClip; clippedPlotCanvas.IsVisibleChanged += clippedPlotCanvas_IsVisibleChanged; clippedPlotCanvas.SizeChanged += clippedPlotCanvas_SizeChanged; }