1 //-------------------------------------------------------------
2 // <copyright company=
\92Microsoft Corporation
\92>
3 // Copyright © Microsoft Corporation. All Rights Reserved.
5 //-------------------------------------------------------------
6 // @owner=alexgor, deliant
7 //=================================================================
8 // File: StepLineChart.cs
10 // Namespace: DataVisualization.Charting.ChartTypes
12 // Classes: StepLineChart
14 // Purpose: Step Line chart uses two line segments (horizontal
15 // and vertical) to connect data points. Markers and
16 // labels drawing code is inherited from the Line chart.
18 // Reviewed: AG - Aug 6, 2002
19 // AG - Microsoft 7, 2007
21 //===================================================================
23 #region Used namespaces
26 using System.Resources;
27 using System.Reflection;
28 using System.Collections;
30 using System.Drawing.Drawing2D;
33 using System.Windows.Forms.DataVisualization.Charting.Data;
34 using System.Windows.Forms.DataVisualization.Charting.ChartTypes;
35 using System.Windows.Forms.DataVisualization.Charting.Utilities;
36 using System.Windows.Forms.DataVisualization.Charting.Borders3D;
37 using System.Windows.Forms.DataVisualization.Charting;
39 using System.Web.UI.DataVisualization.Charting;
41 using System.Web.UI.DataVisualization.Charting.ChartTypes;
42 using System.Web.UI.DataVisualization.Charting.Data;
43 using System.Web.UI.DataVisualization.Charting.Utilities;
49 namespace System.Windows.Forms.DataVisualization.Charting.ChartTypes
51 namespace System.Web.UI.DataVisualization.Charting.ChartTypes
55 /// StepLine class extends its base class LineChart by changing how two
56 /// neighbouring data points are connected with a line. Step Line chart
57 /// uses two line segments (horizontal and vertical) to connect data
58 /// points. Markers and labels drawing code is inherited from the Line chart.
60 internal class StepLineChart : LineChart
65 /// StepLineChart class constructor.
67 public StepLineChart()
73 #region IChartType interface implementation
78 public override string Name { get{ return ChartTypeNames.StepLine;}}
81 /// Gets chart type image.
83 /// <param name="registry">Chart types registry object.</param>
84 /// <returns>Chart type image.</returns>
85 override public System.Drawing.Image GetImage(ChartTypeRegistry registry)
87 return (System.Drawing.Image)registry.ResourceManager.GetObject(this.Name + "ChartType");
92 #region Line drawing and selecting methods
95 /// Draw chart line using horisontal and vertical lines.
97 /// <param name="graph">Graphics object.</param>
98 /// <param name="common">The Common elements object</param>
99 /// <param name="point">Point to draw the line for.</param>
100 /// <param name="series">Point series.</param>
101 /// <param name="points">Array of points coordinates.</param>
102 /// <param name="pointIndex">Index of point to draw.</param>
103 /// <param name="tension">Line tension</param>
104 override protected void DrawLine(
106 CommonElements common,
113 // Start drawing from the second point
120 PointF point1 = points[pointIndex - 1];
121 PointF point2 = new PointF(points[pointIndex].X, points[pointIndex - 1].Y);
122 PointF point3 = points[pointIndex];
123 graph.DrawLineRel( point.Color, point.BorderWidth, point.BorderDashStyle, graph.GetRelativePoint(point1), graph.GetRelativePoint(point2), series.ShadowColor, series.ShadowOffset );
124 graph.DrawLineRel( point.Color, point.BorderWidth, point.BorderDashStyle, graph.GetRelativePoint(point2), graph.GetRelativePoint(point3), series.ShadowColor, series.ShadowOffset );
126 if( common.ProcessModeRegions )
128 // Create grapics path object for the line
129 // Split line into 2 segments.
130 GraphicsPath path = new GraphicsPath();
133 path.AddLine(point2, point3);
134 if (!point2.Equals(point3))
136 path.Widen(new Pen(point.Color, point.BorderWidth + 2));
139 catch (OutOfMemoryException)
141 // GraphicsPath.Widen incorrectly throws OutOfMemoryException
142 // catching here and reacting by not widening
144 catch (ArgumentException)
148 // Allocate array of floats
149 PointF pointNew = PointF.Empty;
150 float[] coord = new float[path.PointCount * 2];
151 PointF[] pathPoints = path.PathPoints;
152 for( int i = 0; i < path.PointCount; i++ )
154 pointNew = graph.GetRelativePoint( pathPoints[i] );
155 coord[2*i] = pointNew.X;
156 coord[2*i + 1] = pointNew.Y;
159 common.HotRegionsList.AddHotRegion(
167 // Create grapics path object for the line
168 path = new GraphicsPath();
171 path.AddLine(point1, point2);
172 path.Widen(new Pen(point.Color, point.BorderWidth + 2));
174 catch (OutOfMemoryException)
176 // GraphicsPath.Widen incorrectly throws OutOfMemoryException
177 // catching here and reacting by not widening
179 catch (ArgumentException)
183 // Allocate array of floats
184 coord = new float[path.PointCount * 2];
185 pathPoints = path.PathPoints;
186 for( int i = 0; i < path.PointCount; i++ )
188 pointNew = graph.GetRelativePoint( pathPoints[i] );
189 coord[2*i] = pointNew.X;
190 coord[2*i + 1] = pointNew.Y;
193 common.HotRegionsList.AddHotRegion(
197 series.Points[pointIndex - 1],
206 #region 3D Line drawing and selection
209 /// Draws a 3D surface connecting the two specified points in 2D space.
210 /// Used to draw Line based charts.
212 /// <param name="area">Chart area reference.</param>
213 /// <param name="graph">Chart graphics.</param>
214 /// <param name="matrix">Coordinates transformation matrix.</param>
215 /// <param name="lightStyle">LightStyle style (None, Simplistic, Realistic).</param>
216 /// <param name="prevDataPointEx">Previous data point object.</param>
217 /// <param name="positionZ">Z position of the back side of the 3D surface.</param>
218 /// <param name="depth">Depth of the 3D surface.</param>
219 /// <param name="points">Array of points.</param>
220 /// <param name="pointIndex">Index of point to draw.</param>
221 /// <param name="pointLoopIndex">Index of points loop.</param>
222 /// <param name="tension">Line tension.</param>
223 /// <param name="operationType">AxisName of operation Drawing, Calculating Path or Both</param>
224 /// <param name="topDarkening">Darkenning scale for top surface. 0 - None.</param>
225 /// <param name="bottomDarkening">Darkenning scale for bottom surface. 0 - None.</param>
226 /// <param name="thirdPointPosition">Position where the third point is actually located or float.NaN if same as in "firstPoint".</param>
227 /// <param name="fourthPointPosition">Position where the fourth point is actually located or float.NaN if same as in "secondPoint".</param>
228 /// <param name="clippedSegment">Indicates that drawn segment is 3D clipped. Only top/bottom should be drawn.</param>
229 /// <returns>Returns elemnt shape path if operationType parameter is set to CalcElementPath, otherwise Null.</returns>
230 protected override GraphicsPath Draw3DSurface(
234 LightStyle lightStyle,
235 DataPoint3D prevDataPointEx,
242 DrawingOperationTypes operationType,
244 float bottomDarkening,
245 PointF thirdPointPosition,
246 PointF fourthPointPosition,
249 // Create graphics path for selection
250 GraphicsPath resultPath = ((operationType & DrawingOperationTypes.CalcElementPath) == DrawingOperationTypes.CalcElementPath)
251 ? new GraphicsPath() : null;
253 // Check if points are drawn from sides to center (do only once)
254 if(centerPointIndex == int.MaxValue)
256 centerPointIndex = GetCenterPointIndex(points);
259 //************************************************************
260 //** Find line first & second points
261 //************************************************************
262 DataPoint3D secondPoint = (DataPoint3D)points[pointIndex];
263 int pointArrayIndex = pointIndex;
264 DataPoint3D firstPoint = ChartGraphics.FindPointByIndex(
266 secondPoint.index - 1,
267 (this.multiSeries) ? secondPoint : null,
268 ref pointArrayIndex);
270 // Fint point with line properties
271 DataPoint3D pointAttr = secondPoint;
272 if(prevDataPointEx.dataPoint.IsEmpty)
274 pointAttr = prevDataPointEx;
276 else if(firstPoint.index > secondPoint.index)
278 pointAttr = firstPoint;
281 // Adjust point visual properties
282 Color color = (useBorderColor) ? pointAttr.dataPoint.BorderColor : pointAttr.dataPoint.Color;
283 ChartDashStyle dashStyle = pointAttr.dataPoint.BorderDashStyle;
284 if( pointAttr.dataPoint.IsEmpty && pointAttr.dataPoint.Color == Color.Empty)
288 if( pointAttr.dataPoint.IsEmpty && pointAttr.dataPoint.BorderDashStyle == ChartDashStyle.NotSet )
290 dashStyle = ChartDashStyle.Solid;
293 //************************************************************
294 //** Create "middle" point
295 //************************************************************
296 DataPoint3D middlePoint = new DataPoint3D();
297 middlePoint.xPosition = secondPoint.xPosition;
298 middlePoint.yPosition = firstPoint.yPosition;
300 // Check if reversed drawing order required
301 bool originalDrawOrder = true;
302 if((pointIndex + 1) < points.Count)
304 DataPoint3D p = (DataPoint3D)points[pointIndex + 1];
305 if(p.index == firstPoint.index)
307 originalDrawOrder = false;
311 // Check in which order vertical & horizontal lines segments should be drawn
312 if(centerPointIndex != int.MaxValue)
314 if(pointIndex >= centerPointIndex)
316 originalDrawOrder = false;
320 // Draw two segments of the step line
321 GraphicsPath resultPathLine1, resultPathLine2;
322 if(originalDrawOrder)
325 middlePoint.dataPoint = secondPoint.dataPoint;
326 resultPathLine1 = graph.Draw3DSurface(
327 area, matrix, lightStyle, SurfaceNames.Top, positionZ, depth, color,
328 pointAttr.dataPoint.BorderColor, pointAttr.dataPoint.BorderWidth, dashStyle,
329 firstPoint, middlePoint,
330 points, pointIndex, 0f, operationType, LineSegmentType.First,
331 (this.showPointLines) ? true : false, false,
332 area.ReverseSeriesOrder,
333 this.multiSeries, 0, true);
335 // No second draw of the prev. front line required
336 graph.frontLinePen = null;
339 middlePoint.dataPoint = firstPoint.dataPoint;
340 resultPathLine2 = graph.Draw3DSurface(
341 area, matrix, lightStyle, SurfaceNames.Top, positionZ, depth, color,
342 pointAttr.dataPoint.BorderColor, pointAttr.dataPoint.BorderWidth, dashStyle,
343 middlePoint, secondPoint,
344 points, pointIndex, 0f, operationType, LineSegmentType.Last,
345 (this.showPointLines) ? true : false, false,
346 area.ReverseSeriesOrder,
347 this.multiSeries, 0, true);
349 // No second draw of the prev. front line required
350 graph.frontLinePen = null;
355 middlePoint.dataPoint = firstPoint.dataPoint;
356 resultPathLine2 = graph.Draw3DSurface(
357 area, matrix, lightStyle, SurfaceNames.Top, positionZ, depth, color,
358 pointAttr.dataPoint.BorderColor, pointAttr.dataPoint.BorderWidth, dashStyle,
359 middlePoint, secondPoint,
360 points, pointIndex, 0f, operationType, LineSegmentType.Last,
361 (this.showPointLines) ? true : false, false,
362 area.ReverseSeriesOrder,
363 this.multiSeries, 0, true);
365 // No second draw of the prev. front line required
366 graph.frontLinePen = null;
369 middlePoint.dataPoint = secondPoint.dataPoint;
370 resultPathLine1 = graph.Draw3DSurface(
371 area, matrix, lightStyle, SurfaceNames.Top, positionZ, depth, color,
372 pointAttr.dataPoint.BorderColor, pointAttr.dataPoint.BorderWidth, dashStyle,
373 firstPoint, middlePoint,
374 points, pointIndex, 0f, operationType, LineSegmentType.First,
375 (this.showPointLines) ? true : false, false,
376 area.ReverseSeriesOrder,
377 this.multiSeries, 0, true);
379 // No second draw of the prev. front line required
380 graph.frontLinePen = null;
383 if(resultPath != null)
385 if( area.Common.ProcessModeRegions)
387 if(resultPathLine1 != null && resultPathLine1.PointCount > 0)
389 area.Common.HotRegionsList.AddHotRegion(
393 prevDataPointEx.dataPoint,
394 prevDataPointEx.dataPoint.series.Name,
395 prevDataPointEx.index - 1 );
399 if(resultPathLine2 != null && resultPathLine2.PointCount > 0)
401 resultPath.AddPath(resultPathLine2, true);