/// <summary> /// Converts movements to a graphical line and polygon /// </summary> /// <param name="results"></param> /// <param name="color"></param> /// <param name="label"></param> /// <returns></returns> public static LineAndPolygon ConvertResultsToMovementLineAndPolygon(float[] results, Color color, string label) { // Create the Line var chartLine = new ChartPrimitive(); chartLine.Color = color; chartLine.Label = label; chartLine.ShowInLegend = true; chartLine.HitTest = true; for (int monthNo = 0; monthNo < results.Length; ++monthNo) { chartLine.AddSmoothHorizontalBar(new Point(monthNo + .5f, results[monthNo])); } // Create the polygon ChartPrimitive polygon = ChartUtilities.ChartLineToBaseLinedPolygon(chartLine); color.A = (byte)(alpha * color.A); polygon.Color = color; polygon.ShowInLegend = false; polygon.HitTest = false; return(new LineAndPolygon(chartLine, polygon)); }
/// <summary> /// Gets the UIElement that can be added to the plot /// </summary> /// <returns></returns> public UIElement GetUIElement() { var path = new Path(); path.Data = geometry; path.StrokeLineJoin = PenLineJoin.Bevel; if (filled) { path.Stroke = null; path.Fill = dashed ? ChartUtilities.CreateHatch50(color, new Size(2, 2)) : (Brush)(new SolidColorBrush(color)); } else { path.Stroke = new SolidColorBrush(color); path.StrokeThickness = lineThickness; path.Fill = null; if (dashed) { path.StrokeDashArray = new DoubleCollection(new double[] { 2, 2 }); } } return(path); }
public TestPage() { InitializeComponent(); ChartUtilities.AddTestLines(xyLineChart); xyLineChart.SubNotes = new string[] { "Right Mouse Button To Zoom, Left Mouse Button To Pan, Double-Click To Reset" }; copyToClipboard.CopyToClipboardDelegate = CopyChartToClipboard; copyToClipboard.SaveToFileDelegate = SaveToFile; //xyLineChart.FlipYAxis = true; //xyLineChart.PlotAreaOverride = new Rect(new Point(0, -2), new Point(5, 2)); }
/// <summary> /// Copies the chart to the clipboard /// </summary> /// <param name="element"></param> /// <param name="width"></param> /// <param name="height"></param> protected void CopyChartToClipboard(FrameworkElement element, double width, double height) { try { ChartUtilities.CopyChartToClipboard(plotToCopy, xyLineChart, width, height); } catch { // the above might throw a security exception is used in an xbap Trace.WriteLine("Error copying to clipboard"); } }
protected void SaveToFile(FrameworkElement element, double width, double height) { var saveFile = new SaveFileDialog(); saveFile.Filter = "png files (*.png)|*.png"; saveFile.AddExtension = true; saveFile.OverwritePrompt = true; saveFile.Title = "Save Chart To a File"; saveFile.ValidateNames = true; if (saveFile.ShowDialog() == true) { ChartUtilities.CopyFrameworkElemenToPNGFile(plotToCopy, width, height, saveFile.FileName); } }
/// <summary> /// Set the chart transform /// </summary> /// <param name="width"></param> /// <param name="height"></param> protected void SetChartTransform(double width, double height) { // Note This is required even if we are using plotAreaOverride. // Calling this method causes some necessary invalidation of the contents that redraws the graphs later. // Otherwise, when using plotAreaOverride, the graphs are not redrawn. Rect plotArea = ChartUtilities.GetPlotRectangle(primitiveList, 0.1f); if (plotAreaOverride.HasValue) { plotArea = plotAreaOverride.Value; } // Enforce uniform scaling if (UniformScaling) { // TODO Improve this method plotArea.Width = plotArea.Height = Math.Max(plotArea.Width, plotArea.Height); } scaledMinPoint = plotArea.Location; scaledMinPoint.Offset(-plotArea.Width * panZoomCalculator.Pan.X, plotArea.Height * panZoomCalculator.Pan.Y); scaledMinPoint.Offset(0.5 * plotArea.Width * (1 - 1 / panZoomCalculator.Zoom.X), 0.5 * plotArea.Height * (1 - 1 / panZoomCalculator.Zoom.Y)); scaledMaxPoint = scaledMinPoint; scaledMaxPoint.Offset(plotArea.Width / panZoomCalculator.Zoom.X, plotArea.Height / panZoomCalculator.Zoom.Y); var plotScale = new Point(); plotScale.X = (width / plotArea.Width) * panZoomCalculator.Zoom.X; plotScale.Y = (height / plotArea.Height) * panZoomCalculator.Zoom.Y; Matrix shapeMatrix = Matrix.Identity; shapeMatrix.Translate(-scaledMinPoint.X, -scaledMinPoint.Y); shapeMatrix.Scale(plotScale.X, plotScale.Y); shapeTransform.Matrix = shapeMatrix; TextCanvasInfo.ScaledMaxPoint = scaledMaxPoint; TextCanvasInfo.ScaledMinPoint = scaledMinPoint; }
/// <summary> /// Gets ChartLines and ChartPolygons for the population line, and /// the target line. /// </summary> /// <param name="populationLine"></param> /// <param name="results"></param> /// <param name="color"></param> /// <param name="label"></param> /// <returns></returns> public static LineAndPolygon ConvertResultsToTargetLineAndPolygon(ChartPrimitive populationLine, float[] results, Color color, string label) { // Calculate Target Primitives var targetLine = new ChartPrimitive(); targetLine.Color = color; targetLine.Dashed = true; targetLine.Label = label + " Target"; targetLine.ShowInLegend = false; targetLine.HitTest = true; if (populationLine.Points.Count == results.Length) { for (int monthNo = 0; monthNo < results.Length; monthNo += 2) { targetLine.AddPoint(new Point(monthNo * .5f, results[monthNo])); targetLine.AddPoint(new Point(monthNo * .5f + 1f, results[monthNo + 1])); } } else { for (int monthNo = 0; monthNo < results.Length; ++monthNo) { targetLine.AddPoint(new Point(monthNo, results[monthNo])); targetLine.AddPoint(new Point(monthNo + 1f, results[monthNo])); } } ChartPrimitive targetPolygon = ChartUtilities.LineDiffToPolygon(populationLine, targetLine); color.A = (byte)(alpha * color.A); targetPolygon.Color = color; targetPolygon.Dashed = true; targetPolygon.ShowInLegend = false; targetLine.HitTest = false; return(new LineAndPolygon(targetLine, targetPolygon)); }
/// <summary> /// Converts population level to a line and polygon /// </summary> /// <param name="results"></param> /// <param name="color"></param> /// <param name="label"></param> /// <returns></returns> public static LineAndPolygon ConvertResultsToPopulationLineAndPolygon(float[] results, Color color, string label) { var populationLine = new ChartPrimitive(); populationLine.Color = color; populationLine.Label = label; populationLine.ShowInLegend = true; populationLine.HitTest = true; for (int monthNo = 0; monthNo < results.Length; monthNo += 2) { populationLine.AddPoint(new Point(monthNo * .5f, results[monthNo])); populationLine.AddPoint(new Point(monthNo * .5f + 1f, results[monthNo + 1])); } ChartPrimitive populationPolygon = ChartUtilities.ChartLineToBaseLinedPolygon(populationLine); color.A = (byte)(alpha * color.A); populationPolygon.Color = color; populationPolygon.ShowInLegend = false; populationPolygon.HitTest = false; return(new LineAndPolygon(populationLine, populationPolygon)); }
/// <summary> /// Draw all the gridlines and labels for the gridlines /// </summary> /// <param name="size"></param> /// <param name="minXY"></param> /// <param name="maxXY"></param> protected void DrawGridlinesAndLabels(Size size, Point minXY, Point maxXY) { // Clear the text canvas textCanvas.Children.Clear(); // Create brush for writing text Brush axisBrush = new SolidColorBrush(gridLineColor); Brush axisScaleBrush = new SolidColorBrush(gridLineLabelColor); // Need to pick appropriate scale increment. // Go for a 2Exx, 5Exx, or 1Exx type scale double scaleX = 0.0; double scaleY = 0.0; // Work out all the limits if (maxXY.X != minXY.X) { scaleX = size.Width / (maxXY.X - minXY.X); } if (maxXY.Y != minXY.Y) { scaleY = size.Height / (maxXY.Y - minXY.Y); } double optimalSpacingX = optimalGridLineSpacing.X / scaleX; double spacingX = ChartUtilities.ClosestValueInListTimesBaseToInteger(optimalSpacingX, new double[] { 1, 3, 6 }, 12.0); if (spacingX < 2.0) { spacingX = ChartUtilities.Closest_1_2_5_Pow10(optimalSpacingX); } double optimalSpacingY = optimalGridLineSpacing.Y / scaleY; double spacingY = ChartUtilities.Closest_1_2_5_Pow10(optimalSpacingY); var startXmult = (int)Math.Ceiling(minXY.X / spacingX); var endXmult = (int)Math.Floor(maxXY.X / spacingX); var startYmult = (int)Math.Ceiling(minXY.Y / spacingY); var endYmult = (int)Math.Floor(maxXY.Y / spacingY); double maxXLabelHeight = 0; var pathFigure = new PathFigure(); // Draw all the vertical gridlines for (int lineNo = startXmult; lineNo <= endXmult; ++lineNo) { double xValue = lineNo * spacingX; double xPos = (xValue - minXY.X) * scaleX; var startPoint = new Point(xPos, size.Height); var endPoint = new Point(xPos, 0); pathFigure.Segments.Add(new LineSegment(startPoint, false)); pathFigure.Segments.Add(new LineSegment(endPoint, true)); var text = new TextBlock(); text.Text = xValue.ToString(); text.Foreground = axisScaleBrush; text.Measure(size); text.SetValue(Canvas.LeftProperty, xPos - text.DesiredSize.Width * .5); text.SetValue(Canvas.TopProperty, size.Height + 1); textCanvas.Children.Add(text); maxXLabelHeight = Math.Max(maxXLabelHeight, text.DesiredSize.Height); } xGridlineLabels.Height = maxXLabelHeight + 2; // Set string format for vertical text double maxYLabelHeight = 0; // Draw all the horizontal gridlines for (int lineNo = startYmult; lineNo <= endYmult; ++lineNo) { double yValue = lineNo * spacingY; double yPos = flipYAxis ? (yValue - maxXY.Y) * scaleY + size.Height : (-yValue + minXY.Y) * scaleY + size.Height; var startPoint = new Point(0, yPos); var endPoint = new Point(size.Width, yPos); pathFigure.Segments.Add(new LineSegment(startPoint, false)); pathFigure.Segments.Add(new LineSegment(endPoint, true)); var text = new TextBlock(); text.Text = yValue.ToString(); text.LayoutTransform = new RotateTransform(-90); text.Measure(size); text.SetValue(Canvas.LeftProperty, -text.DesiredSize.Width - 1); text.SetValue(Canvas.TopProperty, yPos - text.DesiredSize.Height * .5); textCanvas.Children.Add(text); maxYLabelHeight = Math.Max(maxYLabelHeight, text.DesiredSize.Width); } yGridLineLabels.Height = maxYLabelHeight + 2; var path = new Path(); path.Stroke = axisBrush; var pathGeometry = new PathGeometry(new[] { pathFigure }); pathGeometry.Transform = (Transform)textCanvas.RenderTransform.Inverse; path.Data = pathGeometry; textCanvas.Children.Add(path); }