Index: Core/Common/src/Core.Common.Controls.Charting/Chart.cs
===================================================================
diff -u
--- Core/Common/src/Core.Common.Controls.Charting/Chart.cs (revision 0)
+++ Core/Common/src/Core.Common.Controls.Charting/Chart.cs (revision 3bfa4dc5fb5ea3560752479de86cb843419f8fe3)
@@ -0,0 +1,443 @@
+using System;
+using System.Collections.Generic;
+using System.Drawing;
+using System.Drawing.Imaging;
+using System.IO;
+using System.Linq;
+using System.Windows.Forms;
+using Core.Common.Controls.Charting.Series;
+using Core.Common.Controls.Charting.Properties;
+using Core.Common.Utils.Events;
+
+using log4net;
+using Steema.TeeChart.Drawing;
+using Steema.TeeChart.Export;
+using Steema.TeeChart.Styles;
+
+namespace Core.Common.Controls.Charting
+{
+ ///
+ /// Dataobject for chartcontrol containing set of series.
+ /// Facade for TeeChart Chart.
+ ///
+ public class Chart : IChart
+ {
+ internal readonly Steema.TeeChart.Chart chart;
+ private readonly ILog log = LogManager.GetLogger(typeof(Chart));
+
+ private readonly List seriesList;
+ private bool chartSeriesStacked;
+ private ChartGraphics graphics;
+
+ public Chart()
+ {
+ chart = new Steema.TeeChart.Chart();
+ seriesList = new List();
+
+ SetDefaultValues();
+ }
+
+ public bool TitleVisible
+ {
+ get
+ {
+ return chart.Header.Visible;
+ }
+ set
+ {
+ chart.Header.Visible = value;
+ }
+ }
+
+ public string Title
+ {
+ get
+ {
+ return chart.Header.Text;
+ }
+ set
+ {
+ chart.Header.Text = value;
+ }
+ }
+
+ public Font Font
+ {
+ get
+ {
+ return chart.Header.Font.DrawingFont;
+ }
+ set
+ {
+ chart.Header.Font.Bold = value.Bold;
+ chart.Header.Font.Italic = value.Italic;
+ chart.Header.Font.Name = value.Name;
+ chart.Header.Font.SizeFloat = value.SizeInPoints;
+ chart.Header.Font.Strikeout = value.Strikeout;
+ chart.Header.Font.Underline = value.Underline;
+ }
+ }
+
+ public Color BackGroundColor
+ {
+ get
+ {
+ return chart.Walls.Back.Brush.Color;
+ }
+ set
+ {
+ chart.Walls.Back.Brush = new ChartBrush(chart, value);
+ }
+ }
+
+ public Color SurroundingBackGroundColor
+ {
+ get
+ {
+ return chart.Panel.Brush.Color;
+ }
+ set
+ {
+ chart.Panel.Brush.Color = value;
+ }
+ }
+
+ public bool StackSeries
+ {
+ get
+ {
+ return chartSeriesStacked;
+ }
+ set
+ {
+ chartSeriesStacked = value;
+ var stackType = (chartSeriesStacked)
+ ? CustomStack.Stack
+ : CustomStack.None;
+
+ foreach (var serie in chart.Series.OfType())
+ {
+ serie.Stacked = stackType;
+ }
+ }
+ }
+
+ public IEnumerable Series
+ {
+ get
+ {
+ return seriesList.AsReadOnly();
+ }
+ }
+
+ public IChartAxis LeftAxis
+ {
+ get
+ {
+ return new ChartAxis(chart.Axes.Left);
+ }
+ }
+
+ public IChartAxis RightAxis
+ {
+ get
+ {
+ return new ChartAxis(chart.Axes.Right);
+ }
+ }
+
+ public IChartAxis BottomAxis
+ {
+ get
+ {
+ return new ChartAxis(chart.Axes.Bottom);
+ }
+ }
+
+ public Rectangle ChartBounds
+ {
+ get
+ {
+ return chart.ChartRect;
+ }
+ }
+
+ public IChartLegend Legend
+ {
+ get
+ {
+ return new ChartLegend(chart.Legend);
+ }
+ }
+
+ public ChartGraphics Graphics
+ {
+ get
+ {
+ return graphics ?? (graphics = new ChartGraphics(chart));
+ }
+ }
+
+ public Control ParentControl
+ {
+ get
+ {
+ return (Control) chart.Parent;
+ }
+ }
+
+ public bool CancelMouseEvents
+ {
+ set
+ {
+ chart.CancelMouse = value;
+ }
+ }
+
+ public bool AllowSeriesTypeChange { get; set; }
+
+ public int GetIndexOfChartSeries(ChartSeries series)
+ {
+ return seriesList.IndexOf(series);
+ }
+
+ public void AddChartSeries(ChartSeries series)
+ {
+ if (!seriesList.Contains(series))
+ {
+ series.Chart = this;
+ seriesList.Add(series);
+ chart.Series.Add(series.series);
+ }
+ }
+
+ public void InsertChartSeries(ChartSeries series, int index)
+ {
+ if (seriesList.Contains(series))
+ {
+ chart.Series.MoveTo(series.series, index);
+ }
+ else
+ {
+ series.Chart = this;
+ seriesList.Insert(index, series);
+ chart.Series.Add(series.series);
+ chart.Series.MoveTo(series.series, index);
+ }
+ }
+
+ public bool RemoveChartSeries(ChartSeries series)
+ {
+ if (seriesList.Remove(series))
+ {
+ chart.Series.Remove(series.series);
+ return true;
+ }
+ return false;
+ }
+
+ public void RemoveAllChartSeries()
+ {
+ foreach (var series in seriesList.ToArray())
+ {
+ RemoveChartSeries(series);
+ }
+ }
+
+ public void ExportAsImage(IWin32Window owner)
+ {
+ var dialog = new SaveFileDialog
+ {
+ Filter = GetSupportedFormatsFilter(),
+ FilterIndex = 2,
+ };
+
+ var dialogResult = dialog.ShowDialog(owner);
+ if (dialogResult == DialogResult.OK)
+ {
+ ExportAsImage(dialog.FileName, null, null);
+ }
+ }
+
+ public void ExportAsImage(string filename, int? width, int? height)
+ {
+ if (string.IsNullOrEmpty(filename))
+ {
+ throw new ArgumentException(Resources.Chart_ExportAsImage_Argument_should_not_be_null, "filename");
+ }
+
+ var dir = Path.GetDirectoryName(filename);
+ var filenameWithoutExtension = Path.GetFileNameWithoutExtension(filename);
+ var ext = Path.GetExtension(filename);
+
+ if (string.IsNullOrEmpty(ext))
+ {
+ throw new ArgumentException(Resources.Chart_ExportAsImage_Argument_should_have_an_extension, "filename");
+ }
+
+ if (string.IsNullOrEmpty(filenameWithoutExtension))
+ {
+ throw new ArgumentException(Resources.Chart_ExportAsImage_Argument_did_not_contain_a_filename, "filename");
+ }
+
+ if (ext == ".svg")
+ {
+ var hatchStyleIgnored = seriesList.OfType().Any(cs => cs.UseHatch) ||
+ seriesList.OfType().Any(cs => cs.UseHatch);
+ if (hatchStyleIgnored)
+ {
+ log.WarnFormat(Resources.Chart_ExportAsImage_Hatch_style_is_not_supported_for_exports_and_will_be_ignored_);
+ }
+
+ chart.Export.Image.SVG.Save(filename);
+ return;
+ }
+
+ var filenameToExport = Path.Combine(dir, filenameWithoutExtension) + ext;
+
+ var oldColor = SurroundingBackGroundColor;
+ SurroundingBackGroundColor = Color.FromArgb(255, Color.White);
+
+ // use our own bitmap / graphics stuff because TeeChart's contains a leak
+ var realWidth = width.HasValue ? width.Value : chart.Width == 0 ? 400 : chart.Width;
+ var realHeight = height.HasValue ? height.Value : chart.Height == 0 ? 300 : chart.Height;
+
+ using (var bitmap = new Bitmap(realWidth, realHeight))
+ {
+ using (var g = System.Drawing.Graphics.FromImage(bitmap))
+ {
+ var oldWidth = chart.Width;
+ var oldHeight = chart.Height;
+ try
+ {
+ chart.Width = realWidth;
+ chart.Height = realHeight;
+ chart.Draw(g);
+ }
+ finally
+ {
+ chart.Width = oldWidth;
+ chart.Height = oldHeight;
+ }
+ bitmap.Save(filenameToExport, GetImageFormatByExtension(ext));
+ }
+ }
+ SurroundingBackGroundColor = oldColor;
+ }
+
+ public Bitmap Bitmap()
+ {
+ return chart.Bitmap();
+ }
+
+ ///
+ /// Returns a filter string with the supported export file types to be used in a dialog
+ ///
+ ///
+ private static string GetSupportedFormatsFilter()
+ {
+ return "Bitmap (*.bmp)|*.bmp|JPG (*.jpg)|*.jpg|PNG (*.png)|*.png|GIF (*.gif)|*.gif|Tiff (*.tiff)|*.tiff|Scalable Vector Graphics (*.svg)|*.svg";
+ }
+
+ private ImageFormat GetImageFormatByExtension(string ext)
+ {
+ switch (ext)
+ {
+ case ".jpg":
+ case ".jpeg":
+ return ImageFormat.Jpeg;
+ case ".gif":
+ return ImageFormat.Gif;
+ case ".png":
+ return ImageFormat.Png;
+ case ".tiff":
+ return ImageFormat.Tiff;
+ case ".bmp":
+ return ImageFormat.Bmp;
+ default:
+ throw new ArgumentException(string.Format(Resources.Chart_GetImageFormatByExtension_Extension_0_not_supported, ext), "filename");
+ }
+ }
+
+ private ImageExportFormat GetImageExportFormatByExtension(string ext)
+ {
+ ImageExportFormat format;
+ switch (ext)
+ {
+ case ".pdf":
+ format = chart.Export.Image.PDF;
+ break;
+ case ".jpg":
+ case ".jpeg":
+ format = chart.Export.Image.JPEG;
+ break;
+ case ".gif":
+ format = chart.Export.Image.GIF;
+ break;
+ case ".png":
+ format = chart.Export.Image.PNG;
+ break;
+ case ".tiff":
+ format = chart.Export.Image.TIFF;
+ break;
+ case ".bmp":
+ format = chart.Export.Image.Bitmap;
+ break;
+ case ".eps":
+ format = chart.Export.Image.EPS;
+ break;
+ default:
+ throw new ArgumentException(string.Format(Resources.Chart_GetImageFormatByExtension_Extension_0_not_supported, ext), "filename");
+ }
+ return format;
+ }
+
+ private void SetDefaultValues()
+ {
+ chart.Aspect.View3D = false;
+ chart.Aspect.ZOffset = 0;
+ chart.Axes.Bottom.MaximumOffset = 2;
+ chart.Axes.Bottom.MinimumOffset = 1;
+ chart.Axes.Left.MaximumOffset = 1;
+ chart.Axes.Left.MinimumOffset = 2;
+ chart.Header.Visible = false;
+ chart.Legend.Visible = false;
+ chart.Panel.Brush.Color = Color.FromArgb(0, 212, 208, 200);
+ chart.Panel.Brush.Gradient.Visible = false;
+ chart.Zoom.Animated = true;
+
+ AllowSeriesTypeChange = true;
+ }
+
+ private void SeriesCollectionChanged(object sender, NotifyCollectionChangeEventArgs e)
+ {
+ var chartSeries = e.Item as ChartSeries;
+ if (chartSeries == null)
+ {
+ return;
+ }
+
+ switch (e.Action)
+ {
+ case NotifyCollectionChangeAction.Replace:
+ throw new NotImplementedException();
+
+ case NotifyCollectionChangeAction.Add:
+ chartSeries.Chart = this;
+ if (e.Index != -1)
+ {
+ chart.Series.Add(chartSeries.series);
+ chart.Series.MoveTo(chartSeries.series, e.Index);
+ }
+ else
+ {
+ chart.Series.Add(chartSeries.series);
+ }
+ break;
+ case NotifyCollectionChangeAction.Remove:
+ chart.Series.Remove(chartSeries.series);
+ break;
+ }
+ }
+ }
+}
\ No newline at end of file
Index: Core/Common/src/Core.Common.Controls.Charting/ChartAxis.cs
===================================================================
diff -u
--- Core/Common/src/Core.Common.Controls.Charting/ChartAxis.cs (revision 0)
+++ Core/Common/src/Core.Common.Controls.Charting/ChartAxis.cs (revision 3bfa4dc5fb5ea3560752479de86cb843419f8fe3)
@@ -0,0 +1,191 @@
+using System.Drawing;
+using Steema.TeeChart;
+
+namespace Core.Common.Controls.Charting
+{
+ public class ChartAxis : IChartAxis
+ {
+ private readonly Axis teeChartAxis;
+
+ public ChartAxis(Axis axis)
+ {
+ teeChartAxis = axis;
+ }
+
+ public string LabelsFormat
+ {
+ get
+ {
+ return teeChartAxis.Labels.ValueFormat;
+ }
+ set
+ {
+ teeChartAxis.Labels.ValueFormat = value;
+ }
+ }
+
+ public bool Labels
+ {
+ get
+ {
+ return teeChartAxis.Labels.Visible;
+ }
+ set
+ {
+ teeChartAxis.Labels.Visible = value;
+ }
+ }
+
+ public bool Visible
+ {
+ get
+ {
+ return teeChartAxis.Visible;
+ }
+ set
+ {
+ teeChartAxis.Visible = value;
+ }
+ }
+
+ public bool Automatic
+ {
+ get
+ {
+ return teeChartAxis.Automatic;
+ }
+ set
+ {
+ teeChartAxis.Automatic = value;
+ }
+ }
+
+ public double Minimum
+ {
+ get
+ {
+ // teechart tends to update the min and max of an axis when needed but this is to late
+ // if we want to respond to viewport changed events.
+ teeChartAxis.AdjustMaxMin();
+ return teeChartAxis.Minimum;
+ }
+ set
+ {
+ teeChartAxis.Minimum = value;
+ }
+ }
+
+ public double Maximum
+ {
+ get
+ {
+ teeChartAxis.AdjustMaxMin();
+ return teeChartAxis.Maximum;
+ }
+ set
+ {
+ teeChartAxis.Maximum = value;
+ }
+ }
+
+ public int MinimumOffset
+ {
+ get
+ {
+ return teeChartAxis.MinimumOffset;
+ }
+ set
+ {
+ teeChartAxis.MinimumOffset = value;
+ }
+ }
+
+ public int MaximumOffset
+ {
+ get
+ {
+ return teeChartAxis.MaximumOffset;
+ }
+ set
+ {
+ teeChartAxis.MaximumOffset = value;
+ }
+ }
+
+ public string Title
+ {
+ get
+ {
+ return teeChartAxis.Title.Caption;
+ }
+ set
+ {
+ teeChartAxis.Title.Caption = value;
+ }
+ }
+
+ public Font TitleFont
+ {
+ get
+ {
+ return teeChartAxis.Title.Font.DrawingFont;
+ }
+ set
+ {
+ teeChartAxis.Title.Font.Bold = value.Bold;
+ teeChartAxis.Title.Font.Italic = value.Italic;
+ teeChartAxis.Title.Font.Name = value.Name;
+ teeChartAxis.Title.Font.SizeFloat = value.SizeInPoints;
+ teeChartAxis.Title.Font.Strikeout = value.Strikeout;
+ teeChartAxis.Title.Font.Underline = value.Underline;
+ }
+ }
+
+ public Font LabelsFont
+ {
+ get
+ {
+ return teeChartAxis.Labels.Font.DrawingFont;
+ }
+ set
+ {
+ teeChartAxis.Labels.Font.Bold = value.Bold;
+ teeChartAxis.Labels.Font.Italic = value.Italic;
+ teeChartAxis.Labels.Font.Name = value.Name;
+ teeChartAxis.Labels.Font.SizeFloat = value.SizeInPoints;
+ teeChartAxis.Labels.Font.Strikeout = value.Strikeout;
+ teeChartAxis.Labels.Font.Underline = value.Underline;
+ }
+ }
+
+ public bool Logaritmic
+ {
+ get
+ {
+ return teeChartAxis.Logarithmic;
+ }
+ set
+ {
+ teeChartAxis.Logarithmic = value;
+ }
+ }
+
+ public bool IsDateTime
+ {
+ get
+ {
+ return teeChartAxis.IsDateTime;
+ }
+ }
+
+ public double CalcPosPoint(int position)
+ {
+ return teeChartAxis.CalcPosPoint(position);
+ }
+
+ public int CalcPosValue(double value)
+ {
+ return teeChartAxis.CalcPosValue(value);
+ }
+ }
+}
\ No newline at end of file
Index: Core/Common/src/Core.Common.Controls.Charting/ChartCoordinateService.cs
===================================================================
diff -u
--- Core/Common/src/Core.Common.Controls.Charting/ChartCoordinateService.cs (revision 0)
+++ Core/Common/src/Core.Common.Controls.Charting/ChartCoordinateService.cs (revision 3bfa4dc5fb5ea3560752479de86cb843419f8fe3)
@@ -0,0 +1,120 @@
+using System;
+using Core.GIS.GeoAPI.Geometries;
+using Core.GIS.NetTopologySuite.Geometries;
+
+namespace Core.Common.Controls.Charting
+{
+ public class ChartCoordinateService
+ {
+ public ChartCoordinateService(IChart chart)
+ {
+ Chart = chart;
+ }
+
+ public static int ToDeviceX(IChart chart, double x)
+ {
+ return HorizontalReferenceAxis(chart).CalcPosValue(x);
+ }
+
+ public static int ToDeviceY(IChart chart, double y)
+ {
+ return VerticalReferenceAxis(chart).CalcPosValue(y);
+ }
+
+ public static int ToDeviceWidth(IChart chart, double x)
+ {
+ var xAxis = HorizontalReferenceAxis(chart);
+ return Math.Abs(xAxis.CalcPosValue(x) - xAxis.CalcPosValue(0));
+ }
+
+ public static int ToDeviceHeight(IChart chart, double y)
+ {
+ var yAxis = VerticalReferenceAxis(chart);
+ return Math.Abs(yAxis.CalcPosValue(y) - yAxis.CalcPosValue(0));
+ }
+
+ public static double ToWorldX(IChart chart, int x)
+ {
+ return HorizontalReferenceAxis(chart).CalcPosPoint(x);
+ }
+
+ public static double ToWorldY(IChart chart, int y)
+ {
+ return VerticalReferenceAxis(chart).CalcPosPoint(y);
+ }
+
+ public static double ToWorldWidth(IChart chart, int x)
+ {
+ var xAxis = HorizontalReferenceAxis(chart);
+ return Math.Abs(xAxis.CalcPosPoint(x) - xAxis.CalcPosPoint(0));
+ }
+
+ public static double ToWorldHeight(IChart chart, int y)
+ {
+ var yAxis = VerticalReferenceAxis(chart);
+ return Math.Abs(yAxis.CalcPosPoint(y) - yAxis.CalcPosPoint(0));
+ }
+
+ public static ICoordinate ToCoordinate(IChart chart, int x, int y)
+ {
+ return new Coordinate(ToWorldX(chart, x), ToWorldY(chart, y));
+ }
+
+ public int ToDeviceX(double x)
+ {
+ return ToDeviceX(Chart, x);
+ }
+
+ public int ToDeviceY(double y)
+ {
+ return ToDeviceY(Chart, y);
+ }
+
+ public int ToDeviceWidth(double x)
+ {
+ return ToDeviceWidth(Chart, x);
+ }
+
+ public int ToDeviceHeight(double y)
+ {
+ return ToDeviceHeight(Chart, y);
+ }
+
+ public double ToWorldX(int x)
+ {
+ return ToWorldX(Chart, x);
+ }
+
+ public double ToWorldY(int y)
+ {
+ return ToWorldY(Chart, y);
+ }
+
+ public double ToWorldWidth(int x)
+ {
+ return ToWorldWidth(Chart, x);
+ }
+
+ public double ToWorldHeight(int y)
+ {
+ return ToWorldHeight(Chart, y);
+ }
+
+ public ICoordinate ToCoordinate(int x, int y)
+ {
+ return ToCoordinate(Chart, x, y);
+ }
+
+ private IChart Chart { get; set; }
+
+ private static IChartAxis VerticalReferenceAxis(IChart chart)
+ {
+ return chart.LeftAxis;
+ }
+
+ private static IChartAxis HorizontalReferenceAxis(IChart chart)
+ {
+ return chart.BottomAxis;
+ }
+ }
+}
\ No newline at end of file
Index: Core/Common/src/Core.Common.Controls.Charting/ChartGraphics.cs
===================================================================
diff -u
--- Core/Common/src/Core.Common.Controls.Charting/ChartGraphics.cs (revision 0)
+++ Core/Common/src/Core.Common.Controls.Charting/ChartGraphics.cs (revision 3bfa4dc5fb5ea3560752479de86cb843419f8fe3)
@@ -0,0 +1,198 @@
+using System;
+using System.Drawing;
+using System.Drawing.Drawing2D;
+using Steema.TeeChart.Drawing;
+
+namespace Core.Common.Controls.Charting
+{
+ public class ChartGraphics
+ {
+ private readonly Steema.TeeChart.Chart chart;
+
+ public ChartGraphics(Steema.TeeChart.Chart chart)
+ {
+ this.chart = chart;
+ Graphics3D = chart.Graphics3D; // Needed since TeeChart returns a new graphics object each time the get is called!!
+ }
+
+ ///
+ /// Background color used when drawing
+ ///
+ public Color BackColor
+ {
+ get
+ {
+ return Graphics3D.BackColor;
+ }
+ set
+ {
+ Graphics3D.BackColor = value;
+ }
+ }
+
+ ///
+ /// Pen color used when drawing
+ ///
+ public Color PenColor
+ {
+ get
+ {
+ return Graphics3D.Pen.Color;
+ }
+ set
+ {
+ Graphics3D.Pen.Color = value;
+ }
+ }
+
+ ///
+ /// Pen width used when drawing
+ ///
+ public int PenWidth
+ {
+ get
+ {
+ return Graphics3D.Pen.Width;
+ }
+ set
+ {
+ Graphics3D.Pen.Width = value;
+ }
+ }
+
+ ///
+ /// Dash style of the pen used when drawing
+ ///
+ public DashStyle PenStyle
+ {
+ get
+ {
+ return Graphics3D.Pen.Style;
+ }
+ set
+ {
+ Graphics3D.Pen.Style = value;
+ }
+ }
+
+ ///
+ /// Font to use when drawing text
+ ///
+ public Font Font
+ {
+ get
+ {
+ return Graphics3D.Font.DrawingFont;
+ }
+ set
+ {
+ Graphics3D.Font.DrawingFont = value;
+ }
+ }
+
+ ///
+ /// Draws an ellipse within the supplied region
+ ///
+ /// Region to draw the ellipse in
+ public void Ellipse(Rectangle rectangle)
+ {
+ DrawWithPenEnabled(() => Graphics3D.Ellipse(rectangle));
+ }
+
+ ///
+ /// Draws a rectangle within the supplied region
+ ///
+ /// Region to draw the rectangle in
+ public void Rectangle(Rectangle rectangle)
+ {
+ DrawWithPenEnabled(() => Graphics3D.Rectangle(rectangle));
+ }
+
+ ///
+ /// Draws an image within the supplied region
+ ///
+ /// Region to draw the image in
+ /// Image to draw
+ /// Use transparent color
+ public void Draw(Rectangle rectangle, Image image, bool transparent)
+ {
+ DrawWithPenEnabled(() => Graphics3D.Draw(rectangle, image, transparent));
+ }
+
+ ///
+ /// Sets the position of the pen to provided x and y location (Used in )
+ ///
+ /// x position
+ /// y position
+ public void MoveTo(int x, int y)
+ {
+ Graphics3D.MoveTo(x, y);
+ }
+
+ ///
+ /// Draws a line to from the pen position (set by ) to the provided x and y location
+ ///
+ /// x position
+ /// y position
+ public void LineTo(int x, int y)
+ {
+ Graphics3D.LineTo(x, y);
+ }
+
+ ///
+ /// Draws a graphics path according to the supplied
+ ///
+ /// Pen to use for drawing
+ /// Graphics path to follow
+ public void DrawPath(Pen pen, GraphicsPath graphicsPath)
+ {
+ DrawWithPenEnabled(() => Graphics3D.DrawPath(pen, graphicsPath));
+ }
+
+ ///
+ /// Calculates the size needed to draw the sting
+ ///
+ /// String to calculate for
+ public SizeF MeasureString(string label)
+ {
+ return Graphics3D.MeasureString(Graphics3D.Font, label);
+ }
+
+ ///
+ /// Draws the provided at the provided location
+ ///
+ /// X position
+ /// Y position
+ /// Text to draw
+ public void TextOut(int xpos, int ypos, string label)
+ {
+ Graphics3D.TextOut(xpos, ypos, label);
+ }
+
+ ///
+ /// Draws a polygon using the provided
+ ///
+ /// Points that make up the polygon
+ public void Polygon(Point[] points)
+ {
+ DrawWithPenEnabled(() => Graphics3D.Polygon(points));
+ }
+
+ ///
+ /// Graphics object used for drawing.
+ ///
+ private Graphics3D Graphics3D { get; set; }
+
+ private void DrawWithPenEnabled(Action drawAction)
+ {
+ var originalPenVisible = Graphics3D.Pen.Visible;
+ Graphics3D.Pen.Visible = true;
+
+ Graphics3D.ClipRectangle(chart.ChartBounds);
+ drawAction();
+ Graphics3D.UnClip();
+
+ Graphics3D.Pen.Visible = originalPenVisible;
+ }
+ }
+}
\ No newline at end of file
Index: Core/Common/src/Core.Common.Controls.Charting/ChartLegend.cs
===================================================================
diff -u
--- Core/Common/src/Core.Common.Controls.Charting/ChartLegend.cs (revision 0)
+++ Core/Common/src/Core.Common.Controls.Charting/ChartLegend.cs (revision 3bfa4dc5fb5ea3560752479de86cb843419f8fe3)
@@ -0,0 +1,127 @@
+using System;
+using System.Drawing;
+using Steema.TeeChart;
+
+namespace Core.Common.Controls.Charting
+{
+ ///
+ /// A TeeChart Legend wrapper class
+ ///
+ public class ChartLegend : IChartLegend
+ {
+ private readonly Legend legend;
+
+ ///
+ /// Creates a TeeChart Legend wrapper class
+ ///
+ ///
+ public ChartLegend(Legend legend)
+ {
+ this.legend = legend;
+ legend.LegendStyle = LegendStyles.Series;
+ }
+
+ public bool Visible
+ {
+ get
+ {
+ return legend.Visible;
+ }
+ set
+ {
+ legend.Visible = value;
+ }
+ }
+
+ public LegendAlignment Alignment
+ {
+ get
+ {
+ string enumName = Enum.GetName(typeof(LegendAlignments), legend.Alignment);
+ return (LegendAlignment) Enum.Parse(typeof(LegendAlignment), enumName);
+ }
+ set
+ {
+ string enumName = Enum.GetName(typeof(LegendAlignment), value);
+ legend.Alignment = (LegendAlignments) Enum.Parse(typeof(LegendAlignments), enumName);
+ }
+ }
+
+ ///
+ /// Enables checkboxes in the legend
+ ///
+ public bool ShowCheckBoxes
+ {
+ get
+ {
+ return legend.CheckBoxes;
+ }
+ set
+ {
+ legend.CheckBoxes = value;
+ }
+ }
+
+ public Font Font
+ {
+ get
+ {
+ return legend.Font.DrawingFont;
+ }
+ set
+ {
+ legend.Font.Bold = value.Bold;
+ legend.Font.Italic = value.Italic;
+ legend.Font.Name = value.Name;
+ legend.Font.SizeFloat = value.SizeInPoints;
+ legend.Font.Strikeout = value.Strikeout;
+ legend.Font.Underline = value.Underline;
+ }
+ }
+
+ ///
+ /// Maximum width of the legend
+ ///
+ public int Width
+ {
+ get
+ {
+ return legend.Width;
+ }
+ set
+ {
+ legend.Width = value;
+ }
+ }
+
+ ///
+ /// Distance between the upper left corner of the legend and the top of the axes canvas (in pixels)
+ ///
+ public int Top
+ {
+ get
+ {
+ return legend.Top;
+ }
+ set
+ {
+ legend.Top = value;
+ }
+ }
+
+ ///
+ /// Distance between the upper left corner of the legend and the left side of the axes canvas (in pixels)
+ ///
+ public int Left
+ {
+ get
+ {
+ return legend.Left;
+ }
+ set
+ {
+ legend.Left = value;
+ }
+ }
+ }
+}
\ No newline at end of file
Index: Core/Common/src/Core.Common.Controls.Charting/ChartStyleHelper.cs
===================================================================
diff -u
--- Core/Common/src/Core.Common.Controls.Charting/ChartStyleHelper.cs (revision 0)
+++ Core/Common/src/Core.Common.Controls.Charting/ChartStyleHelper.cs (revision 3bfa4dc5fb5ea3560752479de86cb843419f8fe3)
@@ -0,0 +1,188 @@
+using System.Collections.Generic;
+using System.Linq;
+using Core.Common.Controls.Charting.Series;
+
+namespace Core.Common.Controls.Charting
+{
+ public static class ChartStyleHelper
+ {
+ ///
+ /// Copies chart, axis and series styles from a chart to a chart.
+ /// To copy styles from series this method uses the Tag property of the ChartSeries to identify series to copy a style to.
+ ///
+ /// Source chart
+ /// Target chart
+ public static void CopyStyle(IChart source, IChart target)
+ {
+ // First copy chart styles
+ CopyChartStyle(source, target);
+
+ // Copy axis styles
+ CopyAxisStyle(source.LeftAxis, target.LeftAxis);
+ CopyAxisStyle(source.BottomAxis, target.BottomAxis);
+
+ // Copy series styles
+ CopySeriesStyles(source.Series, target.Series);
+ }
+
+ ///
+ /// Copies only the chart related styles from to .
+ ///
+ /// Source chart
+ /// Target chart
+ public static void CopyChartStyle(IChart source, IChart target)
+ {
+ target.Legend.Visible = source.Legend.Visible;
+ target.Legend.Alignment = source.Legend.Alignment;
+ target.Legend.Font = source.Legend.Font;
+ target.TitleVisible = source.TitleVisible;
+ target.Title = source.Title;
+ target.Font = source.Font;
+ target.StackSeries = source.StackSeries;
+ target.SurroundingBackGroundColor = source.SurroundingBackGroundColor;
+ target.BackGroundColor = source.BackGroundColor;
+ target.AllowSeriesTypeChange = source.AllowSeriesTypeChange;
+ }
+
+ ///
+ /// Copies the style of a axis to a axis. This includes legend style, label style and axis scaling.
+ ///
+ /// Source chart axis
+ /// Target chart axis
+ public static void CopyAxisStyle(IChartAxis source, IChartAxis target)
+ {
+ target.Labels = source.Labels;
+ target.Automatic = source.Automatic;
+ target.Maximum = source.Maximum;
+ target.Minimum = source.Minimum;
+ target.Title = source.Title;
+ target.Visible = source.Visible;
+ target.LabelsFont = source.LabelsFont;
+ target.TitleFont = source.TitleFont;
+ target.LabelsFormat = source.LabelsFormat;
+ target.Logaritmic = source.Logaritmic;
+ }
+
+ ///
+ /// Copies style of all chart series in the collection to styles in the collection. Tag is used to match series (series in the target collection with a tag that is also in one of ther series of the source collection get the style of the first item witht the same Tag in the source collection).
+ ///
+ public static void CopySeriesStyles(IEnumerable source, IEnumerable target)
+ {
+ foreach (var sourceSeries in source)
+ {
+ var series = sourceSeries;
+ foreach (var targetSeries in target.Where(s => series.Tag == s.Tag))
+ {
+ CopyStyle(series, targetSeries);
+
+ var polygonChartSeries = series as IPolygonChartSeries;
+ if (polygonChartSeries != null)
+ {
+ CopyStyle(polygonChartSeries, (IPolygonChartSeries) targetSeries);
+ }
+ var pointChartSeries = series as IPointChartSeries;
+ if (pointChartSeries != null)
+ {
+ CopyStyle(pointChartSeries, (IPointChartSeries) targetSeries);
+ }
+ var areaChartSeries = series as IAreaChartSeries;
+ if (areaChartSeries != null)
+ {
+ CopyStyle(areaChartSeries, (IAreaChartSeries) targetSeries);
+ }
+ var lineChartSeries = series as ILineChartSeries;
+ if (lineChartSeries != null)
+ {
+ CopyStyle(lineChartSeries, (ILineChartSeries) targetSeries);
+ }
+ }
+ }
+ }
+
+ ///
+ /// Copies the style of one chart series to another.
+ ///
+ public static void CopySeriesStyles(IChartSeries sourceSeries, IChartSeries targetSeries)
+ {
+ CopyStyle(sourceSeries, targetSeries);
+ if (sourceSeries is IPointChartSeries && targetSeries is IPointChartSeries)
+ {
+ CopyStyle((IPointChartSeries) sourceSeries, (IPointChartSeries) targetSeries);
+ }
+ if (sourceSeries is ILineChartSeries && targetSeries is ILineChartSeries)
+ {
+ CopyStyle((ILineChartSeries) sourceSeries, (ILineChartSeries) targetSeries);
+ }
+ if (sourceSeries is IAreaChartSeries && targetSeries is IAreaChartSeries)
+ {
+ CopyStyle((IAreaChartSeries) sourceSeries, (IAreaChartSeries) targetSeries);
+ }
+ if (sourceSeries is IPolygonChartSeries && targetSeries is IPolygonChartSeries)
+ {
+ CopyStyle((IPolygonChartSeries) sourceSeries, (IPolygonChartSeries) targetSeries);
+ }
+ }
+
+ private static void CopyStyle(IPolygonChartSeries series, IPolygonChartSeries targetSeries)
+ {
+ targetSeries.HatchStyle = series.HatchStyle;
+ targetSeries.HatchColor = series.HatchColor;
+ targetSeries.UseHatch = series.UseHatch;
+ targetSeries.Transparency = series.Transparency;
+ targetSeries.LineColor = series.LineColor;
+ targetSeries.LineWidth = series.LineWidth;
+ targetSeries.LineVisible = series.LineVisible;
+ targetSeries.LineStyle = series.LineStyle;
+ targetSeries.AutoClose = series.AutoClose;
+ }
+
+ private static void CopyStyle(IAreaChartSeries series, IAreaChartSeries targetSeries)
+ {
+ targetSeries.Transparency = series.Transparency;
+ targetSeries.InterpolationType = series.InterpolationType;
+ targetSeries.UseHatch = series.UseHatch;
+ targetSeries.HatchStyle = series.HatchStyle;
+ targetSeries.HatchColor = series.HatchColor;
+ targetSeries.LineColor = series.LineColor;
+ targetSeries.LineWidth = series.LineWidth;
+ targetSeries.LineVisible = series.LineVisible;
+ targetSeries.PointerColor = series.PointerColor;
+ targetSeries.PointerStyle = series.PointerStyle;
+ targetSeries.PointerVisible = series.PointerVisible;
+ targetSeries.PointerSize = series.PointerSize;
+ targetSeries.PointerLineColor = series.PointerLineColor;
+ targetSeries.PointerLineVisible = series.PointerLineVisible;
+ }
+
+ private static void CopyStyle(ILineChartSeries series, ILineChartSeries targetSeries)
+ {
+ targetSeries.Width = series.Width;
+ targetSeries.InterpolationType = series.InterpolationType;
+ targetSeries.TitleLabelVisible = series.TitleLabelVisible;
+ targetSeries.DashStyle = series.DashStyle;
+ targetSeries.PointerSize = series.PointerSize;
+ targetSeries.PointerColor = series.PointerColor;
+ targetSeries.PointerStyle = series.PointerStyle;
+ targetSeries.PointerVisible = series.PointerVisible;
+ targetSeries.PointerLineColor = series.PointerLineColor;
+ targetSeries.PointerLineVisible = series.PointerLineVisible;
+ }
+
+ private static void CopyStyle(IPointChartSeries series, IPointChartSeries targetSeries)
+ {
+ targetSeries.LineColor = series.LineColor;
+ targetSeries.LineVisible = series.LineVisible;
+ targetSeries.Size = series.Size;
+ targetSeries.Style = series.Style;
+ }
+
+ private static void CopyStyle(IChartSeries series, IChartSeries targetSeries)
+ {
+ targetSeries.ShowInLegend = series.ShowInLegend;
+ targetSeries.Title = series.Title;
+ targetSeries.Color = series.Color;
+ targetSeries.Visible = series.Visible;
+ targetSeries.VertAxis = series.VertAxis;
+ }
+ }
+}
\ No newline at end of file
Index: Core/Common/src/Core.Common.Controls.Charting/ChartView.Designer.cs
===================================================================
diff -u
--- Core/Common/src/Core.Common.Controls.Charting/ChartView.Designer.cs (revision 0)
+++ Core/Common/src/Core.Common.Controls.Charting/ChartView.Designer.cs (revision 3bfa4dc5fb5ea3560752479de86cb843419f8fe3)
@@ -0,0 +1,69 @@
+using Core.Common.Controls.Charting.Customized;
+
+namespace Core.Common.Controls.Charting
+{
+ partial class ChartView
+ {
+ ///
+ /// Required designer variable.
+ ///
+ private System.ComponentModel.IContainer components;
+
+ #region Component Designer generated code
+
+ ///
+ /// Required method for Designer support - do not modify the contents of
+ /// this method with the code editor.
+ /// UPDATE:
+ /// All chart related properties are moved to IChart and Chart.SetDefaultValues
+ /// InitializeComponent
+ /// Important change: the TChart is encapsulated inside Chart class and
+ /// this.teeChart = new Steema.TeeChart.TChart() removed from ChartViewInitializeComponent
+ ///
+ private void InitializeComponent()
+ {
+ this.components = new System.ComponentModel.Container();
+ this.teeChart = new RingtoetsTChart();
+ this.timer1 = new System.Windows.Forms.Timer(this.components);
+ this.SuspendLayout();
+ //
+ // teeChart
+ //
+ this.teeChart.Aspect.View3D = false;
+ this.teeChart.Aspect.ZOffset = 0D;
+ this.teeChart.Axes.Bottom.Title.Transparent = true;
+ this.teeChart.Axes.Depth.Title.Transparent = true;
+ this.teeChart.Axes.DepthTop.Title.Transparent = true;
+ this.teeChart.Axes.Left.Title.Transparent = true;
+ this.teeChart.Axes.Right.Title.Transparent = true;
+ this.teeChart.Axes.Top.Title.Transparent = true;
+ this.teeChart.BackColor = System.Drawing.Color.Transparent;
+ this.teeChart.Cursor = System.Windows.Forms.Cursors.Default;
+ this.teeChart.Dock = System.Windows.Forms.DockStyle.Fill;
+ this.teeChart.Header.Lines = new string[] {""};
+ this.teeChart.Location = new System.Drawing.Point(0, 0);
+ this.teeChart.Name = "Chart";
+ this.teeChart.Size = new System.Drawing.Size(542, 368);
+ this.teeChart.TabIndex = 0;
+ this.teeChart.Walls.Visible = false;
+ //
+ // timer1
+ //
+ this.timer1.Enabled = true;
+ this.timer1.Interval = 500;
+ this.timer1.Tick += new System.EventHandler(this.Timer1Tick);
+ //
+ // ChartView
+ //
+ this.Controls.Add(this.teeChart);
+ this.Name = "ChartView";
+ this.Size = new System.Drawing.Size(542, 368);
+ this.ResumeLayout(false);
+
+ }
+ #endregion
+
+ private RingtoetsTChart teeChart;
+ private System.Windows.Forms.Timer timer1;
+ }
+}
\ No newline at end of file
Index: Core/Common/src/Core.Common.Controls.Charting/ChartView.cs
===================================================================
diff -u
--- Core/Common/src/Core.Common.Controls.Charting/ChartView.cs (revision 0)
+++ Core/Common/src/Core.Common.Controls.Charting/ChartView.cs (revision 3bfa4dc5fb5ea3560752479de86cb843419f8fe3)
@@ -0,0 +1,659 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Drawing;
+using System.Linq;
+using System.Windows.Forms;
+
+using Core.Common.Controls.Charting.Customized;
+using Core.Common.Controls.Charting.Tools;
+using Core.Common.Controls.Charting.Properties;
+
+using Steema.TeeChart;
+using Steema.TeeChart.Drawing;
+using Steema.TeeChart.Tools;
+
+namespace Core.Common.Controls.Charting
+{
+ ///
+ /// Displays series data on a chart
+ ///
+ public partial class ChartView : UserControl, IChartView
+ {
+ ///
+ /// Selected point of the active series has been changed
+ ///
+ public event EventHandler SelectionPointChanged;
+
+ ///
+ /// The visible viewport of the chart has changed either due to a zoom, pan or scroll event
+ ///
+ public event EventHandler ViewPortChanged;
+
+ public event EventHandler GraphResized;
+
+ public event EventHandler ToolsActiveChanged;
+ private const int DisabledBackgroundAlpha = 20;
+ private readonly ICollection tools;
+ private int selectedPointIndex = -1;
+ private bool wheelZoom = true;
+ private bool afterResize = true;
+ private bool chartScrolled;
+
+ private LegendScrollBar legendScrollBarTool;
+ private ZoomUsingMouseWheelTool zoomUsingMouseWheelTool;
+
+ private IChart chart;
+
+ ///
+ /// Displays series data on chart
+ ///
+ public ChartView()
+ {
+ InitializeComponent();
+
+ Chart = new Chart();
+ tools = new HashSet();
+
+ teeChart.Zoomed += TeeChartZoomed;
+ teeChart.UndoneZoom += TeeChartUndoneZoom;
+ teeChart.Scroll += TeeChartScroll;
+ teeChart.BeforeDraw += TeeChartBeforeDraw;
+ teeChart.Resize += ChartViewResize;
+ teeChart.BeforeDrawSeries += ChartBeforeDrawSeries;
+
+ teeChart.MouseDown += TeeChartMouseDown;
+ teeChart.MouseUp += OnMouseUp;
+ teeChart.MouseLeave += delegate { IsMouseDown = false; };
+ teeChart.MouseMove += (s, e) => OnMouseMove(e);
+ teeChart.MouseClick += (s, e) => OnMouseClick(e);
+
+ teeChart.AfterDraw += TeeChartAfterDraw;
+ teeChart.GetAxisLabel += OnGetAxisLabel;
+ teeChart.BeforeDrawAxes += OnBeforeDrawAxes;
+ teeChart.KeyUp += (s, e) => OnKeyUp(e); //bubble the keyup events from the chart..otherwise it does not work..
+
+ DateTimeLabelFormatProvider = new TimeNavigatableLabelFormatProvider();
+
+ InitializeWheelZoom();
+
+ teeChart.Legend.Alignment = LegendAlignments.Bottom;
+ teeChart.Chart.Header.Color = Color.Black; // To avoid blue titles everywhere
+
+ AddTool(new ExportChartAsImageChartTool
+ {
+ Active = true, Enabled = true
+ });
+ }
+
+ public bool IsMouseDown { get; private set; }
+
+ [Browsable(false)]
+ [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
+ public TimeNavigatableLabelFormatProvider DateTimeLabelFormatProvider { get; set; }
+
+ public IWin32Window Owner { get; set; }
+
+ [Browsable(false)]
+ [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
+ public IChart Chart
+ {
+ get
+ {
+ return chart;
+ }
+ set
+ {
+ if (chart == value)
+ {
+ return;
+ }
+
+ if (legendScrollBarTool != null)
+ {
+ teeChart.Tools.Remove(legendScrollBarTool);
+ legendScrollBarTool = null;
+ }
+
+ chart = value;
+ // Todo: change
+ teeChart.Chart = ((Chart)chart).chart;
+
+ if (zoomUsingMouseWheelTool != null)
+ {
+ teeChart.Tools.Remove(zoomUsingMouseWheelTool);
+ InitializeWheelZoom();
+ }
+
+ AddLegendScrollBarTool();
+ }
+ }
+
+ public string Title
+ {
+ get
+ {
+ return chart.Title;
+ }
+ set
+ {
+ chart.TitleVisible = !string.IsNullOrEmpty(value);
+ chart.Title = value ?? "";
+ }
+ }
+
+ ///
+ /// Data: in this case
+ ///
+ [Browsable(false)]
+ [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
+ public object Data
+ {
+ get
+ {
+ return Chart;
+ }
+ set
+ {
+ if (value == null)
+ {
+ //unbind series to prevent updates and memory leaks
+ foreach (var series in Chart.Series)
+ {
+ series.DataSource = null;
+ }
+ CleanAnnotations();
+ Chart.RemoveAllChartSeries();
+ }
+ else
+ {
+ Chart = value as IChart;
+ }
+ }
+ }
+
+ ///
+ /// Enables zoom using mousewheel
+ ///
+ public bool WheelZoom
+ {
+ get
+ {
+ return wheelZoom;
+ }
+ set
+ {
+ wheelZoom = value;
+ if (zoomUsingMouseWheelTool != null)
+ {
+ zoomUsingMouseWheelTool.Active = wheelZoom;
+ }
+ }
+ }
+
+ public bool AllowPanning
+ {
+ get
+ {
+ return teeChart.Panning.Allow == ScrollModes.Both;
+ }
+ set
+ {
+ teeChart.Panning.Allow = (value)
+ ? ScrollModes.Both
+ : ScrollModes.None;
+ }
+ }
+
+ [Browsable(false)]
+ [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
+ public ChartCoordinateService ChartCoordinateService
+ {
+ get
+ {
+ return new ChartCoordinateService(chart);
+ }
+ }
+
+ [Browsable(false)]
+ [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
+ public IEnumerable Tools
+ {
+ get
+ {
+ return tools;
+ }
+ }
+
+ ///
+ /// Set and get the selected Point Index (of the active series)
+ ///
+ public int SelectedPointIndex
+ {
+ get
+ {
+ return selectedPointIndex;
+ }
+ set
+ {
+ if (selectedPointIndex == value)
+ {
+ return;
+ }
+
+ selectedPointIndex = value;
+
+ if (SelectionPointChanged != null)
+ {
+ SelectionPointChanged(this, new EventArgs());
+ }
+ }
+ }
+
+ [Browsable(false)]
+ [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
+ public ViewInfo ViewInfo { get; set; }
+
+ ///
+ /// Gives the range of the bottom axis (assuming the axis is a of type DateTime)
+ ///
+ public TimeSpan GetBottomAxisRangeAsDateTime()
+ {
+ return TeeChart2DateTime(teeChart.Axes.Bottom.Maximum) -
+ TeeChart2DateTime(teeChart.Axes.Bottom.Minimum);
+ }
+
+ public void ZoomToValues(DateTime min, DateTime max)
+ {
+ teeChart.Chart.Axes.Bottom.SetMinMax(min, max);
+ }
+
+ public void ZoomToValues(double min, double max)
+ {
+ teeChart.Chart.Axes.Bottom.SetMinMax(min, max);
+ }
+
+ public T GetTool() where T : IChartViewTool
+ {
+ return (T) tools.FirstOrDefault(t => t is T);
+ }
+
+ ///
+ /// Opens an export dialog.
+ ///
+ public void ExportAsImage()
+ {
+ Chart.ExportAsImage(Owner);
+ }
+
+ public void EnableDelete(bool enable)
+ {
+ foreach (var selectTool in tools.OfType())
+ {
+ selectTool.HandleDelete = enable;
+ }
+ }
+
+ ///
+ /// Clean up any resources being used.
+ ///
+ /// true if managed resources should be disposed; otherwise, false.
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing && (components != null))
+ {
+ components.Dispose();
+ }
+
+ base.Dispose(disposing);
+ }
+
+ internal void InternalUpdate()
+ {
+ if (teeChart.Width > 0 && teeChart.Height > 0)
+ {
+ teeChart.Draw();
+ }
+ }
+
+ private void AddTool(IChartViewTool tool)
+ {
+ tool.ChartView = this;
+ tools.Add(tool);
+
+ tool.ActiveChanged += OnToolsActiveChanged;
+ }
+
+ private void TeeChartMouseDown(object sender, MouseEventArgs e)
+ {
+ IsMouseDown = true;
+ OnMouseDown(e);
+ }
+
+ private void CleanAnnotations()
+ {
+ if (teeChart == null)
+ {
+ return;
+ }
+ for (var i = 0; i < teeChart.Axes.Count; i++)
+ {
+ var axis = teeChart.Axes[i];
+ if (axis.Tag is Annotation)
+ {
+ var annotation = (Annotation)axis.Tag;
+ teeChart.Tools.Remove(annotation);
+ axis.Tag = null;
+ }
+ }
+ }
+
+ private void OnBeforeDrawAxes(object sender, Graphics3D e)
+ {
+ var senderChart = sender as RingtoetsTChart;
+
+ if (senderChart == null)
+ {
+ return;
+ }
+
+ for (int i = 0; i < senderChart.Axes.Count; i++)
+ {
+ var axis = senderChart.Axes[i];
+
+ if (!axis.IsDateTime)
+ {
+ //Use Number format, huge range. Specific (rounded) format is applied in OnGetAxisLabel due to TeeChart issue: TOOLS-4310
+ axis.Labels.ValueFormat = "N20";
+ continue;
+ }
+
+ axis.Labels.DateTimeFormat = DateTimeLabelFormatProvider.CustomDateTimeFormatInfo.FullDateTimePattern;
+ DateTime min = Steema.TeeChart.Utils.DateTime(axis.Minimum);
+ DateTime max = Steema.TeeChart.Utils.DateTime(axis.Maximum);
+
+ // TODO: move this logic completely out to FunctioBindingList and use DisplayName per property descriptor there
+ if (senderChart.Series.Count > 0 && senderChart.Series[0].DataSource is IChartSeries)
+ {
+ var chartSeries = senderChart.Series[0].DataSource as IChartSeries;
+
+ // HACK: parse XValuesDataMember, search for [units] and remove it
+ string oldAxisTitel = chartSeries.XValuesDataMember;
+
+ int indexOfUnitInString = axis.Title.Text.IndexOf("[");
+ string axisTitle = indexOfUnitInString != -1
+ ? oldAxisTitel.Substring(0, indexOfUnitInString)
+ : oldAxisTitel;
+
+ axis.Title.Caption = DateTimeLabelFormatProvider.ShowUnits
+ ? axisTitle + string.Format("[{0}]", DateTimeLabelFormatProvider.GetUnits(max - min))
+ : axisTitle;
+ }
+
+ var annotation = axis.Tag as Annotation;
+
+ if (DateTimeLabelFormatProvider.ShowRangeLabel)
+ {
+ if (annotation == null)
+ {
+ annotation = new Annotation(senderChart.Chart)
+ {
+ AllowEdit = false,
+ AutoSize = true,
+ Left = senderChart.Padding.Left
+ };
+
+ annotation.Shape.Shadow.Visible = false;
+ senderChart.Tools.Add(annotation);
+ axis.Tag = annotation;
+ }
+
+ annotation.Shape.Color = senderChart.BackColor;
+
+ if (annotation.Shape.Pen.Color != senderChart.BackColor)
+ {
+ annotation.Shape.Pen.Dispose();
+ annotation.Shape.Pen = new ChartPen(senderChart.BackColor);
+ }
+
+ annotation.Top = (senderChart.Height - annotation.Bounds.Height) + senderChart.Padding.Bottom;
+
+ //make sure space is reserved for the axis label / annotation
+ if (string.IsNullOrEmpty(axis.Title.Caption))
+ {
+ axis.Title.Caption = " ";
+ }
+
+ string title = DateTimeLabelFormatProvider.GetRangeLabel(min, max);
+
+ if (title != null)
+ {
+ annotation.Text = title;
+ }
+ }
+ else
+ {
+ if (annotation == null)
+ {
+ return;
+ }
+
+ senderChart.Tools.Remove(annotation);
+ axis.Tag = null;
+ }
+ }
+ }
+
+ private void OnGetAxisLabel(object sender, GetAxisLabelEventArgs e)
+ {
+ if (sender is Axis)
+ {
+ var axis = sender as Axis;
+ if (axis.IsDateTime)
+ {
+ DateTime res;
+ DateTime.TryParse(e.LabelText, out res);
+
+ TimeSpan axisRange = GetAxisRange(axis);
+
+ e.LabelText = DateTimeLabelFormatProvider.GetLabel(res, axisRange);
+ }
+ else
+ {
+ //Done here 'manually' per label, due to TeeChart issue: TOOLS-4310
+ double labelValue;
+ if (Double.TryParse(e.LabelText, out labelValue))
+ {
+ labelValue = Math.Round(labelValue, 13); //do some rounding to prevent TeeChart problem (TOOLS-4310)
+ e.LabelText = labelValue.ToString();
+ }
+ }
+ }
+ }
+
+ private void TeeChartBeforeDraw(object sender, Graphics3D g)
+ {
+ if (teeChart.Chart.Axes.Left.Visible &&
+ (double.IsInfinity(teeChart.Chart.Axes.Left.Maximum - teeChart.Chart.Axes.Left.Minimum)))
+ {
+ // check for all axes?
+ // extra error check to prevent stackoverflow in teechart
+ throw new InvalidOperationException(Resources.ChartView_TeeChartBeforeDraw_Can_not_draw_chart);
+ }
+ }
+
+ private void TeeChartAfterDraw(object sender, Graphics3D g)
+ {
+ if (!Enabled)
+ {
+ g.FillRectangle(new SolidBrush(Color.FromArgb(DisabledBackgroundAlpha, Color.Black)), 0, 0, ClientRectangle.Width, ClientRectangle.Height);
+ }
+ }
+
+ private void InitializeWheelZoom()
+ {
+ zoomUsingMouseWheelTool = new ZoomUsingMouseWheelTool(teeChart.Chart)
+ {
+ Active = wheelZoom
+ };
+ }
+
+ private void TeeChartScroll(object sender, EventArgs e)
+ {
+ if (ViewPortChanged != null)
+ {
+ ViewPortChanged(sender, e);
+ }
+ chartScrolled = true;
+ }
+
+ private void TeeChartZoomed(object sender, EventArgs e)
+ {
+ if (ViewPortChanged != null)
+ {
+ ViewPortChanged(sender, e);
+ }
+ }
+
+ private void TeeChartUndoneZoom(object sender, EventArgs e)
+ {
+ if (ViewPortChanged != null)
+ {
+ ViewPortChanged(sender, e);
+ }
+ }
+
+ private void ToolSelectionChanged(object sender, PointEventArgs e)
+ {
+ SelectedPointIndex = e.Index;
+ }
+
+ private void Timer1Tick(object sender, EventArgs e)
+ {
+ //check if any series requires an update and get it done..
+ foreach (var series in Chart.Series)
+ {
+ if (series.RefreshRequired)
+ {
+ series.Refresh();
+ }
+ }
+ }
+
+ private void OnMouseUp(object sender, MouseEventArgs e)
+ {
+ base.OnMouseUp(e);
+
+ if (Chart == null)
+ {
+ return;
+ }
+
+ if (chartScrolled)
+ {
+ chartScrolled = false;
+ return;
+ }
+
+ var contextMenu = new ContextMenuStrip();
+ if (e.Button == MouseButtons.Right)
+ {
+ foreach (IChartViewContextMenuTool tool in tools.OfType().Where(tool => tool.Active))
+ {
+ tool.OnBeforeContextMenu(contextMenu);
+ }
+ }
+
+ contextMenu.Show(PointToScreen(e.Location));
+
+ IsMouseDown = false;
+ }
+
+ private void OnToolsActiveChanged(object sender, EventArgs e)
+ {
+ if (ToolsActiveChanged != null)
+ {
+ ToolsActiveChanged(this, EventArgs.Empty);
+ }
+ }
+
+ private void ChartViewResize(object sender, EventArgs e)
+ {
+ afterResize = true;
+ }
+
+ private void ChartBeforeDrawSeries(object sender, Graphics3D g)
+ {
+ if (!afterResize)
+ {
+ return;
+ }
+
+ if (GraphResized != null)
+ {
+ GraphResized(this, new EventArgs());
+ }
+
+ afterResize = false;
+ }
+
+ private void AddLegendScrollBarTool()
+ {
+ legendScrollBarTool = new LegendScrollBar(teeChart.Chart)
+ {
+ Active = true,
+ DrawStyle = ScrollBarDrawStyle.WhenNeeded
+ };
+
+ legendScrollBarTool.Pen.Color = Color.Transparent;
+ legendScrollBarTool.ArrowBrush.Color = Color.DarkGray;
+ legendScrollBarTool.Brush.Color = SystemColors.Control;
+ legendScrollBarTool.ThumbBrush.Color = Color.LightGray;
+ }
+
+ private static TimeSpan GetAxisRange(Axis axis)
+ {
+ DateTime min = TeeChart2DateTime(axis.Minimum);
+ DateTime max = TeeChart2DateTime(axis.Maximum);
+ return max - min;
+ }
+
+ private static DateTime TeeChart2DateTime(double axisValue)
+ {
+ return Steema.TeeChart.Utils.DateTime(axisValue);
+ }
+
+ #region TeeChart Factory Methods
+
+ public EditPointTool NewEditPointTool()
+ {
+ var tool = new EditPointTool(teeChart);
+ AddTool(tool);
+ return tool;
+ }
+
+ public IAddPointTool NewAddPointTool()
+ {
+ var tool = new AddPointTool(teeChart.Chart);
+ AddTool(tool);
+ return tool;
+ }
+
+ public RulerTool NewRulerTool()
+ {
+ var tool = new RulerTool(teeChart);
+ AddTool(tool);
+ return tool;
+ }
+
+ public SelectPointTool NewSelectPointTool()
+ {
+ var tool = new SelectPointTool(teeChart.Chart);
+ AddTool(tool);
+ tool.SelectionChanged += ToolSelectionChanged;
+ return tool;
+ }
+
+ #endregion
+ }
+}
\ No newline at end of file
Index: Core/Common/src/Core.Common.Controls.Charting/ChartView.resx
===================================================================
diff -u
--- Core/Common/src/Core.Common.Controls.Charting/ChartView.resx (revision 0)
+++ Core/Common/src/Core.Common.Controls.Charting/ChartView.resx (revision 3bfa4dc5fb5ea3560752479de86cb843419f8fe3)
@@ -0,0 +1,123 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ 17, 17
+
+
\ No newline at end of file
Index: Core/Common/src/Core.Common.Controls.Charting/Core.Common.Controls.Charting.csproj
===================================================================
diff -u -r78b769cdeacaa9a56939825e527e7fe71c3a0281 -r3bfa4dc5fb5ea3560752479de86cb843419f8fe3
--- Core/Common/src/Core.Common.Controls.Charting/Core.Common.Controls.Charting.csproj (.../Core.Common.Controls.Charting.csproj) (revision 78b769cdeacaa9a56939825e527e7fe71c3a0281)
+++ Core/Common/src/Core.Common.Controls.Charting/Core.Common.Controls.Charting.csproj (.../Core.Common.Controls.Charting.csproj) (revision 3bfa4dc5fb5ea3560752479de86cb843419f8fe3)
@@ -31,26 +31,126 @@
prompt
+
+ ..\..\..\..\packages\log4net.2.0.4\lib\net40-full\log4net.dll
+ True
+
+
+
+
+
+ False
+ ..\..\..\..\lib\TeeChart.dll
+
Properties\GlobalAssembly.cs
+
+
+
+
+
+
+
+ UserControl
+
+
+
+ Component
+
+
+
+
+
+
+
+
+
+
+
+
+ True
+ True
+ Resources.resx
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Component
+
+
+
+
+ Component
+
+
+ Component
+
+
+ Component
+
+
+
+
+
+ Component
+
+
+ Component
+
+
+ {ffb69466-79de-466a-ada7-5c47c5c5ca3a}
+ Core.GIS.GeoAPI
+
+
+ {5770daa9-84e5-4770-af43-f6b815894368}
+ Core.GIS.NetTopologySuite
+
+
+ {9a2d67e6-26ac-4d17-b11a-2b4372f2f572}
+ Core.Common.Controls
+
+
+ {f49bd8b2-332a-4c91-a196-8cce0a2c7d98}
+ Core.Common.Utils
+
{c90b77da-e421-43cc-b82e-529651bc21ac}
Core.Common.Version
+
+
+
+
+
+
+ ResXFileCodeGenerator
+ Resources.Designer.cs
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ Transparantie moet tussen 0 en 100 liggen.
+
+
+ Argument kan niet de waarde 'null' hebben.
+
+
+ Bestandsnaam moet een extensie hebben.
+
+
+ Argument bevat geen bestandsnaam.
+
+
+ Nieuwe tabel
+
+
+ Kopiëren
+
+
+ Plakken
+
+
+ Verwijderen
+
+
+ Gearceerde stijl wordt niet ondersteund voor exporteren en zal genegeerd worden.
+
+
+ Extensie ({0}) wordt niet ondersteund.
+
+
+ Invoerformaat wordt niet ondersteund. Y moet numeriek zijn maar is van type: {0}.
+
+
+ Ongeldig argument voor databron van gegevensreeks. Biedt u een IEnumerable aan? IList en IListSource worden ondersteund.
+
+
+ Dit programma accepteert alleen {0} als gegevensreeks.
+
+
+ Geen cursor toegewezen aan {0}.
+
+
+ Verschil:
+horizontaal: {0}
+verticaal: {1}
+
+
+ seconden
+
+
+ Actie {0} wordt niet ondersteund door de TableView.
+
+
+ Ongebonden kolommen van type {0} worden niet ondersteund.
+
+
+ Ongeldig rijnummer {0}.
+
+
+ Weet u zeker dat u het volgende item wilt verwijderen: {0}
+
+
+ Kan INodePresenter voor {0} niet vinden. Zorg ervoor dat u de ontbrekende INodePresenter aan de NodePresenters eigenschap van een TreeView heeft toegevoegd.
+
+
+ Kan diagram niet tekenen.
+
+
+ Aantal X-waarden moet gelijk zijn aan het aantal Y-waarden.
+
+
+ Zou geen indices lager dan -1 moeten teruggeven!
+
+
+ Geselecteerde index is buiten bereik van de gevensreeks.
+
+
+ 'LastSelectedSeries' moet gezet zijn voordat 'SelectedPointIndex' wordt gezet.
+
+
+ Onbekende TeeChart gegevensreeks: houdt geen verband met een bekende ChartSeries.
+
+
+ Verwijderen is niet geïmplementeerd voor dit type databron.
+
+
+ X-waarde wordt vastgelegd (linker limiet) {0} => {1}.
+
+
+ X-waarde wordt vastgelegd (rechter limiet) {0} => {1}.
+
+
+ Niet te klonen subitems in menu-item.
+
+
+ De eigenschap 'DockStyle' van de inklapbare splitser kan geen waarde 'Filled' of 'None' hebben.
+
+
+ Er is een kritieke fout opgetreden. Ringtoets moet herstart worden.
+
+
+ {0} tot {1}
+
+
+ Er is een fout opgetreden. Verifieer de invoer alstublieft.
+
+Fout:
+{0}
+
+
+ Fout opgetreden
+
+
+ OnNodeRenamed moet zijn geïmplementeerd in de afgeleide klasse.
+
+
+ Structuurweergave mag niet leeg zijn.
+
+
+ Fout tijdens slepen/neerzetten: {0}.
+
+
+ Het geselecteerde item kan niet worden verwijderd.
+
+
+ De methode of operatie is niet geïmplementeerd.
+
+
+ Datumtijd notatie niet zoals verwacht.
+
+
+ Validatie van cel is mislukt: {0}.
+
+
+ Validatie van rij is mislukt: {0}.
+
+
+ Ongeldige rij: {0}.
+
+
+ Plakken waarden mislukt: {0}.
+
+
+ Ongeldig geplakte rij {0} wordt overgeslagen.
+
+
+ Kan de waarde in cel [{0}, {1}] niet plakken. Rij {0} wordt overgeslagen.
+
+
+ Kan niet plakken in een gefilterde tableview.
+
+
+ Kan niet plakken in gesorteerde kolom.
+
+
+ Er zijn geen waardes om te plakken (kopteksten worden overgeslagen).
+
+
+ Kan alleen in rechthoekige selectie plakken.
+
+
+ Klembord bevat geen tekst. Hierdoor kan het niet in de tabel worden geplakt.
+
+
+ Wilt u de waarde corrigeren?
+
+Kies Ja om de waarde zelf te corrigeren. Kies Nee als u de oorspronkelijke waarde wilt terugkrijgen.
+
+
+ <aangepast>
+
+
+ Het is niet toegestaan om rijen aan deze tabel toe te voegen.
+
+
+ Niet in staat om cellen te selecteren wanneer tableView RowSelect ingeschakeld is. Gebruik in plaats daarvan SelectRow.
+
+
+ Kan tekenreeks {0} niet omzetten naar {1} om te plakken.
+
+
+ Kan waarde in cel [{0}, {1}] niet instellen. Reden: {2}.
+
+
+ Kan waarde voor rij {0} niet instellen. Reden: {1}.
+
+
+ Kopiëer alle kopteksten
+
+
+ Maak kolom los
+
+
+ Pin kolom vast
+
+
+ SelectionChanged event afgevuurd.
+
+
+ {0} exemplaren van {1} zijn met {2} vervangen.
+
+
+ Er is geen tekst om te zoeken.
+
+
+ Einde van document is bereikt.
+
+
+ Mijn Computer
+
+
+ Een optionele randstijl om te tekenen. Zet de waarde op 'Flat' om geen rand te tekenen.
+
+
+ Geen conversie van het type 'string' mogelijk.
+
+
+ Niet in staat om een presentatieobject te vinden voor niet geïnitialiseerd object.
+
+
+ Knoop moet opgegeven zijn om diens toestand op te kunnen nemen.
+
+
+ Knoop data moet aanwezig zijn om de toestand van diens knoop op te kunnen nemen.
+
+
+ Knoop heeft niet dezelfde data als de opgenomen knoop.
+
+
+ tot
+
+
\ No newline at end of file
Index: Core/Common/src/Core.Common.Controls.Charting/Series/AreaChartSeries.cs
===================================================================
diff -u
--- Core/Common/src/Core.Common.Controls.Charting/Series/AreaChartSeries.cs (revision 0)
+++ Core/Common/src/Core.Common.Controls.Charting/Series/AreaChartSeries.cs (revision 3bfa4dc5fb5ea3560752479de86cb843419f8fe3)
@@ -0,0 +1,214 @@
+using System;
+using System.Drawing;
+using System.Drawing.Drawing2D;
+using Core.Common.Utils;
+using Steema.TeeChart.Styles;
+
+namespace Core.Common.Controls.Charting.Series
+{
+ public class AreaChartSeries : ChartSeries, IAreaChartSeries
+ {
+ private readonly Area areaSeries;
+ private InterpolationType interpolationType;
+
+ public AreaChartSeries(IChartSeries chartSeries) : this()
+ {
+ CopySettings(chartSeries);
+ }
+
+ public AreaChartSeries() : base(new Area())
+ {
+ areaSeries = (Area) series;
+ areaSeries.AreaLines.Visible = false;
+ areaSeries.Pointer.Visible = false;
+ }
+
+ public override Color Color
+ {
+ get
+ {
+ return areaSeries.Color;
+ }
+ set
+ {
+ areaSeries.Color = value;
+
+ // also need to set AreaBrush color because TeeChart will otherwise
+ // throw an error (brush == null)
+ areaSeries.AreaBrush.Color = value;
+ }
+ }
+
+ public HatchStyle HatchStyle
+ {
+ get
+ {
+ return areaSeries.AreaBrush.Style;
+ }
+ set
+ {
+ areaSeries.AreaBrush.Style = value;
+ }
+ }
+
+ public Color HatchColor
+ {
+ get
+ {
+ return areaSeries.AreaBrush.ForegroundColor;
+ }
+ set
+ {
+ areaSeries.AreaBrush.ForegroundColor = value;
+ }
+ }
+
+ public bool UseHatch
+ {
+ get
+ {
+ return !areaSeries.AreaBrush.Solid;
+ }
+ set
+ {
+ areaSeries.AreaBrush.Solid = !value;
+ }
+ }
+
+ public int Transparency
+ {
+ get
+ {
+ return areaSeries.Transparency;
+ }
+ set
+ {
+ areaSeries.Transparency = value;
+ }
+ }
+
+ public InterpolationType InterpolationType
+ {
+ get
+ {
+ return interpolationType;
+ }
+ set
+ {
+ interpolationType = value;
+ areaSeries.Stairs = (value == InterpolationType.Constant);
+ }
+ }
+
+ public Color LineColor
+ {
+ get
+ {
+ return areaSeries.LinePen.Color;
+ }
+ set
+ {
+ areaSeries.LinePen.Color = value;
+ }
+ }
+
+ public int LineWidth
+ {
+ get
+ {
+ return areaSeries.LinePen.Width;
+ }
+ set
+ {
+ areaSeries.LinePen.Width = MathUtils.ClipValue(value, MinimumAllowedSize, MaximumAllowedSize);
+ }
+ }
+
+ public bool LineVisible
+ {
+ get
+ {
+ return areaSeries.LinePen.Visible;
+ }
+ set
+ {
+ areaSeries.LinePen.Visible = value;
+ }
+ }
+
+ public Color PointerColor
+ {
+ get
+ {
+ return areaSeries.Pointer.Brush.Color;
+ }
+ set
+ {
+ areaSeries.Pointer.Brush.Color = value;
+ }
+ }
+
+ public bool PointerVisible
+ {
+ get
+ {
+ return areaSeries.Pointer.Visible;
+ }
+ set
+ {
+ areaSeries.Pointer.Visible = value;
+ }
+ }
+
+ public int PointerSize
+ {
+ get
+ {
+ return areaSeries.Pointer.VertSize;
+ }
+ set
+ {
+ areaSeries.Pointer.VertSize = MathUtils.ClipValue(value, MinimumAllowedSize, MaximumAllowedSize);
+ areaSeries.Pointer.HorizSize = MathUtils.ClipValue(value, MinimumAllowedSize, MaximumAllowedSize);
+ }
+ }
+
+ public PointerStyles PointerStyle
+ {
+ get
+ {
+ string pointerStyleName = Enum.GetName(typeof(Steema.TeeChart.Styles.PointerStyles), areaSeries.Pointer.Style);
+ return (PointerStyles) Enum.Parse(typeof(PointerStyles), pointerStyleName);
+ }
+ set
+ {
+ string pointerStyleName = Enum.GetName(typeof(PointerStyles), value);
+ areaSeries.Pointer.Style = (Steema.TeeChart.Styles.PointerStyles) Enum.Parse(typeof(Steema.TeeChart.Styles.PointerStyles), pointerStyleName);
+ }
+ }
+
+ public Color PointerLineColor
+ {
+ get
+ {
+ return areaSeries.Pointer.Pen.Color;
+ }
+ set
+ {
+ areaSeries.Pointer.Pen.Color = value;
+ }
+ }
+
+ public bool PointerLineVisible
+ {
+ get
+ {
+ return areaSeries.Pointer.Pen.Visible;
+ }
+ set
+ {
+ areaSeries.Pointer.Pen.Visible = value;
+ }
+ }
+ }
+}
\ No newline at end of file
Index: Core/Common/src/Core.Common.Controls.Charting/Series/BarSeries.cs
===================================================================
diff -u
--- Core/Common/src/Core.Common.Controls.Charting/Series/BarSeries.cs (revision 0)
+++ Core/Common/src/Core.Common.Controls.Charting/Series/BarSeries.cs (revision 3bfa4dc5fb5ea3560752479de86cb843419f8fe3)
@@ -0,0 +1,86 @@
+using System.Drawing;
+using System.Drawing.Drawing2D;
+using Core.Common.Utils;
+using Steema.TeeChart.Styles;
+
+namespace Core.Common.Controls.Charting.Series
+{
+ public class BarSeries : ChartSeries
+ {
+ private readonly Bar barSeries;
+
+ public BarSeries() : base(new Bar())
+ {
+ barSeries = (Bar) series;
+ barSeries.Marks.Visible = false;
+ barSeries.MultiBar = MultiBars.None;
+ barSeries.BarWidthPercent = 100;
+ barSeries.OffsetPercent = 50;
+ }
+
+ public BarSeries(IChartSeries chartSeries) : this()
+ {
+ CopySettings(chartSeries);
+ }
+
+ public override Color Color
+ {
+ get
+ {
+ return barSeries.Color;
+ }
+ set
+ {
+ barSeries.Color = value;
+ }
+ }
+
+ public DashStyle DashStyle
+ {
+ get
+ {
+ return barSeries.Pen.Style;
+ }
+ set
+ {
+ barSeries.Pen.Style = value;
+ }
+ }
+
+ public bool LineVisible
+ {
+ get
+ {
+ return barSeries.Pen.Visible;
+ }
+ set
+ {
+ barSeries.Pen.Visible = value;
+ }
+ }
+
+ public int LineWidth
+ {
+ get
+ {
+ return barSeries.Pen.Width;
+ }
+ set
+ {
+ barSeries.Pen.Width = MathUtils.ClipValue(value, MinimumAllowedSize, MaximumAllowedSize);
+ }
+ }
+
+ public Color LineColor
+ {
+ get
+ {
+ return barSeries.Pen.Color;
+ }
+ set
+ {
+ barSeries.Pen.Color = value;
+ }
+ }
+ }
+}
\ No newline at end of file
Index: Core/Common/src/Core.Common.Controls.Charting/Series/ChartSeries.cs
===================================================================
diff -u
--- Core/Common/src/Core.Common.Controls.Charting/Series/ChartSeries.cs (revision 0)
+++ Core/Common/src/Core.Common.Controls.Charting/Series/ChartSeries.cs (revision 3bfa4dc5fb5ea3560752479de86cb843419f8fe3)
@@ -0,0 +1,454 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Drawing;
+using System.Windows.Forms;
+using Core.Common.Controls.Charting.Properties;
+using Steema.TeeChart.Drawing;
+using Steema.TeeChart.Styles;
+
+namespace Core.Common.Controls.Charting.Series
+{
+ public abstract class ChartSeries : IChartSeries
+ {
+ protected const int MaximumAllowedSize = 999999;
+ protected const int MinimumAllowedSize = 0;
+ internal readonly Steema.TeeChart.Styles.Series series;
+
+ private string dataMember;
+ private object dataSource;
+ private PropertyDescriptor xPropertyDescriptor;
+ private PropertyDescriptor yPropertyDescriptor;
+ private BindingContext bindingContext;
+
+ private IList noDataValues = new List();
+
+ protected ChartSeries(CustomPoint series) : this((Steema.TeeChart.Styles.Series) series)
+ {
+ series.LinePen.Width = 1;
+
+ SetDefaultPointerStyle(series.Pointer);
+ series.TreatNulls = TreatNullsStyle.DoNotPaint;
+ }
+
+ protected ChartSeries(Steema.TeeChart.Styles.Series series)
+ {
+ this.series = series;
+
+ series.bBrush = new ChartBrush();
+ series.ColorEach = false;
+ series.XValues.Order = ValueListOrder.None;
+
+ //synchronized is the default
+ UpdateASynchronously = false;
+ }
+
+ ///
+ /// Set to force the x-axis to use date-time formatting, even if no data is present.
+ ///
+ public bool XAxisIsDateTime
+ {
+ get
+ {
+ return series.XValues.DateTime;
+ }
+ set
+ {
+ series.XValues.DateTime = value;
+ }
+ }
+
+ ///
+ /// The title of the series
+ ///
+ /// Changes null to an empty string to avoid TeeChart problems (TeeChart cannot cope with null titles)
+ public string Title
+ {
+ get
+ {
+ return series.Title;
+ }
+ set
+ {
+ series.Title = value ?? "";
+ }
+ }
+
+ public object DataSource
+ {
+ get
+ {
+ return dataSource;
+ }
+ set
+ {
+ Unbind();
+ dataSource = value;
+
+ series.DataSource = series; // set TeeChart specific data source to call us to get values
+ try
+ {
+ Bind();
+ }
+ catch (InvalidCastException ex)
+ {
+ throw new ArgumentException(Resources.ChartSeries_DataSource_Invalid_argument_for_series_datasource_Are_you_passing_IEnumerable_IList_and_IListSource_are_supported, ex);
+ }
+ }
+ }
+
+ public string XValuesDataMember
+ {
+ get
+ {
+ return series.XValues.DataMember;
+ }
+ set
+ {
+ series.XValues.DataMember = value;
+ Unbind();
+ Bind();
+ }
+ }
+
+ public string YValuesDataMember
+ {
+ get
+ {
+ return series.YValues.DataMember;
+ }
+ set
+ {
+ series.YValues.DataMember = value;
+ Unbind();
+ Bind();
+ }
+ }
+
+ public VerticalAxis VertAxis
+ {
+ get
+ {
+ string verticalAxisName = Enum.GetName(typeof(Steema.TeeChart.Styles.VerticalAxis), series.VertAxis);
+ return (VerticalAxis) Enum.Parse(typeof(VerticalAxis), verticalAxisName);
+ }
+ set
+ {
+ string verticalAxisName = Enum.GetName(typeof(VerticalAxis), value);
+ series.VertAxis = (Steema.TeeChart.Styles.VerticalAxis) Enum.Parse(typeof(Steema.TeeChart.Styles.VerticalAxis), verticalAxisName);
+ }
+ }
+
+ public bool Visible
+ {
+ get
+ {
+ return series.Visible;
+ }
+ set
+ {
+ series.Visible = value;
+ }
+ }
+
+ public bool ShowInLegend
+ {
+ get
+ {
+ return series.ShowInLegend;
+ }
+ set
+ {
+ series.ShowInLegend = value;
+ }
+ }
+
+ public double DefaultNullValue
+ {
+ get
+ {
+ return series.DefaultNullValue;
+ }
+ set
+ {
+ series.DefaultNullValue = value;
+ }
+ }
+
+ public IList NoDataValues
+ {
+ get
+ {
+ return noDataValues;
+ }
+ set
+ {
+ noDataValues = value;
+ }
+ }
+
+ public bool UpdateASynchronously { get; set; }
+
+ public object Tag { get; set; }
+
+ public bool RefreshRequired { get; private set; }
+
+ public IChart Chart { get; set; }
+
+ public abstract Color Color { get; set; }
+
+ public void CheckDataSource()
+ {
+ if (DataSource != null && (CurrencyManager == null || CurrencyManager.Count == 0))
+ {
+ return;
+ }
+
+ series.CheckDataSource();
+ }
+
+ public double XScreenToValue(int x)
+ {
+ return series.XScreenToValue(x);
+ }
+
+ public void Refresh()
+ {
+ FillValues();
+ CheckDataSource();
+ RefreshRequired = false;
+ }
+
+ public void Add(DateTime dateTime, double value)
+ {
+ series.Add(dateTime, value);
+ }
+
+ public void Add(double? x, double? y)
+ {
+ series.Add(x, y);
+ }
+
+ public void Add(double?[] xValues, double?[] yValues)
+ {
+ series.Add(xValues, yValues);
+ }
+
+ public void Clear()
+ {
+ series.Clear();
+ }
+
+ protected void CopySettings(IChartSeries chartSeries)
+ {
+ Title = chartSeries.Title;
+
+ if (chartSeries.DataSource == null)
+ {
+ var teeChartSeries = ((ChartSeries) chartSeries).series;
+
+ for (int i = 0; i < teeChartSeries.XValues.Count; i++)
+ {
+ series.Add(teeChartSeries.XValues[i], teeChartSeries.YValues[i]);
+ }
+ }
+ else
+ {
+ DataSource = chartSeries.DataSource;
+ XValuesDataMember = chartSeries.XValuesDataMember;
+ YValuesDataMember = chartSeries.YValuesDataMember;
+ RefreshRequired = true;
+ }
+
+ VertAxis = chartSeries.VertAxis;
+ Visible = chartSeries.Visible;
+ ShowInLegend = chartSeries.ShowInLegend;
+ DefaultNullValue = chartSeries.DefaultNullValue;
+ noDataValues = new List(chartSeries.NoDataValues);
+ UpdateASynchronously = chartSeries.UpdateASynchronously;
+ Color = chartSeries.Color;
+
+ if (series is CustomPoint && chartSeries.Chart != null && chartSeries.Chart.StackSeries)
+ {
+ ((CustomPoint) series).Stacked = CustomStack.Stack;
+ }
+ }
+
+ private BindingContext BindingContext
+ {
+ get
+ {
+ if (bindingContext == null)
+ {
+ bindingContext = new BindingContext();
+ }
+
+ return bindingContext;
+ }
+ }
+
+ private CurrencyManager CurrencyManager
+ {
+ get
+ {
+ if (dataMember == null)
+ {
+ dataMember = String.Empty;
+ }
+
+ if (DataSource == null)
+ {
+ return null;
+ }
+
+ return (CurrencyManager) BindingContext[DataSource, dataMember];
+ }
+ }
+
+ private void SetDefaultPointerStyle(SeriesPointer seriesPointer)
+ {
+ seriesPointer.Pen.Color = Color.LimeGreen;
+ seriesPointer.Brush = new ChartBrush(series.Chart, Color.White);
+ seriesPointer.Pen.Width = 1;
+ seriesPointer.Style = Steema.TeeChart.Styles.PointerStyles.Circle;
+ seriesPointer.VertSize = 1;
+ seriesPointer.HorizSize = 1;
+ seriesPointer.Visible = true;
+ }
+
+ private void Bind()
+ {
+ if (DataSource == null || CurrencyManager == null)
+ {
+ return; // no binding
+ }
+
+ foreach (PropertyDescriptor property in CurrencyManager.GetItemProperties())
+ {
+ if (!property.IsBrowsable)
+ {
+ continue;
+ }
+
+ if (property.DisplayName == XValuesDataMember)
+ {
+ xPropertyDescriptor = property;
+
+ if (property.PropertyType == typeof(DateTime))
+ {
+ //log.Warn("TODO: set axis type to date time");
+ }
+ }
+
+ if (property.DisplayName == YValuesDataMember)
+ {
+ yPropertyDescriptor = property;
+ }
+ }
+
+ if (xPropertyDescriptor == null || yPropertyDescriptor == null)
+ {
+ return; // nothing to bind to yet
+ }
+
+ FillValues();
+
+ //synchronize the changed code since it should run in the UI thread.
+ CurrencyManager.ListChanged += CurrencyManagerListChanged; //OnListChanged;
+
+ CheckDataSource();
+ }
+
+ private void CurrencyManagerListChanged(object sender, ListChangedEventArgs e)
+ {
+ OnListChanged();
+ }
+
+ private void FillValues()
+ {
+ series.Clear();
+ foreach (object element in CurrencyManager.List)
+ {
+ Add(xPropertyDescriptor.GetValue(element), yPropertyDescriptor.GetValue(element));
+ }
+ }
+
+ private void Add(object x, object y)
+ {
+ if (x == null || y == null)
+ {
+ return;
+ }
+
+ int addedIndex;
+
+ bool xIsNumeric = xPropertyDescriptor.PropertyType == typeof(double) ||
+ xPropertyDescriptor.PropertyType == typeof(float) ||
+ xPropertyDescriptor.PropertyType == typeof(short) ||
+ xPropertyDescriptor.PropertyType == typeof(int) ||
+ xPropertyDescriptor.PropertyType == typeof(bool);
+
+ bool yIsNumeric = yPropertyDescriptor.PropertyType == typeof(double) ||
+ yPropertyDescriptor.PropertyType == typeof(float) ||
+ yPropertyDescriptor.PropertyType == typeof(short) ||
+ yPropertyDescriptor.PropertyType == typeof(int) ||
+ yPropertyDescriptor.PropertyType == typeof(bool);
+
+ bool xIsDateTime = xPropertyDescriptor.PropertyType == typeof(DateTime);
+
+ if (!yIsNumeric)
+ {
+ throw new NotSupportedException(String.Format(Resources.ChartSeries_Add_Input_format_not_supported_y_must_be_numeric_but_is_of_type_0_, y.GetType()));
+ }
+
+ double yValue = Convert.ToDouble(y);
+ double yValueToSet = Double.IsNaN(yValue) ? 0.0 : yValue;
+
+ if (xIsNumeric)
+ {
+ double xValue = Convert.ToDouble(x);
+ addedIndex = series.Add(xValue, yValueToSet);
+ }
+ else if (xIsDateTime)
+ {
+ addedIndex = series.Add((DateTime) x, yValueToSet);
+ }
+ else //x is something non-numeric, so use the index here
+ {
+ addedIndex = series.Add((double) series.XValues.Count - 1, yValueToSet, x.ToString());
+ }
+
+ if (NoDataValues.Contains(yValue) || Double.IsNaN(yValue))
+ {
+ series.SetNull(addedIndex); //make sure we don't actually display the added point
+ }
+ }
+
+ private void Unbind()
+ {
+ if (DataSource == null)
+ {
+ return;
+ }
+
+ CurrencyManager.ListChanged -= CurrencyManagerListChanged;
+
+ xPropertyDescriptor = null;
+ yPropertyDescriptor = null;
+ }
+
+ private void OnListChanged()
+ {
+ if (UpdateASynchronously)
+ {
+ RefreshRequired = true;
+ }
+ else
+ {
+ //synchronous update immediately
+ FillValues();
+ CheckDataSource();
+ }
+ }
+ }
+}
\ No newline at end of file
Index: Core/Common/src/Core.Common.Controls.Charting/Series/ChartSeriesFactory.cs
===================================================================
diff -u
--- Core/Common/src/Core.Common.Controls.Charting/Series/ChartSeriesFactory.cs (revision 0)
+++ Core/Common/src/Core.Common.Controls.Charting/Series/ChartSeriesFactory.cs (revision 3bfa4dc5fb5ea3560752479de86cb843419f8fe3)
@@ -0,0 +1,43 @@
+using System;
+using Core.Common.Controls.Charting.Properties;
+
+namespace Core.Common.Controls.Charting.Series
+{
+ public static class ChartSeriesFactory
+ {
+ public static ILineChartSeries CreateLineSeries(IChartSeries baseSeries = null)
+ {
+ return baseSeries != null
+ ? new LineChartSeries(baseSeries)
+ : new LineChartSeries();
+ }
+
+ public static IPointChartSeries CreatePointSeries(IChartSeries baseSeries = null)
+ {
+ return baseSeries != null
+ ? new PointChartSeries(baseSeries)
+ : new PointChartSeries();
+ }
+
+ public static IAreaChartSeries CreateAreaSeries(IChartSeries baseSeries = null)
+ {
+ return baseSeries != null
+ ? new AreaChartSeries(baseSeries)
+ : new AreaChartSeries();
+ }
+
+ public static IChartSeries CreateBarSeries(IChartSeries baseSeries = null)
+ {
+ return baseSeries != null
+ ? new BarSeries(baseSeries)
+ : new BarSeries();
+ }
+
+ public static IPolygonChartSeries CreatePolygonSeries(IChartSeries baseSeries = null)
+ {
+ return baseSeries != null
+ ? new PolygonChartSeries(baseSeries)
+ : new PolygonChartSeries();
+ }
+ }
+}
\ No newline at end of file
Index: Core/Common/src/Core.Common.Controls.Charting/Series/ChartSeriesType.cs
===================================================================
diff -u
--- Core/Common/src/Core.Common.Controls.Charting/Series/ChartSeriesType.cs (revision 0)
+++ Core/Common/src/Core.Common.Controls.Charting/Series/ChartSeriesType.cs (revision 3bfa4dc5fb5ea3560752479de86cb843419f8fe3)
@@ -0,0 +1,11 @@
+namespace Core.Common.Controls.Charting.Series
+{
+ public enum ChartSeriesType
+ {
+ PointSeries,
+ LineSeries,
+ AreaSeries,
+ BarSeries,
+ PolygonSeries
+ }
+}
\ No newline at end of file
Index: Core/Common/src/Core.Common.Controls.Charting/Series/IAreaChartSeries.cs
===================================================================
diff -u
--- Core/Common/src/Core.Common.Controls.Charting/Series/IAreaChartSeries.cs (revision 0)
+++ Core/Common/src/Core.Common.Controls.Charting/Series/IAreaChartSeries.cs (revision 3bfa4dc5fb5ea3560752479de86cb843419f8fe3)
@@ -0,0 +1,78 @@
+using System.Drawing;
+using System.Drawing.Drawing2D;
+
+namespace Core.Common.Controls.Charting.Series
+{
+ public interface IAreaChartSeries : IChartSeries
+ {
+ ///
+ /// Style to use for the hatch brush
+ ///
+ HatchStyle HatchStyle { get; set; }
+
+ ///
+ /// Color used for drawing with Hatch
+ ///
+ Color HatchColor { get; set; }
+
+ ///
+ /// Use hatch brush or solid brush
+ ///
+ bool UseHatch { get; set; }
+
+ ///
+ /// Transparency of the series
+ ///
+ int Transparency { get; set; }
+
+ ///
+ /// Type of interpolation to use (constant, linear or none)
+ ///
+ InterpolationType InterpolationType { get; set; }
+
+ ///
+ /// Color of the line above the area
+ ///
+ Color LineColor { get; set; }
+
+ ///
+ /// Width of the line above the area
+ ///
+ int LineWidth { get; set; }
+
+ ///
+ /// Visibility of the line above the area
+ ///
+ bool LineVisible { get; set; }
+
+ ///
+ /// Pointer color
+ ///
+ Color PointerColor { get; set; }
+
+ ///
+ /// Visibility of pointer
+ ///
+ bool PointerVisible { get; set; }
+
+ ///
+ /// Size of the points
+ ///
+ int PointerSize { get; set; }
+
+ ///
+ /// Figure (style) to use for the points
+ ///
+ PointerStyles PointerStyle { get; set; }
+
+ ///
+ /// Color of the line around the points
+ ///
+ Color PointerLineColor { get; set; }
+
+ ///
+ /// Show a line around the points
+ ///
+ bool PointerLineVisible { get; set; }
+ }
+}
\ No newline at end of file
Index: Core/Common/src/Core.Common.Controls.Charting/Series/ILineChartSeries.cs
===================================================================
diff -u
--- Core/Common/src/Core.Common.Controls.Charting/Series/ILineChartSeries.cs (revision 0)
+++ Core/Common/src/Core.Common.Controls.Charting/Series/ILineChartSeries.cs (revision 3bfa4dc5fb5ea3560752479de86cb843419f8fe3)
@@ -0,0 +1,58 @@
+using System.Drawing;
+using System.Drawing.Drawing2D;
+
+namespace Core.Common.Controls.Charting.Series
+{
+ public interface ILineChartSeries : IChartSeries
+ {
+ ///
+ /// Width of the line
+ ///
+ int Width { get; set; }
+
+ ///
+ /// Dash style of the line
+ ///
+ DashStyle DashStyle { get; set; }
+
+ ///
+ /// Pointer color
+ ///
+ Color PointerColor { get; set; }
+
+ ///
+ /// Visibility of pointer
+ ///
+ bool PointerVisible { get; set; }
+
+ ///
+ /// Size of the line points
+ ///
+ int PointerSize { get; set; }
+
+ ///
+ /// Figure (style) to use for the points
+ ///
+ PointerStyles PointerStyle { get; set; }
+
+ ///
+ /// Type of interpolation to use (constant, linear or none)
+ ///
+ InterpolationType InterpolationType { get; set; }
+
+ ///
+ /// Show title of the series as label
+ ///
+ bool TitleLabelVisible { get; set; }
+
+ ///
+ /// Color of the line around the points
+ ///
+ Color PointerLineColor { get; set; }
+
+ ///
+ /// Show a line around the points
+ ///
+ bool PointerLineVisible { get; set; }
+ }
+}
\ No newline at end of file
Index: Core/Common/src/Core.Common.Controls.Charting/Series/IPointChartSeries.cs
===================================================================
diff -u
--- Core/Common/src/Core.Common.Controls.Charting/Series/IPointChartSeries.cs (revision 0)
+++ Core/Common/src/Core.Common.Controls.Charting/Series/IPointChartSeries.cs (revision 3bfa4dc5fb5ea3560752479de86cb843419f8fe3)
@@ -0,0 +1,27 @@
+using System.Drawing;
+
+namespace Core.Common.Controls.Charting.Series
+{
+ public interface IPointChartSeries : IChartSeries
+ {
+ ///
+ /// Size of the points
+ ///
+ int Size { get; set; }
+
+ ///
+ /// Figure (style) to use for the points
+ ///
+ PointerStyles Style { get; set; }
+
+ ///
+ /// Show a line around the points
+ ///
+ bool LineVisible { get; set; }
+
+ ///
+ /// Color of the line around the points
+ ///
+ Color LineColor { get; set; }
+ }
+}
\ No newline at end of file
Index: Core/Common/src/Core.Common.Controls.Charting/Series/IPolygonChartSeries.cs
===================================================================
diff -u
--- Core/Common/src/Core.Common.Controls.Charting/Series/IPolygonChartSeries.cs (revision 0)
+++ Core/Common/src/Core.Common.Controls.Charting/Series/IPolygonChartSeries.cs (revision 3bfa4dc5fb5ea3560752479de86cb843419f8fe3)
@@ -0,0 +1,78 @@
+using System.Drawing;
+using System.Drawing.Drawing2D;
+
+namespace Core.Common.Controls.Charting.Series
+{
+ public interface IPolygonChartSeries : IChartSeries
+ {
+ // TODO: Add support for points
+ ///
+ /// Style to use for the hatch brush
+ ///
+ HatchStyle HatchStyle { get; set; }
+
+ ///
+ /// Color used for drawing with Hatch
+ ///
+ Color HatchColor { get; set; }
+
+ ///
+ /// Use hatch brush or solid brush
+ ///
+ bool UseHatch { get; set; }
+
+ ///
+ /// Transparency of the series (percentage)
+ ///
+ int Transparency { get; set; }
+
+ ///
+ /// Color of the line above the area
+ ///
+ Color LineColor { get; set; }
+
+ ///
+ /// Width of the line above the area
+ ///
+ int LineWidth { get; set; }
+
+ ///
+ /// Visibility of the line above the area
+ ///
+ bool LineVisible { get; set; }
+
+ DashStyle LineStyle { get; set; }
+
+ bool AutoClose { get; set; }
+
+ /*///
+ /// Pointer color
+ ///
+ Color PointerColor { get; set; }
+
+ ///
+ /// Visibility of pointer
+ ///
+ bool PointerVisible { get; set; }
+
+ ///
+ /// Size of the points
+ ///
+ int PointerSize { get; set; }
+
+ ///
+ /// Figure (style) to use for the points
+ ///
+ PointerStyles PointerStyle { get; set; }
+
+ ///
+ /// Color of the line around the points
+ ///
+ Color PointerLineColor { get; set; }
+
+ ///
+ /// Show a line around the points
+ ///
+ bool PointerLineVisible { get; set; }*/
+ }
+}
\ No newline at end of file
Index: Core/Common/src/Core.Common.Controls.Charting/Series/LineChartSeries.cs
===================================================================
diff -u
--- Core/Common/src/Core.Common.Controls.Charting/Series/LineChartSeries.cs (revision 0)
+++ Core/Common/src/Core.Common.Controls.Charting/Series/LineChartSeries.cs (revision 3bfa4dc5fb5ea3560752479de86cb843419f8fe3)
@@ -0,0 +1,228 @@
+using System;
+using System.Drawing;
+using System.Drawing.Drawing2D;
+using Core.Common.Utils;
+using Steema.TeeChart.Styles;
+
+namespace Core.Common.Controls.Charting.Series
+{
+ ///
+ /// LineChartSeries is represented by a line in a chart.
+ ///
+ public class LineChartSeries : ChartSeries, ILineChartSeries
+ {
+ private readonly Line lineSeries;
+ private InterpolationType interpolationType;
+
+ public LineChartSeries() : base(new Line())
+ {
+ lineSeries = (Line) series;
+
+ lineSeries.ColorEachLine = true;
+ lineSeries.ClickableLine = true;
+
+ lineSeries.GetSeriesMark += (s, e) => e.MarkText = Title;
+ }
+
+ public LineChartSeries(IChartSeries chartSeries) : this()
+ {
+ CopySettings(chartSeries);
+ }
+
+ public override Color Color
+ {
+ get
+ {
+ return lineSeries.Color;
+ }
+ set
+ {
+ lineSeries.Color = value;
+ }
+ }
+
+ public int Width
+ {
+ get
+ {
+ return lineSeries.LinePen.Width;
+ }
+ set
+ {
+ lineSeries.LinePen.Width = MathUtils.ClipValue(value, MinimumAllowedSize, MaximumAllowedSize);
+ }
+ }
+
+ public DashStyle DashStyle
+ {
+ get
+ {
+ return lineSeries.LinePen.Style;
+ }
+ set
+ {
+ lineSeries.LinePen.Style = value;
+ }
+ }
+
+ public float[] DashPattern
+ {
+ get
+ {
+ return lineSeries.LinePen.DashPattern;
+ }
+ set
+ {
+ lineSeries.LinePen.DashPattern = value;
+ }
+ }
+
+ public Color PointerColor
+ {
+ get
+ {
+ return lineSeries.Pointer.Brush.Color;
+ }
+ set
+ {
+ lineSeries.Pointer.Brush.Color = value;
+ }
+ }
+
+ public bool PointerVisible
+ {
+ get
+ {
+ return lineSeries.Pointer.Visible;
+ }
+ set
+ {
+ lineSeries.Pointer.Visible = value;
+ }
+ }
+
+ public int PointerSize
+ {
+ get
+ {
+ return lineSeries.Pointer.VertSize;
+ }
+ set
+ {
+ // just keep it square at this moment.
+ lineSeries.Pointer.VertSize = MathUtils.ClipValue(value, MinimumAllowedSize, MaximumAllowedSize);
+ lineSeries.Pointer.HorizSize = MathUtils.ClipValue(value, MinimumAllowedSize, MaximumAllowedSize);
+ }
+ }
+
+ public PointerStyles PointerStyle
+ {
+ get
+ {
+ string enumName = Enum.GetName(typeof(Steema.TeeChart.Styles.PointerStyles), lineSeries.Pointer.Style);
+ return (PointerStyles) Enum.Parse(typeof(PointerStyles), enumName);
+ }
+ set
+ {
+ string enumName = Enum.GetName(typeof(PointerStyles), value);
+ lineSeries.Pointer.Style =
+ (Steema.TeeChart.Styles.PointerStyles)
+ Enum.Parse(typeof(Steema.TeeChart.Styles.PointerStyles), enumName);
+ }
+ }
+
+ public InterpolationType InterpolationType
+ {
+ get
+ {
+ return interpolationType;
+ }
+ set
+ {
+ interpolationType = value;
+ lineSeries.Stairs = (value == InterpolationType.Constant);
+ }
+ }
+
+ public bool TitleLabelVisible
+ {
+ get
+ {
+ return lineSeries.Marks.Visible;
+ }
+ set
+ {
+ lineSeries.Marks.Visible = value;
+ lineSeries.Marks.Text = Title;
+ }
+ }
+
+ public bool XValuesDateTime
+ {
+ get
+ {
+ return lineSeries.XValues.DateTime;
+ }
+ set
+ {
+ lineSeries.XValues.DateTime = value;
+ }
+ }
+
+ public Color PointerLineColor
+ {
+ get
+ {
+ return lineSeries.Pointer.Pen.Color;
+ }
+ set
+ {
+ lineSeries.Pointer.Pen.Color = value;
+ }
+ }
+
+ public bool PointerLineVisible
+ {
+ get
+ {
+ return lineSeries.Pointer.Pen.Visible;
+ }
+ set
+ {
+ lineSeries.Pointer.Pen.Visible = value;
+ }
+ }
+
+ public int Transparency
+ {
+ get
+ {
+ return lineSeries.Transparency;
+ }
+ set
+ {
+ lineSeries.Transparency = value;
+ }
+ }
+
+ public double MaxYValue()
+ {
+ return lineSeries.MaxYValue();
+ }
+
+ public double MinYValue()
+ {
+ return lineSeries.MinYValue();
+ }
+
+ public double CalcXPos(int index)
+ {
+ return lineSeries.CalcXPos(index);
+ }
+
+ public double CalcYPos(int index)
+ {
+ return lineSeries.CalcYPos(index);
+ }
+ }
+}
\ No newline at end of file
Index: Core/Common/src/Core.Common.Controls.Charting/Series/PointChartSeries.cs
===================================================================
diff -u
--- Core/Common/src/Core.Common.Controls.Charting/Series/PointChartSeries.cs (revision 0)
+++ Core/Common/src/Core.Common.Controls.Charting/Series/PointChartSeries.cs (revision 3bfa4dc5fb5ea3560752479de86cb843419f8fe3)
@@ -0,0 +1,90 @@
+using System;
+using System.Drawing;
+using Core.Common.Utils;
+using Steema.TeeChart.Styles;
+
+namespace Core.Common.Controls.Charting.Series
+{
+ ///
+ /// Series to display points on a chart
+ ///
+ public class PointChartSeries : ChartSeries, IPointChartSeries
+ {
+ private readonly Points pointSeries;
+
+ public PointChartSeries() : base(new Points())
+ {
+ pointSeries = (Points) series;
+ LineVisible = false;
+ }
+
+ public PointChartSeries(IChartSeries chartSeries) : this()
+ {
+ CopySettings(chartSeries);
+ }
+
+ public override Color Color
+ {
+ get
+ {
+ return pointSeries.Pointer.Brush.Color;
+ }
+ set
+ {
+ pointSeries.Pointer.Brush.Color = value;
+ }
+ }
+
+ public int Size
+ {
+ get
+ {
+ return pointSeries.Pointer.VertSize;
+ }
+ set
+ {
+ // just keep it square at this moment.
+ pointSeries.Pointer.VertSize = MathUtils.ClipValue(value, MinimumAllowedSize, MaximumAllowedSize);
+ pointSeries.Pointer.HorizSize = MathUtils.ClipValue(value, MinimumAllowedSize, MaximumAllowedSize);
+ }
+ }
+
+ public PointerStyles Style
+ {
+ get
+ {
+ string enumName = Enum.GetName(typeof(Steema.TeeChart.Styles.PointerStyles), pointSeries.Pointer.Style);
+ return (PointerStyles) Enum.Parse(typeof(PointerStyles), enumName);
+ }
+ set
+ {
+ string enumName = Enum.GetName(typeof(PointerStyles), value);
+ pointSeries.Pointer.Style = (Steema.TeeChart.Styles.PointerStyles) Enum.Parse(typeof(Steema.TeeChart.Styles.PointerStyles), enumName);
+ }
+ }
+
+ public bool LineVisible
+ {
+ get
+ {
+ return pointSeries.Pointer.Pen.Visible;
+ }
+ set
+ {
+ pointSeries.Pointer.Pen.Visible = value;
+ }
+ }
+
+ public Color LineColor
+ {
+ get
+ {
+ return pointSeries.Pointer.Pen.Color;
+ }
+ set
+ {
+ pointSeries.Pointer.Pen.Color = value;
+ }
+ }
+ }
+}
\ No newline at end of file
Index: Core/Common/src/Core.Common.Controls.Charting/Series/PolygonChartSeries.cs
===================================================================
diff -u
--- Core/Common/src/Core.Common.Controls.Charting/Series/PolygonChartSeries.cs (revision 0)
+++ Core/Common/src/Core.Common.Controls.Charting/Series/PolygonChartSeries.cs (revision 3bfa4dc5fb5ea3560752479de86cb843419f8fe3)
@@ -0,0 +1,163 @@
+using System;
+using System.Drawing;
+using System.Drawing.Drawing2D;
+using Core.Common.Controls.Charting.Properties;
+using Core.Common.Utils;
+
+namespace Core.Common.Controls.Charting.Series
+{
+ public class PolygonChartSeries : ChartSeries, IPolygonChartSeries
+ {
+ private readonly PolygonSeries polygonSeries;
+
+ public PolygonChartSeries(IChartSeries chartSeries) : this()
+ {
+ CopySettings(chartSeries);
+ ChartStyleHelper.CopySeriesStyles(chartSeries, this);
+ Tag = chartSeries.Tag;
+ }
+
+ public PolygonChartSeries() : base(new PolygonSeries())
+ {
+ polygonSeries = (PolygonSeries) series;
+ DefaultNullValue = double.NaN;
+ }
+
+ public override Color Color
+ {
+ get
+ {
+ return series.Color;
+ }
+ set
+ {
+ series.Color = value;
+
+ // also need to set AreaBrush color because TeeChart will otherwise
+ // throw an error (brush == null)
+ (polygonSeries).bBrush.Color = value;
+ }
+ }
+
+ public Color LineColor
+ {
+ get
+ {
+ return polygonSeries.Pen.Color;
+ }
+ set
+ {
+ polygonSeries.Pen.Color = value;
+ }
+ }
+
+ public int LineWidth
+ {
+ get
+ {
+ return polygonSeries.Pen.Width;
+ }
+ set
+ {
+ polygonSeries.Pen.Width = MathUtils.ClipValue(value, MinimumAllowedSize, MaximumAllowedSize);
+ }
+ }
+
+ public bool LineVisible
+ {
+ get
+ {
+ return polygonSeries.Pen.Visible;
+ }
+ set
+ {
+ polygonSeries.Pen.Visible = value;
+ polygonSeries.Repaint();
+ }
+ }
+
+ public DashStyle LineStyle
+ {
+ get
+ {
+ return polygonSeries.Pen.Style;
+ }
+ set
+ {
+ polygonSeries.Pen.Style = value;
+ }
+ }
+
+ public bool AutoClose
+ {
+ get
+ {
+ return polygonSeries.AutoClose;
+ }
+ set
+ {
+ polygonSeries.AutoClose = value;
+ }
+ }
+
+ # region Hatch
+
+ public HatchStyle HatchStyle
+ {
+ get
+ {
+ return polygonSeries.bBrush.Style;
+ }
+ set
+ {
+ polygonSeries.bBrush.Style = value;
+ }
+ }
+
+ public Color HatchColor
+ {
+ get
+ {
+ return polygonSeries.bBrush.ForegroundColor;
+ }
+ set
+ {
+ polygonSeries.bBrush.ForegroundColor = value;
+ }
+ }
+
+ public bool UseHatch
+ {
+ get
+ {
+ return !polygonSeries.bBrush.Solid;
+ }
+ set
+ {
+ polygonSeries.bBrush.Solid = !value;
+ }
+ }
+
+ ///
+ /// Percentage transparancy. This should be between 0 and 100.
+ ///
+ public int Transparency
+ {
+ get
+ {
+ return polygonSeries.Pen.Transparency;
+ }
+ set
+ {
+ if (value < 0 || value > 100)
+ {
+ throw new ArgumentOutOfRangeException("value", Resources.PolygonChartSeries_Transparency_Transparancy_should_be_between_0_and_100);
+ }
+ polygonSeries.Pen.Transparency = value;
+ polygonSeries.bBrush.Transparency = value;
+ }
+ }
+
+ # endregion
+ }
+}
\ No newline at end of file
Index: Core/Common/src/Core.Common.Controls.Charting/Series/PolygonSeries.cs
===================================================================
diff -u
--- Core/Common/src/Core.Common.Controls.Charting/Series/PolygonSeries.cs (revision 0)
+++ Core/Common/src/Core.Common.Controls.Charting/Series/PolygonSeries.cs (revision 3bfa4dc5fb5ea3560752479de86cb843419f8fe3)
@@ -0,0 +1,156 @@
+using System;
+using System.Collections.Generic;
+using System.Drawing;
+using System.Drawing.Drawing2D;
+using System.Linq;
+using Core.Common.Controls.Charting.Properties;
+using Steema.TeeChart.Drawing;
+
+namespace Core.Common.Controls.Charting.Series
+{
+ ///
+ /// TeeChart wrapper class to fix PolygonSeries when drawn into a 2D axes (was meant for drawing on a Map).
+ ///
+ internal class PolygonSeries : Steema.TeeChart.Styles.PolygonSeries
+ {
+ private bool autoClose;
+
+ ///
+ /// Closes the polygon automatically when true.
+ ///
+ public bool AutoClose
+ {
+ get
+ {
+ return autoClose;
+ }
+ set
+ {
+ autoClose = value;
+ Repaint();
+ }
+ }
+
+ ///
+ /// Override Draw method and use the TeeChart Graphics3D object to draw the polygon shape
+ ///
+ public override void Draw()
+ {
+ if (XValues.Count < 2)
+ {
+ return;
+ }
+
+ if (XValues.Count != YValues.Count)
+ {
+ // Just to be sure. I think TeeChart already accounts for this in Add methods.
+ throw new Exception(Resources.PolygonSeries_Draw_Number_of_X_values_should_be_equal_to_the_number_of_Y_values);
+ }
+
+ var g = Chart.Graphics3D;
+ PrepareGraphics3D(g);
+
+ g.ClipRectangle(Chart.ChartBounds);
+
+ // Draw polygon groups:
+ foreach (var pointList in GetDrawingPoints())
+ {
+ g.Polygon(pointList);
+ }
+
+ g.UnClip();
+ }
+
+ ///
+ /// Override DrawLegendShape because it includes a call to Polygon().ParentShape.... which is null if we do not use Polygon to create it.
+ ///
+ ///
+ ///
+ ///
+ protected override void DrawLegendShape(Graphics3D g, int valueIndex, Rectangle rect)
+ {
+ PrepareGraphics3D(g);
+
+ var oldWidth = 1;
+ if (g.Pen.Visible)
+ {
+ oldWidth = g.Pen.Width;
+ g.Pen.Width = 1;
+ }
+
+ base.DrawLegendShape(g, valueIndex, rect);
+
+ if (g.Pen.Visible)
+ {
+ g.Pen.Width = oldWidth;
+ }
+ }
+
+ ///
+ /// Override SetActive because it includes a call to Polygon().ParentShape.... which is null if we do not use Polygon to create it.
+ ///
+ ///
+ protected override void SetActive(bool value)
+ {
+ SetBooleanProperty(ref bActive, value);
+ }
+
+ ///
+ /// Override PrepareLegendCanvas because it includes a call to Polygon().ParentShape.... which is null if we do not use Polygon to create it.
+ ///
+ ///
+ ///
+ ///
+ ///
+ protected override void PrepareLegendCanvas(Graphics3D g, int valueIndex, ref Color backColor, ref ChartBrush aBrush) {}
+
+ private void PrepareGraphics3D(Graphics3D g)
+ {
+ g.Pen = Pen;
+ g.Brush = bBrush;
+ g.Pen.DrawingPen.LineJoin = LineJoin.Round;
+ }
+
+ private IEnumerable GetDrawingPoints()
+ {
+ var pointGroupsToRender = new List();
+ var currentPointsGroup = new List();
+ for (int i = 0; i < XValues.Count; i++)
+ {
+ var xValue = XValues[i];
+ var yValue = YValues[i];
+ if (double.IsNaN(xValue) || double.IsNaN(yValue))
+ {
+ continue;
+ }
+ // TODO: How to distinguish null??
+ // Can cause collision when a regular value has the same value!
+ if (xValue == DefaultNullValue || yValue == DefaultNullValue)
+ {
+ AddToPointsList(pointGroupsToRender, currentPointsGroup);
+ continue;
+ }
+
+ currentPointsGroup.Add(new Point(CalcXPosValue(xValue), CalcYPosValue(yValue)));
+ }
+
+ AddToPointsList(pointGroupsToRender, currentPointsGroup);
+ return pointGroupsToRender;
+ }
+
+ private void AddToPointsList(ICollection pointGroupsToRender, List currentPointsGroup)
+ {
+ if (!currentPointsGroup.Any())
+ {
+ return; // Do nothing for empty list
+ }
+
+ if (autoClose && (currentPointsGroup[0].X != currentPointsGroup.Last().X || currentPointsGroup[0].Y != currentPointsGroup.Last().Y))
+ {
+ currentPointsGroup.Add(currentPointsGroup[0]);
+ }
+ pointGroupsToRender.Add(currentPointsGroup.ToArray());
+ currentPointsGroup.Clear();
+ }
+ }
+}
\ No newline at end of file
Index: Core/Common/src/Core.Common.Controls.Charting/TeeChartHelper.cs
===================================================================
diff -u
--- Core/Common/src/Core.Common.Controls.Charting/TeeChartHelper.cs (revision 0)
+++ Core/Common/src/Core.Common.Controls.Charting/TeeChartHelper.cs (revision 3bfa4dc5fb5ea3560752479de86cb843419f8fe3)
@@ -0,0 +1,67 @@
+using System;
+using System.Drawing;
+using System.Reflection;
+using Core.Common.Controls.Charting.Properties;
+using Core.GIS.NetTopologySuite.Utilities;
+using Steema.TeeChart.Tools;
+
+namespace Core.Common.Controls.Charting
+{
+ ///
+ /// Utility class for common functions used by chart tools
+ ///
+ public class TeeChartHelper
+ {
+ public static int GetNearestPoint(Steema.TeeChart.Styles.Series series, Point p, double tolerance)
+ {
+ int tmpMin = 0;
+ int tmpMax = 0;
+
+ int result = -1;
+ int Dif = 10000;
+
+ // Tool.GetFirstLastSeries is changed from public to internal and we do not want to modify TeeChart
+ object[] args = new object[]
+ {
+ series,
+ tmpMin,
+ tmpMax
+ };
+ MethodInfo getFirstLastSeries = typeof(Tool).GetMethod("GetFirstLastSeries", BindingFlags.Static | BindingFlags.NonPublic);
+ bool getFirstLastSeriesResult = (bool) getFirstLastSeries.Invoke(null, args);
+ // retrieve the out parameters
+ tmpMin = (int) args[1];
+ tmpMax = (int) args[2];
+ if (getFirstLastSeriesResult)
+ {
+ for (int t = tmpMin; t <= tmpMax; t++)
+ {
+ int tmpX = series.CalcXPos(t);
+ int tmpY = series.CalcYPos(t);
+ Rectangle r = series.Chart.ChartRect;
+
+ if (r.Contains(tmpX, tmpY))
+ {
+ int Dist =
+ Steema.TeeChart.Utils.Round(
+ Math.Sqrt(Steema.TeeChart.Utils.Sqr(p.X - tmpX) + Steema.TeeChart.Utils.Sqr(p.Y - tmpY)));
+
+ if (Dist < Dif && Dist < tolerance)
+ {
+ Dif = Dist;
+ result = t;
+ }
+ }
+ }
+ }
+ //THIS is done because Tool.GetFirstLastSeries(series, out tmpMin, out tmpMax)) is not documented (unable to find)
+ Assert.IsTrue(result >= -1, Resources.TeeChartHelper_GetNearestPoint_Should_not_return_indexes_below_1_);
+ return result;
+ }
+
+ public static Color DarkenColor(Color color, int percentage)
+ {
+ return Steema.TeeChart.Utils.DarkenColor(color, percentage);
+ }
+ }
+}
\ No newline at end of file
Index: Core/Common/src/Core.Common.Controls.Charting/TimeNavigatableLabelFormatProvider.cs
===================================================================
diff -u
--- Core/Common/src/Core.Common.Controls.Charting/TimeNavigatableLabelFormatProvider.cs (revision 0)
+++ Core/Common/src/Core.Common.Controls.Charting/TimeNavigatableLabelFormatProvider.cs (revision 3bfa4dc5fb5ea3560752479de86cb843419f8fe3)
@@ -0,0 +1,112 @@
+using System;
+using System.Globalization;
+
+using Core.Common.Controls.Charting.Properties;
+
+namespace Core.Common.Controls.Charting
+{
+ ///
+ /// Provides custom DateTime formatting (e.g. for use on the chart axes based on the zoom level). More detail (eg time) when zoomed in etc.
+ /// Also sets the axis title with the current zoom range. This class contains two methods that can be overwritten to implement
+ /// custom DateTime formatting behavior (eg, show Quarters instead of Months, etc).
+ ///
+ public class TimeNavigatableLabelFormatProvider
+ {
+ private static readonly string strTill = Resources.strTill;
+
+ ///
+ /// Initializes the provider, sets the default CustomDateTimeFormatInfo.
+ ///
+ public TimeNavigatableLabelFormatProvider()
+ {
+ ShowRangeLabel = true; //default
+ ShowUnits = true;
+ CustomDateTimeFormatInfo = CultureInfo.CurrentCulture.DateTimeFormat;
+ }
+
+ ///
+ /// The culture-specific CustomDateTimeFormatInfo to use when rendering the date times.
+ /// Default is the CurrentCulture.CustomDateTimeFormatInfo.
+ ///
+ public DateTimeFormatInfo CustomDateTimeFormatInfo { get; set; }
+
+ ///
+ /// Indicates whether the range label (typically with the date/time range) is shown. Default true.
+ ///
+ public virtual bool ShowRangeLabel { get; set; }
+
+ ///
+ /// Gets or sets flag indicating whether units are shown for time.
+ /// TODO: move it to FunctionBindingList (presentation facade)
+ ///
+ public bool ShowUnits { get; set; }
+
+ ///
+ /// Should be overwritten to implement custom label text for the labelValue.
+ ///
+ /// The datetime value to provide a formatted string for.
+ /// The current (zoomed) axis range. Typically if the range is large,
+ /// you can omit details such as hours and seconds.
+ ///
+ public virtual string GetLabel(DateTime labelValue, TimeSpan duration)
+ {
+ return labelValue.ToString(GetUnits(duration));
+ }
+
+ ///
+ /// Units of measure for a given duration. Not included in labels! Client code should show this units depending on ShowUnits flag.
+ ///
+ /// The current (zoomed) axis range. Typically if the range is large,
+ /// you can omit details such as hours and seconds.
+ ///
+ public virtual string GetUnits(TimeSpan duration)
+ {
+ string format;
+
+ if (duration.TotalHours < 1)
+ {
+ format = CustomDateTimeFormatInfo.LongTimePattern;
+ }
+ else if (duration.TotalDays < 1)
+ {
+ format = CustomDateTimeFormatInfo.ShortTimePattern;
+ }
+ else if (duration.TotalDays < 5)
+ {
+ format = CustomDateTimeFormatInfo.ShortDatePattern + " " + CustomDateTimeFormatInfo.ShortTimePattern;
+ }
+ else if (duration.TotalDays < 30)
+ {
+ format = CustomDateTimeFormatInfo.ShortDatePattern;
+ }
+ else
+ {
+ format = CustomDateTimeFormatInfo.YearMonthPattern;
+ }
+
+ return format;
+ }
+
+ ///
+ /// Should be overwritten to implement a custom axis title text. Requires ShowRangeLabel to be true.
+ /// If you return null, the original title is kept. Default is "date / time ([long date min] till [long date max])"
+ ///
+ /// Minimum value of axis
+ /// Maximum value of axis
+ ///
+ public virtual string GetRangeLabel(DateTime min, DateTime max)
+ {
+ TimeSpan span = max - min;
+
+ if (max.DayOfYear == min.DayOfYear && max.Year == min.Year) //same day: show only one day
+ {
+ return "(" + max.ToString(CustomDateTimeFormatInfo.LongDatePattern) + ")";
+ }
+ else
+ {
+ return "(" + min.ToString(CustomDateTimeFormatInfo.LongDatePattern) + " " + strTill + " " +
+ max.ToString(CustomDateTimeFormatInfo.LongDatePattern) + ")";
+ }
+ }
+ }
+}
\ No newline at end of file
Index: Core/Common/src/Core.Common.Controls.Charting/Tools/AddPointTool.cs
===================================================================
diff -u
--- Core/Common/src/Core.Common.Controls.Charting/Tools/AddPointTool.cs (revision 0)
+++ Core/Common/src/Core.Common.Controls.Charting/Tools/AddPointTool.cs (revision 3bfa4dc5fb5ea3560752479de86cb843419f8fe3)
@@ -0,0 +1,291 @@
+using System;
+using System.Drawing;
+using System.Windows.Forms;
+using Core.Common.Controls.Charting.Series;
+using Core.Common.Controls.Charting.Properties;
+using log4net;
+using Steema.TeeChart;
+using Steema.TeeChart.Styles;
+using Steema.TeeChart.Tools;
+
+namespace Core.Common.Controls.Charting.Tools
+{
+ ///
+ /// Tool that enables interactive adding of points to a series.
+ ///
+ public class AddPointTool : ChartViewSeriesToolBase, IAddPointTool
+ {
+ public event EventHandler PointAdded;
+ private static readonly ILog log = LogManager.GetLogger(typeof(AddPointTool));
+
+ private MouseButtons button = MouseButtons.Left;
+ private bool dragging = false;
+
+ ///
+ /// Tool that enables interactive adding of points to a series.
+ ///
+ ///
+ public AddPointTool(Steema.TeeChart.Chart c) : base(c)
+ {
+ Cursor = Cursors.Hand; //default
+ }
+
+ ///
+ /// Tool that enables interactive adding of points to a series.
+ ///
+ public AddPointTool() : this(null) {}
+
+ ///
+ /// Gets descriptive text.
+ ///
+ public override string Description
+ {
+ get
+ {
+ return "AddPoint";
+ }
+ }
+
+ ///
+ /// Gets detailed descriptive text.
+ ///
+ public override string Summary
+ {
+ get
+ {
+ return Texts.DragPointSummary;
+ }
+ }
+
+ public bool Insert { get; set; }
+
+ ///
+ /// Sets which mousebutton activates DragPoint.
+ ///
+ public MouseButtons Button
+ {
+ get
+ {
+ return button;
+ }
+ set
+ {
+ button = value;
+ }
+ }
+
+ ///
+ /// Determines the type of DragPoint Cursor displayed.
+ ///
+ public Cursor Cursor { get; set; }
+
+ public bool AddOnlyIfOnLine { get; set; }
+
+ public ILineChartSeries Series
+ {
+ get
+ {
+ return (ILineChartSeries) base.Series;
+ }
+ set
+ {
+ base.Series = value;
+ }
+ }
+
+ protected override void Assign(Tool t)
+ {
+ base.Assign(t);
+ AddPointTool tmp = t as AddPointTool;
+ tmp.Button = Button;
+ tmp.Cursor = Cursor;
+ //tmp.Style = Style;
+ }
+
+ protected override void OnMouseMove(MouseEventArgs e, ref Cursor c)
+ {
+ Point P = new Point(e.X, e.Y);
+ if (!dragging)
+ {
+ Steema.TeeChart.Styles.Series s = ClickedSeries(P);
+
+ if (s != null)
+ {
+ int abovePoint = s.Clicked(P);
+ if (abovePoint > -1)
+ {
+ c = Cursor;
+ //new Cursor(Assembly.GetExecutingAssembly().GetManifestResourceStream("Steema.TeeChart.Cursors.moveTracker.cur"));
+ }
+ Chart.CancelMouse = true;
+ }
+ else
+ {
+ c = Cursors.Default;
+ }
+ }
+ }
+
+ protected override void OnMouseUp(MouseEventArgs e)
+ {
+ dragging = false;
+ }
+
+ protected override void OnMouseDown(MouseEventArgs e)
+ {
+ Point p = new Point(e.X, e.Y);
+ //button == Button.Left
+ if (Steema.TeeChart.Utils.GetMouseButton(e) == button)
+ {
+ dragging = false;
+
+ if (LastSelectedSeries == null)
+ {
+ foreach (Steema.TeeChart.Styles.Series s in Chart.Series)
+ {
+ if (s.Active)
+ {
+ dragging = (s.Clicked(p) != -1);
+ if (dragging)
+ {
+ LastSelectedSeries = s;
+ break;
+ }
+ }
+ }
+ }
+
+ if (LastSelectedSeries != null)
+ {
+ {
+ if (AddOnlyIfOnLine && !IsPointOnLine(new Point(e.X, e.Y)))
+ {
+ return;
+ }
+
+ //check if user clicked near enough to line.
+ //calculate real x value from screen value
+
+ double x = LastSelectedSeries.XScreenToValue(e.X);
+
+ //interpolate y value
+ double y = LastSelectedSeries.YScreenToValue(e.Y);
+
+ //add/insert point to the series
+ string oldOrderName = Enum.GetName(typeof(ValueListOrder), LastSelectedSeries.XValues.Order);
+
+ LastSelectedSeries.XValues.Order = ValueListOrder.None; // .Ascending;
+ if (x > Chart.Axes.Bottom.MinXValue
+ && x < Chart.Axes.Bottom.MaxXValue
+ && y > Chart.Axes.Left.MinYValue
+ && y < Chart.Axes.Left.MaxYValue
+ )
+ {
+ // y = LinearInterPolation(theSeries.XValues, theSeries.YValues, x);
+ if (Insert)
+ {
+ // do not use nearest point but try to calculate nearest line segment
+ double minDistance = double.MaxValue;
+ int minIndex = -1;
+ for (int i = 1; i < LastSelectedSeries.XValues.Count; i++)
+ {
+ double dist = LinePointDistance(LastSelectedSeries.XValues[i - 1], LastSelectedSeries.YValues[i - 1],
+ LastSelectedSeries.XValues[i], LastSelectedSeries.YValues[i],
+ x, y);
+ if (dist < minDistance)
+ {
+ minDistance = dist;
+ minIndex = i;
+ }
+ }
+ LastSelectedSeries.Add(x, y);
+ if (PointAdded != null)
+ {
+ PointAdded(this, new PointEventArgs(GetChartSeriesFromInternalSeries(LastSelectedSeries), minIndex, x, y));
+ }
+ }
+ else
+ {
+ int index = LastSelectedSeries.Add(x, y);
+
+ //notify listeners a point was inserted.
+
+ if (PointAdded != null)
+ {
+ PointAdded(this, new PointEventArgs(GetChartSeriesFromInternalSeries(LastSelectedSeries), index, x, y));
+ }
+ }
+ }
+ LastSelectedSeries.XValues.Order = (ValueListOrder) Enum.Parse(typeof(ValueListOrder), oldOrderName);
+ }
+ }
+ }
+ }
+
+ private bool IsPointOnLine(Point clickedPoint)
+ {
+ Steema.TeeChart.Styles.Series s = ClickedSeries(clickedPoint);
+
+ if (s != null)
+ {
+ int abovePoint = s.Clicked(clickedPoint);
+ if (abovePoint > -1)
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ // HACK
+ private static double Distance(double x1, double y1, double X2, double Y2)
+ {
+ return Math.Sqrt((x1 - X2)*(x1 - X2) + (y1 - Y2)*(y1 - Y2));
+ }
+
+ private static double CrossProduct(double Ax, double Ay, double Bx, double By,
+ double cx, double cy)
+ {
+ return (Bx - Ax)*(cy - Ay) - (By - Ay)*(cx - Ax);
+ }
+
+ private static double Dot(double Ax, double Ay, double Bx, double By,
+ double cx, double cy)
+ {
+ return (Bx - Ax)*(cx - Bx) + (By - Ay)*(cy - By);
+ }
+
+ private static double LinePointDistance(double Ax, double Ay, double Bx, double By,
+ double cx, double cy)
+ {
+ var dist = Distance(Ax, Ay, Bx, By);
+ if (dist < 0.000001)
+ {
+ return double.MaxValue;
+ }
+ dist = CrossProduct(Ax, Ay, Bx, By, cx, cy)/dist;
+ // if (isSegment) always true
+ var dot1 = Dot(Ax, Ay, Bx, By, cx, cy);
+ if (dot1 > 0)
+ {
+ return Distance(Bx, By, cx, cy);
+ }
+ var dot2 = Dot(Bx, By, Ax, Ay, cx, cy);
+ if (dot2 > 0)
+ {
+ return Distance(Ax, Ay, cx, cy);
+ }
+ return Math.Abs(dist);
+ }
+ }
+
+ public interface IAddPointTool : IChartViewTool
+ {
+ event EventHandler PointAdded;
+ MouseButtons Button { get; set; }
+ Cursor Cursor { get; set; }
+ bool Insert { get; set; }
+ bool AddOnlyIfOnLine { get; set; }
+ ILineChartSeries Series { get; set; }
+ }
+}
\ No newline at end of file
Index: Core/Common/src/Core.Common.Controls.Charting/Tools/ChartViewSeriesToolBase.cs
===================================================================
diff -u
--- Core/Common/src/Core.Common.Controls.Charting/Tools/ChartViewSeriesToolBase.cs (revision 0)
+++ Core/Common/src/Core.Common.Controls.Charting/Tools/ChartViewSeriesToolBase.cs (revision 3bfa4dc5fb5ea3560752479de86cb843419f8fe3)
@@ -0,0 +1,244 @@
+using System;
+using System.Drawing;
+using System.Linq;
+using System.Windows.Forms;
+using Core.Common.Controls.Charting.Series;
+using Core.Common.Controls.Charting.Properties;
+using Steema.TeeChart;
+using Steema.TeeChart.Styles;
+using Steema.TeeChart.Tools;
+
+namespace Core.Common.Controls.Charting.Tools
+{
+ ///
+ /// Base class for EditPointTool,SelectPointTool and AddPointTool
+ ///
+ public abstract class ChartViewSeriesToolBase : ToolSeries, IChartViewSeriesTool
+ {
+ public event SelectionChangedEventHandler SelectionChanged;
+
+ public event EventHandler ActiveChanged;
+
+ protected int selectedPointIndex = -1;
+ private bool enabled = true;
+
+ private ChartSeries series;
+
+ private Steema.TeeChart.Styles.Series previousSelectedSeries;
+
+ private Steema.TeeChart.Styles.Series lastSelectedSeries;
+
+ protected ChartViewSeriesToolBase(Steema.TeeChart.Chart chart) : base(chart) {}
+
+ protected ChartViewSeriesToolBase(Steema.TeeChart.Styles.Series series) : base(series) {}
+
+ ///
+ /// Selects a point in the chart.
+ ///
+ public int SelectedPointIndex
+ {
+ get
+ {
+ return selectedPointIndex;
+ }
+ protected set
+ {
+ if (selectedPointIndex != value || !ReferenceEquals(previousSelectedSeries, LastSelectedSeries))
+ {
+ previousSelectedSeries = LastSelectedSeries;
+
+ if ((LastSelectedSeries != null))
+ {
+ if ((value > LastSelectedSeries.Count - 1))
+ {
+ throw new ArgumentException(Resources.ChartViewSeriesToolBase_SelectedPointIndex_Selected_index_outside_range_of_series);
+ }
+
+ selectedPointIndex = value;
+ if (SelectionChanged != null)
+ {
+ if (selectedPointIndex != -1)
+ {
+ SelectionChanged(this,
+ new PointEventArgs(
+ GetChartSeriesFromInternalSeries(LastSelectedSeries),
+ selectedPointIndex,
+ LastSelectedSeries.XValues[selectedPointIndex],
+ LastSelectedSeries.YValues[selectedPointIndex]));
+ }
+ else
+ {
+ SelectionChanged(this,
+ new PointEventArgs(
+ GetChartSeriesFromInternalSeries(LastSelectedSeries),
+ selectedPointIndex, double.NaN, double.NaN));
+ }
+ }
+ Invalidate();
+ }
+ else
+ {
+ throw new InvalidOperationException(Resources.ChartViewSeriesToolBase_SelectedPointIndex_LastSelectedSeries_needs_to_be_set_before_SelectedPointIndex_is_set);
+ }
+ }
+ }
+ }
+
+ public IChartView ChartView { get; set; }
+
+ public bool Enabled
+ {
+ get
+ {
+ return enabled;
+ }
+ set
+ {
+ enabled = value;
+ }
+ }
+
+ public new bool Active
+ {
+ get
+ {
+ return base.Active;
+ }
+ set
+ {
+ base.Active = value;
+ if (ActiveChanged != null)
+ {
+ ActiveChanged(this, null);
+ }
+ }
+ }
+
+ public new IChartSeries Series
+ {
+ get
+ {
+ return series;
+ }
+ set
+ {
+ series = (ChartSeries) value;
+ iSeries = series.series;
+ }
+ }
+
+ protected Steema.TeeChart.Styles.Series LastSelectedSeries
+ {
+ get
+ {
+ return iSeries ?? lastSelectedSeries; //if internal series is set, use that (tool is only for that series), otherwise return last selected
+ }
+ set
+ {
+ if (iSeries != null && iSeries != value)
+ {
+ throw new ArgumentException(String.Format(Resources.ChartViewSeriesToolBase_LastSelectedSeries_This_tool_only_accepts_0_as_series, iSeries));
+ }
+ lastSelectedSeries = value;
+ }
+ }
+
+ protected override void SetSeries(Steema.TeeChart.Styles.Series series)
+ {
+ var customPoint = ((ChartSeries) Series).series as CustomPoint;
+ if (customPoint != null)
+ {
+ customPoint.GetPointerStyle -= OnCustomSeriesGetPointerStyle;
+ }
+
+ base.SetSeries(series);
+
+ customPoint = series as CustomPoint;
+ if (customPoint != null)
+ {
+ customPoint.GetPointerStyle += OnCustomSeriesGetPointerStyle;
+ }
+ }
+
+ protected virtual void OnCustomSeriesGetPointerStyle(CustomPoint customSeries, GetPointerStyleEventArgs e) {}
+
+ protected Steema.TeeChart.Styles.Series ClickedSeries(Point p)
+ {
+ return ClickedSeries(p.X, p.Y);
+ }
+
+ protected Steema.TeeChart.Styles.Series ClickedSeries(int x, int y)
+ {
+ if (iSeries == null)
+ {
+ var seriesInRenderOrder = Chart.Series.OfType().Reverse();
+
+ return seriesInRenderOrder.FirstOrDefault(s => (s.Active) && (s.Clicked(x, y) != -1));
+ }
+ else if (iSeries.Clicked(x, y) != -1)
+ {
+ return iSeries;
+ }
+
+ return null;
+ }
+
+ protected IChartSeries GetChartSeriesFromInternalSeries(Steema.TeeChart.Styles.Series internalSeries)
+ {
+ if (ChartView != null && ChartView.Chart != null)
+ {
+ var matchingSeries =
+ ChartView.Chart.Series.FirstOrDefault(
+ cs => ReferenceEquals(cs.series, internalSeries));
+
+ if (matchingSeries != null)
+ {
+ return matchingSeries;
+ }
+
+ matchingSeries =
+ ChartView.Chart.Series.FirstOrDefault(cs => cs.Title == internalSeries.Title);
+
+ if (matchingSeries != null)
+ {
+ return matchingSeries;
+ }
+ }
+ throw new ArgumentException(Resources.ChartViewSeriesToolBase_GetChartSeriesFromInternalSeries_Unknown_TeeChart_series_Not_related_to_any_known_ChartSeries);
+ }
+
+ ///
+ /// Handles mouse events for the tools and chart of Teechart. Teechart uses a special
+ /// mechanism to let tools cooperate via chart.CancelMouse. Therefor do not use
+ /// control mouse events directly.
+ ///
+ ///
+ ///
+ ///
+ protected override void MouseEvent(MouseEventKinds kind, MouseEventArgs e, ref Cursor c)
+ {
+ if (!Enabled)
+ {
+ return;
+ }
+ switch (kind)
+ {
+ case MouseEventKinds.Up:
+ OnMouseUp(e);
+ break;
+ case MouseEventKinds.Move:
+ OnMouseMove(e, ref c);
+ break;
+ case MouseEventKinds.Down:
+ OnMouseDown(e);
+ break;
+ }
+ }
+
+ protected virtual void OnMouseDown(MouseEventArgs mouseEventArgs) {}
+
+ protected virtual void OnMouseMove(MouseEventArgs mouseEventArgs, ref Cursor cursor) {}
+
+ protected virtual void OnMouseUp(MouseEventArgs mouseEventArgs) {}
+ }
+}
\ No newline at end of file
Index: Core/Common/src/Core.Common.Controls.Charting/Tools/EditPointTool.cs
===================================================================
diff -u
--- Core/Common/src/Core.Common.Controls.Charting/Tools/EditPointTool.cs (revision 0)
+++ Core/Common/src/Core.Common.Controls.Charting/Tools/EditPointTool.cs (revision 3bfa4dc5fb5ea3560752479de86cb843419f8fe3)
@@ -0,0 +1,438 @@
+using System;
+using System.Collections.Generic;
+using System.Data;
+using System.Drawing;
+using System.Windows.Forms;
+using Core.Common.Controls.Charting.Customized;
+using Core.Common.Controls.Charting.Series;
+using Core.Common.Controls.Charting.Properties;
+using Core.Common.Utils.Extensions;
+
+using log4net;
+using Steema.TeeChart.Styles;
+
+namespace Core.Common.Controls.Charting.Tools
+{
+ ///
+ /// Tools for moving and deleting points (responds to 'DEL'button)
+ ///
+ public class EditPointTool : ChartViewSeriesToolBase
+ {
+ public event EventHandler BeforeDrag;
+
+ public event EventHandler MouseHoverPoint;
+
+ public event EventHandler AfterPointEdit;
+ private const double clippingTolerance = 1e-4;
+ private static readonly ILog log = LogManager.GetLogger(typeof(EditPointTool));
+ private readonly ToolTip toolTip;
+ private readonly RingtoetsTChart tChart;
+ private DragStyle style = DragStyle.Both;
+ private bool pointHasMoved;
+ private Color selectedPointerColor = Color.LimeGreen;
+ private readonly Steema.TeeChart.Styles.PointerStyles selectedPointerStyle = Steema.TeeChart.Styles.PointerStyles.Diamond;
+ private bool clipXValues = true;
+ private bool restoreZoom;
+
+ ///
+ /// Allows user to interactively change points in a chart
+ ///
+ ///
+ public EditPointTool(Steema.TeeChart.Chart c) : base(c)
+ {
+ toolTip = new ToolTip
+ {
+ ShowAlways = false
+ };
+ }
+
+ ///
+ /// Allows user to interactively change points in a chart
+ ///
+ ///
+ public EditPointTool(Steema.TeeChart.Styles.Series s) : base(s) {}
+
+ ///
+ /// Allows user to interactively change points in a chart
+ ///
+ public EditPointTool() : this(((Steema.TeeChart.Chart) null)) {}
+
+ ///
+ /// Allows user to interactively change points in a chart
+ /// Constructor for schowing a toolTip displaying the coordinates in drga mode.
+ ///
+ ///
+ public EditPointTool(RingtoetsTChart c)
+ : base(c.Chart)
+ {
+ tChart = c;
+ toolTip = new ToolTip();
+ toolTip.ShowAlways = false;
+ }
+
+ ///
+ /// Color of the point selected in the chart
+ ///
+ public Color SelectedPointerColor
+ {
+ get
+ {
+ return selectedPointerColor;
+ }
+ set
+ {
+ selectedPointerColor = value;
+ }
+ }
+
+ ///
+ /// True if series line can represent a polygon, otherwise x-coordinate of every point will be limited by x value of it's neighbours.
+ ///
+ public bool IsPolygon { get; set; }
+
+ ///
+ /// Clip means that a point cannot be dragged PASSED another in X direction
+ ///
+ public bool ClipXValues
+ {
+ get
+ {
+ return clipXValues;
+ }
+ set
+ {
+ clipXValues = value;
+ }
+ }
+
+ ///
+ /// Clip means that a point cannot be dragged PASSED another in Y direction
+ ///
+ public bool ClipYValues { get; set; }
+
+ public DragStyle DragStyles
+ {
+ get
+ {
+ return style;
+ }
+ set
+ {
+ style = value;
+ }
+ }
+
+ public ILineChartSeries Series
+ {
+ get
+ {
+ return (ILineChartSeries) base.Series;
+ }
+ set
+ {
+ base.Series = value;
+ }
+ }
+
+ protected override void KeyEvent(KeyEventArgs e)
+ {
+ base.KeyEvent(e);
+ if (e.KeyCode == Keys.Delete && selectedPointIndex != -1)
+ {
+ // try to delete point from datasource so event is fired
+ DataTable dataTable = LastSelectedSeries.DataSource as DataTable;
+
+ if (dataTable != null)
+ {
+ dataTable.Rows[selectedPointIndex].Delete();
+ return;
+ }
+
+ var lineChartSeries = LastSelectedSeries.DataSource as LineChartSeries;
+ if (lineChartSeries != null)
+ {
+ lineChartSeries.series.Delete(selectedPointIndex);
+ SelectedPointIndex = -1;
+ return;
+ }
+ throw new NotImplementedException(Resources.KeyEvent_Deletion_not_implemented_for_this_type_of_datasource);
+ }
+ }
+
+ protected override void OnMouseDown(MouseEventArgs e)
+ {
+ Point p = new Point(e.X, e.Y);
+
+ //why not e.Button?
+ if (Steema.TeeChart.Utils.GetMouseButton(e) != MouseButtons.Left)
+ {
+ return;
+ }
+
+ // in case of mouseclick, select point nearest to mouse
+ if (LastSelectedSeries != null)
+ {
+ var tolerance = Series != null ? Series.PointerSize : 3;
+ int index = TeeChartHelper.GetNearestPoint(LastSelectedSeries, p, tolerance);
+ if (-1 != index)
+ {
+ if (BeforeDrag != null)
+ {
+ var args = new PointEventArgs(GetChartSeriesFromInternalSeries(LastSelectedSeries), index,
+ LastSelectedSeries.XValues[index],
+ LastSelectedSeries.YValues[index]);
+
+ BeforeDrag(this, args);
+
+ if (args.Cancel)
+ {
+ return;
+ }
+ }
+
+ SelectedPointIndex = index;
+ Chart.CancelMouse = true;
+ restoreZoom = Chart.Zoom.Active;
+ Chart.Zoom.Active = false;
+ Chart.Zoom.Allow = false;
+ pointHasMoved = false;
+ Invalidate();
+ }
+ }
+ }
+
+ protected override void OnMouseMove(MouseEventArgs e, ref Cursor c)
+ {
+ var p = new Point(e.X, e.Y);
+
+ Steema.TeeChart.Styles.Series s = ClickedSeries(p);
+ if (s != null)
+ {
+ var tolerance = Series != null ? Series.PointerSize : 3;
+ int abovePoint = TeeChartHelper.GetNearestPoint(s, p, tolerance);
+ if (abovePoint > -1)
+ {
+ c = GetCursorIcon(style);
+ Chart.CancelMouse = true;
+
+ if (MouseHoverPoint != null)
+ {
+ MouseHoverPoint(this, new HoverPointEventArgs(GetChartSeriesFromInternalSeries(s), abovePoint, 0.0, 0.0, true));
+ }
+ }
+ }
+ else
+ {
+ c = Cursors.Default;
+
+ if (MouseHoverPoint != null)
+ {
+ MouseHoverPoint(this, new HoverPointEventArgs(null, -1, 0.0, 0.0, false));
+ }
+ }
+
+ if (Steema.TeeChart.Utils.GetMouseButton(e) != MouseButtons.Left)
+ {
+ return;
+ }
+
+ if (SelectedPointIndex > -1)
+ {
+ if ((style == DragStyle.X) || (style == DragStyle.Both))
+ {
+ if (LastSelectedSeries != null)
+ {
+ LastSelectedSeries.XValues[SelectedPointIndex] = CalculateXValue(p);
+ }
+ pointHasMoved = true;
+ }
+
+ if ((style == DragStyle.Y) || (style == DragStyle.Both))
+ {
+ if (LastSelectedSeries != null)
+ {
+ LastSelectedSeries.YValues[SelectedPointIndex] = CalculateYValue(p);
+ }
+ pointHasMoved = true;
+ }
+ if (IsPolygon)
+ {
+ SynchronizeFirstAndLastPointOfPolygon();
+ }
+
+ if (pointHasMoved)
+ {
+ Invalidate();
+ }
+ }
+ }
+
+ protected override void OnMouseUp(MouseEventArgs e)
+ {
+ if (Steema.TeeChart.Utils.GetMouseButton(e) != MouseButtons.Left)
+ {
+ return;
+ }
+
+ if (SelectedPointIndex > -1)
+ {
+ //int selectedIndex = SelectedPointIndex;
+ if (pointHasMoved)
+ {
+ if (AfterPointEdit != null)
+ {
+ // AfterPointEdit can change underlying and reset the SelectedPointIndex
+ // MouseMove and MouseUp can run out of sync; return the values set by mousemove = what is visible to the user
+ var chartSeries = GetChartSeriesFromInternalSeries(LastSelectedSeries);
+ AfterPointEdit(this, new PointEventArgs(chartSeries, SelectedPointIndex,
+ LastSelectedSeries.XValues[selectedPointIndex], LastSelectedSeries.YValues[selectedPointIndex]));
+ if (IsPolygon)
+ {
+ if (0 == SelectedPointIndex)
+ {
+ if (LastSelectedSeries != null)
+ {
+ AfterPointEdit(this, new PointEventArgs(chartSeries, LastSelectedSeries.XValues.Count - 1,
+ LastSelectedSeries.XValues[selectedPointIndex], LastSelectedSeries.YValues[selectedPointIndex]));
+ }
+ }
+ else if (LastSelectedSeries != null)
+ {
+ if ((LastSelectedSeries.XValues.Count - 1) == SelectedPointIndex)
+ {
+ AfterPointEdit(this, new PointEventArgs(chartSeries, 0, LastSelectedSeries.XValues[selectedPointIndex], LastSelectedSeries.YValues[selectedPointIndex]));
+ }
+ }
+ }
+ }
+ pointHasMoved = false;
+ }
+
+ Chart.Zoom.Active = restoreZoom;
+ Chart.Zoom.Allow = true;
+
+ //hide tooltip
+ if (tChart != null)
+ {
+ toolTip.ShowAlways = false;
+ toolTip.Hide(tChart);
+ }
+ selectedPointIndex = -1;
+ }
+ }
+
+ protected override void OnCustomSeriesGetPointerStyle(CustomPoint series, GetPointerStyleEventArgs e)
+ {
+ if (e.ValueIndex == selectedPointIndex)
+ {
+ e.Color = selectedPointerColor;
+ e.Style = selectedPointerStyle;
+ }
+ }
+
+ private static Cursor GetCursorIcon(DragStyle dragStyle)
+ {
+ switch (dragStyle)
+ {
+ case DragStyle.Both:
+ return Cursors.SizeAll;
+ case DragStyle.X:
+ return Cursors.SizeWE;
+ case DragStyle.Y:
+ return Cursors.SizeNS;
+ default:
+ throw new NotImplementedException(String.Format(Resources.EditPointTool_GetCursorIcon_No_cursor_assigned_for_0_, dragStyle));
+ }
+ }
+
+ private double CalculateXValue(Point P)
+ {
+ double xValue = LastSelectedSeries.XScreenToValue(P.X);
+ //log.DebugFormat("Clicked at point (x): {0}", xValue);
+ if (!IsPolygon && ClipXValues)
+ {
+ if (SelectedPointIndex > 0)
+ {
+ //do not allow to horizontally drag before a neigbouring point.
+ double lowerLimit = LastSelectedSeries.XValues[SelectedPointIndex - 1];
+ if (xValue < lowerLimit)
+ {
+ log.DebugFormat(Resources.EditPointTool_CalculateXValue_left_limit, xValue, lowerLimit + clippingTolerance);
+ xValue = lowerLimit + clippingTolerance;
+ }
+ }
+ if (SelectedPointIndex < LastSelectedSeries.Count - 1)
+ {
+ //do not allow to horizontally drag past a neigbouring point.
+ double upperLimit = LastSelectedSeries.XValues[SelectedPointIndex + 1];
+ if (xValue > upperLimit)
+ {
+ log.DebugFormat(Resources.EditPointTool_CalculateXValue_right_limit, xValue, upperLimit - clippingTolerance);
+ xValue = upperLimit - clippingTolerance;
+ }
+ }
+ }
+ return xValue;
+ }
+
+ private double CalculateYValue(Point P)
+ {
+ double yValue = LastSelectedSeries.YScreenToValue(P.Y);
+
+ if (!IsPolygon && ClipYValues)
+ {
+ //do not allow to vertical drag beyond a neigbouring point.
+
+ double current = LastSelectedSeries.YValues[SelectedPointIndex];
+ var limits = new List();
+
+ if (SelectedPointIndex > 0)
+ {
+ limits.Add(LastSelectedSeries.YValues[SelectedPointIndex - 1]);
+ }
+ if (SelectedPointIndex < LastSelectedSeries.Count - 1)
+ {
+ limits.Add(LastSelectedSeries.YValues[SelectedPointIndex + 1]);
+ }
+
+ return Clip(yValue, current, clippingTolerance, limits);
+ }
+ return yValue;
+ }
+
+ private static double Clip(double newValue, double oldValue, double margin, IList limits)
+ {
+ foreach (double limit in limits) //note: should these be ordered?
+ {
+ if (limit.IsInRange(newValue, oldValue))
+ {
+ return oldValue < limit ? limit - margin : limit + margin;
+ }
+ }
+
+ return newValue;
+ }
+
+ private void SynchronizeFirstAndLastPointOfPolygon()
+ {
+ //make sure that the last point is equal to the first. If we moved the first we should move the last and vice-versa
+ if (0 == SelectedPointIndex)
+ {
+ LastSelectedSeries.XValues[LastSelectedSeries.XValues.Count - 1] = LastSelectedSeries.XValues[0];
+ LastSelectedSeries.YValues[LastSelectedSeries.YValues.Count - 1] = LastSelectedSeries.YValues[0];
+ }
+ else if ((LastSelectedSeries.XValues.Count - 1) == SelectedPointIndex)
+ {
+ LastSelectedSeries.XValues[0] = LastSelectedSeries.XValues[LastSelectedSeries.XValues.Count - 1];
+ LastSelectedSeries.YValues[0] = LastSelectedSeries.YValues[LastSelectedSeries.YValues.Count - 1];
+ }
+ }
+ }
+
+ public enum DragStyle
+ {
+ Both,
+ X,
+ Y
+ }
+}
\ No newline at end of file
Index: Core/Common/src/Core.Common.Controls.Charting/Tools/ExportChartAsImageChartTool.cs
===================================================================
diff -u
--- Core/Common/src/Core.Common.Controls.Charting/Tools/ExportChartAsImageChartTool.cs (revision 0)
+++ Core/Common/src/Core.Common.Controls.Charting/Tools/ExportChartAsImageChartTool.cs (revision 3bfa4dc5fb5ea3560752479de86cb843419f8fe3)
@@ -0,0 +1,47 @@
+using System;
+using System.Windows.Forms;
+using Core.Common.Controls.Charting.Properties;
+
+namespace Core.Common.Controls.Charting.Tools
+{
+ public class ExportChartAsImageChartTool : IChartViewContextMenuTool
+ {
+ public event EventHandler ActiveChanged;
+ private bool active;
+
+ public IChartView ChartView { get; set; }
+
+ public bool Active
+ {
+ get
+ {
+ return active;
+ }
+ set
+ {
+ active = value;
+ if (ActiveChanged != null)
+ {
+ ActiveChanged(this, null);
+ }
+ }
+ }
+
+ public bool Enabled { get; set; }
+
+ public void OnBeforeContextMenu(ContextMenuStrip menu)
+ {
+ if (menu.Items.Count > 0)
+ {
+ menu.Items.Add(new ToolStripSeparator());
+ }
+
+ menu.Items.Add(new ToolStripMenuItem(Resources.KeyEvent_Deletion_not_implemented_for_this_type_of_datasource, null, ExportChartEventHandler));
+ }
+
+ private void ExportChartEventHandler(object sender, EventArgs e)
+ {
+ ChartView.ExportAsImage();
+ }
+ }
+}
\ No newline at end of file
Index: Core/Common/src/Core.Common.Controls.Charting/Tools/PointEventArgs.cs
===================================================================
diff -u
--- Core/Common/src/Core.Common.Controls.Charting/Tools/PointEventArgs.cs (revision 0)
+++ Core/Common/src/Core.Common.Controls.Charting/Tools/PointEventArgs.cs (revision 3bfa4dc5fb5ea3560752479de86cb843419f8fe3)
@@ -0,0 +1,32 @@
+using System.ComponentModel;
+
+namespace Core.Common.Controls.Charting.Tools
+{
+ public delegate void SelectionChangedEventHandler(object sender, PointEventArgs e);
+
+ public class PointEventArgs : CancelEventArgs
+ {
+ public PointEventArgs(IChartSeries series, int index, double x, double y)
+ {
+ Series = series;
+ Index = index;
+ X = x;
+ Y = y;
+ }
+
+ public IChartSeries Series { get; private set; }
+
+ public int Index { get; private set; }
+
+ public double X { get; private set; }
+
+ public double Y { get; private set; }
+ }
+
+ public class HoverPointEventArgs : PointEventArgs
+ {
+ public HoverPointEventArgs(IChartSeries series, int index, double x, double y, bool entering) : base(series, index, x, y) {}
+
+ public bool Entering { get; set; }
+ }
+}
\ No newline at end of file
Index: Core/Common/src/Core.Common.Controls.Charting/Tools/RulerTool.cs
===================================================================
diff -u
--- Core/Common/src/Core.Common.Controls.Charting/Tools/RulerTool.cs (revision 0)
+++ Core/Common/src/Core.Common.Controls.Charting/Tools/RulerTool.cs (revision 3bfa4dc5fb5ea3560752479de86cb843419f8fe3)
@@ -0,0 +1,444 @@
+using System;
+using System.Drawing;
+using System.Drawing.Drawing2D;
+using System.Linq;
+using System.Windows.Forms;
+using Core.Common.Controls.Charting.Customized;
+using Core.Common.Controls.Charting.Properties;
+using log4net;
+using Steema.TeeChart.Drawing;
+
+namespace Core.Common.Controls.Charting.Tools
+{
+ public class RulerTool : IChartViewTool
+ {
+ private static readonly ILog Log = LogManager.GetLogger(typeof(RulerTool));
+ private readonly RingtoetsTChart teeChart;
+ private string toolTip;
+ private Steema.TeeChart.Chart.ChartToolTip annotationToolTip;
+ private Point measuringStartPoint;
+ private Point measuringEndPoint;
+ private bool measuring;
+ private object horizontalValueStartPoint;
+ private object verticalValueStartPoint;
+ private bool active;
+ private object verticalValueEndPoint;
+ private object horizontalValueEndPoint;
+ private bool showToolTip;
+ private Point lastShowPoint;
+ private Cursor cursor;
+ private bool selectToolOldState = true;
+
+ public RulerTool(RingtoetsTChart teeChart)
+ {
+ var chartView = teeChart.Parent as ChartView;
+
+ this.teeChart = teeChart;
+ teeChart.AfterDraw += TeeChartAfterDraw;
+ teeChart.MouseWheel += SizeChanged;
+ teeChart.MouseDown += MouseDown;
+ teeChart.MouseMove += MouseMove;
+
+ if (chartView != null)
+ {
+ chartView.GraphResized += SizeChanged;
+ chartView.ViewPortChanged += SizeChanged;
+ }
+
+ LineColor = Color.DarkSlateGray;
+ LineWidth = 2;
+ DashStyle = DashStyle.Dash;
+ }
+
+ private void StartMeasuring(Point point)
+ {
+ var chartView = teeChart.Parent as ChartView;
+ if (chartView == null)
+ {
+ return;
+ }
+
+ var bottomMinValue = chartView.Chart.BottomAxis.Minimum;
+ var bottomMaxValue = chartView.Chart.BottomAxis.Maximum;
+ var leftMinValue = chartView.Chart.LeftAxis.Minimum;
+ var leftMaxValue = chartView.Chart.LeftAxis.Maximum;
+
+ measuringStartPoint = point;
+
+ var chartRect = teeChart.Chart.ChartRect;
+
+ horizontalValueStartPoint = GetAxesValue(bottomMinValue,
+ bottomMaxValue,
+ chartRect.Left,
+ (chartRect.Left + chartRect.Width),
+ point.X);
+ verticalValueStartPoint = GetAxesValue(leftMinValue,
+ leftMaxValue,
+ (chartRect.Top + chartRect.Height),
+ chartRect.Top,
+ point.Y);
+ horizontalValueEndPoint = double.NaN;
+ verticalValueEndPoint = double.NaN;
+
+ measuringEndPoint = measuringStartPoint;
+ RemoveToolTip();
+ measuring = true;
+ }
+
+ private void StopMeasuring(Point point)
+ {
+ var chartView = teeChart.Parent as ChartView;
+ if (chartView == null)
+ {
+ return;
+ }
+
+ var bottomMinValue = chartView.Chart.BottomAxis.Minimum;
+ var bottomMaxValue = chartView.Chart.BottomAxis.Maximum;
+ var leftMinValue = chartView.Chart.LeftAxis.Minimum;
+ var leftMaxValue = chartView.Chart.LeftAxis.Maximum;
+
+ var chartRect = teeChart.Chart.ChartRect;
+
+ horizontalValueEndPoint = GetAxesValue(bottomMinValue,
+ bottomMaxValue,
+ chartRect.Left,
+ (chartRect.Left + chartRect.Width),
+ point.X);
+ verticalValueEndPoint = GetAxesValue(leftMinValue,
+ leftMaxValue,
+ (chartRect.Top + chartRect.Height),
+ chartRect.Top,
+ point.Y);
+
+ var dx = teeChart.Chart.Axes.Bottom.IsDateTime
+ ? (object)
+ (DateTime.FromOADate((double) horizontalValueEndPoint) -
+ DateTime.FromOADate((double) horizontalValueStartPoint))
+ : (double) horizontalValueEndPoint - (double) horizontalValueStartPoint;
+ var dy = teeChart.Chart.Axes.Left.IsDateTime
+ ? (object)
+ (DateTime.FromOADate((double) verticalValueEndPoint) - DateTime.FromOADate((double) verticalValueStartPoint))
+ : (double) verticalValueEndPoint - (double) verticalValueStartPoint;
+ toolTip = DifferenceToString != null ? DifferenceToString(dx, dy) : GetDefaultDifferenceString(dx, dy);
+ showToolTip = true;
+
+ RemoveToolTip();
+ lastShowPoint = new Point(measuringEndPoint.X - 20, measuringEndPoint.Y - 20);
+ AddToolTip(point);
+ AddLogMessage();
+
+ measuring = false;
+ }
+
+ private void TeeChartAfterDraw(object sender, Graphics3D graphics3D)
+ {
+ if (Active && measuringStartPoint != measuringEndPoint && ChartView.Chart.Series.Any(s => s.Visible))
+ {
+ if (measuringStartPoint.X == int.MinValue || measuringStartPoint.Y == int.MinValue || measuringEndPoint.X == int.MinValue || measuringEndPoint.Y == int.MinValue)
+ {
+ return;
+ }
+ using (Graphics3D gr = teeChart.Graphics3D)
+ {
+ gr.Pen = new ChartPen(teeChart.Chart, LineColor)
+ {
+ Width = LineWidth, Style = DashStyle
+ };
+ gr.ClipRectangle(teeChart.Chart.ChartRect);
+ gr.Line(measuringStartPoint, measuringEndPoint);
+ }
+ }
+ }
+
+ private void AddToolTip(Point point)
+ {
+ if (!showToolTip)
+ {
+ return;
+ }
+
+ var distanceToLine = LineToPointDistance2D(measuringStartPoint, measuringEndPoint, point, true);
+ if (!string.IsNullOrEmpty(toolTip) && distanceToLine < 5 && Distance(point, lastShowPoint) > 5)
+ {
+ lastShowPoint = point;
+ annotationToolTip = teeChart.Chart.ToolTip;
+ annotationToolTip.Text = toolTip;
+ annotationToolTip.Show();
+ }
+ }
+
+ private void RemoveToolTip()
+ {
+ if (annotationToolTip != null)
+ {
+ annotationToolTip.Hide();
+ annotationToolTip = null;
+ showToolTip = false;
+ toolTip = "";
+ }
+ }
+
+ private void AddLogMessage()
+ {
+ Log.Info(toolTip);
+ }
+
+ private string GetDefaultDifferenceString(object dx, object dy)
+ {
+ var dxText = dx is TimeSpan
+ ? ((TimeSpan) dx).TotalSeconds.ToString("0.## ") + Resources.RulerTool_GetDefaultDifferenceString_seconds
+ : ((double) dx).ToString("0.##");
+ var dyText = dy is TimeSpan
+ ? ((TimeSpan) dy).TotalSeconds.ToString("0.## ") + Resources.RulerTool_GetDefaultDifferenceString_seconds
+ : ((double) dy).ToString("0.##");
+
+ return string.Format(Resources.RulerTool_GetDefaultDifferenceString_Difference_horizontal_0_vertical_1_, dxText, dyText);
+ }
+
+ private object GetAxesValue(double minValue, double maxValue, int minPixel, int maxPixel, int pixel)
+ {
+ return minValue + ((maxValue - minValue)/(maxPixel - minPixel))*(pixel - minPixel);
+ }
+
+ private int GetPixelValue(double minValue, double maxValue, int minPixel, int maxPixel, double value)
+ {
+ return (int) (minPixel + ((maxPixel - minPixel)/(maxValue - minValue))*(value - minValue));
+ }
+
+ # region IChartViewTool members
+
+ public IChartView ChartView { get; set; }
+
+ public event EventHandler ActiveChanged;
+
+ public bool Active
+ {
+ get
+ {
+ return active;
+ }
+ set
+ {
+ if (active == value)
+ {
+ return;
+ }
+ active = value;
+ SetActive();
+ if (ActiveChanged != null)
+ {
+ ActiveChanged(this, null);
+ }
+ }
+ }
+
+ private void SetActive()
+ {
+ measuring = false;
+ teeChart.Chart.Zoom.Allow = !active;
+ RemoveToolTip();
+ teeChart.Chart.Invalidate();
+
+ var selectTool = ChartView.GetTool();
+ if (active)
+ {
+ measuringStartPoint = new Point();
+ measuringEndPoint = new Point();
+ horizontalValueStartPoint = double.NaN;
+ verticalValueStartPoint = double.NaN;
+ horizontalValueEndPoint = double.NaN;
+ verticalValueEndPoint = double.NaN;
+ if (selectTool != null)
+ {
+ selectToolOldState = selectTool.Active;
+ selectTool.Active = false;
+ }
+ }
+ else
+ {
+ if (selectTool != null)
+ {
+ selectTool.Active = selectToolOldState;
+ }
+ }
+ teeChart.Cursor = active ? Cursor : Cursors.Default;
+ }
+
+ public bool Enabled { get; set; }
+
+ # endregion
+
+ # region IRulerTool members
+
+ public int LineWidth { get; set; }
+
+ public DashStyle DashStyle { get; set; }
+
+ public Color LineColor { get; set; }
+
+ public Cursor Cursor
+ {
+ get
+ {
+ return cursor ?? Cursors.Default;
+ }
+ set
+ {
+ cursor = value;
+ teeChart.Cursor = active ? Cursor : Cursors.Default;
+ }
+ }
+
+ public Func