1 //------------------------------------------------------------- 2 // <copyright company=�Microsoft Corporation�> 3 // Copyright � Microsoft Corporation. All Rights Reserved. 4 // </copyright> 5 //------------------------------------------------------------- 6 // @owner=alexgor, deliant 7 //================================================================= 8 // File: AxisLabels.cs 9 // 10 // Namespace: System.Web.UI.WebControls[Windows.Forms].Charting 11 // 12 // Classes: AxisLabels 13 // 14 // Purpose: Base class for the Axis class which defines axis 15 // labels related properties and methods. 16 // 17 // Reviewed: GS - August 8, 2002 18 // AG - August 8, 2002 19 // 20 //=================================================================== 21 22 #region Used namespaces 23 using System; 24 using System.Collections; 25 using System.Collections.Specialized; 26 using System.Collections.Generic; 27 using System.ComponentModel; 28 using System.ComponentModel.Design; 29 using System.Data; 30 using System.Drawing; 31 using System.Drawing.Design; 32 using System.Drawing.Drawing2D; 33 34 #if Microsoft_CONTROL 35 using System.Windows.Forms.DataVisualization.Charting.Data; 36 using System.Windows.Forms.DataVisualization.Charting.ChartTypes; 37 using System.Windows.Forms.DataVisualization.Charting.Utilities; 38 using System.Windows.Forms.DataVisualization.Charting.Borders3D; 39 using System.Windows.Forms.DataVisualization.Charting; 40 #else 41 using System.Web; 42 using System.Web.UI; 43 using System.Web.UI.DataVisualization.Charting; 44 using System.Web.UI.DataVisualization.Charting.Data; 45 using System.Web.UI.DataVisualization.Charting.ChartTypes; 46 using System.Web.UI.DataVisualization.Charting.Utilities; 47 #endif 48 49 #endregion 50 51 #if Microsoft_CONTROL 52 namespace System.Windows.Forms.DataVisualization.Charting 53 #else 54 namespace System.Web.UI.DataVisualization.Charting 55 56 #endif 57 { 58 /// <summary> 59 /// The Axis class provides functionality for 60 /// drawing axis labels. 61 /// </summary> 62 public partial class Axis 63 { 64 #region Fields 65 66 // Custom Labels collection 67 private CustomLabelsCollection _customLabels = null; 68 69 #endregion 70 71 #region Axis labels properties 72 73 /// <summary> 74 /// Gets or sets the style of the label. 75 /// </summary> 76 [ 77 SRCategory("CategoryAttributeLabels"), 78 Bindable(true), 79 NotifyParentPropertyAttribute(true), 80 SRDescription("DescriptionAttributeLabelStyle"), 81 #if Microsoft_CONTROL 82 DesignerSerializationVisibility(DesignerSerializationVisibility.Content), 83 #else 84 PersistenceMode(PersistenceMode.InnerProperty), 85 #endif 86 TypeConverter(typeof(NoNameExpandableObjectConverter)) 87 ] 88 public LabelStyle LabelStyle 89 { 90 get 91 { 92 return labelStyle; 93 } 94 set 95 { 96 labelStyle = value; 97 labelStyle.Axis = (Axis)this; 98 this.Invalidate(); 99 } 100 } 101 102 /// <summary> 103 /// Gets a collection of custom labels. 104 /// </summary> 105 [ 106 SRCategory("CategoryAttributeLabels"), 107 Bindable(true), 108 SRDescription("DescriptionAttributeCustomLabels"), 109 #if Microsoft_CONTROL 110 DesignerSerializationVisibility(DesignerSerializationVisibility.Content), 111 #else 112 PersistenceMode(PersistenceMode.InnerProperty), 113 #endif 114 Editor(Editors.ChartCollectionEditor.Editor, Editors.ChartCollectionEditor.Base) 115 ] 116 public CustomLabelsCollection CustomLabels 117 { 118 get 119 { 120 return _customLabels; 121 } 122 } 123 124 #endregion 125 126 #region Axis labels methods 127 128 /// <summary> 129 /// Indicates that custom grid lines should be painted. 130 /// </summary> 131 /// <returns>Indicates that custom grid lines should be painted.</returns> IsCustomGridLines()132 internal bool IsCustomGridLines() 133 { 134 if(this.CustomLabels.Count > 0) 135 { 136 // Check if at least one custom label has a flag set 137 foreach(CustomLabel label in this.CustomLabels) 138 { 139 if((label.GridTicks & GridTickTypes.Gridline) == GridTickTypes.Gridline) 140 { 141 return true; 142 } 143 } 144 } 145 146 return false; 147 } 148 149 /// <summary> 150 /// Indicates that custom tick marks should be painted. 151 /// </summary> 152 /// <returns>Indicates that custom tick marks should be painted.</returns> IsCustomTickMarks()153 internal bool IsCustomTickMarks() 154 { 155 if(this.CustomLabels.Count > 0) 156 { 157 // Check if at least one custom label has a flag set 158 foreach(CustomLabel label in this.CustomLabels) 159 { 160 if((label.GridTicks & GridTickTypes.TickMark) == GridTickTypes.TickMark) 161 { 162 return true; 163 } 164 } 165 } 166 167 return false; 168 } 169 170 /// <summary> 171 /// Gets the type of the axis. 172 /// </summary> 173 /// <value>The type of the axis.</value> GetAxisType()174 internal AxisType GetAxisType() 175 { 176 if (this.axisType == AxisName.X || this.axisType == AxisName.Y) 177 { 178 return AxisType.Primary; 179 } 180 else 181 { 182 return AxisType.Secondary; 183 } 184 } 185 186 /// <summary> 187 /// Gets the axis series. 188 /// </summary> 189 /// <returns></returns> GetAxisSeries()190 internal ArrayList GetAxisSeries() 191 { 192 ArrayList dataSeries = new ArrayList(); 193 194 // check for attached series. 195 foreach (string seriesName in this.ChartArea.Series) 196 { 197 Series series = this.Common.DataManager.Series[seriesName]; 198 if (this.axisType == AxisName.X || this.axisType == AxisName.X2) 199 { 200 if (series.XAxisType == this.GetAxisType()) 201 { 202 dataSeries.Add(series); 203 } 204 } 205 else 206 { 207 if (series.YAxisType == this.GetAxisType()) 208 { 209 dataSeries.Add(series); 210 } 211 } 212 } 213 return dataSeries; 214 } 215 216 /// <summary> 217 /// Gets the other (primary/secondary) axis. 218 /// </summary> 219 /// <returns></returns> GetOtherTypeAxis()220 internal Axis GetOtherTypeAxis() 221 { 222 return ChartArea.GetAxis( 223 this.axisType, 224 this.GetAxisType() == AxisType.Primary ? AxisType.Secondary : AxisType.Primary, 225 String.Empty 226 ); 227 } 228 229 /// <summary> 230 /// Checks if the other (primary/secondary) axis has custom labels labels. 231 /// These labels will be added if this axis has no series attached and no custom labels. 232 /// This works only on category axes. 233 /// </summary> PostFillLabels()234 internal void PostFillLabels() 235 { 236 foreach (CustomLabel label in this.CustomLabels) 237 { 238 if (label.customLabel) 239 { 240 return; 241 } 242 } 243 244 // Labels are disabled for this axis 245 if ( 246 !this.LabelStyle.Enabled || 247 !this.enabled || 248 !String.IsNullOrEmpty(((Axis)this).SubAxisName) || 249 this.axisType == AxisName.Y || 250 this.axisType == AxisName.Y2 251 ) 252 { 253 return; 254 } 255 256 // check if no series attached. 257 if (this.GetAxisSeries().Count > 0) 258 { 259 return; 260 } 261 this.CustomLabels.Clear(); 262 foreach (CustomLabel label in this.GetOtherTypeAxis().CustomLabels) 263 { 264 this.CustomLabels.Add(label.Clone()); 265 } 266 } 267 268 /// <summary> 269 /// Fill labels from data from data manager or 270 /// from axis scale. 271 /// </summary> 272 /// <param name="removeFirstRow">True if first row of auto generated labels must be removed.</param> FillLabels(bool removeFirstRow)273 internal void FillLabels(bool removeFirstRow) 274 { 275 #if SUBAXES 276 // Process all sub-axis 277 foreach(SubAxis subAxis in ((Axis)this).SubAxes) 278 { 279 subAxis.FillLabels(true); 280 } 281 #endif // SUBAXES 282 283 // Labels are disabled for this axis 284 if( !this.LabelStyle.Enabled || !this.enabled ) 285 { 286 return; 287 } 288 289 // For circular chart area fill only Y axis labels 290 if(this.ChartArea != null && this.ChartArea.chartAreaIsCurcular) 291 { 292 if(this.axisType != AxisName.Y) 293 { 294 ICircularChartType type = this.ChartArea.GetCircularChartType(); 295 if(type == null || !type.XAxisLabelsSupported()) 296 { 297 return; 298 } 299 } 300 } 301 302 // Check if the custom labels exist 303 bool customLabelsFlag = false; 304 foreach( CustomLabel lab in CustomLabels ) 305 { 306 if( lab.customLabel ) 307 { 308 if( lab.RowIndex == 0 || 309 this.ChartArea.chartAreaIsCurcular) 310 { 311 customLabelsFlag = true; 312 } 313 } 314 } 315 316 317 // Remove the first row of labels if custom labels not exist 318 if(removeFirstRow) 319 { 320 if( customLabelsFlag == false ) 321 { 322 for( int index = 0; index < CustomLabels.Count; index++ ) 323 { 324 if( CustomLabels[index].RowIndex == 0 ) 325 { 326 CustomLabels.RemoveAt( index ); 327 index = -1; 328 } 329 } 330 } 331 else 332 { 333 return; 334 } 335 } 336 337 // Get data series for this axis. 338 List<string> dataSeries = null; 339 switch( axisType ) 340 { 341 case AxisName.X: 342 dataSeries = ChartArea.GetXAxesSeries( AxisType.Primary, ((Axis)this).SubAxisName ); 343 break; 344 case AxisName.Y: 345 dataSeries = ChartArea.GetYAxesSeries( AxisType.Primary, ((Axis)this).SubAxisName ); 346 break; 347 case AxisName.X2: 348 dataSeries = ChartArea.GetXAxesSeries( AxisType.Secondary, ((Axis)this).SubAxisName ); 349 break; 350 case AxisName.Y2: 351 dataSeries = ChartArea.GetYAxesSeries( AxisType.Secondary, ((Axis)this).SubAxisName ); 352 break; 353 } 354 355 // There aren't data series connected with this axis. 356 if( dataSeries.Count == 0 ) 357 { 358 return; 359 } 360 361 //Let's convert the ArrayList of the series names into to string[] 362 string[] dataSeriesNames = new string[dataSeries.Count]; 363 for (int i = 0; i < dataSeries.Count; i++) 364 dataSeriesNames[i] = (string)dataSeries[i]; 365 366 // Check if series X values all set to zeros 367 bool seriesXValuesZeros = ChartHelper.SeriesXValuesZeros(this.Common, dataSeriesNames); 368 369 // Check if series is indexed (All X values zeros or IsXValueIndexed flag set) 370 bool indexedSeries = true; 371 if (!seriesXValuesZeros) 372 { 373 indexedSeries = ChartHelper.IndexedSeries(this.Common, dataSeriesNames); 374 } 375 376 // Show End Labels 377 int endLabels = 0; 378 if( labelStyle.IsEndLabelVisible ) 379 { 380 endLabels = 1; 381 } 382 383 // Get chart type of the first series 384 IChartType chartType = Common.ChartTypeRegistry.GetChartType( ChartArea.GetFirstSeries().ChartTypeName ); 385 bool fromSeries = false; 386 if( !chartType.RequireAxes ) 387 { 388 return; 389 } 390 else if( axisType == AxisName.Y || axisType == AxisName.Y2 ) 391 { 392 fromSeries = false; 393 } 394 else 395 { 396 fromSeries = true; 397 } 398 399 // X values from data points are not 0. 400 if (fromSeries && !ChartHelper.SeriesXValuesZeros(this.Common, dataSeries.ToArray())) 401 { 402 fromSeries = false; 403 } 404 405 // X values from data points are not 0. 406 if( fromSeries && ( labelStyle.GetIntervalOffset() != 0 || labelStyle.GetInterval() != 0 ) ) 407 { 408 fromSeries = false; 409 } 410 411 // Get value type 412 ChartValueType valueType; 413 if( axisType == AxisName.X || axisType == AxisName.X2 ) 414 { 415 // If X value is indexed the type is always String. So we use indexed type instead 416 valueType = Common.DataManager.Series[dataSeries[0]].indexedXValueType; 417 } 418 else 419 { 420 valueType = Common.DataManager.Series[dataSeries[0]].YValueType; 421 } 422 423 if( labelStyle.GetIntervalType() != DateTimeIntervalType.Auto && 424 labelStyle.GetIntervalType() != DateTimeIntervalType.Number ) 425 { 426 if (valueType != ChartValueType.Time && 427 valueType != ChartValueType.Date && 428 valueType != ChartValueType.DateTimeOffset) 429 { 430 valueType = ChartValueType.DateTime; 431 } 432 } 433 434 // *********************************** 435 // Pre calculate some values 436 // *********************************** 437 double viewMaximum = this.ViewMaximum; 438 double viewMinimum = this.ViewMinimum; 439 440 // *********************************** 441 // Labels are filled from data series. 442 // *********************************** 443 if( fromSeries ) 444 { 445 int numOfPoints; 446 numOfPoints = Common.DataManager.GetNumberOfPoints( dataSeries.ToArray() ); 447 448 // Show end labels 449 if( endLabels == 1 ) 450 { 451 // min position 452 CustomLabels.Add( - 0.5, 0.5, ValueConverter.FormatValue( 453 this.Common.Chart, 454 this, 455 null, 456 0.0, 457 this.LabelStyle.Format, 458 valueType, 459 ChartElementType.AxisLabels), 460 false); 461 } 462 463 // Labels from point position 464 for( int point = 0; point < numOfPoints; point++ ) 465 { 466 CustomLabels.Add( ((double)point)+ 0.5, ((double)point)+ 1.5, 467 ValueConverter.FormatValue( 468 this.Common.Chart, 469 this, 470 null, 471 point + 1, 472 this.LabelStyle.Format, 473 valueType, 474 ChartElementType.AxisLabels), 475 false); 476 } 477 478 // Show end labels 479 if( endLabels == 1 ) 480 { 481 // max position 482 CustomLabels.Add( ((double)numOfPoints)+ 0.5, ((double)numOfPoints)+ 1.5, 483 ValueConverter.FormatValue( 484 this.Common.Chart, 485 this, 486 null, 487 numOfPoints + 1, 488 this.LabelStyle.Format, 489 valueType, 490 ChartElementType.AxisLabels), 491 false); 492 } 493 494 int pointIndx; 495 foreach( string seriesIndx in dataSeries ) 496 { 497 // End labels enabled 498 if( endLabels == 1 ) 499 pointIndx = 1; 500 else 501 pointIndx = 0; 502 503 // Set labels from data points labels 504 foreach( DataPoint dataPoint in Common.DataManager.Series[ seriesIndx ].Points ) 505 { 506 // Find first row of labels 507 while( CustomLabels[pointIndx].RowIndex > 0 ) 508 { 509 pointIndx++; 510 } 511 512 // Add X labels 513 if( axisType == AxisName.X || axisType == AxisName.X2 ) 514 { 515 if( dataPoint.AxisLabel.Length > 0 ) 516 { 517 CustomLabels[pointIndx].Text = dataPoint.AxisLabel; 518 } 519 } 520 521 pointIndx++; 522 } 523 } 524 } 525 // *********************************** 526 // Labels are filled from axis scale. 527 // *********************************** 528 else 529 { 530 if( viewMinimum == viewMaximum ) 531 return; 532 533 double labValue; // Value, which will be converted to text and used for, labels. 534 double beginPosition; // Begin position for a label 535 double endPosition; // End position for a label 536 double start; // Start position for all labels 537 538 // Get first series attached to this axis 539 Series axisSeries = null; 540 if(axisType == AxisName.X || axisType == AxisName.X2) 541 { 542 List<string> seriesArray = ChartArea.GetXAxesSeries((axisType == AxisName.X) ? AxisType.Primary : AxisType.Secondary, ((Axis)this).SubAxisName); 543 if(seriesArray.Count > 0) 544 { 545 axisSeries = Common.DataManager.Series[seriesArray[0]]; 546 if(axisSeries != null && !axisSeries.IsXValueIndexed) 547 { 548 axisSeries = null; 549 } 550 } 551 } 552 553 // *********************************** 554 // Check if the AJAX zooming and scrolling mode is enabled. 555 // Labels are filled slightly different in this case. 556 // *********************************** 557 DateTimeIntervalType offsetType = (labelStyle.GetIntervalOffsetType() == DateTimeIntervalType.Auto) ? labelStyle.GetIntervalType() : labelStyle.GetIntervalOffsetType(); 558 559 // By default start is equal to minimum 560 start = viewMinimum; 561 562 // Adjust start position depending on the interval type 563 if(!this.ChartArea.chartAreaIsCurcular || 564 this.axisType == AxisName.Y || 565 this.axisType == AxisName.Y2 ) 566 { 567 start = ChartHelper.AlignIntervalStart(start, labelStyle.GetInterval(), labelStyle.GetIntervalType(), axisSeries); 568 } 569 570 // Move start if there is start position 571 if( labelStyle.GetIntervalOffset() != 0 && axisSeries == null) 572 { 573 start += ChartHelper.GetIntervalSize(start, labelStyle.GetIntervalOffset(), 574 offsetType, axisSeries, 0, DateTimeIntervalType.Number, true, false); 575 } 576 577 // *************************************** 578 // Date type 579 // *************************************** 580 if( valueType == ChartValueType.DateTime || 581 valueType == ChartValueType.Date || 582 valueType == ChartValueType.Time || 583 valueType == ChartValueType.DateTimeOffset || 584 axisSeries != null) 585 { 586 double position = start; 587 double dateInterval; 588 589 // Too many labels 590 if ((viewMaximum - start) / ChartHelper.GetIntervalSize(start, labelStyle.GetInterval(), labelStyle.GetIntervalType(), axisSeries, 0, DateTimeIntervalType.Number, true) > ChartHelper.MaxNumOfGridlines) 591 return; 592 593 int counter = 0; 594 double endLabelMaxPosition = viewMaximum - ChartHelper.GetIntervalSize(viewMaximum, labelStyle.GetInterval(), labelStyle.GetIntervalType(), axisSeries, labelStyle.GetIntervalOffset(), offsetType, true) / 2f; 595 double endLabelMinPosition = viewMinimum + ChartHelper.GetIntervalSize(viewMinimum, labelStyle.GetInterval(), labelStyle.GetIntervalType(), axisSeries, labelStyle.GetIntervalOffset(), offsetType, true) / 2f; 596 while( (decimal)position <= (decimal)viewMaximum ) 597 { 598 dateInterval = ChartHelper.GetIntervalSize(position, labelStyle.GetInterval(), labelStyle.GetIntervalType(), axisSeries, labelStyle.GetIntervalOffset(), offsetType, true); 599 labValue = position; 600 601 // For IsLogarithmic axes 602 if( this.IsLogarithmic ) 603 { 604 labValue = Math.Pow( this.logarithmBase, labValue ); 605 } 606 607 // Check if we do not exceed max number of elements 608 if (counter++ > ChartHelper.MaxNumOfGridlines) 609 { 610 break; 611 } 612 613 if (endLabels == 0 && position >= endLabelMaxPosition) 614 { 615 break; 616 } 617 618 beginPosition = position - dateInterval * 0.5; 619 endPosition = position + dateInterval * 0.5; 620 621 if(endLabels == 0 && position <= endLabelMinPosition) 622 { 623 position += dateInterval; 624 continue; 625 } 626 627 if( (decimal)beginPosition > (decimal)viewMaximum ) 628 { 629 position += dateInterval; 630 continue; 631 } 632 633 // NOTE: Fixes issue #6466 634 // Following code is removed due to the issues caused by the rounding error 635 636 //if( (((decimal)beginPosition + (decimal)endPosition) / 2.0m) < (decimal)viewMinimum ) 637 //{ 638 // position += dateInterval; 639 // continue; 640 //} 641 //if ((decimal)viewMaximum < (((decimal)beginPosition + (decimal)endPosition) / 2m)) 642 //{ 643 // position += dateInterval; 644 // continue; 645 //} 646 647 string pointLabel = GetPointLabel( dataSeries, labValue, !seriesXValuesZeros, indexedSeries ); 648 if( pointLabel.Length == 0 ) 649 { 650 // Do not draw last label for indexed series 651 if( position <= this.maximum ) 652 { 653 // Add a label to the collection 654 if( position != this.maximum || !Common.DataManager.Series[ dataSeries[0] ].IsXValueIndexed ) 655 { 656 CustomLabels.Add( beginPosition, 657 endPosition, 658 ValueConverter.FormatValue( 659 this.Common.Chart, 660 this, 661 null, 662 labValue, 663 this.LabelStyle.Format, 664 valueType, 665 ChartElementType.AxisLabels), 666 false); 667 } 668 } 669 } 670 else 671 { 672 // Add a label to the collection 673 CustomLabels.Add( beginPosition, 674 endPosition, 675 pointLabel, 676 false); 677 } 678 position += dateInterval; 679 } 680 } 681 else 682 { 683 // *************************************** 684 // Scale value type 685 // *************************************** 686 687 // Show First label if Start Label position is used 688 if( start != viewMinimum ) 689 endLabels = 1; 690 691 // Set labels 692 int labelCounter = 0; 693 for (double position = start - endLabels * labelStyle.GetInterval(); position < viewMaximum - 1.5 * labelStyle.GetInterval() * (1 - endLabels); position = (double)((decimal)position + (decimal)labelStyle.GetInterval())) 694 { 695 // Prevent endless loop that may be caused by very small interval 696 // and double/decimal rounding errors 697 ++labelCounter; 698 if(labelCounter > ChartHelper.MaxNumOfGridlines) 699 { 700 break; 701 } 702 703 labValue = (double)((decimal)position + (decimal)labelStyle.GetInterval()); 704 705 // This line is introduce because sometimes 0 value will appear as 706 // very small value close to zero. 707 double inter = Math.Log(labelStyle.GetInterval()); 708 double valu = Math.Log(Math.Abs(labValue)); 709 int digits = (int)Math.Abs(inter)+5; 710 711 if( digits > 15 ) 712 { 713 digits = 15; 714 } 715 716 if( Math.Abs(inter) < Math.Abs(valu)-5 ) 717 { 718 labValue = Math.Round(labValue,digits); 719 } 720 721 // Too many labels 722 if( ( viewMaximum - start ) / labelStyle.GetInterval() > ChartHelper.MaxNumOfGridlines ) 723 { 724 return; 725 } 726 727 // For IsLogarithmic axes 728 if( this.IsLogarithmic ) 729 labValue = Math.Pow( this.logarithmBase, labValue ); 730 731 beginPosition = (double)((decimal)position + (decimal)labelStyle.GetInterval() * 0.5m); 732 endPosition = (double)((decimal)position + (decimal)labelStyle.GetInterval() * 1.5m); 733 734 if( (decimal)beginPosition > (decimal)viewMaximum ) 735 { 736 continue; 737 } 738 739 // Show End label if Start Label position is used 740 // Use decimal type to solve rounding issues 741 if( (decimal)(( beginPosition + endPosition )/2.0) > (decimal)viewMaximum ) 742 { 743 continue; 744 } 745 746 string pointLabel = GetPointLabel( dataSeries, labValue, !seriesXValuesZeros, indexedSeries ); 747 if( pointLabel.Length > 15 && labValue < 0.000001) 748 { 749 labValue = 0.0; 750 } 751 752 if( pointLabel.Length == 0 ) 753 { 754 // Do not draw last label for indexed series 755 if( !(Common.DataManager.Series[ dataSeries[0] ].IsXValueIndexed && position > this.maximum) ) 756 { 757 // Add a label to the collection 758 CustomLabels.Add( beginPosition, 759 endPosition, 760 ValueConverter.FormatValue( 761 this.Common.Chart, 762 this, 763 null, 764 labValue, 765 this.LabelStyle.Format, 766 valueType, 767 ChartElementType.AxisLabels), 768 false); 769 } 770 } 771 else 772 { 773 // Add a label to the collection 774 CustomLabels.Add( beginPosition, 775 endPosition, 776 pointLabel, 777 false); 778 } 779 } 780 } 781 } 782 } 783 784 /// <summary> 785 /// This method checks if there is a data point which has value X equal 786 /// to valuePosition, and returns label from data point if such value exist. 787 /// If data point with this value not exists empty string will be returned. 788 /// If all data points have X value zero, index is used instead of X value. 789 /// </summary> 790 /// <param name="series">Data series</param> 791 /// <param name="valuePosition">A value which should be found in data points x values</param> 792 /// <param name="nonZeroXValues">Series X values are not zeros.</param> 793 /// <param name="indexedSeries">Series is indexed. All X values are zeros or IsXValueIndexed flag set.</param> 794 /// <returns>LabelStyle</returns> GetPointLabel( List<string> series, double valuePosition, bool nonZeroXValues, bool indexedSeries )795 private string GetPointLabel( 796 List<string> series, 797 double valuePosition, 798 bool nonZeroXValues, 799 bool indexedSeries 800 ) 801 { 802 // Get max number of data points in the series 803 int maxPointCount = 0; 804 foreach (string seriesName in series) 805 { 806 Series ser = Common.DataManager.Series[seriesName]; 807 maxPointCount = Math.Max(maxPointCount, ser.Points.Count); 808 } 809 810 // Check if axis only contains axis abels 811 bool allEmpty = true; 812 foreach( string seriesName in series ) 813 { 814 // Get series by name 815 Series ser = Common.DataManager.Series[ seriesName ]; 816 817 // Check if series has axis labels set 818 if ((axisType == AxisName.X || axisType == AxisName.X2) && (margin != 0 || maxPointCount == 1 || !this._autoMinimum) && !ser.IsXValueIndexed) 819 { 820 if( ser.Points[ 0 ].AxisLabel.Length > 0 && ser.Points[ ser.Points.Count - 1 ].AxisLabel.Length > 0 ) 821 { 822 allEmpty = false; 823 } 824 } 825 826 // Try getting label from the point 827 if(!ser.noLabelsInPoints || (nonZeroXValues && indexedSeries)) 828 { 829 string result = GetPointLabel( ser, valuePosition, nonZeroXValues, indexedSeries ); 830 if(!String.IsNullOrEmpty(result)) 831 { 832 return result; 833 } 834 } 835 836 // VSTS 140676: Serach for IndexedSeriesLabelsSourceAttr attribute 837 // to find if we have indexed series as source of formula generated nonindexed series. 838 String labelSeriesName = ser[DataFormula.IndexedSeriesLabelsSourceAttr]; 839 if (!String.IsNullOrEmpty(labelSeriesName)) 840 { 841 Series labelsSeries = Common.DataManager.Series[labelSeriesName]; 842 if (labelsSeries != null) 843 { 844 string result = GetPointLabel(labelsSeries, valuePosition, nonZeroXValues, true); 845 if (!String.IsNullOrEmpty(result)) 846 { 847 return result; 848 } 849 } 850 } 851 852 } 853 854 if( !allEmpty ) 855 { 856 return " "; 857 } 858 else 859 { 860 return ""; 861 } 862 } 863 864 /// <summary> 865 /// This method checks if there is a data point which has value X equal 866 /// to valuePosition, and returns label from data point if such value exist. 867 /// If data point with this value not exists empty string will be returned. 868 /// If all data points have X value zero, index is used instead of X value. 869 /// </summary> 870 /// <param name="series">Data series</param> 871 /// <param name="valuePosition">A value which should be found in data points x values</param> 872 /// <param name="nonZeroXValues">Series X values are not zeros.</param> 873 /// <param name="indexedSeries">Series is indexed. All X values are zeros or IsXValueIndexed flag set.</param> 874 /// <returns>LabelStyle</returns> GetPointLabel( Series series, double valuePosition, bool nonZeroXValues, bool indexedSeries)875 private string GetPointLabel( 876 Series series, 877 double valuePosition, 878 bool nonZeroXValues, 879 bool indexedSeries) 880 { 881 int pointIndx = 1; 882 883 if( axisType == AxisName.Y || axisType == AxisName.Y2 ) 884 { 885 return ""; 886 } 887 888 if( !(( axisType == AxisName.X && series.XAxisType == AxisType.Primary ) || ( axisType == AxisName.X2 && series.XAxisType == AxisType.Secondary )) ) 889 { 890 #if SUBAXES 891 if(series.XSubAxisName != ((Axis)this).SubAxisName) 892 { 893 return ""; 894 } 895 #endif // SUBAXES 896 return ""; 897 } 898 899 // Loop through all series data points 900 foreach( DataPoint point in series.Points ) 901 { 902 // If series is indexed (all X values are zeros or IsXValueIndexed flag set) 903 if( indexedSeries ) 904 { 905 // If axis label position matches point index 906 if( valuePosition == pointIndx ) 907 { 908 // Use X value if axis label is not set and X values in series are not zeros 909 if(point.AxisLabel.Length == 0 && nonZeroXValues) 910 { 911 return ValueConverter.FormatValue( 912 this.Common.Chart, 913 this, 914 null, 915 point.XValue, 916 this.LabelStyle.Format, 917 series.XValueType, 918 ChartElementType.AxisLabels); 919 } 920 921 // Return axis label from data point 922 return point.ReplaceKeywords(point.AxisLabel); 923 } 924 } 925 else 926 { 927 // Find x value using Data point X values 928 if( point.XValue == valuePosition ) 929 { 930 // Return label 931 return point.ReplaceKeywords(point.AxisLabel); 932 } 933 } 934 pointIndx++; 935 } 936 return ""; 937 } 938 939 #endregion 940 } 941 } 942