1 //------------------------------------------------------------- 2 // <copyright company=�Microsoft Corporation�> 3 // Copyright � Microsoft Corporation. All Rights Reserved. 4 // </copyright> 5 //------------------------------------------------------------- 6 // @owner=alexgor, deliant 7 //================================================================= 8 // File: FastLineChart.cs 9 // 10 // Namespace: DataVisualization.Charting.ChartTypes 11 // 12 // Classes: FastLineChart 13 // 14 // Purpose: When performance is critical, the FastLine chart 15 // type is a good alternative to the Line chart. FastLine 16 // charts significantly reduce the drawing time of a 17 // series that contains a very large number of data points. 18 // 19 // To make the FastLine chart a high performance chart, 20 // some charting features have been omitted. The features 21 // omitted include the ability to control Point level 22 // visual properties, the ability to draw markers, the 23 // use of data point labels, shadows, and the use of 24 // chart animation. 25 // 26 // FastLine chart performance was improved by limiting 27 // visual appearance features and by introducing data 28 // point compacting algorithm. When chart contains 29 // thousands of data points, it is common to have tens 30 // or hundreds points displayed in the area comparable 31 // to a single pixel. FastLine algorithm accumulates 32 // point information and only draw points if they extend 33 // outside currently filled pixels. 34 // 35 // Reviewed: AG - Microsoft 6, 2007 36 // 37 //=================================================================== 38 39 #region Used namespaces 40 41 using System; 42 using System.Collections; 43 using System.Drawing; 44 using System.Drawing.Drawing2D; 45 using System.Globalization; 46 47 #if Microsoft_CONTROL 48 using System.Windows.Forms.DataVisualization.Charting.Utilities; 49 #else 50 using System.Web.UI.DataVisualization.Charting; 51 52 using System.Web.UI.DataVisualization.Charting.Utilities; 53 #endif 54 #endregion 55 56 #if Microsoft_CONTROL 57 namespace System.Windows.Forms.DataVisualization.Charting.ChartTypes 58 #else 59 namespace System.Web.UI.DataVisualization.Charting.ChartTypes 60 #endif 61 { 62 /// <summary> 63 /// FastLineChart class implements a simplified line chart drawing 64 /// algorithm which is optimized for the performance. 65 /// </summary> 66 internal class FastLineChart : IChartType 67 { 68 #region Fields and Constructor 69 70 /// <summary> 71 /// Indicates that chart is drawn in 3D area 72 /// </summary> 73 internal bool chartArea3DEnabled = false; 74 75 /// <summary> 76 /// Current chart graphics 77 /// </summary> 78 internal ChartGraphics Graph { get; set; } 79 80 /// <summary> 81 /// Z coordinate of the 3D series 82 /// </summary> 83 internal float seriesZCoordinate = 0f; 84 85 /// <summary> 86 /// 3D transformation matrix 87 /// </summary> 88 internal Matrix3D matrix3D = null; 89 90 /// <summary> 91 /// Reference to common chart elements 92 /// </summary> 93 internal CommonElements Common { get; set; } 94 95 /// <summary> 96 /// Default constructor 97 /// </summary> FastLineChart()98 public FastLineChart() 99 { 100 } 101 102 #endregion 103 104 #region IChartType interface implementation 105 106 /// <summary> 107 /// Chart type name 108 /// </summary> 109 virtual public string Name { get{ return ChartTypeNames.FastLine;}} 110 111 /// <summary> 112 /// True if chart type is stacked 113 /// </summary> 114 virtual public bool Stacked { get{ return false;}} 115 116 117 /// <summary> 118 /// True if stacked chart type supports groups 119 /// </summary> 120 virtual public bool SupportStackedGroups { get { return false; } } 121 122 123 /// <summary> 124 /// True if stacked chart type should draw separately positive and 125 /// negative data points ( Bar and column Stacked types ). 126 /// </summary> 127 public bool StackSign { get{ return false;}} 128 129 /// <summary> 130 /// True if chart type supports axeses 131 /// </summary> 132 virtual public bool RequireAxes { get{ return true;} } 133 134 /// <summary> 135 /// Chart type with two y values used for scale ( bubble chart type ) 136 /// </summary> 137 virtual public bool SecondYScale{ get{ return false;} } 138 139 /// <summary> 140 /// True if chart type requires circular chart area. 141 /// </summary> 142 public bool CircularChartArea { get{ return false;} } 143 144 /// <summary> 145 /// True if chart type supports logarithmic axes 146 /// </summary> 147 virtual public bool SupportLogarithmicAxes { get{ return true;} } 148 149 /// <summary> 150 /// True if chart type requires to switch the value (Y) axes position 151 /// </summary> 152 virtual public bool SwitchValueAxes { get{ return false;} } 153 154 /// <summary> 155 /// True if chart series can be placed side-by-side. 156 /// </summary> 157 virtual public bool SideBySideSeries { get{ return false;} } 158 159 /// <summary> 160 /// True if each data point of a chart must be represented in the legend 161 /// </summary> 162 virtual public bool DataPointsInLegend { get{ return false;} } 163 164 /// <summary> 165 /// If the crossing value is auto Crossing value should be 166 /// automatically set to zero for some chart 167 /// types (Bar, column, area etc.) 168 /// </summary> 169 virtual public bool ZeroCrossing { get{ return false;} } 170 171 /// <summary> 172 /// True if palette colors should be applied for each data paoint. 173 /// Otherwise the color is applied to the series. 174 /// </summary> 175 virtual public bool ApplyPaletteColorsToPoints { get { return false; } } 176 177 /// <summary> 178 /// Indicates that extra Y values are connected to the scale of the Y axis 179 /// </summary> 180 virtual public bool ExtraYValuesConnectedToYAxis{ get { return false; } } 181 182 /// <summary> 183 /// Indicates that it's a hundredred percent chart. 184 /// Axis scale from 0 to 100 percent should be used. 185 /// </summary> 186 virtual public bool HundredPercent{ get{return false;} } 187 188 /// <summary> 189 /// Indicates that it's a hundredred percent chart. 190 /// Axis scale from 0 to 100 percent should be used. 191 /// </summary> 192 virtual public bool HundredPercentSupportNegative{ get{return false;} } 193 194 /// <summary> 195 /// How to draw series/points in legend: 196 /// Filled rectangle, Line or Marker 197 /// </summary> 198 /// <param name="series">Legend item series.</param> 199 /// <returns>Legend item style.</returns> GetLegendImageStyle(Series series)200 virtual public LegendImageStyle GetLegendImageStyle(Series series) 201 { 202 return LegendImageStyle.Line; 203 } 204 205 /// <summary> 206 /// Number of supported Y value(s) per point 207 /// </summary> 208 virtual public int YValuesPerPoint { get { return 1; } } 209 210 /// <summary> 211 /// Gets chart type image. 212 /// </summary> 213 /// <param name="registry">Chart types registry object.</param> 214 /// <returns>Chart type image.</returns> GetImage(ChartTypeRegistry registry)215 virtual public System.Drawing.Image GetImage(ChartTypeRegistry registry) 216 { 217 return (System.Drawing.Image)registry.ResourceManager.GetObject(this.Name + "ChartType"); 218 } 219 220 #endregion 221 222 #region Painting 223 224 /// <summary> 225 /// Paint FastLine Chart. 226 /// </summary> 227 /// <param name="graph">The Chart Graphics object.</param> 228 /// <param name="common">The Common elements object.</param> 229 /// <param name="area">Chart area for this chart.</param> 230 /// <param name="seriesToDraw">Chart series to draw.</param> Paint( ChartGraphics graph, CommonElements common, ChartArea area, Series seriesToDraw )231 virtual public void Paint( 232 ChartGraphics graph, 233 CommonElements common, 234 ChartArea area, 235 Series seriesToDraw ) 236 { 237 this.Common = common; 238 this.Graph = graph; 239 bool clipRegionSet = false; 240 if(area.Area3DStyle.Enable3D) 241 { 242 // Initialize variables 243 this.chartArea3DEnabled = true; 244 matrix3D = area.matrix3D; 245 } 246 else 247 { 248 this.chartArea3DEnabled = false; 249 } 250 251 //************************************************************ 252 //** Loop through all series 253 //************************************************************ 254 foreach( Series series in common.DataManager.Series ) 255 { 256 // Process non empty series of the area with FastLine chart type 257 if( String.Compare( series.ChartTypeName, this.Name, true, System.Globalization.CultureInfo.CurrentCulture ) != 0 258 || series.ChartArea != area.Name || 259 !series.IsVisible()) 260 { 261 continue; 262 } 263 264 // Get 3D series depth and Z position 265 if(this.chartArea3DEnabled) 266 { 267 float seriesDepth; 268 area.GetSeriesZPositionAndDepth(series, out seriesDepth, out seriesZCoordinate); 269 this.seriesZCoordinate += seriesDepth/2.0f; 270 } 271 272 // Set active horizontal/vertical axis 273 Axis hAxis = area.GetAxis(AxisName.X, series.XAxisType, (area.Area3DStyle.Enable3D) ? string.Empty : series.XSubAxisName); 274 Axis vAxis = area.GetAxis(AxisName.Y, series.YAxisType, (area.Area3DStyle.Enable3D) ? string.Empty : series.YSubAxisName); 275 double hAxisMin = hAxis.ViewMinimum; 276 double hAxisMax = hAxis.ViewMaximum; 277 double vAxisMin = vAxis.ViewMinimum; 278 double vAxisMax = vAxis.ViewMaximum; 279 280 // Get "PermittedPixelError" attribute 281 float permittedPixelError = 1.0f; 282 if (series.IsCustomPropertySet(CustomPropertyName.PermittedPixelError)) 283 { 284 string attrValue = series[CustomPropertyName.PermittedPixelError]; 285 286 float pixelError; 287 bool parseSucceed = float.TryParse(attrValue, NumberStyles.Any, CultureInfo.CurrentCulture, out pixelError); 288 289 if (parseSucceed) 290 { 291 permittedPixelError = pixelError; 292 } 293 else 294 { 295 throw (new InvalidOperationException(SR.ExceptionCustomAttributeValueInvalid2("PermittedPixelError"))); 296 } 297 298 // "PermittedPixelError" attribute value should be in range from zero to 1 299 if (permittedPixelError < 0f || permittedPixelError > 1f) 300 { 301 throw (new InvalidOperationException(SR.ExceptionCustomAttributeIsNotInRange0to1("PermittedPixelError"))); 302 } 303 } 304 305 // Get pixel size in axes coordinates 306 SizeF pixelSize = graph.GetRelativeSize(new SizeF(permittedPixelError, permittedPixelError)); 307 SizeF axesMin = graph.GetRelativeSize(new SizeF((float)hAxisMin, (float)vAxisMin)); 308 double axesValuesPixelSizeX = Math.Abs(hAxis.PositionToValue(axesMin.Width + pixelSize.Width, false) - hAxis.PositionToValue(axesMin.Width, false)); 309 310 // Create line pen 311 Pen linePen = new Pen(series.Color, series.BorderWidth); 312 linePen.DashStyle = graph.GetPenStyle( series.BorderDashStyle ); 313 linePen.StartCap = LineCap.Round; 314 linePen.EndCap = LineCap.Round; 315 316 // Create empty line pen 317 Pen emptyLinePen = new Pen(series.EmptyPointStyle.Color, series.EmptyPointStyle.BorderWidth); 318 emptyLinePen.DashStyle = graph.GetPenStyle( series.EmptyPointStyle.BorderDashStyle ); 319 emptyLinePen.StartCap = LineCap.Round; 320 emptyLinePen.EndCap = LineCap.Round; 321 322 // Check if series is indexed 323 bool indexedSeries = ChartHelper.IndexedSeries(this.Common, series.Name ); 324 325 // Loop through all ponts in the series 326 int index = 0; 327 double yValueRangeMin = double.NaN; 328 double yValueRangeMax = double.NaN; 329 DataPoint pointRangeMin = null; 330 DataPoint pointRangeMax = null; 331 double xValue = 0; 332 double yValue = 0; 333 double xValuePrev = 0; 334 double yValuePrev = 0; 335 DataPoint prevDataPoint = null; 336 PointF lastVerticalSegmentPoint = PointF.Empty; 337 PointF prevPoint = PointF.Empty; 338 PointF currentPoint = PointF.Empty; 339 bool prevPointInAxesCoordinates = false; 340 bool verticalLineDetected = false; 341 bool prevPointIsEmpty = false; 342 bool currentPointIsEmpty = false; 343 bool firstNonEmptyPoint = false; 344 double xPixelConverter = (graph.Common.ChartPicture.Width - 1.0) / 100.0; 345 double yPixelConverter = (graph.Common.ChartPicture.Height - 1.0) / 100.0; 346 foreach( DataPoint point in series.Points ) 347 { 348 // Get point X and Y values 349 xValue = (indexedSeries) ? index + 1 : point.XValue; 350 xValue = hAxis.GetLogValue(xValue); 351 yValue = vAxis.GetLogValue(point.YValues[0]); 352 currentPointIsEmpty = point.IsEmpty; 353 354 // NOTE: Fixes issue #7094 355 // If current point is non-empty but the previous one was, 356 // use empty point style properties to draw it. 357 if (prevPointIsEmpty && !currentPointIsEmpty && !firstNonEmptyPoint) 358 { 359 firstNonEmptyPoint = true; 360 currentPointIsEmpty = true; 361 } 362 else 363 { 364 firstNonEmptyPoint = false; 365 } 366 367 // Check if line is completly out of the data scaleView 368 if( !verticalLineDetected && 369 ((xValue < hAxisMin && xValuePrev < hAxisMin) || 370 (xValue > hAxisMax && xValuePrev > hAxisMax) || 371 (yValue < vAxisMin && yValuePrev < vAxisMin) || 372 (yValue > vAxisMax && yValuePrev > vAxisMax) )) 373 { 374 xValuePrev = xValue; 375 yValuePrev = yValue; 376 prevPointInAxesCoordinates = true; 377 ++index; 378 continue; 379 } 380 else if(!clipRegionSet) 381 { 382 // Check if line is partialy in the data scaleView 383 if(xValuePrev < hAxisMin || xValuePrev > hAxisMax || 384 xValue > hAxisMax || xValue < hAxisMin || 385 yValuePrev < vAxisMin || yValuePrev > vAxisMax || 386 yValue < vAxisMin || yValue > vAxisMax ) 387 { 388 // Set clipping region for line drawing 389 graph.SetClip( area.PlotAreaPosition.ToRectangleF() ); 390 clipRegionSet = true; 391 } 392 } 393 394 // Check if point may be skipped 395 if(index > 0 && 396 currentPointIsEmpty == prevPointIsEmpty) 397 { 398 // Check if points X value in acceptable error boundary 399 if( Math.Abs(xValue - xValuePrev) < axesValuesPixelSizeX) 400 { 401 if(!verticalLineDetected) 402 { 403 verticalLineDetected = true; 404 if(yValue > yValuePrev) 405 { 406 yValueRangeMax = yValue; 407 yValueRangeMin = yValuePrev; 408 pointRangeMax = point; 409 pointRangeMin = prevDataPoint; 410 } 411 else 412 { 413 yValueRangeMax = yValuePrev; 414 yValueRangeMin = yValue; 415 pointRangeMax = prevDataPoint; 416 pointRangeMin = point; 417 } 418 419 // NOTE: Prev. version code - A.G. 420 // yValueRangeMin = Math.Min(yValue, yValuePrev); 421 // yValueRangeMax = Math.Max(yValue, yValuePrev); 422 } 423 else 424 { 425 if(yValue > yValueRangeMax) 426 { 427 yValueRangeMax = yValue; 428 pointRangeMax = point; 429 } 430 431 else if(yValue < yValueRangeMin) 432 { 433 yValueRangeMin = yValue; 434 pointRangeMin = point; 435 } 436 437 // NOTE: Prev. version code - A.G. 438 // yValueRangeMin = Math.Min(yValue, yValueRangeMin); 439 // yValueRangeMax = Math.Max(yValue, yValueRangeMax); 440 } 441 442 // Remember last point 443 prevDataPoint = point; 444 445 // Remember last vertical range point 446 // Note! Point is in axes coordinate. 447 lastVerticalSegmentPoint.Y = (float)yValue; 448 449 // Increase counter and proceed to next data point 450 ++index; 451 continue; 452 } 453 } 454 455 // Get point pixel position 456 currentPoint.X = (float) 457 (hAxis.GetLinearPosition( xValue ) * xPixelConverter); 458 currentPoint.Y = (float) 459 (vAxis.GetLinearPosition( yValue ) * yPixelConverter); 460 461 // Check if previous point must be converted from axes values to pixels 462 if(prevPointInAxesCoordinates) 463 { 464 prevPoint.X = (float) 465 (hAxis.GetLinearPosition( xValuePrev ) * xPixelConverter); 466 prevPoint.Y = (float) 467 (vAxis.GetLinearPosition( yValuePrev ) * yPixelConverter); 468 } 469 470 // Draw accumulated vertical line (with minimal X values differences) 471 if(verticalLineDetected) 472 { 473 // Convert Y coordinates to pixels 474 yValueRangeMin = (vAxis.GetLinearPosition( yValueRangeMin ) * yPixelConverter); 475 yValueRangeMax = (vAxis.GetLinearPosition( yValueRangeMax ) * yPixelConverter); 476 477 // Draw accumulated vertical line 478 DrawLine( 479 series, 480 prevDataPoint, 481 pointRangeMin, 482 pointRangeMax, 483 index, 484 (prevPointIsEmpty) ? emptyLinePen : linePen, 485 prevPoint.X, 486 (float)yValueRangeMin, 487 prevPoint.X, 488 (float)yValueRangeMax); 489 490 // Reset vertical line detected flag 491 verticalLineDetected = false; 492 493 // Convert last point of the vertical line segment to pixel coordinates 494 prevPoint.Y = (float) 495 (vAxis.GetLinearPosition( lastVerticalSegmentPoint.Y ) * yPixelConverter); 496 } 497 498 // Draw line from previous to current point 499 if(index > 0) 500 { 501 DrawLine( 502 series, 503 point, 504 pointRangeMin, 505 pointRangeMax, 506 index, 507 (currentPointIsEmpty) ? emptyLinePen : linePen, 508 prevPoint.X, 509 prevPoint.Y, 510 currentPoint.X, 511 currentPoint.Y); 512 } 513 514 // Remember last point coordinates 515 xValuePrev = xValue; 516 yValuePrev = yValue; 517 prevDataPoint = point; 518 prevPoint = currentPoint; 519 prevPointInAxesCoordinates = false; 520 prevPointIsEmpty = currentPointIsEmpty; 521 ++index; 522 } 523 524 // Draw last accumulated line segment 525 if(verticalLineDetected) 526 { 527 // Check if previous point must be converted from axes values to pixels 528 if(prevPointInAxesCoordinates) 529 { 530 prevPoint.X = (float) 531 (hAxis.GetLinearPosition( xValuePrev ) * xPixelConverter); 532 prevPoint.Y = (float) 533 (vAxis.GetLinearPosition( yValuePrev ) * yPixelConverter); 534 } 535 536 // Convert Y coordinates to pixels 537 yValueRangeMin = (vAxis.GetLinearPosition( yValueRangeMin ) * yPixelConverter); 538 yValueRangeMax = (vAxis.GetLinearPosition( yValueRangeMax ) * yPixelConverter); 539 540 // Draw accumulated vertical line 541 DrawLine( 542 series, 543 prevDataPoint, 544 pointRangeMin, 545 pointRangeMax, 546 index - 1, 547 (prevPointIsEmpty) ? emptyLinePen : linePen, 548 prevPoint.X, 549 (float)yValueRangeMin, 550 prevPoint.X, 551 (float)yValueRangeMax); 552 553 verticalLineDetected = false; 554 yValueRangeMin = double.NaN; 555 yValueRangeMax = double.NaN; 556 pointRangeMin = null; 557 pointRangeMax = null; 558 } 559 560 } 561 562 // Reset Clip Region 563 if(clipRegionSet) 564 { 565 graph.ResetClip(); 566 } 567 568 } 569 570 /// <summary> 571 /// Draws a line connecting two PointF structures. 572 /// </summary> 573 /// <param name="series">Chart series.</param> 574 /// <param name="point">Series last data point in the group.</param> 575 /// <param name="pointMin">Series minimum Y value data point in the group.</param> 576 /// <param name="pointMax">Series maximum Y value data point in the group.</param> 577 /// <param name="pointIndex">Point index.</param> 578 /// <param name="pen">Pen object that determines the color, width, and style of the line.</param> 579 /// <param name="firstPointX">First point X coordinate.</param> 580 /// <param name="firstPointY">First point Y coordinate</param> 581 /// <param name="secondPointX">Second point X coordinate.</param> 582 /// <param name="secondPointY">Second point Y coordinate</param> DrawLine( Series series, DataPoint point, DataPoint pointMin, DataPoint pointMax, int pointIndex, Pen pen, float firstPointX, float firstPointY, float secondPointX, float secondPointY )583 public virtual void DrawLine( 584 Series series, 585 DataPoint point, 586 DataPoint pointMin, 587 DataPoint pointMax, 588 int pointIndex, 589 Pen pen, 590 float firstPointX, 591 float firstPointY, 592 float secondPointX, 593 float secondPointY 594 ) 595 { 596 // Transform 3D coordinates 597 if(chartArea3DEnabled) 598 { 599 Point3D [] points = new Point3D[2]; 600 601 // All coordinates has to be transformed in relative coordinate system 602 // NOTE: Fixes issue #5496 603 PointF firstPoint = Graph.GetRelativePoint(new PointF(firstPointX, firstPointY)); 604 PointF secondPoint = Graph.GetRelativePoint(new PointF(secondPointX, secondPointY)); 605 606 points[0] = new Point3D(firstPoint.X, firstPoint.Y, seriesZCoordinate); 607 points[1] = new Point3D(secondPoint.X, secondPoint.Y, seriesZCoordinate); 608 matrix3D.TransformPoints( points ); 609 610 // All coordinates has to be transformed back to pixels 611 // NOTE: Fixes issue #5496 612 points[0].PointF = Graph.GetAbsolutePoint(points[0].PointF); 613 points[1].PointF = Graph.GetAbsolutePoint(points[1].PointF); 614 615 firstPointX = points[0].X; 616 firstPointY = points[0].Y; 617 secondPointX = points[1].X; 618 secondPointY = points[1].Y; 619 } 620 621 // Draw line 622 Graph.DrawLine(pen, firstPointX, firstPointY, secondPointX,secondPointY); 623 624 // Process selection regions 625 if( this.Common.ProcessModeRegions ) 626 { 627 // Create grapics path object for the line 628 using (GraphicsPath path = new GraphicsPath()) 629 { 630 float width = pen.Width + 2; 631 632 if (Math.Abs(firstPointX - secondPointX) > Math.Abs(firstPointY - secondPointY)) 633 { 634 path.AddLine(firstPointX, firstPointY - width, secondPointX, secondPointY - width); 635 path.AddLine(secondPointX, secondPointY + width, firstPointX, firstPointY + width); 636 path.CloseAllFigures(); 637 } 638 else 639 { 640 path.AddLine(firstPointX - width, firstPointY, secondPointX - width, secondPointY); 641 path.AddLine(secondPointX + width, secondPointY, firstPointX + width, firstPointY); 642 path.CloseAllFigures(); 643 } 644 645 // Calculate bounding rectangle 646 RectangleF pathBounds = path.GetBounds(); 647 648 // If one side of the bounding rectangle is less than 2 pixels 649 // use rectangle region shape to optimize used coordinates space 650 if (pathBounds.Width <= 2.0 || pathBounds.Height <= 2.0) 651 { 652 // Add hot region path as rectangle 653 pathBounds.Inflate(pen.Width, pen.Width); 654 this.Common.HotRegionsList.AddHotRegion( 655 Graph.GetRelativeRectangle(pathBounds), 656 point, 657 point.series.Name, 658 pointIndex); 659 } 660 else 661 { 662 // Add hot region path as polygon 663 this.Common.HotRegionsList.AddHotRegion( 664 path, 665 false, 666 Graph, 667 point, 668 point.series.Name, 669 pointIndex); 670 } 671 } 672 } 673 } 674 675 #endregion 676 677 #region Y values related methods 678 679 /// <summary> 680 /// Helper function, which returns the Y value of the point. 681 /// </summary> 682 /// <param name="common">Chart common elements.</param> 683 /// <param name="area">Chart area the series belongs to.</param> 684 /// <param name="series">Sereis of the point.</param> 685 /// <param name="point">Point object.</param> 686 /// <param name="pointIndex">Index of the point.</param> 687 /// <param name="yValueIndex">Index of the Y value to get.</param> 688 /// <returns>Y value of the point.</returns> GetYValue( CommonElements common, ChartArea area, Series series, DataPoint point, int pointIndex, int yValueIndex)689 virtual public double GetYValue( 690 CommonElements common, 691 ChartArea area, 692 Series series, 693 DataPoint point, 694 int pointIndex, 695 int yValueIndex) 696 { 697 return point.YValues[yValueIndex]; 698 } 699 700 #endregion 701 702 #region SmartLabelStyle methods 703 704 /// <summary> 705 /// Adds markers position to the list. Used to check SmartLabelStyle overlapping. 706 /// </summary> 707 /// <param name="common">Common chart elements.</param> 708 /// <param name="area">Chart area.</param> 709 /// <param name="series">Series values to be used.</param> 710 /// <param name="list">List to add to.</param> AddSmartLabelMarkerPositions(CommonElements common, ChartArea area, Series series, ArrayList list)711 public void AddSmartLabelMarkerPositions(CommonElements common, ChartArea area, Series series, ArrayList list) 712 { 713 // Fast Line chart type do not support labels 714 } 715 716 #endregion 717 718 #region IDisposable interface implementation 719 /// <summary> 720 /// Releases unmanaged and - optionally - managed resources 721 /// </summary> 722 /// <param name="disposing"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param> Dispose(bool disposing)723 protected virtual void Dispose(bool disposing) 724 { 725 //Nothing to dispose at the base class. 726 } 727 728 /// <summary> 729 /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. 730 /// </summary> Dispose()731 public void Dispose() 732 { 733 Dispose(true); 734 GC.SuppressFinalize(this); 735 } 736 #endregion 737 } 738 } 739