Updates referencesource to .NET 4.7
[mono.git] / mcs / class / referencesource / System.Web.DataVisualization / Common / ChartTypes / StockChart.cs
1 //-------------------------------------------------------------
2 // <copyright company=\92Microsoft Corporation\92>
3 //   Copyright © Microsoft Corporation. All Rights Reserved.
4 // </copyright>
5 //-------------------------------------------------------------
6 // @owner=alexgor, deliant
7 //=================================================================
8 //  File:               StockChart.cs
9 //
10 //  Namespace:  DataVisualization.Charting.ChartTypes
11 //
12 //      Classes:        StockChart, CandleStickChart
13 //
14 //  Purpose:    Stock chart requires 4 Y values High, Low, Open and Close.
15 //  
16 //  The Stock chart displays opening and closing values by using 
17 //  markers, which are typically lines or triangles. \93OpenCloseStyle\94 
18 //  custom attribute may be used to control the style of the markers. 
19 //  The opening values are shown by the markers on the left, and the 
20 //  closing values are shown by the markers on the right.
21 //  
22 //  A stock chart is typically used to illustrate significant stock 
23 //  price points including a stock's open, close, high, and low price 
24 //  points. However, this type of chart can also be used to analyze 
25 //  scientific data, because each series of data displays a high, low, 
26 //  open, and close value.
27 //
28 //      Reviewed:       AG - Aug 6, 2002
29 //              AG - Microsoft 7, 2007
30 //
31 //===================================================================
32
33 #region Used namespaces
34
35 using System;
36 using System.Collections;
37 using System.Drawing;
38 using System.Drawing.Drawing2D;
39 using System.Collections.Generic;
40
41 #if Microsoft_CONTROL
42         using System.Windows.Forms.DataVisualization.Charting.Utilities;
43 #else
44         using System.Web.UI.DataVisualization.Charting.Utilities;
45 #endif
46
47 #endregion
48
49 #if Microsoft_CONTROL
50         namespace System.Windows.Forms.DataVisualization.Charting.ChartTypes
51 #else
52         namespace System.Web.UI.DataVisualization.Charting.ChartTypes
53 #endif
54 {
55         #region Open/close marks style enumeration
56
57         /// <summary>
58         /// Style of the Open-Close marks in the stock chart
59         /// </summary>
60         internal enum StockOpenCloseMarkStyle
61         {
62                 /// <summary>
63                 /// Line
64                 /// </summary>
65                 Line,
66
67                 /// <summary>
68                 /// Triangle
69                 /// </summary>
70                 Triangle,
71
72                 /// <summary>
73                 /// CandleStick. Color of the bar depends if Open value was bigger than Close value.
74                 /// </summary>
75                 Candlestick
76         }
77
78         #endregion
79
80         /// <summary>
81         /// CandleStick class provides chart unique name and changes the marking 
82     /// style in the StockChart class to StockOpenCloseMarkStyle.CandleStick.
83         /// </summary>
84         internal class CandleStickChart : StockChart
85         {
86                 #region Constructor
87
88                 /// <summary>
89                 /// CandleStick chart constructor.
90                 /// </summary>
91                 public CandleStickChart() : base(StockOpenCloseMarkStyle.Candlestick)
92                 {
93                         forceCandleStick = true;
94                 }
95
96                 #endregion
97
98                 #region IChartType interface implementation
99
100                 /// <summary>
101                 /// Chart type name
102                 /// </summary>
103                 override public string Name                     { get{ return ChartTypeNames.Candlestick;}}
104
105                 /// <summary>
106                 /// Gets chart type image.
107                 /// </summary>
108                 /// <param name="registry">Chart types registry object.</param>
109                 /// <returns>Chart type image.</returns>
110                 override public System.Drawing.Image GetImage(ChartTypeRegistry registry)
111                 {
112                         return (System.Drawing.Image)registry.ResourceManager.GetObject(this.Name + "ChartType");
113                 }
114
115                 #endregion
116         }
117
118         /// <summary>
119     /// StockChart class provides 2D/3D drawing and hit testing 
120     /// functionality for the Stock and CandleStick charts.
121         /// </summary>
122         internal class StockChart : IChartType
123         {
124                 #region Fields
125
126                 /// <summary>
127                 /// Vertical axis
128                 /// </summary>
129         internal Axis VAxis { get; set; }
130
131                 /// <summary>
132                 /// Horizontal axis
133                 /// </summary>
134         internal Axis HAxis { get; set; }
135
136                 /// <summary>
137                 /// Default open-close style
138                 /// </summary>
139                 protected       StockOpenCloseMarkStyle openCloseStyle = StockOpenCloseMarkStyle.Line;
140
141                 /// <summary>
142                 /// Indicates that only candle-stick type of the open-close marks should be used
143                 /// </summary>
144                 protected       bool    forceCandleStick = false;
145
146                 #endregion
147
148                 #region Constructor
149
150                 /// <summary>
151                 /// Stock chart constructor.
152                 /// </summary>
153                 public StockChart()
154                 {
155                 }
156
157                 /// <summary>
158                 /// Stock chart constructor.
159                 /// </summary>
160                 /// <param name="style">Open-close marks default style.</param>
161                 public StockChart(StockOpenCloseMarkStyle style)
162                 {
163                         this.openCloseStyle = style;
164                 }
165
166                 #endregion
167
168                 #region IChartType interface implementation
169
170                 /// <summary>
171                 /// Chart type name
172                 /// </summary>
173                 virtual public string Name                      { get{ return ChartTypeNames.Stock;}}
174
175                 /// <summary>
176                 /// True if chart type is stacked
177                 /// </summary>
178                 virtual public bool Stacked             { get{ return false;}}
179
180
181                 /// <summary>
182                 /// True if stacked chart type supports groups
183                 /// </summary>
184                 virtual public bool SupportStackedGroups        { get { return false; } }
185
186
187                 /// <summary>
188                 /// True if stacked chart type should draw separately positive and 
189                 /// negative data points ( Bar and column Stacked types ).
190                 /// </summary>
191                 public bool StackSign           { get{ return false;}}
192
193                 /// <summary>
194                 /// True if chart type supports axeses
195                 /// </summary>
196                 virtual public bool RequireAxes { get{ return true;} }
197
198                 /// <summary>
199                 /// Chart type with two y values used for scale ( bubble chart type )
200                 /// </summary>
201                 public bool SecondYScale{ get{ return false;} }
202
203                 /// <summary>
204                 /// True if chart type requires circular chart area.
205                 /// </summary>
206                 public bool CircularChartArea   { get{ return false;} }
207
208                 /// <summary>
209                 /// True if chart type supports Logarithmic axes
210                 /// </summary>
211                 virtual public bool SupportLogarithmicAxes      { get{ return true;} }
212
213                 /// <summary>
214                 /// True if chart type requires to switch the value (Y) axes position
215                 /// </summary>
216                 virtual public bool SwitchValueAxes     { get{ return false;} }
217
218                 /// <summary>
219                 /// True if chart series can be placed side-by-side.
220                 /// </summary>
221                 public bool SideBySideSeries { get{ return false;} }
222
223                 /// <summary>
224                 /// True if each data point of a chart must be represented in the legend
225                 /// </summary>
226                 virtual public bool DataPointsInLegend  { get{ return false;} }
227
228                 /// <summary>
229                 /// If the crossing value is auto Crossing value should be 
230                 /// automatically set to zero for some chart 
231                 /// types (Bar, column, area etc.)
232                 /// </summary>
233                 virtual public bool ZeroCrossing { get{ return false;} }
234
235                 /// <summary>
236                 /// True if palette colors should be applied for each data paoint.
237                 /// Otherwise the color is applied to the series.
238                 /// </summary>
239                 virtual public bool ApplyPaletteColorsToPoints  { get { return false; } }
240
241                 /// <summary>
242                 /// Indicates that extra Y values are connected to the scale of the Y axis
243                 /// </summary>
244                 virtual public bool ExtraYValuesConnectedToYAxis{ get { return true; } }
245                 
246                 /// <summary>
247                 /// Indicates that it's a hundredred percent chart.
248                 /// Axis scale from 0 to 100 percent should be used.
249                 /// </summary>
250                 virtual public bool HundredPercent{ get{return false;} }
251
252                 /// <summary>
253                 /// Indicates that it's a hundredred percent chart.
254                 /// Axis scale from 0 to 100 percent should be used.
255                 /// </summary>
256                 virtual public bool HundredPercentSupportNegative{ get{return false;} }
257
258                 /// <summary>
259                 /// How to draw series/points in legend:
260                 /// Filled rectangle, Line or Marker
261                 /// </summary>
262                 /// <param name="series">Legend item series.</param>
263                 /// <returns>Legend item style.</returns>
264                 virtual public LegendImageStyle GetLegendImageStyle(Series series)
265                 {
266                         return LegendImageStyle.Line;
267                 }
268         
269                 /// <summary>
270                 /// Number of supported Y value(s) per point 
271                 /// </summary>
272                 virtual public int YValuesPerPoint      { get { return 4; } }
273
274                 /// <summary>
275                 /// Gets chart type image.
276                 /// </summary>
277                 /// <param name="registry">Chart types registry object.</param>
278                 /// <returns>Chart type image.</returns>
279                 virtual public System.Drawing.Image GetImage(ChartTypeRegistry registry)
280                 {
281                         return (System.Drawing.Image)registry.ResourceManager.GetObject(this.Name + "ChartType");
282                 }
283                 #endregion
284
285                 #region Painting and Selection methods
286
287                 /// <summary>
288                 /// Paint stock chart.
289                 /// </summary>
290                 /// <param name="graph">The Chart Graphics object.</param>
291                 /// <param name="common">The Common elements object.</param>
292                 /// <param name="area">Chart area for this chart.</param>
293                 /// <param name="seriesToDraw">Chart series to draw.</param>
294                 virtual public void Paint( ChartGraphics graph, CommonElements common, ChartArea area, Series seriesToDraw )
295                 {       
296                         ProcessChartType( false, graph, common, area, seriesToDraw );
297                 }
298
299                 /// <summary>
300                 /// This method recalculates size of the bars. This method is used 
301                 /// from Paint or Select method.
302                 /// </summary>
303                 /// <param name="selection">If True selection mode is active, otherwise paint mode is active.</param>
304                 /// <param name="graph">The Chart Graphics object.</param>
305                 /// <param name="common">The Common elements object.</param>
306                 /// <param name="area">Chart area for this chart.</param>
307                 /// <param name="seriesToDraw">Chart series to draw.</param>
308                 virtual protected void ProcessChartType( 
309                         bool selection, 
310                         ChartGraphics graph, 
311                         CommonElements common, 
312                         ChartArea area, 
313                         Series seriesToDraw )
314                 {
315                         
316                         // Prosess 3D chart type
317                         if(area.Area3DStyle.Enable3D)
318                         {
319                                 ProcessChartType3D( selection, graph, common, area, seriesToDraw );
320                                 return;
321                         }
322                         
323
324                         // All data series from chart area which have Stock chart type
325                         List<string>    typeSeries = area.GetSeriesFromChartType(this.Name);
326
327                         // Zero X values mode.
328                         bool indexedSeries = ChartHelper.IndexedSeries(common, typeSeries.ToArray() );
329
330                         //************************************************************
331                         //** Loop through all series
332                         //************************************************************
333                         foreach( Series ser in common.DataManager.Series )
334                         {
335                                 // Process non empty series of the area with stock chart type
336                                 if( String.Compare( ser.ChartTypeName, this.Name, StringComparison.OrdinalIgnoreCase ) != 0 
337                                         || ser.ChartArea != area.Name || !ser.IsVisible())
338                                 {
339                                         continue;
340                                 }
341
342                                 // Check that we have at least 4 Y values
343                                 if(ser.YValuesPerPoint < 4)
344                                 {
345                                         throw(new ArgumentException(SR.ExceptionChartTypeRequiresYValues("StockChart", "4")));
346                                 }
347
348                                 // Set active horizontal/vertical axis
349                                 HAxis = area.GetAxis(AxisName.X, ser.XAxisType, ser.XSubAxisName);
350                                 VAxis = area.GetAxis(AxisName.Y, ser.YAxisType, ser.YSubAxisName);
351
352                                 // Get interval between points
353                                 double interval = (indexedSeries) ? 1 : area.GetPointsInterval( HAxis.IsLogarithmic, HAxis.logarithmBase );
354
355                                 // Calculates the width of the candles.
356                                 float width = (float)(ser.GetPointWidth(graph, HAxis, interval, 0.8));
357
358                                 // Call Back Paint event
359                                 if( !selection )
360                                 {
361                     common.Chart.CallOnPrePaint(new ChartPaintEventArgs(ser, graph, common, area.PlotAreaPosition));
362                                 }
363
364
365                                 //************************************************************
366                                 //** Series data points loop
367                                 //************************************************************
368                                 int     index = 1;
369                                 foreach( DataPoint point in ser.Points )
370                                 {
371                                         // Reset pre-calculated point position
372                                         point.positionRel = new PointF(float.NaN, float.NaN);
373
374                                         // Get point X position
375                                         double  xValue = point.XValue;
376                                         if( indexedSeries )
377                                         {
378                                                 xValue = (double)index;
379                                         }
380                                         float xPosition = (float)HAxis.GetPosition( xValue );
381
382                                         double yValue0 = VAxis.GetLogValue( point.YValues[0] );
383                                         double yValue1 = VAxis.GetLogValue( point.YValues[1] );
384                                         xValue = HAxis.GetLogValue(xValue);
385                                         
386                                         // Check if chart is completly out of the data scaleView
387                                         if(xValue < HAxis.ViewMinimum || 
388                                                 xValue > HAxis.ViewMaximum ||
389                                                 (yValue0 < VAxis.ViewMinimum && yValue1 < VAxis.ViewMinimum) ||
390                                                 (yValue0 > VAxis.ViewMaximum && yValue1 > VAxis.ViewMaximum) )
391                                         {
392                                                 ++index;
393                                                 continue;
394                                         }
395                                         
396                                         // Make sure High/Low values are in data scaleView range                                                
397                                         double  high = VAxis.GetLogValue( point.YValues[0] );
398                                         double  low = VAxis.GetLogValue( point.YValues[1] );
399                                         
400                                         if( high > VAxis.ViewMaximum )
401                                         {
402                                                 high = VAxis.ViewMaximum;
403                                         }
404                                         if( high < VAxis.ViewMinimum )
405                                         {
406                                                 high = VAxis.ViewMinimum;
407                                         }
408                                         high = (float)VAxis.GetLinearPosition(high);
409                                         
410                                         if( low > VAxis.ViewMaximum )
411                                         {
412                                                 low = VAxis.ViewMaximum;
413                                         }
414                                         if( low < VAxis.ViewMinimum )
415                                         {
416                                                 low = VAxis.ViewMinimum;
417                                         }
418                                         low = VAxis.GetLinearPosition(low);
419
420                                         // Remeber pre-calculated point position
421                                         point.positionRel = new PointF((float)xPosition, (float)high);
422
423                                         if( common.ProcessModePaint )
424                                         {
425
426                                                 // Check if chart is partialy in the data scaleView
427                                                 bool    clipRegionSet = false;
428                                                 if(xValue == HAxis.ViewMinimum || xValue == HAxis.ViewMaximum )
429                                                 {
430                                                         // Set clipping region for line drawing 
431                                                         graph.SetClip( area.PlotAreaPosition.ToRectangleF() );
432                                                         clipRegionSet = true;
433                                                 }
434
435                                                 // Start Svg Selection mode
436                                                 graph.StartHotRegion( point );
437
438                                                 // Draw Hi-Low line
439                                                 graph.DrawLineRel( 
440                                                         point.Color, 
441                                                         point.BorderWidth, 
442                                                         point.BorderDashStyle, 
443                                                         new PointF(xPosition, (float)high), 
444                                                         new PointF(xPosition, (float)low),
445                                                         ser.ShadowColor, 
446                                                         ser.ShadowOffset );
447
448                                                 // Draw Open-Close marks
449                                                 DrawOpenCloseMarks(graph, area, ser, point, xPosition, width);
450
451                                                 // End Svg Selection mode
452                                                 graph.EndHotRegion( );
453
454                                                 // Reset Clip Region
455                                                 if(clipRegionSet)
456                                                 {
457                                                         graph.ResetClip();
458                                                 }
459                                         }
460
461                                         if( common.ProcessModeRegions )
462                                         {
463                                                 // Calculate rect around the hi-lo line and open-close marks
464                                                 RectangleF      areaRect = RectangleF.Empty;
465                                                 areaRect.X = xPosition - width / 2f;
466                                                 areaRect.Y = (float)Math.Min(high, low);
467                                                 areaRect.Width = width;
468                                                 areaRect.Height = (float)Math.Max(high, low) - areaRect.Y;
469
470                                                 common.HotRegionsList.AddHotRegion( 
471                                                         areaRect, 
472                                                         point, 
473                                                         ser.Name, 
474                                                         index - 1 );
475                                                 
476                                         }
477                                         ++index;
478                                 }
479
480                                 //************************************************************
481                                 //** Second series data points loop, when markers and labels
482                                 //** are drawn.
483                                 //************************************************************
484                                 
485                                 int markerIndex = 0;
486                                 index = 1;
487                                 foreach( DataPoint point in ser.Points )
488                                 {
489                                         // Get point X position
490                                         double  xValue = point.XValue;
491                                         if( indexedSeries )
492                                         {
493                                                 xValue = (double)index;
494                                         }
495                                         float xPosition = (float)HAxis.GetPosition( xValue );
496
497                                         double yValue0 = VAxis.GetLogValue( point.YValues[0] );
498                                         double yValue1 = VAxis.GetLogValue( point.YValues[1] );
499                                         xValue = HAxis.GetLogValue(xValue);
500                                 
501                                         // Check if chart is completly out of the data scaleView
502                                         if(xValue < HAxis.ViewMinimum || 
503                                                 xValue > HAxis.ViewMaximum ||
504                                                 (yValue0 < VAxis.ViewMinimum && yValue1 < VAxis.ViewMinimum) ||
505                                                 (yValue0 > VAxis.ViewMaximum && yValue1 > VAxis.ViewMaximum) )
506                                         {
507                                                 ++index;
508                                                 continue;
509                                         }
510
511                                         // Make sure High/Low values are in data scaleView range                                                
512                                         double  high = VAxis.GetLogValue( point.YValues[0] );
513                                         double  low = VAxis.GetLogValue( point.YValues[1] );
514                                 
515                                         if( high > VAxis.ViewMaximum )
516                                         {
517                                                 high = VAxis.ViewMaximum;
518                                         }
519                                         if( high < VAxis.ViewMinimum )
520                                         {
521                                                 high = VAxis.ViewMinimum;
522                                         }
523                                         high = (float)VAxis.GetLinearPosition(high);
524                                 
525                                         if( low > VAxis.ViewMaximum )
526                                         {
527                                                 low = VAxis.ViewMaximum;
528                                         }
529                                         if( low < VAxis.ViewMinimum )
530                                         {
531                                                 low = VAxis.ViewMinimum;
532                                         }
533                                         low = VAxis.GetLinearPosition(low);
534
535                                         // Draw marker
536                                         if(point.MarkerStyle != MarkerStyle.None || point.MarkerImage.Length > 0)
537                                         {
538                                                 // Get marker size
539                                                 SizeF markerSize = SizeF.Empty;
540                                                 markerSize.Width = point.MarkerSize;
541                                                 markerSize.Height = point.MarkerSize;
542                         if (graph != null && graph.Graphics != null)
543                         {
544                             // Marker size is in pixels and we do the mapping for higher DPIs
545                             markerSize.Width = point.MarkerSize * graph.Graphics.DpiX / 96;
546                             markerSize.Height = point.MarkerSize * graph.Graphics.DpiY / 96;
547                         }
548
549                         if (point.MarkerImage.Length > 0)
550                             common.ImageLoader.GetAdjustedImageSize(point.MarkerImage, graph.Graphics, ref markerSize);
551                         
552                                                 // Get marker position
553                                                 PointF markerPosition = PointF.Empty;
554                                                 markerPosition.X = xPosition;
555                                                 markerPosition.Y = (float)high - graph.GetRelativeSize(markerSize).Height/2f;
556
557                                                 // Draw marker
558                                                 if(markerIndex == 0)
559                                                 {
560                                                         // Draw the marker
561                                                         graph.DrawMarkerRel(markerPosition, 
562                                                                 point.MarkerStyle,
563                                                                 (int)markerSize.Height,
564                                                                 (point.MarkerColor == Color.Empty) ? point.Color : point.MarkerColor,
565                                                                 (point.MarkerBorderColor == Color.Empty) ? point.BorderColor : point.MarkerBorderColor,
566                                                                 point.MarkerBorderWidth,
567                                                                 point.MarkerImage,
568                                                                 point.MarkerImageTransparentColor,
569                                                                 (point.series != null) ? point.series.ShadowOffset : 0,
570                                                                 (point.series != null) ? point.series.ShadowColor : Color.Empty,
571                                                                 new RectangleF(markerPosition.X, markerPosition.Y, markerSize.Width, markerSize.Height));
572
573                                                         if( common.ProcessModeRegions )
574                                                         {
575                                                                 // Get relative marker size
576                                                                 SizeF relativeMarkerSize = graph.GetRelativeSize(markerSize);
577
578                                                                 // Insert area just after the last custom area
579                                                                 int insertIndex = common.HotRegionsList.FindInsertIndex();
580                                                                 common.HotRegionsList.FindInsertIndex();
581
582                                                                 // Insert circle area
583                                                                 if(point.MarkerStyle == MarkerStyle.Circle)
584                                                                 {
585                                                                         float[] circCoord = new float[3];
586                                                                         circCoord[0] = markerPosition.X;
587                                                                         circCoord[1] = markerPosition.Y;
588                                                                         circCoord[2] = relativeMarkerSize.Width/2f;
589
590                                                                         common.HotRegionsList.AddHotRegion( 
591                                                                                 insertIndex, 
592                                                                                 graph, 
593                                                                                 circCoord[0], 
594                                                                                 circCoord[1], 
595                                                                                 circCoord[2], 
596                                                                                 point, 
597                                                                                 ser.Name, 
598                                                                                 index - 1 );
599                                                                 }
600                                                                 // All other markers represented as rectangles
601                                                                 else
602                                                                 {
603                                                                         common.HotRegionsList.AddHotRegion(
604                                                                                 new RectangleF(markerPosition.X - relativeMarkerSize.Width/2f, markerPosition.Y - relativeMarkerSize.Height/2f, relativeMarkerSize.Width, relativeMarkerSize.Height),
605                                                                                 point,
606                                                                                 ser.Name,
607                                                                                 index - 1 );
608                                                                 }
609                                                         }
610
611                                                 }
612                                 
613                                                 // Increase the markers counter
614                                                 ++markerIndex;
615                                                 if(ser.MarkerStep == markerIndex)
616                                                 {
617                                                         markerIndex = 0;
618                                                 }
619                                         }
620
621                                         // Draw label
622                                         DrawLabel(common, area, graph, ser, point, new PointF(xPosition, (float)Math.Min(high, low)), index);
623
624                                         // Increase point counter
625                                         ++index;
626                                 }
627                                 
628                                 // Call Paint event
629                                 if( !selection )
630                                 {
631                     common.Chart.CallOnPostPaint(new ChartPaintEventArgs(ser, graph, common, area.PlotAreaPosition));
632                                 }
633                         }
634                 }
635
636                 /// <summary>
637                 /// Draws stock chart open-close marks depending on selected style.
638                 /// </summary>
639                 /// <param name="graph">Chart graphics object.</param>
640                 /// <param name="area">Chart area.</param>
641                 /// <param name="ser">Data point series.</param>
642                 /// <param name="point">Data point to draw.</param>
643                 /// <param name="xPosition">X position.</param>
644                 /// <param name="width">Point width.</param>
645                 virtual protected void DrawOpenCloseMarks(
646                         ChartGraphics graph, 
647                         ChartArea area,
648                         Series ser, 
649                         DataPoint point, 
650                         float xPosition, 
651                         float width)
652                 {
653                         double openY = VAxis.GetLogValue( point.YValues[2] );
654                         double closeY = VAxis.GetLogValue( point.YValues[3] );
655
656                         // Check if mark is inside data scaleView
657                         if( (openY > VAxis.ViewMaximum ||
658                                 openY < VAxis.ViewMinimum) &&
659                                 (closeY > VAxis.ViewMaximum ||
660                                 closeY < VAxis.ViewMinimum) )
661                         {
662                                 //return;
663                         }
664
665                         // Calculate open-close position
666                         float   open = (float)VAxis.GetLinearPosition(openY);
667                         float   close = (float)VAxis.GetLinearPosition(closeY);
668                         SizeF   absSize = graph.GetAbsoluteSize(new SizeF(width, width));
669                         float   height = graph.GetRelativeSize(absSize).Height;
670
671                         // Detect style
672                         StockOpenCloseMarkStyle style = openCloseStyle;
673                         string  styleType = "";
674                         if(point.IsCustomPropertySet(CustomPropertyName.OpenCloseStyle))
675                         {
676                                 styleType = point[CustomPropertyName.OpenCloseStyle];
677                         }
678                         else if(ser.IsCustomPropertySet(CustomPropertyName.OpenCloseStyle))
679                         {
680                                 styleType = ser[CustomPropertyName.OpenCloseStyle];
681                         }
682
683                         if(styleType != null && styleType.Length > 0)
684                         {
685                                 if(String.Compare(styleType, "Candlestick", StringComparison.OrdinalIgnoreCase) == 0)
686                                 {
687                                         style = StockOpenCloseMarkStyle.Candlestick;
688                                 }
689                 else if (String.Compare(styleType, "Triangle", StringComparison.OrdinalIgnoreCase) == 0)
690                                 {
691                                         style = StockOpenCloseMarkStyle.Triangle;
692                                 }
693                 else if (String.Compare(styleType, "Line", StringComparison.OrdinalIgnoreCase) == 0)
694                                 {
695                                         style = StockOpenCloseMarkStyle.Line;
696                                 }
697                         }
698
699                         // Get attribute which controls if open/close marks are shown
700                         bool    showOpen = true;
701                         bool    showClose = true;
702                         string  showOpenClose = "";
703                         if(point.IsCustomPropertySet(CustomPropertyName.ShowOpenClose))
704                         {
705                                 showOpenClose = point[CustomPropertyName.ShowOpenClose];
706                         }
707                         else if(ser.IsCustomPropertySet(CustomPropertyName.ShowOpenClose))
708                         {
709                                 showOpenClose = ser[CustomPropertyName.ShowOpenClose];
710                         }
711
712                         if(showOpenClose != null && showOpenClose.Length > 0)
713                         {
714                                 if(String.Compare(showOpenClose, "Both", StringComparison.OrdinalIgnoreCase) == 0)
715                                 {
716                                         showOpen = true;
717                                         showClose = true;
718                                 }
719                 else if (String.Compare(showOpenClose, "Open", StringComparison.OrdinalIgnoreCase) == 0)
720                                 {
721                                         showOpen = true;
722                                         showClose = false;
723                                 }
724                 else if (String.Compare(showOpenClose, "Close", StringComparison.OrdinalIgnoreCase) == 0)
725                                 {
726                                         showOpen = false;
727                                         showClose = true;
728                                 }
729                         }
730
731                         // Check if chart is partialy in the data scaleView
732                         bool    clipRegionSet = false;
733                         if( style == StockOpenCloseMarkStyle.Candlestick || (xPosition - width / 2f) < area.PlotAreaPosition.X || (xPosition + width / 2f) > area.PlotAreaPosition.Right)
734                         {
735                                 // Set clipping region for line drawing 
736                                 graph.SetClip( area.PlotAreaPosition.ToRectangleF() );
737                                 clipRegionSet = true;
738                         }
739
740                         
741                         // Draw open-close marks as bar
742                         if(forceCandleStick || style == StockOpenCloseMarkStyle.Candlestick)
743                         {
744                                 // Colors used to draw bar of the open-close style
745                                 ColorConverter  colorConverter = new ColorConverter();
746                                 Color                   priceUpColor = point.Color;
747                                 Color                   priceDownColor = point.BackSecondaryColor;
748
749                                 // Check if special color properties are set
750                                 string  attrValue = point[CustomPropertyName.PriceUpColor];
751                                 if(attrValue != null && attrValue.Length > 0)
752                                 {
753                     bool failed = false;
754                     try
755                     {
756                         priceUpColor = (Color)colorConverter.ConvertFromString(attrValue);
757                     }
758                     catch (ArgumentException)
759                     {
760                         failed = true;
761                     }
762                     catch (NotSupportedException)
763                     {
764                         failed = true;
765                     }
766
767                     if (failed)
768                     {
769                         priceUpColor = (Color)colorConverter.ConvertFromInvariantString(attrValue);
770                     }
771                                 }
772
773                                 attrValue = point[CustomPropertyName.PriceDownColor];
774                                 if(attrValue != null && attrValue.Length > 0)
775                                 {
776                     bool failed = false;
777                     try
778                     {
779                         priceDownColor = (Color)colorConverter.ConvertFromString(attrValue);
780                     }
781                     catch (ArgumentException)
782                     {
783                         failed = true;
784                     }
785                     catch (NotSupportedException)
786                     {
787                         failed = true;
788                     }
789
790                     if (failed)
791                     {
792                         priceDownColor = (Color)colorConverter.ConvertFromInvariantString(attrValue);
793                     }
794                                 }
795
796                                 // Calculate bar rectangle
797                                 RectangleF      rect = RectangleF.Empty;
798                                 rect.Y = (float)Math.Min(open, close);
799                                 rect.X = xPosition - width / 2f;
800                                 rect.Height = (float)Math.Max(open, close) - rect.Y;
801                                 rect.Width = width;
802
803                                 // Bar and border color
804                                 Color   barColor = (open > close) ? priceUpColor : priceDownColor;
805                                 Color   barBorderColor = (point.BorderColor == Color.Empty) ? (barColor == Color.Empty) ? point.Color : barColor : point.BorderColor;
806                                 
807                                 // Get absolute height
808                                 SizeF sizeOfHeight = new SizeF( rect.Height, rect.Height );
809                                 sizeOfHeight = graph.GetAbsoluteSize( sizeOfHeight );
810
811                                 // Draw open-close bar
812                                 if( sizeOfHeight.Height > 1 )
813                                 {
814                                         graph.FillRectangleRel( 
815                                                 rect, 
816                                                 barColor,
817                                                 point.BackHatchStyle, 
818                                                 point.BackImage, 
819                                                 point.BackImageWrapMode, 
820                                                 point.BackImageTransparentColor,
821                                                 point.BackImageAlignment,
822                                                 point.BackGradientStyle, 
823                                                 point.BackSecondaryColor, 
824                                                 barBorderColor, 
825                                                 point.BorderWidth, 
826                                                 point.BorderDashStyle, 
827                                                 ser.ShadowColor, 
828                                                 ser.ShadowOffset,
829                                                 PenAlignment.Inset );
830                                 }
831                                 else
832                                 {
833                                         graph.DrawLineRel(barBorderColor, point.BorderWidth, point.BorderDashStyle, 
834                                                 new PointF(rect.X, rect.Y), 
835                                                 new PointF(rect.Right, rect.Y),
836                                                 ser.ShadowColor, ser.ShadowOffset );
837                                 }
838                         }
839
840                         // Draw open-close marks as triangals
841                         else if(style == StockOpenCloseMarkStyle.Triangle)
842                         {
843                 using (GraphicsPath path = new GraphicsPath())
844                 {
845                     PointF point1 = graph.GetAbsolutePoint(new PointF(xPosition, open));
846                     PointF point2 = graph.GetAbsolutePoint(new PointF(xPosition - width / 2f, open + height / 2f));
847                     PointF point3 = graph.GetAbsolutePoint(new PointF(xPosition - width / 2f, open - height / 2f));
848
849                     using (Brush brush = new SolidBrush(point.Color))
850                     {
851                         // Draw Open mark line
852                         if (showOpen)
853                         {
854                             if (openY <= VAxis.ViewMaximum && openY >= VAxis.ViewMinimum)
855                             {
856                                 path.AddLine(point2, point1);
857                                 path.AddLine(point1, point3);
858                                 path.AddLine(point3, point3);
859                                 graph.FillPath(brush, path);
860                             }
861                         }
862
863                         // Draw close mark line
864                         if (showClose)
865                         {
866                             if (closeY <= VAxis.ViewMaximum && closeY >= VAxis.ViewMinimum)
867                             {
868                                 path.Reset();
869                                 point1 = graph.GetAbsolutePoint(new PointF(xPosition, close));
870                                 point2 = graph.GetAbsolutePoint(new PointF(xPosition + width / 2f, close + height / 2f));
871                                 point3 = graph.GetAbsolutePoint(new PointF(xPosition + width / 2f, close - height / 2f));
872                                 path.AddLine(point2, point1);
873                                 path.AddLine(point1, point3);
874                                 path.AddLine(point3, point3);
875                                 graph.FillPath(brush, path);
876                             }
877                         }
878                     }
879                 }
880
881                         }
882
883                         // Draw ope-close marks as lines
884                         else
885                         {
886                                 // Draw Open mark line
887                                 if(showOpen)
888                                 {
889                                         if(openY <= VAxis.ViewMaximum && openY >= VAxis.ViewMinimum)
890                                         {
891                                                 graph.DrawLineRel(point.Color, point.BorderWidth, point.BorderDashStyle, 
892                                                         new PointF(xPosition - width/2f, open), 
893                                                         new PointF(xPosition, open),
894                                                         ser.ShadowColor, ser.ShadowOffset );
895                                         }
896                                 }
897
898                                 // Draw Close mark line
899                                 if(showClose)
900                                 {
901                                         if(closeY <= VAxis.ViewMaximum && closeY >= VAxis.ViewMinimum)
902                                         {
903                                                 graph.DrawLineRel(point.Color, point.BorderWidth, point.BorderDashStyle, 
904                                                         new PointF(xPosition, close), 
905                                                         new PointF(xPosition + width/2f, close),
906                                                         ser.ShadowColor, ser.ShadowOffset );
907                                         }
908                                 }
909                         }
910
911                         // Reset Clip Region
912                         if(clipRegionSet)
913                         {
914                                 graph.ResetClip();
915                         }
916                 }
917
918                 /// <summary>
919                 /// Draws stock chart data point label.
920                 /// </summary>
921                 /// <param name="common">The Common elements object</param>
922                 /// <param name="area">Chart area for this chart</param>
923                 /// <param name="graph">Chart graphics object.</param>
924                 /// <param name="ser">Data point series.</param>
925                 /// <param name="point">Data point to draw.</param>
926                 /// <param name="position">Label position.</param>
927                 /// <param name="pointIndex">Data point index in the series.</param>
928                 virtual protected void DrawLabel(
929                         CommonElements common,
930                         ChartArea area, 
931                         ChartGraphics graph, 
932                         Series ser, 
933                         DataPoint point, 
934                         PointF position,
935                         int pointIndex)
936                 {
937                         if(ser.IsValueShownAsLabel || point.IsValueShownAsLabel || point.Label.Length > 0)
938                         {
939                                 // Label text format
940                 using (StringFormat format = new StringFormat())
941                 {
942                     format.Alignment = StringAlignment.Near;
943                     format.LineAlignment = StringAlignment.Center;
944                     if (point.LabelAngle == 0)
945                     {
946                         format.Alignment = StringAlignment.Center;
947                         format.LineAlignment = StringAlignment.Far;
948                     }
949
950                     // Get label text
951                     string text;
952                     if (point.Label.Length == 0)
953                     {
954                         // Check what value to show (High, Low, Open, Close)
955                         int valueIndex = 3;
956                         string valueType = "";
957                         if (point.IsCustomPropertySet(CustomPropertyName.LabelValueType))
958                         {
959                             valueType = point[CustomPropertyName.LabelValueType];
960                         }
961                         else if (ser.IsCustomPropertySet(CustomPropertyName.LabelValueType))
962                         {
963                             valueType = ser[CustomPropertyName.LabelValueType];
964                         }
965
966                         if (String.Compare(valueType, "High", StringComparison.OrdinalIgnoreCase) == 0)
967                         {
968                             valueIndex = 0;
969                         }
970                         else if (String.Compare(valueType, "Low", StringComparison.OrdinalIgnoreCase) == 0)
971                         {
972                             valueIndex = 1;
973                         }
974                         else if (String.Compare(valueType, "Open", StringComparison.OrdinalIgnoreCase) == 0)
975                         {
976                             valueIndex = 2;
977                         }
978
979                         text = ValueConverter.FormatValue(
980                             ser.Chart,
981                             point,
982                             point.Tag,
983                             point.YValues[valueIndex],
984                             point.LabelFormat,
985                             ser.YValueType,
986                             ChartElementType.DataPoint);
987                     }
988                     else
989                     {
990                         text = point.ReplaceKeywords(point.Label);
991                     }
992
993                     // Get text angle
994                     int textAngle = point.LabelAngle;
995
996                     // Check if text contains white space only
997                     if (text.Trim().Length != 0)
998                     {
999                         SizeF sizeFont = SizeF.Empty;
1000
1001
1002                         // Check if Smart Labels are enabled
1003                         if (ser.SmartLabelStyle.Enabled)
1004                         {
1005                             // Get marker size
1006                             SizeF markerSize = SizeF.Empty;
1007                             markerSize.Width = point.MarkerSize;
1008                             markerSize.Height = point.MarkerSize;
1009                             if (graph != null && graph.Graphics != null)
1010                             {
1011                                 // Marker size is in pixels and we do the mapping for higher DPIs
1012                                 markerSize.Width = point.MarkerSize * graph.Graphics.DpiX / 96;
1013                                 markerSize.Height = point.MarkerSize * graph.Graphics.DpiY / 96;
1014                             }
1015
1016                             if (point.MarkerImage.Length > 0)
1017                                 common.ImageLoader.GetAdjustedImageSize(point.MarkerImage, graph.Graphics, ref markerSize);
1018                             
1019                             // Get point label style attribute
1020                             markerSize = graph.GetRelativeSize(markerSize);
1021                             sizeFont = graph.GetRelativeSize(graph.MeasureString(text, point.Font, new SizeF(1000f, 1000f), StringFormat.GenericTypographic));
1022
1023                             // Adjust label position using SmartLabelStyle algorithm
1024                             position = area.smartLabels.AdjustSmartLabelPosition(
1025                                 common,
1026                                 graph,
1027                                 area,
1028                                 ser.SmartLabelStyle,
1029                                 position,
1030                                 sizeFont,
1031                                 format,
1032                                 position,
1033                                 markerSize,
1034                                 LabelAlignmentStyles.Top);
1035
1036                             // Smart labels always use 0 degrees text angle
1037                             textAngle = 0;
1038
1039                         }
1040
1041
1042
1043                         // Draw label
1044                         if (!position.IsEmpty)
1045                         {
1046                             RectangleF labelBackPosition = RectangleF.Empty;
1047
1048                             if (!point.LabelBackColor.IsEmpty ||
1049                                 point.LabelBorderWidth > 0 ||
1050                                 !point.LabelBorderColor.IsEmpty)
1051                             {
1052                                 // Get text size
1053                                 if (sizeFont.IsEmpty)
1054                                 {
1055                                     sizeFont = graph.GetRelativeSize(graph.MeasureString(text, point.Font, new SizeF(1000f, 1000f), StringFormat.GenericTypographic));
1056                                 }
1057
1058                                 // Adjust label y coordinate
1059                                 position.Y -= sizeFont.Height / 8;
1060
1061                                 // Get label background position
1062                                 SizeF sizeLabel = new SizeF(sizeFont.Width, sizeFont.Height);
1063                                 sizeLabel.Height += sizeFont.Height / 8;
1064                                 sizeLabel.Width += sizeLabel.Width / text.Length;
1065                                 labelBackPosition = PointChart.GetLabelPosition(
1066                                     graph,
1067                                     position,
1068                                     sizeLabel,
1069                                     format,
1070                                     true);
1071                             }
1072
1073
1074                             // Draw label text
1075                             using (Brush brush = new SolidBrush(point.LabelForeColor))
1076                             {
1077                                 graph.DrawPointLabelStringRel(
1078                                     common,
1079                                     text,
1080                                     point.Font,
1081                                     brush,
1082                                     position,
1083                                     format,
1084                                     textAngle,
1085                                     labelBackPosition,
1086
1087                                     point.LabelBackColor,
1088                                     point.LabelBorderColor,
1089                                     point.LabelBorderWidth,
1090                                     point.LabelBorderDashStyle,
1091                                     ser,
1092                                     point,
1093                                     pointIndex - 1);
1094                             }
1095                         }
1096                     }
1097                 }
1098                         }
1099                 }
1100
1101                 #endregion
1102
1103                 #region 3D Drawing and Selection methods
1104
1105                 /// <summary>
1106                 /// This method recalculates size of the bars. This method is used 
1107                 /// from Paint or Select method.
1108                 /// </summary>
1109                 /// <param name="selection">If True selection mode is active, otherwise paint mode is active.</param>
1110                 /// <param name="graph">The Chart Graphics object.</param>
1111                 /// <param name="common">The Common elements object.</param>
1112                 /// <param name="area">Chart area for this chart.</param>
1113                 /// <param name="seriesToDraw">Chart series to draw.</param>
1114                 virtual protected void ProcessChartType3D( 
1115                         bool selection, 
1116                         ChartGraphics graph, 
1117                         CommonElements common, 
1118                         ChartArea area, 
1119                         Series seriesToDraw )
1120                 {
1121                         
1122                         // All data series from chart area which have Stock chart type
1123                         List<string>    typeSeries = area.GetSeriesFromChartType(this.Name);
1124
1125                         // Zero X values mode.
1126                         bool indexedSeries = ChartHelper.IndexedSeries(common, typeSeries.ToArray() );
1127
1128                         //************************************************************
1129                         //** Loop through all series
1130                         //************************************************************
1131                         foreach( Series ser in common.DataManager.Series )
1132                         {
1133                                 // Process non empty series of the area with stock chart type
1134                                 if( String.Compare( ser.ChartTypeName, this.Name, StringComparison.OrdinalIgnoreCase ) != 0 
1135                                         || ser.ChartArea != area.Name || !ser.IsVisible())
1136                                 {
1137                                         continue;
1138                                 }
1139
1140                                 // Check if drawn series is specified
1141                                 if(seriesToDraw != null && seriesToDraw.Name != ser.Name)
1142                                 {
1143                                         continue;
1144                                 }
1145
1146                                 // Check that we have at least 4 Y values
1147                                 if(ser.YValuesPerPoint < 4)
1148                                 {
1149                                         throw(new ArgumentException(SR.ExceptionChartTypeRequiresYValues("StockChart", "4" )));
1150                                 }
1151
1152                                 // Set active horizontal/vertical axis
1153                                 HAxis = area.GetAxis(AxisName.X, ser.XAxisType, ser.XSubAxisName);
1154                                 VAxis = area.GetAxis(AxisName.Y, ser.YAxisType, ser.YSubAxisName);
1155
1156                                 // Get interval between points
1157                                 double interval = (indexedSeries) ? 1 : area.GetPointsInterval( HAxis.IsLogarithmic, HAxis.logarithmBase );
1158
1159                                 // Calculates the width of the candles.
1160                                 float width = (float)(ser.GetPointWidth(graph, HAxis, interval, 0.8));
1161
1162                                 // Call Back Paint event
1163                                 if( !selection )
1164                                 {
1165                     common.Chart.CallOnPrePaint(new ChartPaintEventArgs(ser, graph, common, area.PlotAreaPosition));
1166                                 }
1167
1168                                 //************************************************************
1169                                 //** Get series depth and Z position
1170                                 //************************************************************
1171                                 float seriesDepth, seriesZPosition;
1172                                 area.GetSeriesZPositionAndDepth(ser, out seriesDepth, out seriesZPosition);
1173
1174                                 //************************************************************
1175                                 //** Series data points loop
1176                                 //************************************************************
1177                                 int     index = 1;
1178                                 foreach( DataPoint point in ser.Points )
1179                                 {
1180                                         // Reset pre-calculated point position
1181                                         point.positionRel = new PointF(float.NaN, float.NaN);
1182
1183                                         // Get point X position
1184                                         double  xValue = point.XValue;
1185                                         if( indexedSeries )
1186                                         {
1187                                                 xValue = (double)index;
1188                                         }
1189                                         float xPosition = (float)HAxis.GetPosition( xValue );
1190
1191                                         double yValue0 = VAxis.GetLogValue( point.YValues[0] );
1192                                         double yValue1 = VAxis.GetLogValue( point.YValues[1] );
1193                                         xValue = HAxis.GetLogValue(xValue);
1194                                         
1195                                         // Check if chart is completly out of the data scaleView
1196                                         if(xValue < HAxis.ViewMinimum || 
1197                                                 xValue > HAxis.ViewMaximum ||
1198                                                 (yValue0 < VAxis.ViewMinimum && yValue1 < VAxis.ViewMinimum) ||
1199                                                 (yValue0 > VAxis.ViewMaximum && yValue1 > VAxis.ViewMaximum) )
1200                                         {
1201                                                 ++index;
1202                                                 continue;
1203                                         }
1204
1205                                         // Check if chart is partialy in the data scaleView
1206                                         bool    clipRegionSet = false;
1207                                         if(xValue == HAxis.ViewMinimum || xValue == HAxis.ViewMaximum )
1208                                         {
1209                                                 // Set clipping region for line drawing 
1210                                                 graph.SetClip( area.PlotAreaPosition.ToRectangleF() );
1211                                                 clipRegionSet = true;
1212                                         }
1213
1214                                         // Make sure High/Low values are in data scaleView range                                                
1215                                         double  high = VAxis.GetLogValue( point.YValues[0] );
1216                                         double  low = VAxis.GetLogValue( point.YValues[1] );
1217                                         
1218                                         if( high > VAxis.ViewMaximum )
1219                                         {
1220                                                 high = VAxis.ViewMaximum;
1221                                         }
1222                                         if( high < VAxis.ViewMinimum )
1223                                         {
1224                                                 high = VAxis.ViewMinimum;
1225                                         }
1226                                         high = (float)VAxis.GetLinearPosition(high);
1227                                         
1228                                         if( low > VAxis.ViewMaximum )
1229                                         {
1230                                                 low = VAxis.ViewMaximum;
1231                                         }
1232                                         if( low < VAxis.ViewMinimum )
1233                                         {
1234                                                 low = VAxis.ViewMinimum;
1235                                         }
1236                                         low = VAxis.GetLinearPosition(low);
1237
1238                                         // Remeber pre-calculated point position
1239                                         point.positionRel = new PointF((float)xPosition, (float)high);
1240
1241                                         // 3D Transform coordinates
1242                                         Point3D[] points = new Point3D[2];
1243                                         points[0] = new Point3D(xPosition, (float)high, seriesZPosition+seriesDepth/2f);
1244                                         points[1] = new Point3D(xPosition, (float)low, seriesZPosition+seriesDepth/2f);
1245                                         area.matrix3D.TransformPoints(points);
1246
1247                                         // Start Svg Selection mode
1248                                         graph.StartHotRegion( point );
1249
1250                                         // Draw Hi-Low line
1251                                         graph.DrawLineRel( 
1252                                                 point.Color, 
1253                                                 point.BorderWidth, 
1254                                                 point.BorderDashStyle, 
1255                                                 points[0].PointF, 
1256                                                 points[1].PointF,
1257                                                 ser.ShadowColor, 
1258                                                 ser.ShadowOffset );
1259
1260                                         // Draw Open-Close marks
1261                                         DrawOpenCloseMarks3D(graph, area, ser, point, xPosition, width, seriesZPosition, seriesDepth);
1262                                         xPosition = points[0].X;
1263                                         high = points[0].Y;
1264                                         low = points[1].Y;
1265
1266                                         // End Svg Selection mode
1267                                         graph.EndHotRegion( );
1268
1269                                         // Reset Clip Region
1270                                         if(clipRegionSet)
1271                                         {
1272                                                 graph.ResetClip();
1273                                         }
1274
1275                                         if( common.ProcessModeRegions )
1276                                         {
1277                                                 // Calculate rect around the hi-lo line and open-close marks
1278                                                 RectangleF      areaRect = RectangleF.Empty;
1279                                                 areaRect.X = xPosition - width / 2f;
1280                                                 areaRect.Y = (float)Math.Min(high, low);
1281                                                 areaRect.Width = width;
1282                                                 areaRect.Height = (float)Math.Max(high, low) - areaRect.Y;
1283
1284                                                 common.HotRegionsList.AddHotRegion( 
1285                                                         areaRect, 
1286                                                         point, 
1287                                                         ser.Name, 
1288                                                         index - 1 );
1289                                         
1290                                         }
1291                                 
1292                                         ++index;
1293                                 }
1294
1295                                 //************************************************************
1296                                 //** Second series data points loop, when markers and labels
1297                                 //** are drawn.
1298                                 //************************************************************
1299                                 int markerIndex = 0;
1300                                 index = 1;
1301                                 foreach( DataPoint point in ser.Points )
1302                                 {
1303                                         // Get point X position
1304                                         double  xValue = point.XValue;
1305                                         if( indexedSeries )
1306                                         {
1307                                                 xValue = (double)index;
1308                                         }
1309                                         float xPosition = (float)HAxis.GetPosition( xValue );
1310
1311                                         double yValue0 = VAxis.GetLogValue( point.YValues[0] );
1312                                         double yValue1 = VAxis.GetLogValue( point.YValues[1] );
1313                                         xValue = HAxis.GetLogValue(xValue);
1314                                 
1315                                         // Check if chart is completly out of the data scaleView
1316                                         if(xValue < HAxis.ViewMinimum || 
1317                                                 xValue > HAxis.ViewMaximum ||
1318                                                 (yValue0 < VAxis.ViewMinimum && yValue1 < VAxis.ViewMinimum) ||
1319                                                 (yValue0 > VAxis.ViewMaximum && yValue1 > VAxis.ViewMaximum) )
1320                                         {
1321                                                 ++index;
1322                                                 continue;
1323                                         }
1324
1325                                         // Make sure High/Low values are in data scaleView range                                                
1326                                         double  high = VAxis.GetLogValue( point.YValues[0] );
1327                                         double  low = VAxis.GetLogValue( point.YValues[1] );
1328                                 
1329                                         if( high > VAxis.ViewMaximum )
1330                                         {
1331                                                 high = VAxis.ViewMaximum;
1332                                         }
1333                                         if( high < VAxis.ViewMinimum )
1334                                         {
1335                                                 high = VAxis.ViewMinimum;
1336                                         }
1337                                         high = (float)VAxis.GetLinearPosition(high);
1338                                 
1339                                         if( low > VAxis.ViewMaximum )
1340                                         {
1341                                                 low = VAxis.ViewMaximum;
1342                                         }
1343                                         if( low < VAxis.ViewMinimum )
1344                                         {
1345                                                 low = VAxis.ViewMinimum;
1346                                         }
1347                                         low = VAxis.GetLinearPosition(low);
1348
1349
1350                                         // 3D Transform coordinates
1351                                         Point3D[] points = new Point3D[2];
1352                                         points[0] = new Point3D(xPosition, (float)high, seriesZPosition+seriesDepth/2f);
1353                                         points[1] = new Point3D(xPosition, (float)low, seriesZPosition+seriesDepth/2f);
1354                                         area.matrix3D.TransformPoints(points);
1355                                         xPosition = points[0].X;
1356                                         high = points[0].Y;
1357                                         low = points[1].Y;
1358
1359                                         // Draw label
1360                                         DrawLabel(common, area, graph, ser, point, new PointF(xPosition, (float)Math.Min(high, low)), index);
1361
1362                                         // Draw marker
1363                                         if(point.MarkerStyle != MarkerStyle.None || point.MarkerImage.Length > 0)
1364                                         {
1365                                                 // Get marker size
1366                                                 SizeF markerSize = SizeF.Empty;
1367                                                 markerSize.Width = point.MarkerSize;
1368                                                 markerSize.Height = point.MarkerSize;
1369                         if (graph != null && graph.Graphics != null)
1370                         {
1371                             // Marker size is in pixels and we do the mapping for higher DPIs
1372                             markerSize.Width = point.MarkerSize * graph.Graphics.DpiX / 96;
1373                             markerSize.Height = point.MarkerSize * graph.Graphics.DpiY / 96;
1374                         }
1375
1376                         if (point.MarkerImage.Length > 0)
1377                             common.ImageLoader.GetAdjustedImageSize(point.MarkerImage, graph.Graphics, ref markerSize);
1378                                                 
1379                                                 // Get marker position
1380                                                 PointF markerPosition = PointF.Empty;
1381                                                 markerPosition.X = xPosition;
1382                                                 markerPosition.Y = (float)high - graph.GetRelativeSize(markerSize).Height/2f;
1383
1384                                                 // Draw marker
1385                                                 if(markerIndex == 0)
1386                                                 {
1387                                                         // Draw the marker
1388                                                         graph.DrawMarkerRel(markerPosition, 
1389                                                                 point.MarkerStyle,
1390                                                                 (int)markerSize.Height,
1391                                                                 (point.MarkerColor == Color.Empty) ? point.Color : point.MarkerColor,
1392                                                                 (point.MarkerBorderColor == Color.Empty) ? point.BorderColor : point.MarkerBorderColor,
1393                                                                 point.MarkerBorderWidth,
1394                                                                 point.MarkerImage,
1395                                                                 point.MarkerImageTransparentColor,
1396                                                                 (point.series != null) ? point.series.ShadowOffset : 0,
1397                                                                 (point.series != null) ? point.series.ShadowColor : Color.Empty,
1398                                                                 new RectangleF(markerPosition.X, markerPosition.Y, markerSize.Width, markerSize.Height));
1399
1400                                                         if( common.ProcessModeRegions )
1401                                                         {
1402                                                                 // Get relative marker size
1403                                                                 SizeF relativeMarkerSize = graph.GetRelativeSize(markerSize);
1404
1405                                                                 // Insert area just after the last custom area
1406                                                                 int insertIndex = common.HotRegionsList.FindInsertIndex();
1407                                                                 common.HotRegionsList.FindInsertIndex();
1408
1409                                                                 // Insert circle area
1410                                                                 if(point.MarkerStyle == MarkerStyle.Circle)
1411                                                                 {
1412                                                                         float[] circCoord = new float[3];
1413                                                                         circCoord[0] = markerPosition.X;
1414                                                                         circCoord[1] = markerPosition.Y;
1415                                                                         circCoord[2] = relativeMarkerSize.Width/2f;
1416
1417                                                                         common.HotRegionsList.AddHotRegion( 
1418                                                                                 insertIndex, 
1419                                                                                 graph, 
1420                                                                                 circCoord[0], 
1421                                                                                 circCoord[1], 
1422                                                                                 circCoord[2], 
1423                                                                                 point, 
1424                                                                                 ser.Name, 
1425                                                                                 index - 1 );
1426                                                                 }
1427                                                                         // All other markers represented as rectangles
1428                                                                 else
1429                                                                 {
1430                                                                         common.HotRegionsList.AddHotRegion(
1431                                                                                 new RectangleF(markerPosition.X - relativeMarkerSize.Width/2f, markerPosition.Y - relativeMarkerSize.Height/2f, relativeMarkerSize.Width, relativeMarkerSize.Height),
1432                                                                                 point,
1433                                                                                 ser.Name,
1434                                                                                 index - 1 );
1435                                                                 }
1436                                                         }
1437                                                 }
1438                                 
1439                                                 // Increase the markers counter
1440                                                 ++markerIndex;
1441                                                 if(ser.MarkerStep == markerIndex)
1442                                                 {
1443                                                         markerIndex = 0;
1444                                                 }
1445                                         }
1446                                         ++index;
1447                                 }
1448                                 
1449                                 // Call Paint event
1450                                 if( !selection )
1451                                 {
1452                     common.Chart.CallOnPostPaint(new ChartPaintEventArgs(ser, graph, common, area.PlotAreaPosition));
1453                                 }
1454                         }
1455                 }
1456
1457                 /// <summary>
1458                 /// Draws stock chart open-close marks depending on selected style.
1459                 /// </summary>
1460                 /// <param name="graph">Chart graphics object.</param>
1461                 /// <param name="area">Chart area.</param>
1462                 /// <param name="ser">Data point series.</param>
1463                 /// <param name="point">Data point to draw.</param>
1464                 /// <param name="xPosition">X position.</param>
1465                 /// <param name="width">Point width.</param>
1466                 /// <param name="zPosition">Series Z position.</param>
1467                 /// <param name="depth">Series depth.</param>
1468                 virtual protected void DrawOpenCloseMarks3D(
1469                         ChartGraphics graph, 
1470                         ChartArea area,
1471                         Series ser, 
1472                         DataPoint point, 
1473                         float xPosition, 
1474                         float width,
1475                         float zPosition,
1476                         float depth)
1477                 {
1478                         double openY = VAxis.GetLogValue( point.YValues[2] );
1479                         double closeY = VAxis.GetLogValue( point.YValues[3] );
1480
1481                         // Check if mark is inside data scaleView
1482                         if( (openY > VAxis.ViewMaximum ||
1483                                 openY < VAxis.ViewMinimum) &&
1484                                 (closeY > VAxis.ViewMaximum ||
1485                                 closeY < VAxis.ViewMinimum) )
1486                         {
1487                                 //return;
1488                         }
1489
1490                         // Calculate open-close position
1491                         float   open = (float)VAxis.GetLinearPosition(openY);
1492                         float   close = (float)VAxis.GetLinearPosition(closeY);
1493                         SizeF   absSize = graph.GetAbsoluteSize(new SizeF(width, width));
1494                         float   height = graph.GetRelativeSize(absSize).Height;
1495
1496                         // Detect style
1497                         StockOpenCloseMarkStyle style = openCloseStyle;
1498                         string  styleType = "";
1499                         if(point.IsCustomPropertySet(CustomPropertyName.OpenCloseStyle))
1500                         {
1501                                 styleType = point[CustomPropertyName.OpenCloseStyle];
1502                         }
1503                         else if(ser.IsCustomPropertySet(CustomPropertyName.OpenCloseStyle))
1504                         {
1505                                 styleType = ser[CustomPropertyName.OpenCloseStyle];
1506                         }
1507
1508                         if(styleType != null && styleType.Length > 0)
1509                         {
1510                                 if(String.Compare(styleType, "Candlestick", StringComparison.OrdinalIgnoreCase) == 0)
1511                                 {
1512                                         style = StockOpenCloseMarkStyle.Candlestick;
1513                                 }
1514                 else if (String.Compare(styleType, "Triangle", StringComparison.OrdinalIgnoreCase) == 0)
1515                                 {
1516                                         style = StockOpenCloseMarkStyle.Triangle;
1517                                 }
1518                 else if (String.Compare(styleType, "Line", StringComparison.OrdinalIgnoreCase) == 0)
1519                                 {
1520                                         style = StockOpenCloseMarkStyle.Line;
1521                                 }
1522                         }
1523
1524                         // Get attribute which controls if open/close marks are shown
1525                         bool    showOpen = true;
1526                         bool    showClose = true;
1527                         string  showOpenClose = "";
1528                         if(point.IsCustomPropertySet(CustomPropertyName.ShowOpenClose))
1529                         {
1530                                 showOpenClose = point[CustomPropertyName.ShowOpenClose];
1531                         }
1532                         else if(ser.IsCustomPropertySet(CustomPropertyName.ShowOpenClose))
1533                         {
1534                                 showOpenClose = ser[CustomPropertyName.ShowOpenClose];
1535                         }
1536
1537                         if(showOpenClose != null && showOpenClose.Length > 0)
1538                         {
1539                                 if(String.Compare(showOpenClose, "Both", StringComparison.OrdinalIgnoreCase) == 0)
1540                                 {
1541                                         showOpen = true;
1542                                         showClose = true;
1543                                 }
1544                 else if (String.Compare(showOpenClose, "Open", StringComparison.OrdinalIgnoreCase) == 0)
1545                                 {
1546                                         showOpen = true;
1547                                         showClose = false;
1548                                 }
1549                 else if (String.Compare(showOpenClose, "Close", StringComparison.OrdinalIgnoreCase) == 0)
1550                                 {
1551                                         showOpen = false;
1552                                         showClose = true;
1553                                 }
1554                         }
1555
1556                         // Check if chart is partialy in the data scaleView
1557                         bool    clipRegionSet = false;
1558                         if((xPosition - width / 2f) < area.PlotAreaPosition.X || (xPosition + width / 2f) > area.PlotAreaPosition.Right)
1559                         {
1560                                 // Set clipping region for line drawing 
1561                                 graph.SetClip( area.PlotAreaPosition.ToRectangleF() );
1562                                 clipRegionSet = true;
1563                         }
1564
1565                         
1566                         // Draw open-close marks as bar
1567                         if(forceCandleStick || style == StockOpenCloseMarkStyle.Candlestick)
1568                         {
1569                                 // Colors used to draw bar of the open-close style
1570                                 ColorConverter  colorConverter = new ColorConverter();
1571                                 Color                   priceUpColor = point.Color;
1572                                 Color                   priceDownColor = point.BackSecondaryColor;
1573
1574                                 // Check if special color properties are set
1575                                 string  attrValue = point[CustomPropertyName.PriceUpColor];
1576                                 if(attrValue != null && attrValue.Length > 0)
1577                                 {
1578                     bool failed = false;
1579                     try
1580                     {
1581                         priceUpColor = (Color)colorConverter.ConvertFromString(attrValue);
1582                     }
1583                     catch (NotSupportedException)
1584                     {
1585                         failed = true;
1586                     }
1587                     catch (ArgumentException)
1588                     {
1589                         failed = true;
1590                     }
1591
1592                     if (failed)
1593                     {
1594                         priceUpColor = (Color)colorConverter.ConvertFromInvariantString(attrValue);
1595                     }
1596                                 }
1597
1598                                 attrValue = point[CustomPropertyName.PriceDownColor];
1599                                 if(attrValue != null && attrValue.Length > 0)
1600                                 {
1601                     bool failed = false;
1602                     try
1603                     {
1604                         priceDownColor = (Color)colorConverter.ConvertFromString(attrValue);
1605                     }
1606                     catch (ArgumentException)
1607                     {
1608                         failed = true;
1609                     }
1610                     catch (NotSupportedException)
1611                     {
1612                         failed = true;
1613                     }
1614
1615                     if (failed)
1616                     {
1617                         priceDownColor = (Color)colorConverter.ConvertFromInvariantString(attrValue);
1618                     }
1619                                 }
1620
1621                                 // Calculate bar rectangle
1622                                 RectangleF      rect = RectangleF.Empty;
1623                                 rect.Y = (float)Math.Min(open, close);
1624                                 rect.X = xPosition - width / 2f;
1625                                 rect.Height = (float)Math.Max(open, close) - rect.Y;
1626                                 rect.Width = width;
1627
1628                                 // Bar and border color
1629                                 Color   barColor = (open > close) ? priceUpColor : priceDownColor;
1630                                 Color   barBorderColor = (point.BorderColor == Color.Empty) ? (barColor == Color.Empty) ? point.Color : barColor : point.BorderColor;
1631
1632                                 // Translate coordinates
1633                                 Point3D[] points = new Point3D[2];
1634                                 points[0] = new Point3D(rect.X, rect.Y, zPosition + depth/2f);
1635                                 points[1] = new Point3D(rect.Right, rect.Bottom, zPosition + depth/2f);
1636                                 area.matrix3D.TransformPoints(points);
1637                                 rect.Location = points[0].PointF;
1638                                 rect.Width = (float)Math.Abs(points[1].X - points[0].X);
1639                                 rect.Height = (float)Math.Abs(points[1].Y - points[0].Y);
1640                                 
1641                                 // Draw open-close bar
1642                                 if(rect.Height > 1)
1643                                 {
1644                                         graph.FillRectangleRel( 
1645                                                 rect, 
1646                                                 barColor,
1647                                                 point.BackHatchStyle, 
1648                                                 point.BackImage, 
1649                                                 point.BackImageWrapMode, 
1650                                                 point.BackImageTransparentColor,
1651                                                 point.BackImageAlignment,
1652                                                 point.BackGradientStyle, 
1653                                                 point.BackSecondaryColor, 
1654                                                 barBorderColor, 
1655                                                 point.BorderWidth, 
1656                                                 point.BorderDashStyle, 
1657                                                 ser.ShadowColor,
1658                                                 ser.ShadowOffset,
1659                                                 PenAlignment.Inset);
1660                                 }
1661                                 else
1662                                 {
1663                                         graph.DrawLineRel(barBorderColor, point.BorderWidth, point.BorderDashStyle, 
1664                                                 new PointF(rect.X, rect.Y), 
1665                                                 new PointF(rect.Right, rect.Y),
1666                                                 ser.ShadowColor, ser.ShadowOffset );
1667                                 }
1668                         }
1669
1670                                 // Draw open-close marks as triangals
1671                         else if(style == StockOpenCloseMarkStyle.Triangle)
1672                         {
1673                 using (GraphicsPath path = new GraphicsPath())
1674                 {
1675
1676                     // Translate coordinates
1677                     Point3D[] points = new Point3D[3];
1678                     points[0] = new Point3D(xPosition, open, zPosition + depth / 2f);
1679                     points[1] = new Point3D(xPosition - width / 2f, open + height / 2f, zPosition + depth / 2f);
1680                     points[2] = new Point3D(xPosition - width / 2f, open - height / 2f, zPosition + depth / 2f);
1681                     area.matrix3D.TransformPoints(points);
1682                     points[0].PointF = graph.GetAbsolutePoint(points[0].PointF);
1683                     points[1].PointF = graph.GetAbsolutePoint(points[1].PointF);
1684                     points[2].PointF = graph.GetAbsolutePoint(points[2].PointF);
1685
1686                     using (Brush brush = new SolidBrush(point.Color))
1687                     {
1688                         // Draw Open mark line
1689                         if (showOpen)
1690                         {
1691                             if (openY <= VAxis.ViewMaximum && openY >= VAxis.ViewMinimum)
1692                             {
1693                                 path.AddLine(points[1].PointF, points[0].PointF);
1694                                 path.AddLine(points[0].PointF, points[2].PointF);
1695                                 path.AddLine(points[2].PointF, points[2].PointF);
1696                                 graph.FillPath(brush, path);
1697                             }
1698                         }
1699
1700                         // Draw close mark line
1701                         if (showClose)
1702                         {
1703                             if (closeY <= VAxis.ViewMaximum && closeY >= VAxis.ViewMinimum)
1704                             {
1705                                 points[0] = new Point3D(xPosition, close, zPosition + depth / 2f);
1706                                 points[1] = new Point3D(xPosition + width / 2f, close + height / 2f, zPosition + depth / 2f);
1707                                 points[2] = new Point3D(xPosition + width / 2f, close - height / 2f, zPosition + depth / 2f);
1708                                 area.matrix3D.TransformPoints(points);
1709                                 points[0].PointF = graph.GetAbsolutePoint(points[0].PointF);
1710                                 points[1].PointF = graph.GetAbsolutePoint(points[1].PointF);
1711                                 points[2].PointF = graph.GetAbsolutePoint(points[2].PointF);
1712
1713                                 path.Reset();
1714                                 path.AddLine(points[1].PointF, points[0].PointF);
1715                                 path.AddLine(points[0].PointF, points[2].PointF);
1716                                 path.AddLine(points[2].PointF, points[2].PointF);
1717                                 graph.FillPath(brush, path);
1718                             }
1719                         }
1720                     }                    
1721                 }
1722                         }
1723
1724                                 // Draw ope-close marks as lines
1725                         else
1726                         {
1727                                 // Draw Open mark line
1728                                 if(showOpen)
1729                                 {
1730                                         if(openY <= VAxis.ViewMaximum && openY >= VAxis.ViewMinimum)
1731                                         {
1732                                                 // Translate coordinates
1733                                                 Point3D[] points = new Point3D[2];
1734                                                 points[0] = new Point3D(xPosition - width/2f, open, zPosition + depth/2f);
1735                                                 points[1] = new Point3D(xPosition, open, zPosition + depth/2f);
1736                                                 area.matrix3D.TransformPoints(points);
1737
1738                                                 graph.DrawLineRel(point.Color, point.BorderWidth, point.BorderDashStyle, 
1739                                                         points[0].PointF, 
1740                                                         points[1].PointF,
1741                                                         ser.ShadowColor, ser.ShadowOffset );
1742                                         }
1743                                 }
1744
1745                                 // Draw Close mark line
1746                                 if(showClose)
1747                                 {
1748                                         if(closeY <= VAxis.ViewMaximum && closeY >= VAxis.ViewMinimum)
1749                                         {
1750                                                 // Translate coordinates
1751                                                 Point3D[] points = new Point3D[2];
1752                                                 points[0] = new Point3D(xPosition, close, zPosition + depth/2f);
1753                                                 points[1] = new Point3D(xPosition + width/2f, close, zPosition + depth/2f);
1754                                                 area.matrix3D.TransformPoints(points);
1755
1756                                                 graph.DrawLineRel(point.Color, point.BorderWidth, point.BorderDashStyle, 
1757                                                         points[0].PointF, 
1758                                                         points[1].PointF,
1759                                                         ser.ShadowColor, ser.ShadowOffset );
1760                                         }
1761                                 }
1762                         }
1763
1764                         // Reset Clip Region
1765                         if(clipRegionSet)
1766                         {
1767                                 graph.ResetClip();
1768                         }
1769                 }
1770
1771                 #endregion
1772
1773                 #region Y values related methods
1774
1775                 /// <summary>
1776                 /// Helper function, which returns the Y value of the point.
1777                 /// </summary>
1778                 /// <param name="common">Chart common elements.</param>
1779                 /// <param name="area">Chart area the series belongs to.</param>
1780                 /// <param name="series">Sereis of the point.</param>
1781                 /// <param name="point">Point object.</param>
1782                 /// <param name="pointIndex">Index of the point.</param>
1783                 /// <param name="yValueIndex">Index of the Y value to get.</param>
1784                 /// <returns>Y value of the point.</returns>
1785                 virtual public double GetYValue(
1786                         CommonElements common, 
1787                         ChartArea area, 
1788                         Series series, 
1789                         DataPoint point, 
1790                         int pointIndex, 
1791                         int yValueIndex)
1792                 {
1793                         return point.YValues[yValueIndex];
1794                 }
1795
1796                 #endregion
1797
1798                 #region SmartLabelStyle methods
1799
1800                 /// <summary>
1801                 /// Adds markers position to the list. Used to check SmartLabelStyle overlapping.
1802                 /// </summary>
1803                 /// <param name="common">Common chart elements.</param>
1804                 /// <param name="area">Chart area.</param>
1805                 /// <param name="series">Series values to be used.</param>
1806                 /// <param name="list">List to add to.</param>
1807                 public void AddSmartLabelMarkerPositions(CommonElements common, ChartArea area, Series series, ArrayList list)
1808                 {
1809                         // Check if series is indexed
1810                         bool indexedSeries = ChartHelper.IndexedSeries(common, area.GetSeriesFromChartType(this.Name).ToArray() );
1811
1812                         //************************************************************
1813                         //** Set active horizontal/vertical axis
1814                         //************************************************************
1815                         Axis hAxis = area.GetAxis(AxisName.X, series.XAxisType, series.XSubAxisName);
1816                         Axis vAxis = area.GetAxis(AxisName.Y, series.YAxisType, series.YSubAxisName);
1817
1818                         //************************************************************
1819                         //** Loop through all data points in the series
1820                         //************************************************************
1821                         int     markerIndex = 0;                // Marker index
1822                         int     index = 1;                              // Data points loop
1823                         foreach( DataPoint point in series.Points )
1824                         {
1825                                 //************************************************************
1826                                 //** Check if point values are in the chart area
1827                                 //************************************************************
1828
1829                                 // Check for min/max Y values
1830                                 double  yValue = GetYValue(common, area, series, point, index - 1, 0);
1831
1832                                 // Axis is Logarithmic
1833                                 yValue = vAxis.GetLogValue( yValue );
1834                                 
1835                                 if( yValue > vAxis.ViewMaximum || yValue < vAxis.ViewMinimum)
1836                                 {
1837                                         index++;
1838                                         continue;
1839                                 }
1840
1841                                 // Check for min/max X values
1842                                 double xValue = (indexedSeries) ? (double)index : point.XValue;
1843                                 xValue = hAxis.GetLogValue(xValue);
1844                                 if(xValue > hAxis.ViewMaximum || xValue < hAxis.ViewMinimum)
1845                                 {
1846                                         index++;
1847                                         continue;
1848                                 }
1849
1850                                 //************************************************************
1851                                 //** Get marker position and size
1852                                 //************************************************************
1853
1854                                 // Get marker position
1855                                 PointF markerPosition = PointF.Empty;
1856                                 markerPosition.Y = (float)vAxis.GetLinearPosition(yValue);
1857                                 if( indexedSeries )
1858                                 {
1859                                         // The formula for position is based on a distance 
1860                                         // from the grid line or nPoints position.
1861                                         markerPosition.X = (float)hAxis.GetPosition( (double)index );
1862                                 }
1863                                 else
1864                                 {
1865                                         markerPosition.X = (float)hAxis.GetPosition( point.XValue );
1866                                 }
1867
1868                                 // Get point some point properties and save them in variables
1869                                 string          pointMarkerImage = point.MarkerImage;
1870                                 MarkerStyle     pointMarkerStyle = point.MarkerStyle;
1871
1872                                 // Get marker size
1873                                 SizeF markerSize = SizeF.Empty;
1874                                 markerSize.Width = point.MarkerSize;
1875                                 markerSize.Height = point.MarkerSize;
1876                 if (common != null && common.graph != null && common.graph.Graphics != null)
1877                 {
1878                     // Marker size is in pixels and we do the mapping for higher DPIs
1879                     markerSize.Width = point.MarkerSize * common.graph.Graphics.DpiX / 96;
1880                     markerSize.Height = point.MarkerSize * common.graph.Graphics.DpiY / 96;
1881                 }
1882                 
1883                 if (point.MarkerImage.Length > 0)
1884                     if(common.graph != null)
1885                         common.ImageLoader.GetAdjustedImageSize(point.MarkerImage, common.graph.Graphics, ref markerSize);
1886                 
1887                                 // Transform marker position in 3D space
1888                                 if(area.Area3DStyle.Enable3D)
1889                                 {
1890                                         // Get series depth and Z position
1891                                         float seriesDepth, seriesZPosition;
1892                                         area.GetSeriesZPositionAndDepth(series, out seriesDepth, out seriesZPosition);
1893
1894                                         Point3D[]       marker3DPosition = new Point3D[1];
1895                                         marker3DPosition[0] = new Point3D(
1896                                                 markerPosition.X, 
1897                                                 markerPosition.Y, 
1898                                                 (float)(seriesZPosition + seriesDepth/2f));
1899
1900                                         // Transform coordinates
1901                                         area.matrix3D.TransformPoints(marker3DPosition);
1902                                         markerPosition = marker3DPosition[0].PointF;
1903                                 }
1904
1905                                 // Check if marker visible
1906                                 if(pointMarkerStyle != MarkerStyle.None || 
1907                                         pointMarkerImage.Length > 0)
1908                                 {
1909                                         // Check marker index
1910                                         if(markerIndex == 0)
1911                                         {
1912                                                 markerSize = common.graph.GetRelativeSize(markerSize);
1913
1914                                                 // Add marker position into the list
1915                                                 RectangleF      markerRect = new RectangleF(
1916                                                         markerPosition.X - markerSize.Width / 2f,
1917                                                         markerPosition.Y - markerSize.Height,
1918                                                         markerSize.Width,
1919                                                         markerSize.Height);
1920                                                 list.Add(markerRect);
1921                                         }
1922                                         
1923                                         // Increase the markers counter
1924                                         ++markerIndex;
1925                                         if(series.MarkerStep == markerIndex)
1926                                         {
1927                                                 markerIndex = 0;
1928                                         }
1929                                 }
1930
1931                                 ++index;
1932                         }
1933                 }
1934
1935                 #endregion
1936
1937         #region IDisposable interface implementation
1938         /// <summary>
1939         /// Releases unmanaged and - optionally - managed resources
1940         /// </summary>
1941         /// <param name="disposing"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
1942         protected virtual void Dispose(bool disposing)
1943         {
1944             //Nothing to dispose at the base class. 
1945         }
1946
1947         /// <summary>
1948         /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
1949         /// </summary>
1950         public void Dispose()
1951         {
1952             Dispose(true);
1953             GC.SuppressFinalize(this);
1954         }
1955         #endregion
1956         }
1957 }