1 //------------------------------------------------------------- 2 // <copyright company=�Microsoft Corporation�> 3 // Copyright � Microsoft Corporation. All Rights Reserved. 4 // </copyright> 5 //------------------------------------------------------------- 6 // @owner=alexgor, deliant 7 //================================================================= 8 // File: Chart.cs 9 // 10 // Namespace: System.Web.UI.WebControls[Windows.Forms].Charting 11 // 12 // Classes: ChartImage, ChartPicture, ChartPaintEventArgs 13 // 14 // Purpose: This file contains classes, which are used for Image 15 // creation and chart painting. This file has also a 16 // class, which is used for Paint events arguments. 17 // 18 // Reviewed: GS - August 2, 2002 19 // AG - August 8, 2002 20 // AG - Microsoft 16, 2007 21 // 22 //=================================================================== 23 24 #region Used Namespaces 25 26 using System; 27 using System.Drawing; 28 using System.Drawing.Drawing2D; 29 using System.Drawing.Design; 30 using System.ComponentModel; 31 using System.ComponentModel.Design; 32 using System.Resources; 33 using System.Reflection; 34 using System.IO; 35 using System.Data; 36 using System.Collections; 37 using System.Drawing.Imaging; 38 using System.Drawing.Text; 39 using System.Xml; 40 using System.Globalization; 41 using System.Diagnostics.CodeAnalysis; 42 using System.Diagnostics; 43 using System.Security; 44 using System.Runtime.InteropServices; 45 using System.Collections.Generic; 46 47 #if Microsoft_CONTROL 48 49 using System.Windows.Forms.DataVisualization.Charting.Data; 50 using System.Windows.Forms.DataVisualization.Charting.ChartTypes; 51 using System.Windows.Forms.DataVisualization.Charting.Utilities; 52 using System.Windows.Forms.DataVisualization.Charting.Borders3D; 53 using System.Windows.Forms.DataVisualization.Charting; 54 #else 55 using System.Web; 56 using System.Web.UI; 57 using System.Net; 58 using System.Web.UI.DataVisualization.Charting; 59 using System.Web.UI.DataVisualization.Charting.Data; 60 using System.Web.UI.DataVisualization.Charting.ChartTypes; 61 using System.Web.UI.DataVisualization.Charting.Utilities; 62 using System.Web.UI.DataVisualization.Charting.Borders3D; 63 #endif 64 65 66 #endregion 67 68 #if Microsoft_CONTROL 69 namespace System.Windows.Forms.DataVisualization.Charting 70 #else 71 namespace System.Web.UI.DataVisualization.Charting 72 73 #endif 74 { 75 #region Enumerations 76 77 #if !Microsoft_CONTROL 78 79 /// <summary> 80 /// An enumeration of supported image types 81 /// </summary> 82 public enum ChartImageType 83 { 84 /// <summary> 85 /// BMP image format 86 /// </summary> 87 Bmp, 88 /// <summary> 89 /// Jpeg image format 90 /// </summary> 91 Jpeg, 92 93 /// <summary> 94 /// Png image format 95 /// </summary> 96 [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Png")] 97 Png, 98 99 /// <summary> 100 /// Enhanced Meta File (Emf) image format. 101 /// </summary> 102 Emf, 103 104 }; 105 #endif 106 107 108 #endregion 109 110 /// <summary> 111 /// ChartImage class adds image type and data binding functionality to 112 /// the base ChartPicture class. 113 /// </summary> 114 internal class ChartImage : ChartPicture 115 { 116 #region Fields 117 118 // Private data members, which store properties values 119 private int _compression = 0; 120 121 // Chart data source object 122 private object _dataSource = null; 123 124 // Indicates that control was bound to the data source 125 internal bool boundToDataSource = false; 126 127 #if !Microsoft_CONTROL 128 private ChartImageType imageType = ChartImageType.Png; 129 #endif 130 131 #endregion 132 133 #region Constructor 134 135 /// <summary> 136 /// Chart internal constructor. 137 /// </summary> 138 /// <param name="container">Service container</param> ChartImage(IServiceContainer container)139 internal ChartImage(IServiceContainer container) 140 : base(container) 141 { 142 } 143 144 #endregion // Constructor 145 146 #region Properties 147 148 /// <summary> 149 /// Gets or sets the data source for the Chart object. 150 /// </summary> 151 [ 152 SRCategory("CategoryAttributeData"), 153 Bindable(true), 154 SRDescription("DescriptionAttributeDataSource"), 155 DefaultValue(null), 156 DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), 157 SerializationVisibilityAttribute(SerializationVisibility.Hidden) 158 ] 159 public object DataSource 160 { 161 get 162 { 163 return _dataSource; 164 } 165 set 166 { 167 if(_dataSource != value) 168 { 169 _dataSource = value; 170 this.boundToDataSource = false; 171 } 172 } 173 } 174 175 #if !Microsoft_CONTROL 176 177 /// <summary> 178 /// Image type (Jpeg, BMP, Png) 179 /// </summary> 180 [ 181 SRCategory("CategoryAttributeImage"), 182 Bindable(true), 183 DefaultValue(ChartImageType.Png), 184 SRDescription("DescriptionAttributeImageType"), 185 PersistenceMode(PersistenceMode.Attribute) 186 ] 187 public ChartImageType ImageType 188 { 189 get 190 { 191 return imageType; 192 } 193 set 194 { 195 imageType = value; 196 } 197 } 198 199 #endif 200 201 /// <summary> 202 /// Image compression value 203 /// </summary> 204 [ 205 SRCategory("CategoryAttributeImage"), 206 Bindable(true), 207 DefaultValue(0), 208 SRDescription("DescriptionAttributeChartImage_Compression"), 209 #if !Microsoft_CONTROL 210 PersistenceMode(PersistenceMode.Attribute) 211 #endif 212 ] 213 public int Compression 214 { 215 get 216 { 217 return _compression; 218 } 219 set 220 { 221 if(value < 0 || value > 100) 222 { 223 throw (new ArgumentOutOfRangeException("value", SR.ExceptionChartCompressionInvalid)); 224 } 225 _compression = value; 226 } 227 } 228 229 #endregion 230 231 #region Methods 232 233 #region Image Manipulation 234 235 236 /// <summary> 237 /// Saves image into the metafile stream. 238 /// </summary> 239 /// <param name="imageStream">Image stream.</param> 240 /// <param name="emfType">Image stream.</param> 241 [SecuritySafeCritical] SaveIntoMetafile(Stream imageStream, EmfType emfType)242 public void SaveIntoMetafile(Stream imageStream, EmfType emfType) 243 { 244 // Check arguments 245 if (imageStream == null) 246 throw new ArgumentNullException("imageStream"); 247 248 // Create temporary Graphics object for metafile 249 using (Bitmap bitmap = new Bitmap(this.Width, this.Height)) 250 { 251 using (Graphics newGraphics = Graphics.FromImage(bitmap)) 252 { 253 IntPtr hdc = IntPtr.Zero; 254 try 255 { 256 System.Security.Permissions.SecurityPermission securityPermission = new System.Security.Permissions.SecurityPermission(System.Security.Permissions.SecurityPermissionFlag.UnmanagedCode); 257 securityPermission.Demand(); 258 259 hdc = newGraphics.GetHdc(); 260 261 262 // Create metafile object to record. 263 using (Metafile metaFile = new Metafile( 264 imageStream, 265 hdc, 266 new Rectangle(0, 0, this.Width, this.Height), 267 MetafileFrameUnit.Pixel, 268 emfType)) 269 { 270 271 // Create graphics object to record metaFile. 272 using (Graphics metaGraphics = Graphics.FromImage(metaFile)) 273 { 274 275 // Note: Fix for issue #3674. Some 3D borders shadows may be drawn outside 276 // of image boundaries. This causes issues when generated EMF file 277 // is placed in IE. Image looks shifted down and hot areas do not align. 278 if (this.BorderSkin.SkinStyle != BorderSkinStyle.None) 279 { 280 metaGraphics.Clip = new Region(new Rectangle(0, 0, this.Width, this.Height)); 281 } 282 283 // Draw chart in the metafile 284 this.ChartGraph.IsMetafile = true; 285 this.Paint(metaGraphics, false); 286 this.ChartGraph.IsMetafile = false; 287 288 } 289 } 290 } 291 finally 292 { 293 if (hdc != IntPtr.Zero) 294 { 295 newGraphics.ReleaseHdc(hdc); 296 } 297 } 298 } 299 } 300 } 301 GetImage()302 public Bitmap GetImage() 303 { 304 return this.GetImage(96); 305 } 306 /// <summary> 307 /// Create Image and draw chart picture 308 /// </summary> GetImage(float resolution)309 public Bitmap GetImage(float resolution) 310 { 311 // Create a new bitmap 312 313 Bitmap image = null; 314 315 while (image == null) 316 { 317 bool failed = true; 318 try 319 { 320 image = new Bitmap(Math.Max(1,Width), Math.Max(1,Height)); 321 image.SetResolution(resolution, resolution); 322 failed = false; 323 } 324 catch (ArgumentException) 325 { 326 failed = true; 327 } 328 catch (OverflowException) 329 { 330 failed = true; 331 } 332 catch (InvalidOperationException) 333 { 334 failed = true; 335 } 336 catch (ExternalException) 337 { 338 failed = true; 339 } 340 341 if (failed) 342 { 343 // if failed to create the image, decrease the size and the resolution of the chart 344 image = null; 345 float newResolution = Math.Max(resolution / 2, 96); 346 Width = (int)Math.Ceiling(Width * newResolution / resolution); 347 Height = (int)Math.Ceiling(Height * newResolution / resolution); 348 resolution = newResolution; 349 } 350 } 351 352 // Creates a new Graphics object from the 353 // specified Image object. 354 Graphics offScreen = Graphics.FromImage( image ); 355 356 357 358 Color backGroundColor; 359 360 if (this.BackColor != Color.Empty) 361 backGroundColor = this.BackColor; 362 else 363 backGroundColor = Color.White; 364 365 // Get the page color if border skin is visible. 366 if (GetBorderSkinVisibility() && 367 this.BorderSkin.PageColor != Color.Empty) 368 { 369 backGroundColor = this.BorderSkin.PageColor; 370 } 371 372 // draw a rctangle first with the size of the control, this prevent strange behavior when printing in the reporting services, 373 // without this rectangle, the printed picture is blurry 374 Pen pen = new Pen(backGroundColor); 375 offScreen.DrawRectangle(pen, 0, 0, Width, Height); 376 pen.Dispose(); 377 378 // Paint the chart 379 Paint( offScreen , false); 380 381 // Dispose Graphic object 382 offScreen.Dispose(); 383 384 // Return reference to the image 385 return image; 386 } 387 388 #endregion // Image Manipulation 389 390 #region Data Binding 391 392 /// <summary> 393 /// Checks if the type of the data source is valid. 394 /// </summary> 395 /// <param name="dataSource">Data source object to test.</param> 396 /// <returns>True if valid data source object.</returns> IsValidDataSource(object dataSource)397 static internal bool IsValidDataSource(object dataSource) 398 { 399 if( null != dataSource && 400 ( 401 dataSource is IEnumerable || 402 dataSource is DataSet || 403 dataSource is DataView || 404 dataSource is DataTable || 405 dataSource is System.Data.OleDb.OleDbCommand || 406 dataSource is System.Data.SqlClient.SqlCommand || 407 dataSource is System.Data.OleDb.OleDbDataAdapter || 408 dataSource is System.Data.SqlClient.SqlDataAdapter || 409 // ADDED: for VS2005 compatibility, DT Nov 25, 2005 410 dataSource.GetType().GetInterface("IDataSource") != null 411 // END ADDED 412 ) 413 ) 414 { 415 return true; 416 } 417 418 return false; 419 } 420 421 422 423 /// <summary> 424 /// Gets an list of the data source member names. 425 /// </summary> 426 /// <param name="dataSource">Data source object to get the members for.</param> 427 /// <param name="usedForYValue">Indicates that member will be used for Y values.</param> 428 /// <returns>List of member names.</returns> 429 [SuppressMessage("Microsoft.Performance", "CA1800:DoNotCastUnnecessarily", 430 Justification = "Too large of a code change to justify making this change")] GetDataSourceMemberNames(object dataSource, bool usedForYValue)431 static internal ArrayList GetDataSourceMemberNames(object dataSource, bool usedForYValue) 432 { 433 ArrayList names = new ArrayList(); 434 if (dataSource != null) 435 { 436 // ADDED: for VS2005 compatibility, DT Nov 25, 2004 437 if (dataSource.GetType().GetInterface("IDataSource") != null) 438 { 439 try 440 { 441 MethodInfo m = dataSource.GetType().GetMethod("Select"); 442 if (m != null) 443 { 444 if (m.GetParameters().Length == 1) 445 { 446 // SQL derived datasource 447 Type selectArgsType = dataSource.GetType().Assembly.GetType("System.Web.UI.DataSourceSelectArguments", true); 448 ConstructorInfo ci = selectArgsType.GetConstructor(new Type[] { }); 449 dataSource = m.Invoke(dataSource, new object[] { ci.Invoke(new object[] { }) }); 450 } 451 else 452 { 453 // object data source 454 dataSource = m.Invoke(dataSource, new object[] { }); 455 } 456 } 457 } 458 catch (TargetException) 459 { 460 } 461 catch (TargetInvocationException) 462 { 463 } 464 } 465 // END ADDED 466 467 // Check all DataTable based data souces 468 DataTable dataTable = null; 469 470 if (dataSource is DataTable) 471 { 472 dataTable = (DataTable)dataSource; 473 } 474 else if (dataSource is DataView) 475 { 476 dataTable = ((DataView)dataSource).Table; 477 } 478 else if (dataSource is DataSet && ((DataSet)dataSource).Tables.Count > 0) 479 { 480 dataTable = ((DataSet)dataSource).Tables[0]; 481 } 482 else if (dataSource is System.Data.OleDb.OleDbDataAdapter) 483 { 484 dataTable = new DataTable(); 485 dataTable.Locale = CultureInfo.CurrentCulture; 486 dataTable = ((System.Data.OleDb.OleDbDataAdapter)dataSource).FillSchema(dataTable, SchemaType.Mapped); 487 } 488 else if (dataSource is System.Data.SqlClient.SqlDataAdapter) 489 { 490 dataTable = new DataTable(); 491 dataTable.Locale = CultureInfo.CurrentCulture; 492 dataTable = ((System.Data.SqlClient.SqlDataAdapter)dataSource).FillSchema(dataTable, SchemaType.Mapped); 493 } 494 else if (dataSource is System.Data.OleDb.OleDbDataReader) 495 { 496 // Add table columns names 497 for (int fieldIndex = 0; fieldIndex < ((System.Data.OleDb.OleDbDataReader)dataSource).FieldCount; fieldIndex++) 498 { 499 if (!usedForYValue || ((System.Data.OleDb.OleDbDataReader)dataSource).GetFieldType(fieldIndex) != typeof(string)) 500 { 501 names.Add(((System.Data.OleDb.OleDbDataReader)dataSource).GetName(fieldIndex)); 502 } 503 } 504 } 505 else if (dataSource is System.Data.SqlClient.SqlDataReader) 506 { 507 // Add table columns names 508 for (int fieldIndex = 0; fieldIndex < ((System.Data.SqlClient.SqlDataReader)dataSource).FieldCount; fieldIndex++) 509 { 510 if (!usedForYValue || ((System.Data.SqlClient.SqlDataReader)dataSource).GetFieldType(fieldIndex) != typeof(string)) 511 { 512 names.Add(((System.Data.SqlClient.SqlDataReader)dataSource).GetName(fieldIndex)); 513 } 514 } 515 } 516 else if (dataSource is System.Data.OleDb.OleDbCommand) 517 { 518 System.Data.OleDb.OleDbCommand command = (System.Data.OleDb.OleDbCommand)dataSource; 519 if (command.Connection != null) 520 { 521 command.Connection.Open(); 522 System.Data.OleDb.OleDbDataReader dataReader = command.ExecuteReader(); 523 if (dataReader.Read()) 524 { 525 for (int fieldIndex = 0; fieldIndex < dataReader.FieldCount; fieldIndex++) 526 { 527 if (!usedForYValue || dataReader.GetFieldType(fieldIndex) != typeof(string)) 528 { 529 names.Add(dataReader.GetName(fieldIndex)); 530 } 531 } 532 } 533 534 dataReader.Close(); 535 command.Connection.Close(); 536 } 537 } 538 else if (dataSource is System.Data.SqlClient.SqlCommand) 539 { 540 System.Data.SqlClient.SqlCommand command = (System.Data.SqlClient.SqlCommand)dataSource; 541 if (command.Connection != null) 542 { 543 command.Connection.Open(); 544 System.Data.SqlClient.SqlDataReader dataReader = command.ExecuteReader(); 545 if (dataReader.Read()) 546 { 547 for (int fieldIndex = 0; fieldIndex < dataReader.FieldCount; fieldIndex++) 548 { 549 if (!usedForYValue || dataReader.GetFieldType(fieldIndex) != typeof(string)) 550 { 551 names.Add(dataReader.GetName(fieldIndex)); 552 } 553 } 554 } 555 556 dataReader.Close(); 557 command.Connection.Close(); 558 } 559 } 560 561 562 // Check if DataTable was set 563 if (dataTable != null) 564 { 565 // Add table columns names 566 foreach (DataColumn column in dataTable.Columns) 567 { 568 if (!usedForYValue || column.DataType != typeof(string)) 569 { 570 names.Add(column.ColumnName); 571 } 572 } 573 } 574 575 else if (names.Count == 0 && dataSource is ITypedList) 576 { 577 foreach (PropertyDescriptor pd in ((ITypedList)dataSource).GetItemProperties(null)) 578 { 579 if (!usedForYValue || pd.PropertyType != typeof(string)) 580 { 581 names.Add(pd.Name); 582 } 583 } 584 } 585 else if (names.Count == 0 && dataSource is IEnumerable) 586 { 587 // .Net 2.0 ObjectDataSource processing 588 IEnumerator e = ((IEnumerable)dataSource).GetEnumerator(); 589 e.Reset(); 590 e.MoveNext(); 591 foreach (PropertyDescriptor pd in TypeDescriptor.GetProperties(e.Current)) 592 { 593 if (!usedForYValue || pd.PropertyType != typeof(string)) 594 { 595 names.Add(pd.Name); 596 } 597 598 } 599 } 600 601 602 603 // Check if list still empty 604 if (names.Count == 0) 605 { 606 // Add first column or any data member name 607 names.Add("0"); 608 } 609 610 } 611 612 return names; 613 } 614 615 /// <summary> 616 /// Data binds control to the data source 617 /// </summary> 618 [SuppressMessage("Microsoft.Performance", "CA1800:DoNotCastUnnecessarily", 619 Justification="Too large of a code change to justify making this change")] DataBind()620 internal void DataBind() 621 { 622 // Set bound flag 623 this.boundToDataSource = true; 624 625 object dataSource = this.DataSource; 626 if (dataSource != null) 627 { 628 629 // Convert data adapters to command object 630 if (dataSource is System.Data.OleDb.OleDbDataAdapter) 631 { 632 dataSource = ((System.Data.OleDb.OleDbDataAdapter)dataSource).SelectCommand; 633 } 634 else if (dataSource is System.Data.SqlClient.SqlDataAdapter) 635 { 636 dataSource = ((System.Data.SqlClient.SqlDataAdapter)dataSource).SelectCommand; 637 } 638 639 // Convert data source to recognizable source for the series 640 if (dataSource is DataSet && ((DataSet)dataSource).Tables.Count > 0) 641 { 642 dataSource = ((DataSet)dataSource).DefaultViewManager.CreateDataView(((DataSet)dataSource).Tables[0]); 643 644 } 645 else if (dataSource is DataTable) 646 { 647 dataSource = new DataView((DataTable)dataSource); 648 } 649 else if (dataSource is System.Data.OleDb.OleDbCommand) 650 { 651 System.Data.OleDb.OleDbCommand command = (System.Data.OleDb.OleDbCommand)dataSource; 652 command.Connection.Open(); 653 System.Data.OleDb.OleDbDataReader dataReader = command.ExecuteReader(); 654 655 this.DataBind(dataReader, null); 656 657 dataReader.Close(); 658 command.Connection.Close(); 659 return; 660 } 661 else if (dataSource is System.Data.SqlClient.SqlCommand) 662 { 663 System.Data.SqlClient.SqlCommand command = (System.Data.SqlClient.SqlCommand)dataSource; 664 command.Connection.Open(); 665 System.Data.SqlClient.SqlDataReader dataReader = command.ExecuteReader(); 666 667 this.DataBind(dataReader, null); 668 669 dataReader.Close(); 670 command.Connection.Close(); 671 return; 672 } 673 else if (dataSource is IList) 674 { 675 dataSource = dataSource as IList; 676 } 677 else if (dataSource is IListSource ) 678 { 679 if (((IListSource)dataSource).ContainsListCollection && ((IListSource)dataSource).GetList().Count > 0) 680 { 681 dataSource = ((IListSource)dataSource).GetList()[0] as IEnumerable; 682 } 683 else 684 { 685 dataSource = ((IListSource)dataSource).GetList(); 686 } 687 } 688 else 689 { 690 dataSource = dataSource as IEnumerable; 691 } 692 693 // Data bind 694 DataBind(dataSource as IEnumerable, null); 695 } 696 } 697 698 /// <summary> 699 /// Data binds control to the data source 700 /// </summary> 701 /// <param name="dataSource">Data source to bind to.</param> 702 /// <param name="seriesList">List of series to bind.</param> DataBind(IEnumerable dataSource, ArrayList seriesList)703 internal void DataBind(IEnumerable dataSource, ArrayList seriesList) 704 { 705 // Data bind series 706 if(dataSource != null && this.Common != null) 707 { 708 //************************************************************ 709 //** If list of series is not provided - bind all of them. 710 //************************************************************ 711 if(seriesList == null) 712 { 713 seriesList = new ArrayList(); 714 foreach(Series series in this.Common.Chart.Series) 715 { 716 // note: added for design time data binding 717 if (this.Common.Chart.IsDesignMode()) 718 { 719 if (series.YValueMembers.Length > 0) 720 { 721 seriesList.Add(series); 722 } 723 } 724 else 725 { 726 seriesList.Add(series); 727 } 728 } 729 } 730 731 //************************************************************ 732 //** Clear all data points in data bound series 733 //************************************************************ 734 foreach(Series series in seriesList) 735 { 736 if(series.XValueMember.Length > 0 || series.YValueMembers.Length > 0) 737 { 738 series.Points.Clear(); 739 } 740 } 741 742 //************************************************************ 743 //** Get and reset data enumerator. 744 //************************************************************ 745 IEnumerator enumerator = dataSource.GetEnumerator(); 746 if(enumerator.GetType() != typeof(System.Data.Common.DbEnumerator) ) 747 { 748 try 749 { 750 enumerator.Reset(); 751 } 752 // Some enumerators may not support Resetting 753 catch (InvalidOperationException) 754 { 755 } 756 catch (NotImplementedException) 757 { 758 } 759 catch (NotSupportedException) 760 { 761 } 762 } 763 764 765 //************************************************************ 766 //** Loop through the enumerator. 767 //************************************************************ 768 bool valueExsists = true; 769 bool autoDetectType = true; 770 do 771 { 772 // Move to the next item 773 valueExsists = enumerator.MoveNext(); 774 775 // Loop through all series 776 foreach(Series series in seriesList) 777 { 778 if(series.XValueMember.Length > 0 || series.YValueMembers.Length > 0) 779 { 780 //************************************************************ 781 //** Check and convert fields names. 782 //************************************************************ 783 784 // Convert comma separated field names string to array of names 785 string[] yFieldNames = null; 786 if(series.YValueMembers.Length > 0) 787 { 788 yFieldNames = series.YValueMembers.Replace(",,", "\n").Split(','); 789 for(int index = 0; index < yFieldNames.Length; index++) 790 { 791 yFieldNames[index] = yFieldNames[index].Replace("\n", ",").Trim(); 792 } 793 } 794 795 // Double check that a string object is not provided for data binding 796 if(dataSource is string) 797 { 798 throw (new ArgumentException(SR.ExceptionDataBindYValuesToString, "dataSource")); 799 } 800 801 // Check number of fields 802 if(yFieldNames == null || yFieldNames.GetLength(0) > series.YValuesPerPoint) 803 { 804 throw(new ArgumentOutOfRangeException("dataSource", SR.ExceptionDataPointYValuesCountMismatch(series.YValuesPerPoint.ToString(System.Globalization.CultureInfo.InvariantCulture) ) ) ); 805 } 806 807 //************************************************************ 808 //** Create new data point. 809 //************************************************************ 810 if(valueExsists) 811 { 812 // Auto detect values type 813 if(autoDetectType) 814 { 815 autoDetectType = false; 816 817 // Make sure Y field is not empty 818 string yField = yFieldNames[0]; 819 int fieldIndex = 1; 820 while(yField.Length == 0 && fieldIndex < yFieldNames.Length) 821 { 822 yField = yFieldNames[fieldIndex++]; 823 } 824 825 DataPointCollection.AutoDetectValuesType(series, enumerator, series.XValueMember.Trim(), enumerator, yField); 826 } 827 828 829 // Create new point 830 DataPoint newDataPoint = new DataPoint(series); 831 bool emptyValues = false; 832 bool xValueIsNull = false; 833 834 //************************************************************ 835 //** Get new point X and Y values. 836 //************************************************************ 837 object[] yValuesObj = new object[yFieldNames.Length]; 838 object xValueObj = null; 839 840 // Set X to the value provided or use sequence numbers starting with 1 841 if(series.XValueMember.Length > 0) 842 { 843 xValueObj = DataPointCollection.ConvertEnumerationItem(enumerator.Current, series.XValueMember.Trim()); 844 if(xValueObj is System.DBNull || xValueObj == null) 845 { 846 xValueIsNull = true; 847 emptyValues = true; 848 xValueObj = 0.0; 849 } 850 } 851 852 if(yFieldNames.Length == 0) 853 { 854 yValuesObj[0] = DataPointCollection.ConvertEnumerationItem(enumerator.Current, null); 855 if(yValuesObj[0] is System.DBNull || yValuesObj[0] == null) 856 { 857 emptyValues = true; 858 yValuesObj[0] = 0.0; 859 } 860 } 861 else 862 { 863 for(int i = 0; i < yFieldNames.Length; i++) 864 { 865 if(yFieldNames[i].Length > 0) 866 { 867 yValuesObj[i] = DataPointCollection.ConvertEnumerationItem(enumerator.Current, yFieldNames[i]); 868 if(yValuesObj[i] is System.DBNull || yValuesObj[i] == null) 869 { 870 emptyValues = true; 871 yValuesObj[i] = 0.0; 872 } 873 } 874 else 875 { 876 yValuesObj[i] = (((Series)seriesList[0]).IsYValueDateTime()) ? DateTime.Now.Date.ToOADate() : 0.0; 877 } 878 } 879 } 880 881 882 // Add data point if X value is not Null 883 if(!xValueIsNull) 884 { 885 if(emptyValues) 886 { 887 if(xValueObj != null) 888 { 889 newDataPoint.SetValueXY(xValueObj, yValuesObj); 890 } 891 else 892 { 893 newDataPoint.SetValueXY(0, yValuesObj); 894 } 895 series.Points.DataPointInit(ref newDataPoint); 896 newDataPoint.IsEmpty = true; 897 series.Points.Add(newDataPoint); 898 } 899 else 900 { 901 if(xValueObj != null) 902 { 903 newDataPoint.SetValueXY(xValueObj, yValuesObj); 904 } 905 else 906 { 907 newDataPoint.SetValueXY(0, yValuesObj); 908 } 909 series.Points.DataPointInit(ref newDataPoint); 910 series.Points.Add(newDataPoint); 911 } 912 } 913 if (this.Common.Chart.IsDesignMode()) 914 { 915 series["TempDesignData"] = "true"; 916 } 917 } 918 } 919 } 920 921 } while(valueExsists); 922 923 } 924 } 925 926 927 /// <summary> 928 /// Aligns data points using their axis labels. 929 /// </summary> 930 /// <param name="sortAxisLabels">Indicates if points should be sorted by axis labels.</param> 931 /// <param name="sortingOrder">Sorting pointSortOrder.</param> AlignDataPointsByAxisLabel(bool sortAxisLabels, PointSortOrder sortingOrder)932 internal void AlignDataPointsByAxisLabel(bool sortAxisLabels, PointSortOrder sortingOrder) 933 { 934 // Find series which are attached to the same X axis in the same chart area 935 foreach(ChartArea chartArea in this.ChartAreas) 936 { 937 938 // Check if chart area is visible 939 if(chartArea.Visible) 940 941 { 942 // Create series list for primary and secondary X axis 943 ArrayList chartAreaSeriesPrimary = new ArrayList(); 944 ArrayList chartAreaSeriesSecondary = new ArrayList(); 945 foreach(Series series in this.Common.Chart.Series) 946 { 947 // Check if series belongs to the chart area 948 if (series.ChartArea == chartArea.Name) 949 { 950 if(series.XSubAxisName.Length == 0) 951 { 952 if(series.XAxisType == AxisType.Primary) 953 { 954 chartAreaSeriesPrimary.Add(series); 955 } 956 else 957 { 958 chartAreaSeriesSecondary.Add(series); 959 } 960 } 961 } 962 } 963 964 // Align series 965 AlignDataPointsByAxisLabel(chartAreaSeriesPrimary, sortAxisLabels, sortingOrder); 966 AlignDataPointsByAxisLabel(chartAreaSeriesSecondary, sortAxisLabels, sortingOrder); 967 } 968 } 969 } 970 971 /// <summary> 972 /// Aligns data points using their axis labels. 973 /// </summary> 974 /// <param name="seriesList">List of series to align.</param> 975 /// <param name="sortAxisLabels">Indicates if points should be sorted by axis labels.</param> 976 /// <param name="sortingOrder">Sorting order.</param> AlignDataPointsByAxisLabel( ArrayList seriesList, bool sortAxisLabels, PointSortOrder sortingOrder)977 internal void AlignDataPointsByAxisLabel( 978 ArrayList seriesList, 979 bool sortAxisLabels, 980 PointSortOrder sortingOrder) 981 { 982 // List is empty 983 if(seriesList.Count == 0) 984 { 985 return; 986 } 987 988 // Collect information about all points in all series 989 bool indexedX = true; 990 bool uniqueAxisLabels = true; 991 ArrayList axisLabels = new ArrayList(); 992 foreach(Series series in seriesList) 993 { 994 ArrayList seriesAxisLabels = new ArrayList(); 995 foreach(DataPoint point in series.Points) 996 { 997 // Check if series has indexed X values 998 if(!series.IsXValueIndexed && point.XValue != 0.0) 999 { 1000 indexedX = false; 1001 break; 1002 } 1003 1004 // Add axis label to the list and make sure it's non-empty and unique 1005 if(point.AxisLabel.Length == 0) 1006 { 1007 uniqueAxisLabels = false; 1008 break; 1009 } 1010 else if(seriesAxisLabels.Contains(point.AxisLabel)) 1011 { 1012 uniqueAxisLabels = false; 1013 break; 1014 } 1015 else if(!axisLabels.Contains(point.AxisLabel)) 1016 { 1017 axisLabels.Add(point.AxisLabel); 1018 } 1019 1020 seriesAxisLabels.Add(point.AxisLabel); 1021 } 1022 } 1023 1024 // Sort axis labels 1025 if(sortAxisLabels) 1026 { 1027 axisLabels.Sort(); 1028 if(sortingOrder == PointSortOrder.Descending) 1029 { 1030 axisLabels.Reverse(); 1031 } 1032 } 1033 1034 // All series must be indexed 1035 if(!indexedX) 1036 { 1037 throw (new InvalidOperationException(SR.ExceptionChartDataPointsAlignmentFaild)); 1038 } 1039 1040 // AxisLabel can't be empty or duplicated 1041 if(!uniqueAxisLabels) 1042 { 1043 throw (new InvalidOperationException(SR.ExceptionChartDataPointsAlignmentFaildAxisLabelsInvalid)); 1044 } 1045 1046 // Assign unique X values for data points in all series with same axis LabelStyle 1047 if(indexedX && uniqueAxisLabels) 1048 { 1049 foreach(Series series in seriesList) 1050 { 1051 foreach(DataPoint point in series.Points) 1052 { 1053 point.XValue = axisLabels.IndexOf(point.AxisLabel) + 1; 1054 } 1055 1056 // Sort points by X value 1057 series.Sort(PointSortOrder.Ascending, "X"); 1058 } 1059 1060 // Make sure ther are no missing points 1061 foreach(Series series in seriesList) 1062 { 1063 series.IsXValueIndexed = true; 1064 for(int index = 0; index < axisLabels.Count; index++) 1065 { 1066 if(index >= series.Points.Count || 1067 series.Points[index].XValue != index + 1) 1068 { 1069 DataPoint newPoint = new DataPoint(series); 1070 newPoint.AxisLabel = (string)axisLabels[index]; 1071 newPoint.XValue = index + 1; 1072 newPoint.YValues[0] = 0.0; 1073 newPoint.IsEmpty = true; 1074 series.Points.Insert(index, newPoint); 1075 } 1076 } 1077 } 1078 1079 } 1080 1081 } 1082 1083 /// <summary> 1084 /// Data bind chart to the table. Series will be automatically added to the chart depending on 1085 /// the number of unique values in the seriesGroupByField column of the data source. 1086 /// Data source can be the Ole(SQL)DataReader, DataView, DataSet, DataTable or DataRow. 1087 /// </summary> 1088 /// <param name="dataSource">Data source.</param> 1089 /// <param name="seriesGroupByField">Name of the field used to group data into series.</param> 1090 /// <param name="xField">Name of the field for X values.</param> 1091 /// <param name="yFields">Comma separated name(s) of the field(s) for Y value(s).</param> 1092 /// <param name="otherFields">Other point properties binding rule in format: PointProperty=Field[{Format}] [,PointProperty=Field[{Format}]]. For example: "Tooltip=Price{C1},Url=WebSiteName".</param> 1093 /// <param name="sort">Indicates that series should be sorted by group field.</param> 1094 /// <param name="sortingOrder">Series sorting order by group field.</param> DataBindCrossTab( IEnumerable dataSource, string seriesGroupByField, string xField, string yFields, string otherFields, bool sort, PointSortOrder sortingOrder)1095 internal void DataBindCrossTab( 1096 IEnumerable dataSource, 1097 string seriesGroupByField, 1098 string xField, 1099 string yFields, 1100 string otherFields, 1101 bool sort, 1102 PointSortOrder sortingOrder) 1103 { 1104 // Check arguments 1105 if (dataSource == null) 1106 throw (new ArgumentNullException("dataSource", SR.ExceptionDataPointInsertionNoDataSource)); 1107 1108 if (dataSource is string) 1109 throw (new ArgumentException(SR.ExceptionDataBindSeriesToString, "dataSource")); 1110 1111 if (String.IsNullOrEmpty(yFields)) 1112 throw (new ArgumentException(SR.ExceptionChartDataPointsInsertionFailedYValuesEmpty, "yFields")); 1113 1114 if (String.IsNullOrEmpty(seriesGroupByField)) 1115 throw (new ArgumentException(SR.ExceptionDataBindSeriesGroupByParameterIsEmpty, "seriesGroupByField")); 1116 1117 1118 // List of series and group by field values 1119 ArrayList seriesList = new ArrayList(); 1120 ArrayList groupByValueList = new ArrayList(); 1121 1122 // Convert comma separated Y values field names string to array of names 1123 string[] yFieldNames = null; 1124 if(yFields != null) 1125 { 1126 yFieldNames = yFields.Replace(",,", "\n").Split(','); 1127 for(int index = 0; index < yFieldNames.Length; index++) 1128 { 1129 yFieldNames[index] = yFieldNames[index].Replace("\n", ","); 1130 } 1131 } 1132 1133 // Convert other fields/properties names to two arrays of names 1134 string[] otherAttributeNames = null; 1135 string[] otherFieldNames = null; 1136 string[] otherValueFormat = null; 1137 DataPointCollection.ParsePointFieldsParameter( 1138 otherFields, 1139 ref otherAttributeNames, 1140 ref otherFieldNames, 1141 ref otherValueFormat); 1142 1143 1144 // Get and reset enumerator 1145 IEnumerator enumerator = DataPointCollection.GetDataSourceEnumerator(dataSource); 1146 if(enumerator.GetType() != typeof(System.Data.Common.DbEnumerator)) 1147 { 1148 try 1149 { 1150 enumerator.Reset(); 1151 } 1152 // Some enumerators may not support Resetting 1153 catch (NotSupportedException) 1154 { 1155 } 1156 catch (NotImplementedException) 1157 { 1158 } 1159 catch (InvalidOperationException) 1160 { 1161 } 1162 1163 } 1164 1165 // Add data points 1166 bool valueExsist = true; 1167 object[] yValuesObj = new object[yFieldNames.Length]; 1168 object xValueObj = null; 1169 bool autoDetectType = true; 1170 1171 do 1172 { 1173 // Move to the next objects in the enumerations 1174 if(valueExsist) 1175 { 1176 valueExsist = enumerator.MoveNext(); 1177 } 1178 1179 // Create and initialize data point 1180 if(valueExsist) 1181 { 1182 // Get value of the group by field 1183 object groupObj = DataPointCollection.ConvertEnumerationItem( 1184 enumerator.Current, 1185 seriesGroupByField); 1186 1187 // Check series group by field and create new series if required 1188 Series series = null; 1189 int seriesIndex = groupByValueList.IndexOf(groupObj); 1190 if(seriesIndex >= 0) 1191 { 1192 // Select existing series from the list 1193 series = (Series)seriesList[seriesIndex]; 1194 } 1195 else 1196 { 1197 // Create new series 1198 series = new Series(); 1199 series.YValuesPerPoint = yFieldNames.GetLength(0); 1200 1201 // If not the first series in the list copy some properties 1202 if(seriesList.Count > 0) 1203 { 1204 series.XValueType = ((Series)seriesList[0]).XValueType; 1205 series.autoXValueType = ((Series)seriesList[0]).autoXValueType; 1206 series.YValueType = ((Series)seriesList[0]).YValueType; 1207 series.autoYValueType = ((Series)seriesList[0]).autoYValueType; 1208 } 1209 1210 // Try to set series name based on grouping vlaue 1211 string groupObjStr = groupObj as string; 1212 if(groupObjStr != null) 1213 { 1214 series.Name = groupObjStr; 1215 } 1216 else 1217 { 1218 series.Name = seriesGroupByField + " - " + groupObj.ToString(); 1219 } 1220 1221 1222 // Add series and group value into the lists 1223 groupByValueList.Add(groupObj); 1224 seriesList.Add(series); 1225 } 1226 1227 1228 // Auto detect valu(s) type 1229 if(autoDetectType) 1230 { 1231 autoDetectType = false; 1232 DataPointCollection.AutoDetectValuesType(series, enumerator, xField, enumerator, yFieldNames[0]); 1233 } 1234 1235 // Create new data point 1236 DataPoint newDataPoint = new DataPoint(series); 1237 bool emptyValues = false; 1238 1239 // Set X to the value provided 1240 if(xField.Length > 0) 1241 { 1242 xValueObj = DataPointCollection.ConvertEnumerationItem(enumerator.Current, xField); 1243 if( DataPointCollection.IsEmptyValue(xValueObj) ) 1244 { 1245 emptyValues = true; 1246 xValueObj = 0.0; 1247 } 1248 } 1249 1250 // Set Y values 1251 if(yFieldNames.Length == 0) 1252 { 1253 yValuesObj[0] = DataPointCollection.ConvertEnumerationItem(enumerator.Current, null); 1254 if( DataPointCollection.IsEmptyValue(yValuesObj[0]) ) 1255 { 1256 emptyValues = true; 1257 yValuesObj[0] = 0.0; 1258 } 1259 } 1260 else 1261 { 1262 for(int i = 0; i < yFieldNames.Length; i++) 1263 { 1264 yValuesObj[i] = DataPointCollection.ConvertEnumerationItem(enumerator.Current, yFieldNames[i]); 1265 if( DataPointCollection.IsEmptyValue(yValuesObj[i] ) ) 1266 { 1267 emptyValues = true; 1268 yValuesObj[i] = 0.0; 1269 } 1270 } 1271 } 1272 1273 // Set other values 1274 if(otherAttributeNames != null && 1275 otherAttributeNames.Length > 0) 1276 { 1277 for(int i = 0; i < otherFieldNames.Length; i++) 1278 { 1279 // Get object by field name 1280 object obj = DataPointCollection.ConvertEnumerationItem(enumerator.Current, otherFieldNames[i]); 1281 if( !DataPointCollection.IsEmptyValue( obj ) ) 1282 { 1283 newDataPoint.SetPointCustomProperty( 1284 obj, 1285 otherAttributeNames[i], 1286 otherValueFormat[i]); 1287 } 1288 } 1289 } 1290 1291 // IsEmpty value was detected 1292 if(emptyValues) 1293 { 1294 if(xValueObj != null) 1295 { 1296 newDataPoint.SetValueXY(xValueObj, yValuesObj); 1297 } 1298 else 1299 { 1300 newDataPoint.SetValueXY(0, yValuesObj); 1301 } 1302 DataPointCollection.DataPointInit(series, ref newDataPoint); 1303 newDataPoint.IsEmpty = true; 1304 series.Points.Add(newDataPoint); 1305 } 1306 else 1307 { 1308 if(xValueObj != null) 1309 { 1310 newDataPoint.SetValueXY(xValueObj, yValuesObj); 1311 } 1312 else 1313 { 1314 newDataPoint.SetValueXY(0, yValuesObj); 1315 } 1316 DataPointCollection.DataPointInit(series, ref newDataPoint); 1317 series.Points.Add(newDataPoint); 1318 } 1319 } 1320 1321 } while(valueExsist); 1322 1323 // Sort series usig values of group by field 1324 if(sort) 1325 { 1326 // Duplicate current list 1327 ArrayList oldList = (ArrayList)groupByValueList.Clone(); 1328 1329 // Sort list 1330 groupByValueList.Sort(); 1331 if(sortingOrder == PointSortOrder.Descending) 1332 { 1333 groupByValueList.Reverse(); 1334 } 1335 1336 // Change order of series in collection 1337 ArrayList sortedSeriesList = new ArrayList(); 1338 foreach(object obj in groupByValueList) 1339 { 1340 sortedSeriesList.Add(seriesList[oldList.IndexOf(obj)]); 1341 } 1342 seriesList = sortedSeriesList; 1343 } 1344 1345 // Add all series from the list into the series collection 1346 foreach(Series series in seriesList) 1347 { 1348 this.Common.Chart.Series.Add(series); 1349 } 1350 } 1351 1352 /// <summary> 1353 /// Automatically creates and binds series to specified data table. 1354 /// Each column of the table becomes a Y value in a separate series. 1355 /// Series X value field may also be provided. 1356 /// </summary> 1357 /// <param name="dataSource">Data source.</param> 1358 /// <param name="xField">Name of the field for series X values.</param> DataBindTable( IEnumerable dataSource, string xField)1359 internal void DataBindTable( 1360 IEnumerable dataSource, 1361 string xField) 1362 { 1363 // Check arguments 1364 if (dataSource == null) 1365 throw new ArgumentNullException("dataSource"); 1366 1367 // Get list of member names from the data source 1368 ArrayList dataSourceFields = GetDataSourceMemberNames(dataSource, true); 1369 1370 // Remove X value field if it's there 1371 if (xField != null && xField.Length > 0) 1372 { 1373 int index = -1; 1374 for (int i = 0; i < dataSourceFields.Count; i++) 1375 { 1376 if ( String.Equals((string)dataSourceFields[i], xField, StringComparison.OrdinalIgnoreCase ) ) 1377 { 1378 index = i; 1379 break; 1380 } 1381 } 1382 if (index >= 0) 1383 { 1384 dataSourceFields.RemoveAt(index); 1385 } 1386 else 1387 { 1388 // Check if field name passed as index 1389 bool parseSucceed = int.TryParse(xField, NumberStyles.Any, CultureInfo.InvariantCulture, out index); 1390 if (parseSucceed && index >= 0 && index < dataSourceFields.Count) 1391 { 1392 dataSourceFields.RemoveAt(index); 1393 } 1394 } 1395 } 1396 1397 // Get number of series 1398 int seriesNumber = dataSourceFields.Count; 1399 if (seriesNumber > 0) 1400 { 1401 // Create as many series as fields in the data source 1402 ArrayList seriesList = new ArrayList(); 1403 int index = 0; 1404 foreach (string fieldName in dataSourceFields) 1405 { 1406 Series series = new Series(fieldName); 1407 1408 // Set binding properties 1409 series.YValueMembers = fieldName; 1410 series.XValueMember = xField; 1411 1412 // Add to list 1413 seriesList.Add(series); 1414 ++index; 1415 } 1416 1417 1418 // Data bind series 1419 this.DataBind(dataSource, seriesList); 1420 1421 // Add all series from the list into the series collection 1422 foreach (Series series in seriesList) 1423 { 1424 // Clear binding properties 1425 series.YValueMembers = String.Empty; 1426 series.XValueMember = String.Empty; 1427 1428 // Add series into the list 1429 this.Common.Chart.Series.Add(series); 1430 } 1431 } 1432 } 1433 1434 #endregion // Data Binding 1435 1436 #endregion 1437 1438 } 1439 1440 /// <summary> 1441 /// ChartPicture class represents chart content like legends, titles, 1442 /// chart areas and series. It provides methods for positioning and 1443 /// drawing all chart elements. 1444 /// </summary> 1445 internal class ChartPicture : ChartElement, IServiceProvider 1446 { 1447 #region Fields 1448 1449 /// <summary> 1450 /// Indicates that chart exceptions should be suppressed. 1451 /// </summary> 1452 private bool _suppressExceptions = false; 1453 1454 // Chart Graphic object 1455 internal ChartGraphics ChartGraph { get; set; } 1456 1457 // Private data members, which store properties values 1458 private GradientStyle _backGradientStyle = GradientStyle.None; 1459 private Color _backSecondaryColor = Color.Empty; 1460 private Color _backColor = Color.White; 1461 private string _backImage = ""; 1462 private ChartImageWrapMode _backImageWrapMode = ChartImageWrapMode.Tile; 1463 private Color _backImageTransparentColor = Color.Empty; 1464 private ChartImageAlignmentStyle _backImageAlign = ChartImageAlignmentStyle.TopLeft; 1465 private Color _borderColor = Color.White; 1466 private int _borderWidth = 1; 1467 private ChartDashStyle _borderDashStyle = ChartDashStyle.NotSet; 1468 private ChartHatchStyle _backHatchStyle = ChartHatchStyle.None; 1469 private AntiAliasingStyles _antiAliasing = AntiAliasingStyles.All; 1470 private TextAntiAliasingQuality _textAntiAliasingQuality = TextAntiAliasingQuality.High; 1471 private bool _isSoftShadows = true; 1472 private int _width = 300; 1473 private int _height = 300; 1474 private DataManipulator _dataManipulator = new DataManipulator(); 1475 internal HotRegionsList hotRegionsList = null; 1476 private BorderSkin _borderSkin = null; 1477 #if !Microsoft_CONTROL 1478 private bool _isMapEnabled = true; 1479 private MapAreasCollection _mapAreas = null; 1480 #endif 1481 // Chart areas collection 1482 private ChartAreaCollection _chartAreas = null; 1483 1484 // Chart legend collection 1485 private LegendCollection _legends = null; 1486 1487 // Chart title collection 1488 private TitleCollection _titles = null; 1489 1490 // Chart annotation collection 1491 private AnnotationCollection _annotations = null; 1492 1493 // Annotation smart labels class 1494 internal AnnotationSmartLabel annotationSmartLabel = new AnnotationSmartLabel(); 1495 1496 // Chart picture events 1497 internal event EventHandler<ChartPaintEventArgs> BeforePaint; 1498 internal event EventHandler<ChartPaintEventArgs> AfterPaint; 1499 1500 // Chart title position rectangle 1501 private RectangleF _titlePosition = RectangleF.Empty; 1502 1503 // Element spacing size 1504 internal const float elementSpacing = 3F; 1505 1506 // Maximum size of the font in percentage 1507 internal const float maxTitleSize = 15F; 1508 1509 // Printing indicator 1510 internal bool isPrinting = false; 1511 1512 // Indicates chart selection mode 1513 internal bool isSelectionMode = false; 1514 1515 private FontCache _fontCache = new FontCache(); 1516 1517 // Position of the chart 3D border 1518 private RectangleF _chartBorderPosition = RectangleF.Empty; 1519 1520 #if Microsoft_CONTROL 1521 1522 // Saving As Image indicator 1523 internal bool isSavingAsImage = false; 1524 1525 // Indicates that chart background is restored from the double buffer 1526 // prior to drawing top level objects like annotations, cursors and selection. 1527 internal bool backgroundRestored = false; 1528 1529 // Buffered image of non-top level chart elements 1530 internal Bitmap nonTopLevelChartBuffer = null; 1531 1532 #endif // Microsoft_CONTROL 1533 1534 #endregion 1535 1536 #region Constructors 1537 1538 /// <summary> 1539 /// Constructor. 1540 /// </summary> 1541 /// <param name="container">Service container</param> ChartPicture(IServiceContainer container)1542 public ChartPicture(IServiceContainer container) 1543 { 1544 if(container == null) 1545 { 1546 throw(new ArgumentNullException(SR.ExceptionInvalidServiceContainer)); 1547 } 1548 1549 // Create and set Common Elements 1550 Common = new CommonElements(container); 1551 ChartGraph= new ChartGraphics(Common); 1552 hotRegionsList = new HotRegionsList(Common); 1553 1554 // Create border properties class 1555 _borderSkin = new BorderSkin(this); 1556 1557 // Create a collection of chart areas 1558 _chartAreas = new ChartAreaCollection(this); 1559 1560 // Create a collection of legends 1561 _legends = new LegendCollection(this); 1562 1563 // Create a collection of titles 1564 _titles = new TitleCollection(this); 1565 1566 // Create a collection of annotations 1567 _annotations = new AnnotationCollection(this); 1568 1569 // Set Common elements for data manipulator 1570 _dataManipulator.Common = Common; 1571 1572 #if !Microsoft_CONTROL 1573 // Create map areas collection 1574 _mapAreas = new MapAreasCollection(); 1575 #endif 1576 } 1577 1578 /// <summary> 1579 /// Returns Chart service object 1580 /// </summary> 1581 /// <param name="serviceType">Service AxisName</param> 1582 /// <returns>Chart picture</returns> 1583 [EditorBrowsableAttribute(EditorBrowsableState.Never)] IServiceProvider.GetService(Type serviceType)1584 object IServiceProvider.GetService(Type serviceType) 1585 { 1586 if(serviceType == typeof(ChartPicture)) 1587 { 1588 return this; 1589 } 1590 throw (new ArgumentException( SR.ExceptionChartPictureUnsupportedType( serviceType.ToString() ) ) ); 1591 } 1592 1593 #endregion 1594 1595 #region Painting and selection methods 1596 1597 /// <summary> 1598 /// Performs empty painting. 1599 /// </summary> PaintOffScreen()1600 internal void PaintOffScreen() 1601 { 1602 // Check chart size 1603 // NOTE: Fixes issue #4733 1604 if (this.Width <= 0 || this.Height <= 0) 1605 { 1606 return; 1607 } 1608 1609 // Set process Mode to hot regions 1610 this.Common.HotRegionsList.ProcessChartMode |= ProcessMode.HotRegions; 1611 #if Microsoft_CONTROL 1612 this.Common.HotRegionsList.hitTestCalled = true; 1613 #endif // Microsoft_CONTROL 1614 1615 // Enable selection mode 1616 this.isSelectionMode = true; 1617 1618 // Hot Region list does not exist. Create the list. 1619 //this.common.HotRegionsList.List = new ArrayList(); 1620 this.Common.HotRegionsList.Clear(); 1621 1622 // Create a new bitmap 1623 Bitmap image = new Bitmap(Math.Max(1,Width), Math.Max(1,Height)); 1624 1625 // Creates a new Graphics object from the 1626 // specified Image object. 1627 Graphics offScreen = Graphics.FromImage(image); 1628 1629 // Connect Graphics object with Chart Graphics object 1630 ChartGraph.Graphics = offScreen; 1631 1632 // Remember the previous dirty flag 1633 #if Microsoft_CONTROL 1634 bool oldDirtyFlag = this.Common.Chart.dirtyFlag; 1635 #endif //Microsoft_CONTROL 1636 1637 1638 Paint(ChartGraph.Graphics, false); 1639 1640 image.Dispose(); 1641 1642 // Restore the previous dirty flag 1643 #if Microsoft_CONTROL 1644 this.Common.Chart.dirtyFlag = oldDirtyFlag; 1645 #endif //Microsoft_CONTROL 1646 1647 // Disable selection mode 1648 this.isSelectionMode = false; 1649 1650 // Set process Mode to hot regions 1651 this.Common.HotRegionsList.ProcessChartMode |= ProcessMode.HotRegions; 1652 1653 } 1654 1655 /// <summary> 1656 /// Gets text rendering quality. 1657 /// </summary> 1658 /// <returns>Text rendering quality.</returns> GetTextRenderingHint()1659 internal TextRenderingHint GetTextRenderingHint() 1660 { 1661 TextRenderingHint result = TextRenderingHint.SingleBitPerPixelGridFit; 1662 if( (this.AntiAliasing & AntiAliasingStyles.Text) == AntiAliasingStyles.Text ) 1663 { 1664 result = TextRenderingHint.ClearTypeGridFit; 1665 if(this.TextAntiAliasingQuality == TextAntiAliasingQuality.Normal) 1666 { 1667 result = TextRenderingHint.AntiAlias; 1668 } 1669 else if(this.TextAntiAliasingQuality == TextAntiAliasingQuality.SystemDefault) 1670 { 1671 result = TextRenderingHint.SystemDefault; 1672 } 1673 } 1674 else 1675 { 1676 result = TextRenderingHint.SingleBitPerPixelGridFit; 1677 } 1678 1679 return result; 1680 } 1681 GetBorderSkinVisibility()1682 internal bool GetBorderSkinVisibility() 1683 { 1684 return _borderSkin.SkinStyle != BorderSkinStyle.None && this.Width > 20 && this.Height > 20; 1685 } 1686 1687 /// <summary> 1688 /// This function paints a chart. 1689 /// </summary> 1690 /// <param name="graph">The graph provides drawing object to the display device. A Graphics object is associated with a specific device context.</param> 1691 /// <param name="paintTopLevelElementOnly">Indicates that only chart top level elements like cursors, selection or annotation objects must be redrawn.</param> 1692 [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "3#svg")] Paint( Graphics graph, bool paintTopLevelElementOnly )1693 internal void Paint( 1694 Graphics graph, 1695 bool paintTopLevelElementOnly ) 1696 { 1697 1698 #if Microsoft_CONTROL 1699 1700 // Reset restored and saved backgound flags 1701 this.backgroundRestored = false; 1702 1703 #endif // Microsoft_CONTROL 1704 1705 // Reset Annotation Smart Labels 1706 this.annotationSmartLabel.Reset(); 1707 1708 // Do not draw the control if size is less than 5 pixel 1709 if (this.Width < 5 || this.Height < 5) 1710 { 1711 return; 1712 } 1713 1714 #if Microsoft_CONTROL 1715 1716 bool resetHotRegionList = false; 1717 1718 if( 1719 this.Common.HotRegionsList.hitTestCalled 1720 || IsToolTipsEnabled() 1721 ) 1722 { 1723 Common.HotRegionsList.ProcessChartMode = ProcessMode.HotRegions | ProcessMode.Paint; 1724 1725 this.Common.HotRegionsList.hitTestCalled = false; 1726 1727 // Clear list of hot regions 1728 if(paintTopLevelElementOnly) 1729 { 1730 // If repainting only top level elements (annotations) - 1731 // clear top level objects hot regions only 1732 for(int index = 0; index < this.Common.HotRegionsList.List.Count; index++) 1733 { 1734 HotRegion region = (HotRegion)this.Common.HotRegionsList.List[index]; 1735 if(region.Type == ChartElementType.Annotation) 1736 { 1737 this.Common.HotRegionsList.List.RemoveAt(index); 1738 --index; 1739 } 1740 } 1741 } 1742 else 1743 { 1744 // If repainting whole chart - clear all hot regions 1745 resetHotRegionList = true; 1746 } 1747 } 1748 else 1749 { 1750 Common.HotRegionsList.ProcessChartMode = ProcessMode.Paint; 1751 1752 // If repainting whole chart - clear all hot regions 1753 resetHotRegionList = true; 1754 } 1755 1756 // Reset hot region list 1757 if(resetHotRegionList) 1758 { 1759 this.Common.HotRegionsList.Clear(); 1760 } 1761 1762 #else 1763 if( this.IsMapEnabled ) 1764 { 1765 Common.HotRegionsList.ProcessChartMode |= ProcessMode.ImageMaps | ProcessMode.Paint; 1766 1767 // Clear any existing non-custom image map areas 1768 for(int index = 0; index < this.MapAreas.Count; index++) 1769 { 1770 MapArea mapArea = this.MapAreas[index]; 1771 if(!mapArea.IsCustom) 1772 { 1773 this.MapAreas.RemoveAt(index); 1774 --index; 1775 } 1776 } 1777 } 1778 1779 1780 #endif //#if Microsoft_CONTROL 1781 1782 // Check if control was data bound 1783 ChartImage chartImage = this as ChartImage; 1784 if(chartImage != null && !chartImage.boundToDataSource) 1785 { 1786 if(this.Common != null && this.Common.Chart != null && !this.Common.Chart.IsDesignMode()) 1787 { 1788 this.Common.Chart.DataBind(); 1789 } 1790 } 1791 1792 // Connect Graphics object with Chart Graphics object 1793 ChartGraph.Graphics = graph; 1794 1795 Common.graph = ChartGraph; 1796 1797 // Set anti alias mode 1798 ChartGraph.AntiAliasing = _antiAliasing; 1799 ChartGraph.softShadows = _isSoftShadows; 1800 ChartGraph.TextRenderingHint = GetTextRenderingHint(); 1801 1802 try 1803 { 1804 // Check if only chart area cursors and annotations must be redrawn 1805 if(!paintTopLevelElementOnly) 1806 { 1807 // Fire Before Paint event 1808 OnBeforePaint(new ChartPaintEventArgs(this.Chart, this.ChartGraph, this.Common, new ElementPosition(0, 0, 100, 100))); 1809 1810 // Flag indicates that resize method should be called 1811 // after adjusting the intervals in 3D charts 1812 bool resizeAfterIntervalAdjusting = false; 1813 1814 // RecalculateAxesScale paint chart areas 1815 foreach (ChartArea area in _chartAreas ) 1816 { 1817 1818 // Check if area is visible 1819 if(area.Visible) 1820 1821 { 1822 area.Set3DAnglesAndReverseMode(); 1823 area.SetTempValues(); 1824 area.ReCalcInternal(); 1825 1826 // Resize should be called the second time 1827 if( area.Area3DStyle.Enable3D && !area.chartAreaIsCurcular) 1828 { 1829 resizeAfterIntervalAdjusting = true; 1830 } 1831 } 1832 } 1833 1834 // Call Customize event 1835 this.Common.Chart.CallOnCustomize(); 1836 1837 // Resize picture 1838 Resize(ChartGraph, resizeAfterIntervalAdjusting); 1839 1840 1841 // This code is introduce because labels has to 1842 // be changed when scene is rotated. 1843 bool intervalReCalculated = false; 1844 foreach (ChartArea area in _chartAreas ) 1845 { 1846 if( area.Area3DStyle.Enable3D && 1847 !area.chartAreaIsCurcular 1848 1849 && area.Visible 1850 1851 ) 1852 1853 { 1854 // Make correction for interval in 3D space 1855 intervalReCalculated = true; 1856 area.Estimate3DInterval( ChartGraph ); 1857 area.ReCalcInternal(); 1858 } 1859 } 1860 1861 // Resize chart areas after updating 3D interval 1862 if(resizeAfterIntervalAdjusting) 1863 { 1864 // NOTE: Fixes issue #6808. 1865 // In 3D chart area interval will be changed to compenstae for the axis rotation angle. 1866 // This will cause all standard labels to be changed. We need to call the customize event 1867 // the second time to give user a chance to modify those labels. 1868 if (intervalReCalculated) 1869 { 1870 // Call Customize event 1871 this.Common.Chart.CallOnCustomize(); 1872 } 1873 1874 // Resize chart elements 1875 Resize(ChartGraph); 1876 } 1877 1878 1879 //*********************************************************************** 1880 //** Draw chart 3D border 1881 //*********************************************************************** 1882 if (GetBorderSkinVisibility()) 1883 { 1884 // Fill rectangle with page color 1885 ChartGraph.FillRectangleAbs( new RectangleF( 0, 0, Width-1 , Height-1 ), 1886 _borderSkin.PageColor, 1887 ChartHatchStyle.None, 1888 "", 1889 ChartImageWrapMode.Tile, 1890 Color.Empty, 1891 ChartImageAlignmentStyle.Center, 1892 GradientStyle.None, 1893 Color.Empty, 1894 _borderSkin.PageColor, 1895 1, 1896 ChartDashStyle.Solid, 1897 PenAlignment.Inset ); 1898 1899 // Draw 3D border 1900 ChartGraph.Draw3DBorderAbs( 1901 _borderSkin, 1902 this._chartBorderPosition, 1903 BackColor, 1904 BackHatchStyle, 1905 BackImage, 1906 BackImageWrapMode, 1907 BackImageTransparentColor, 1908 BackImageAlignment, 1909 BackGradientStyle, 1910 BackSecondaryColor, 1911 BorderColor, 1912 BorderWidth, 1913 BorderDashStyle); 1914 } 1915 1916 // Paint Background 1917 else 1918 { 1919 ChartGraph.FillRectangleAbs( new RectangleF( 0, 0, Width-1 , Height-1 ), 1920 BackColor, 1921 BackHatchStyle, 1922 BackImage, 1923 BackImageWrapMode, 1924 BackImageTransparentColor, 1925 BackImageAlignment, 1926 BackGradientStyle, 1927 BackSecondaryColor, 1928 BorderColor, 1929 BorderWidth, 1930 BorderDashStyle, 1931 PenAlignment.Inset ); 1932 } 1933 1934 // Call BackPaint event 1935 this.Chart.CallOnPrePaint(new ChartPaintEventArgs(this.Chart, this.ChartGraph, this.Common, new ElementPosition(0, 0, 100, 100))); 1936 1937 // Call paint function for each chart area. 1938 foreach (ChartArea area in _chartAreas ) 1939 { 1940 1941 // Check if area is visible 1942 if(area.Visible) 1943 1944 { 1945 area.Paint(ChartGraph); 1946 } 1947 } 1948 1949 // This code is introduced because of GetPointsInterval method, 1950 // which is very time consuming. There is no reason to calculate 1951 // interval after painting. 1952 foreach (ChartArea area in _chartAreas ) 1953 { 1954 // Reset interval data 1955 area.intervalData = double.NaN; 1956 } 1957 1958 // Draw Legends 1959 foreach(Legend legendCurrent in this.Legends) 1960 { 1961 legendCurrent.Paint(ChartGraph); 1962 } 1963 1964 // Draw chart titles from the collection 1965 foreach(Title titleCurrent in this.Titles) 1966 { 1967 titleCurrent.Paint(ChartGraph); 1968 } 1969 1970 // Call Paint event 1971 this.Chart.CallOnPostPaint(new ChartPaintEventArgs(this.Chart, this.ChartGraph, this.Common, new ElementPosition(0, 0, 100, 100))); 1972 } 1973 1974 // Draw annotation objects 1975 this.Annotations.Paint(ChartGraph, paintTopLevelElementOnly); 1976 1977 // Draw chart areas cursors in all areas. 1978 // Only if not in selection 1979 if(!this.isSelectionMode) 1980 { 1981 foreach (ChartArea area in _chartAreas ) 1982 { 1983 1984 // Check if area is visible 1985 if(area.Visible) 1986 1987 { 1988 area.PaintCursors(ChartGraph, paintTopLevelElementOnly); 1989 } 1990 } 1991 } 1992 1993 // Return default values 1994 foreach (ChartArea area in _chartAreas ) 1995 { 1996 1997 // Check if area is visible 1998 if(area.Visible) 1999 2000 { 2001 area.Restore3DAnglesAndReverseMode(); 2002 area.GetTempValues(); 2003 } 2004 } 2005 } 2006 catch(System.Exception) 2007 { 2008 throw; 2009 } 2010 finally 2011 { 2012 // Fire After Paint event 2013 OnAfterPaint(new ChartPaintEventArgs(this.Chart, this.ChartGraph, this.Common, new ElementPosition(0, 0, 100, 100))); 2014 2015 // Restore temp values for each chart area 2016 foreach (ChartArea area in _chartAreas ) 2017 { 2018 2019 // Check if area is visible 2020 if(area.Visible) 2021 2022 { 2023 area.Restore3DAnglesAndReverseMode(); 2024 area.GetTempValues(); 2025 } 2026 } 2027 2028 #if !Microsoft_CONTROL 2029 if (this.Chart.IsDesignMode()) 2030 { 2031 this.Chart.MapAreas.RemoveNonCustom(); 2032 } 2033 #endif //!Microsoft_CONTROL 2034 } 2035 } 2036 2037 /// <summary> 2038 /// Invoke before paint delegates. 2039 /// </summary> 2040 /// <param name="e">Event arguments.</param> OnBeforePaint(ChartPaintEventArgs e)2041 protected virtual void OnBeforePaint(ChartPaintEventArgs e) 2042 { 2043 if (BeforePaint != null) 2044 { 2045 //Invokes the delegates. 2046 BeforePaint(this, e); 2047 } 2048 } 2049 2050 /// <summary> 2051 /// Invoke after paint delegates. 2052 /// </summary> 2053 /// <param name="e">Event arguments.</param> OnAfterPaint(ChartPaintEventArgs e)2054 protected virtual void OnAfterPaint(ChartPaintEventArgs e) 2055 { 2056 if (AfterPaint != null) 2057 { 2058 //Invokes the delegates. 2059 AfterPaint(this, e); 2060 } 2061 } 2062 Invalidate()2063 internal override void Invalidate() 2064 { 2065 base.Invalidate(); 2066 2067 #if Microsoft_CONTROL 2068 if (Chart!=null) 2069 Chart.Invalidate(); 2070 #endif 2071 } 2072 #endregion 2073 2074 #region Resizing methods 2075 2076 /// <summary> 2077 /// Resize the chart picture. 2078 /// </summary> 2079 /// <param name="chartGraph">Chart graphics.</param> Resize(ChartGraphics chartGraph)2080 public void Resize(ChartGraphics chartGraph) 2081 { 2082 Resize(chartGraph, false); 2083 } 2084 2085 /// <summary> 2086 /// Resize the chart picture. 2087 /// </summary> 2088 /// <param name="chartGraph">Chart graphics.</param> 2089 /// <param name="calcAreaPositionOnly">Indicates that only chart area position is calculated.</param> Resize(ChartGraphics chartGraph, bool calcAreaPositionOnly)2090 public void Resize(ChartGraphics chartGraph, bool calcAreaPositionOnly) 2091 { 2092 // Set the chart size for Common elements 2093 Common.Width = _width; 2094 Common.Height = _height; 2095 2096 // Set the chart size for Chart graphics 2097 chartGraph.SetPictureSize( _width, _height ); 2098 2099 // Initialize chart area(s) rectangle 2100 RectangleF chartAreasRectangle = new RectangleF(0, 0, _width - 1, _height - 1); 2101 chartAreasRectangle = chartGraph.GetRelativeRectangle(chartAreasRectangle); 2102 2103 //****************************************************** 2104 //** Get the 3D border interface 2105 //****************************************************** 2106 _titlePosition = RectangleF.Empty; 2107 IBorderType border3D = null; 2108 bool titleInBorder = false; 2109 2110 if(_borderSkin.SkinStyle != BorderSkinStyle.None) 2111 { 2112 // Set border size 2113 this._chartBorderPosition = chartGraph.GetAbsoluteRectangle(chartAreasRectangle); 2114 2115 // Get border interface 2116 border3D = Common.BorderTypeRegistry.GetBorderType(_borderSkin.SkinStyle.ToString()); 2117 if(border3D != null) 2118 { 2119 border3D.Resolution = chartGraph.Graphics.DpiX; 2120 // Check if title should be displayed in the border 2121 titleInBorder = border3D.GetTitlePositionInBorder() != RectangleF.Empty; 2122 _titlePosition = chartGraph.GetRelativeRectangle(border3D.GetTitlePositionInBorder()); 2123 _titlePosition.Width = chartAreasRectangle.Width - _titlePosition.Width; 2124 2125 // Adjust are position to the border size 2126 border3D.AdjustAreasPosition(chartGraph, ref chartAreasRectangle); 2127 } 2128 } 2129 2130 //****************************************************** 2131 //** Calculate position of all titles in the collection 2132 //****************************************************** 2133 RectangleF frameTitlePosition = RectangleF.Empty; 2134 if(titleInBorder) 2135 { 2136 frameTitlePosition = new RectangleF(_titlePosition.Location, _titlePosition.Size); 2137 } 2138 foreach(Title title in this.Titles) 2139 { 2140 if (title.DockedToChartArea == Constants.NotSetValue && 2141 title.Position.Auto && 2142 title.Visible) 2143 { 2144 title.CalcTitlePosition(chartGraph, ref chartAreasRectangle, ref frameTitlePosition, elementSpacing); 2145 } 2146 } 2147 2148 //****************************************************** 2149 //** Calculate position of all legends in the collection 2150 //****************************************************** 2151 this.Legends.CalcLegendPosition(chartGraph, ref chartAreasRectangle, elementSpacing); 2152 2153 //****************************************************** 2154 //** Calculate position of the chart area(s) 2155 //****************************************************** 2156 chartAreasRectangle.Width -= elementSpacing; 2157 chartAreasRectangle.Height -= elementSpacing; 2158 RectangleF areaPosition = new RectangleF(); 2159 2160 2161 // Get number of chart areas that requeres automatic positioning 2162 int areaNumber = 0; 2163 foreach (ChartArea area in _chartAreas ) 2164 { 2165 2166 // Check if area is visible 2167 if(area.Visible) 2168 2169 { 2170 if(area.Position.Auto) 2171 { 2172 ++areaNumber; 2173 } 2174 } 2175 } 2176 2177 // Calculate how many columns & rows of areas we going to have 2178 int areaColumns = (int)Math.Floor(Math.Sqrt(areaNumber)); 2179 if(areaColumns < 1) 2180 { 2181 areaColumns = 1; 2182 } 2183 int areaRows = (int)Math.Ceiling(((float)areaNumber) / ((float)areaColumns)); 2184 2185 // Set position for all areas 2186 int column = 0; 2187 int row = 0; 2188 foreach (ChartArea area in _chartAreas ) 2189 { 2190 2191 // Check if area is visible 2192 if(area.Visible) 2193 2194 { 2195 if(area.Position.Auto) 2196 { 2197 // Calculate area position 2198 areaPosition.Width = chartAreasRectangle.Width / areaColumns - elementSpacing; 2199 areaPosition.Height = chartAreasRectangle.Height / areaRows - elementSpacing; 2200 areaPosition.X = chartAreasRectangle.X + column * (chartAreasRectangle.Width / areaColumns) + elementSpacing; 2201 areaPosition.Y = chartAreasRectangle.Y + row * (chartAreasRectangle.Height / areaRows) + elementSpacing; 2202 2203 // Calculate position of all titles in the collection docked outside of the chart area 2204 TitleCollection.CalcOutsideTitlePosition(this, chartGraph, area, ref areaPosition, elementSpacing); 2205 2206 // Calculate position of the legend if it's docked outside of the chart area 2207 this.Legends.CalcOutsideLegendPosition(chartGraph, area, ref areaPosition, elementSpacing); 2208 2209 // Set area position without changing the Auto flag 2210 area.Position.SetPositionNoAuto(areaPosition.X, areaPosition.Y, areaPosition.Width, areaPosition.Height); 2211 2212 // Go to next area 2213 ++row; 2214 if(row >= areaRows) 2215 { 2216 row = 0; 2217 ++column; 2218 } 2219 } 2220 else 2221 { 2222 RectangleF rect = area.Position.ToRectangleF(); 2223 2224 // Calculate position of all titles in the collection docked outside of the chart area 2225 TitleCollection.CalcOutsideTitlePosition(this, chartGraph, area, ref rect, elementSpacing); 2226 2227 // Calculate position of the legend if it's docked outside of the chart area 2228 this.Legends.CalcOutsideLegendPosition(chartGraph, area, ref rect, elementSpacing); 2229 } 2230 } 2231 } 2232 2233 //****************************************************** 2234 //** Align chart areas Position if required 2235 //****************************************************** 2236 AlignChartAreasPosition(); 2237 2238 //******************************************************** 2239 //** Check if only chart area position must be calculated. 2240 //******************************************************** 2241 if(!calcAreaPositionOnly) 2242 { 2243 2244 //****************************************************** 2245 //** Call Resize function for each chart area. 2246 //****************************************************** 2247 foreach (ChartArea area in _chartAreas ) 2248 { 2249 2250 // Check if area is visible 2251 if(area.Visible) 2252 2253 { 2254 area.Resize(chartGraph); 2255 } 2256 } 2257 2258 //****************************************************** 2259 //** Align chart areas InnerPlotPosition if required 2260 //****************************************************** 2261 AlignChartAreas(AreaAlignmentStyles.PlotPosition); 2262 2263 //****************************************************** 2264 //** Calculate position of the legend if it's inside 2265 //** chart plotting area 2266 //****************************************************** 2267 2268 // Calculate position of all titles in the collection docked outside of the chart area 2269 TitleCollection.CalcInsideTitlePosition(this, chartGraph, elementSpacing); 2270 2271 this.Legends.CalcInsideLegendPosition(chartGraph, elementSpacing); 2272 } 2273 } 2274 2275 /// <summary> 2276 /// Minimum and maximum do not have to be calculated 2277 /// from data series every time. It is very time 2278 /// consuming. Minimum and maximum are buffered 2279 /// and only when this flags are set Minimum and 2280 /// Maximum are refreshed from data. 2281 /// </summary> ResetMinMaxFromData()2282 internal void ResetMinMaxFromData() 2283 { 2284 if (_chartAreas != null) 2285 { 2286 // Call ResetMinMaxFromData function for each chart area. 2287 foreach (ChartArea area in _chartAreas) 2288 { 2289 2290 // Check if area is visible 2291 if (area.Visible) 2292 { 2293 area.ResetMinMaxFromData(); 2294 } 2295 } 2296 } 2297 } 2298 2299 /// <summary> 2300 /// RecalculateAxesScale the chart picture. 2301 /// </summary> Recalculate()2302 public void Recalculate() 2303 { 2304 // Call ReCalc function for each chart area. 2305 foreach (ChartArea area in _chartAreas ) 2306 { 2307 2308 // Check if area is visible 2309 if(area.Visible) 2310 2311 { 2312 area.ReCalcInternal(); 2313 } 2314 } 2315 } 2316 2317 #endregion 2318 2319 #region Chart picture properties 2320 2321 // VSTS 96787-Text Direction (RTL/LTR) 2322 #if !Microsoft_CONTROL 2323 private RightToLeft rightToLeft = RightToLeft.No; 2324 #endif //!Microsoft_CONTROL 2325 /// <summary> 2326 /// Gets or sets the RightToLeft type. 2327 /// </summary> 2328 [ 2329 DefaultValue(RightToLeft.No) 2330 ] 2331 public RightToLeft RightToLeft 2332 { 2333 get 2334 { 2335 #if Microsoft_CONTROL 2336 return this.Common.Chart.RightToLeft; 2337 #else // !WIN_CONTROL 2338 return this.rightToLeft; 2339 #endif // WIN_CONTROL 2340 } 2341 set 2342 { 2343 #if Microsoft_CONTROL 2344 this.Common.Chart.RightToLeft = value; 2345 #else // !Microsoft_CONTROL 2346 this.rightToLeft = value; 2347 #endif // Microsoft_CONTROL 2348 } 2349 } 2350 2351 /// <summary> 2352 /// Indicates that non-critical chart exceptions will be suppressed. 2353 /// </summary> 2354 [ 2355 SRCategory("CategoryAttributeMisc"), 2356 DefaultValue(false), 2357 SRDescription("DescriptionAttributeSuppressExceptions"), 2358 ] 2359 internal bool SuppressExceptions 2360 { 2361 set 2362 { 2363 _suppressExceptions = value; 2364 } 2365 get 2366 { 2367 return _suppressExceptions; 2368 } 2369 } 2370 2371 /// <summary> 2372 /// Chart border skin style. 2373 /// </summary> 2374 [ 2375 SRCategory("CategoryAttributeAppearance"), 2376 Bindable(true), 2377 DefaultValue(BorderSkinStyle.None), 2378 SRDescription("DescriptionAttributeBorderSkin"), 2379 #if !Microsoft_CONTROL 2380 PersistenceMode(PersistenceMode.InnerProperty), 2381 #endif 2382 ] 2383 public BorderSkin BorderSkin 2384 { 2385 get 2386 { 2387 return _borderSkin; 2388 } 2389 set 2390 { 2391 _borderSkin = value; 2392 } 2393 } 2394 2395 #if ! Microsoft_CONTROL 2396 2397 /// <summary> 2398 /// Indicates that chart image map is enabled. 2399 /// </summary> 2400 [ 2401 SRCategory("CategoryAttributeMap"), 2402 Bindable(true), 2403 SRDescription("DescriptionAttributeMapEnabled"), 2404 PersistenceMode(PersistenceMode.InnerProperty), 2405 DefaultValue(true) 2406 ] 2407 public bool IsMapEnabled 2408 { 2409 get 2410 { 2411 return _isMapEnabled; 2412 } 2413 set 2414 { 2415 _isMapEnabled = value; 2416 } 2417 } 2418 2419 /// <summary> 2420 /// Chart map areas collection. 2421 /// </summary> 2422 [ 2423 SRCategory("CategoryAttributeMap"), 2424 SRDescription("DescriptionAttributeMapAreas"), 2425 PersistenceMode(PersistenceMode.InnerProperty), 2426 Editor(Editors.ChartCollectionEditor.Editor, Editors.ChartCollectionEditor.Base) 2427 ] 2428 public MapAreasCollection MapAreas 2429 { 2430 get 2431 { 2432 return _mapAreas; 2433 } 2434 } 2435 #endif 2436 2437 /// <summary> 2438 /// Reference to chart area collection 2439 /// </summary> 2440 [ 2441 SRCategory("CategoryAttributeAppearance"), 2442 Bindable(true), 2443 SRDescription("DescriptionAttributeChartAreas"), 2444 #if !Microsoft_CONTROL 2445 PersistenceMode(PersistenceMode.InnerProperty), 2446 #endif 2447 Editor(Editors.ChartCollectionEditor.Editor, Editors.ChartCollectionEditor.Base) 2448 ] 2449 public ChartAreaCollection ChartAreas 2450 { 2451 get 2452 { 2453 return _chartAreas; 2454 } 2455 } 2456 2457 /// <summary> 2458 /// Chart legend collection. 2459 /// </summary> 2460 [ 2461 SRCategory("CategoryAttributeChart"), 2462 SRDescription("DescriptionAttributeLegends"), 2463 Editor(Editors.LegendCollectionEditor.Editor, Editors.LegendCollectionEditor.Base), 2464 #if !Microsoft_CONTROL 2465 PersistenceMode(PersistenceMode.InnerProperty), 2466 #endif 2467 ] 2468 public LegendCollection Legends 2469 { 2470 get 2471 { 2472 return _legends; 2473 } 2474 } 2475 2476 /// <summary> 2477 /// Chart title collection. 2478 /// </summary> 2479 [ 2480 SRCategory("CategoryAttributeCharttitle"), 2481 SRDescription("DescriptionAttributeTitles"), 2482 Editor(Editors.ChartCollectionEditor.Editor, Editors.ChartCollectionEditor.Base), 2483 #if !Microsoft_CONTROL 2484 PersistenceMode(PersistenceMode.InnerProperty), 2485 #endif 2486 ] 2487 public TitleCollection Titles 2488 { 2489 get 2490 { 2491 return _titles; 2492 } 2493 } 2494 2495 2496 2497 /// <summary> 2498 /// Chart annotation collection. 2499 /// </summary> 2500 [ 2501 SRCategory("CategoryAttributeChart"), 2502 SRDescription("DescriptionAttributeAnnotations3"), 2503 Editor(Editors.AnnotationCollectionEditor.Editor, Editors.AnnotationCollectionEditor.Base), 2504 #if !Microsoft_CONTROL 2505 PersistenceMode(PersistenceMode.InnerProperty), 2506 #endif 2507 ] 2508 public AnnotationCollection Annotations 2509 { 2510 get 2511 { 2512 return _annotations; 2513 } 2514 } 2515 2516 2517 2518 /// <summary> 2519 /// Background color for the Chart 2520 /// </summary> 2521 [ 2522 2523 SRCategory("CategoryAttributeAppearance"), 2524 Bindable(true), 2525 DefaultValue(typeof(Color), "White"), 2526 SRDescription("DescriptionAttributeBackColor"), 2527 TypeConverter(typeof(ColorConverter)), 2528 Editor(Editors.ChartColorEditor.Editor, Editors.ChartColorEditor.Base), 2529 #if !Microsoft_CONTROL 2530 PersistenceMode(PersistenceMode.Attribute) 2531 #endif 2532 ] 2533 public Color BackColor 2534 { 2535 get 2536 { 2537 return _backColor; 2538 } 2539 set 2540 { 2541 #if !Microsoft_CONTROL 2542 if(value == Color.Empty || value.A != 255 || value == Color.Transparent) 2543 { 2544 // NOTE: Transparent colors are valid 2545 } 2546 #endif 2547 _backColor = value; 2548 } 2549 } 2550 2551 /// <summary> 2552 /// Border color for the Chart 2553 /// </summary> 2554 [ 2555 2556 SRCategory("CategoryAttributeAppearance"), 2557 Bindable(true), 2558 DefaultValue(typeof(Color), "White"), 2559 SRDescription("DescriptionAttributeBorderColor"), 2560 TypeConverter(typeof(ColorConverter)), 2561 Editor(Editors.ChartColorEditor.Editor, Editors.ChartColorEditor.Base), 2562 #if !Microsoft_CONTROL 2563 PersistenceMode(PersistenceMode.Attribute) 2564 #endif 2565 ] 2566 public Color BorderColor 2567 { 2568 get 2569 { 2570 return _borderColor; 2571 } 2572 set 2573 { 2574 _borderColor = value; 2575 } 2576 } 2577 2578 /// <summary> 2579 /// Chart width 2580 /// </summary> 2581 [ 2582 SRCategory("CategoryAttributeAppearance"), 2583 Bindable(true), 2584 DefaultValue(300), 2585 SRDescription("DescriptionAttributeWidth"), 2586 #if !Microsoft_CONTROL 2587 PersistenceMode(PersistenceMode.Attribute) 2588 #endif 2589 ] 2590 public int Width 2591 { 2592 get 2593 { 2594 return _width; 2595 } 2596 set 2597 { 2598 this.InspectChartDimensions(value, this.Height); 2599 _width = value; 2600 Common.Width = _width; 2601 } 2602 } 2603 2604 /// <summary> 2605 /// Series Data Manipulator 2606 /// </summary> 2607 [ 2608 SRCategory("CategoryAttributeData"), 2609 SRDescription("DescriptionAttributeDataManipulator"), 2610 Browsable(false), 2611 DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Hidden), 2612 SerializationVisibilityAttribute(SerializationVisibility.Hidden) 2613 ] 2614 public DataManipulator DataManipulator 2615 { 2616 get 2617 { 2618 return _dataManipulator; 2619 } 2620 } 2621 2622 2623 2624 2625 /// <summary> 2626 /// Chart height 2627 /// </summary> 2628 [ 2629 SRCategory("CategoryAttributeAppearance"), 2630 Bindable(true), 2631 DefaultValue(300), 2632 SRDescription("DescriptionAttributeHeight3"), 2633 #if !Microsoft_CONTROL 2634 PersistenceMode(PersistenceMode.Attribute) 2635 #endif 2636 ] 2637 public int Height 2638 { 2639 get 2640 { 2641 return _height; 2642 } 2643 set 2644 { 2645 this.InspectChartDimensions(this.Width, value); 2646 _height = value; 2647 Common.Height = value; 2648 } 2649 } 2650 2651 /// <summary> 2652 /// Back Hatch style 2653 /// </summary> 2654 [ 2655 2656 SRCategory("CategoryAttributeAppearance"), 2657 Bindable(true), 2658 DefaultValue(ChartHatchStyle.None), 2659 SRDescription("DescriptionAttributeBackHatchStyle"), 2660 #if !Microsoft_CONTROL 2661 PersistenceMode(PersistenceMode.Attribute), 2662 #endif 2663 Editor(Editors.HatchStyleEditor.Editor, Editors.HatchStyleEditor.Base) 2664 ] 2665 public ChartHatchStyle BackHatchStyle 2666 { 2667 get 2668 { 2669 return _backHatchStyle; 2670 } 2671 set 2672 { 2673 _backHatchStyle = value; 2674 } 2675 } 2676 2677 /// <summary> 2678 /// Chart area background image 2679 /// </summary> 2680 [ 2681 SRCategory("CategoryAttributeAppearance"), 2682 Bindable(true), 2683 DefaultValue(""), 2684 SRDescription("DescriptionAttributeBackImage"), 2685 Editor(Editors.ImageValueEditor.Editor, Editors.ImageValueEditor.Base), 2686 #if !Microsoft_CONTROL 2687 PersistenceMode(PersistenceMode.Attribute), 2688 #endif 2689 NotifyParentPropertyAttribute(true) 2690 ] 2691 public string BackImage 2692 { 2693 get 2694 { 2695 return _backImage; 2696 } 2697 set 2698 { 2699 _backImage = value; 2700 } 2701 } 2702 2703 /// <summary> 2704 /// Chart area background image drawing mode. 2705 /// </summary> 2706 [ 2707 SRCategory("CategoryAttributeAppearance"), 2708 Bindable(true), 2709 DefaultValue(ChartImageWrapMode.Tile), 2710 NotifyParentPropertyAttribute(true), 2711 SRDescription("DescriptionAttributeImageWrapMode"), 2712 #if !Microsoft_CONTROL 2713 PersistenceMode(PersistenceMode.Attribute) 2714 #endif 2715 ] 2716 public ChartImageWrapMode BackImageWrapMode 2717 { 2718 get 2719 { 2720 return _backImageWrapMode; 2721 } 2722 set 2723 { 2724 _backImageWrapMode = value; 2725 } 2726 } 2727 2728 /// <summary> 2729 /// Background image transparent color. 2730 /// </summary> 2731 [ 2732 SRCategory("CategoryAttributeAppearance"), 2733 Bindable(true), 2734 DefaultValue(typeof(Color), ""), 2735 NotifyParentPropertyAttribute(true), 2736 SRDescription("DescriptionAttributeImageTransparentColor"), 2737 TypeConverter(typeof(ColorConverter)), 2738 Editor(Editors.ChartColorEditor.Editor, Editors.ChartColorEditor.Base), 2739 #if !Microsoft_CONTROL 2740 PersistenceMode(PersistenceMode.Attribute) 2741 #endif 2742 ] 2743 public Color BackImageTransparentColor 2744 { 2745 get 2746 { 2747 return _backImageTransparentColor; 2748 } 2749 set 2750 { 2751 _backImageTransparentColor = value; 2752 } 2753 } 2754 2755 /// <summary> 2756 /// Background image alignment used by ClampUnscale drawing mode. 2757 /// </summary> 2758 [ 2759 SRCategory("CategoryAttributeAppearance"), 2760 Bindable(true), 2761 DefaultValue(ChartImageAlignmentStyle.TopLeft), 2762 NotifyParentPropertyAttribute(true), 2763 SRDescription("DescriptionAttributeBackImageAlign"), 2764 #if !Microsoft_CONTROL 2765 PersistenceMode(PersistenceMode.Attribute) 2766 #endif 2767 ] 2768 public ChartImageAlignmentStyle BackImageAlignment 2769 { 2770 get 2771 { 2772 return _backImageAlign; 2773 } 2774 set 2775 { 2776 _backImageAlign = value; 2777 } 2778 } 2779 2780 /// <summary> 2781 /// Indicates that smoothing is applied while drawing shadows. 2782 /// </summary> 2783 [ 2784 SRCategory("CategoryAttributeImage"), 2785 Bindable(true), 2786 DefaultValue(true), 2787 SRDescription("DescriptionAttributeSoftShadows3"), 2788 #if !Microsoft_CONTROL 2789 PersistenceMode(PersistenceMode.Attribute) 2790 #endif 2791 ] 2792 public bool IsSoftShadows 2793 { 2794 get 2795 { 2796 return _isSoftShadows; 2797 } 2798 set 2799 { 2800 _isSoftShadows = value; 2801 } 2802 } 2803 2804 /// <summary> 2805 /// Specifies whether smoothing (antialiasing) is applied while drawing chart. 2806 /// </summary> 2807 [ 2808 SRCategory("CategoryAttributeImage"), 2809 Bindable(true), 2810 DefaultValue(typeof(AntiAliasingStyles), "All"), 2811 SRDescription("DescriptionAttributeAntiAlias"), 2812 #if !Microsoft_CONTROL 2813 PersistenceMode(PersistenceMode.Attribute) 2814 #endif 2815 ] 2816 public AntiAliasingStyles AntiAliasing 2817 { 2818 get 2819 { 2820 return _antiAliasing; 2821 } 2822 set 2823 { 2824 _antiAliasing = value; 2825 } 2826 } 2827 2828 /// <summary> 2829 /// Specifies the quality of text antialiasing. 2830 /// </summary> 2831 [ 2832 SRCategory("CategoryAttributeImage"), 2833 Bindable(true), 2834 DefaultValue(typeof(TextAntiAliasingQuality), "High"), 2835 SRDescription("DescriptionAttributeTextAntiAliasingQuality"), 2836 #if !Microsoft_CONTROL 2837 PersistenceMode(PersistenceMode.Attribute) 2838 #endif 2839 ] 2840 public TextAntiAliasingQuality TextAntiAliasingQuality 2841 { 2842 get 2843 { 2844 return _textAntiAliasingQuality; 2845 } 2846 set 2847 { 2848 _textAntiAliasingQuality = value; 2849 } 2850 } 2851 2852 /// <summary> 2853 /// A type for the background gradient 2854 /// </summary> 2855 [ 2856 2857 SRCategory("CategoryAttributeAppearance"), 2858 Bindable(true), 2859 DefaultValue(GradientStyle.None), 2860 SRDescription("DescriptionAttributeBackGradientStyle"), 2861 #if !Microsoft_CONTROL 2862 PersistenceMode(PersistenceMode.Attribute), 2863 #endif 2864 Editor(Editors.GradientEditor.Editor, Editors.GradientEditor.Base) 2865 ] 2866 public GradientStyle BackGradientStyle 2867 { 2868 get 2869 { 2870 return _backGradientStyle; 2871 } 2872 set 2873 { 2874 _backGradientStyle = value; 2875 } 2876 } 2877 2878 /// <summary> 2879 /// The second color which is used for a gradient 2880 /// </summary> 2881 [ 2882 2883 SRCategory("CategoryAttributeAppearance"), 2884 Bindable(true), 2885 DefaultValue(typeof(Color), ""), 2886 SRDescription("DescriptionAttributeBackSecondaryColor"), 2887 TypeConverter(typeof(ColorConverter)), 2888 Editor(Editors.ChartColorEditor.Editor, Editors.ChartColorEditor.Base), 2889 #if !Microsoft_CONTROL 2890 PersistenceMode(PersistenceMode.Attribute) 2891 #endif 2892 ] 2893 public Color BackSecondaryColor 2894 { 2895 get 2896 { 2897 return _backSecondaryColor; 2898 } 2899 set 2900 { 2901 #if !Microsoft_CONTROL 2902 if(value != Color.Empty && (value.A != 255 || value == Color.Transparent)) 2903 { 2904 throw (new ArgumentException( SR.ExceptionBackSecondaryColorIsTransparent)); 2905 } 2906 #endif 2907 _backSecondaryColor = value; 2908 } 2909 } 2910 2911 /// <summary> 2912 /// The width of the border line 2913 /// </summary> 2914 [ 2915 2916 SRCategory("CategoryAttributeAppearance"), 2917 Bindable(true), 2918 DefaultValue(1), 2919 SRDescription("DescriptionAttributeChart_BorderlineWidth"), 2920 #if !Microsoft_CONTROL 2921 PersistenceMode(PersistenceMode.Attribute) 2922 #endif 2923 ] 2924 public int BorderWidth 2925 { 2926 get 2927 { 2928 return _borderWidth; 2929 } 2930 set 2931 { 2932 if(value < 0) 2933 { 2934 throw(new ArgumentOutOfRangeException("value", SR.ExceptionChartBorderIsNegative)); 2935 } 2936 _borderWidth = value; 2937 } 2938 } 2939 2940 /// <summary> 2941 /// The style of the border line 2942 /// </summary> 2943 [ 2944 2945 SRCategory("CategoryAttributeAppearance"), 2946 Bindable(true), 2947 DefaultValue(ChartDashStyle.NotSet), 2948 SRDescription("DescriptionAttributeBorderDashStyle"), 2949 #if !Microsoft_CONTROL 2950 PersistenceMode(PersistenceMode.Attribute) 2951 #endif 2952 ] 2953 public ChartDashStyle BorderDashStyle 2954 { 2955 get 2956 { 2957 return _borderDashStyle; 2958 } 2959 set 2960 { 2961 _borderDashStyle = value; 2962 } 2963 } 2964 2965 /// <summary> 2966 /// Gets the font cache. 2967 /// </summary> 2968 /// <value>The font cache.</value> 2969 internal FontCache FontCache 2970 { 2971 get { return _fontCache; } 2972 } 2973 2974 #endregion 2975 2976 #region Chart areas alignment methods 2977 2978 /// <summary> 2979 /// Checks if any of the chart areas are aligned. 2980 /// Also checks if the chart ares name in AlignWithChartArea property is valid. 2981 /// </summary> 2982 /// <returns>True if at least one area requires alignment.</returns> IsAreasAlignmentRequired()2983 private bool IsAreasAlignmentRequired() 2984 { 2985 bool alignmentRequired = false; 2986 2987 // Loop through all chart areas 2988 foreach(ChartArea area in this.ChartAreas) 2989 { 2990 2991 // Check if chart area is visible 2992 if(area.Visible) 2993 2994 { 2995 // Check if area is aligned 2996 if (area.AlignWithChartArea != Constants.NotSetValue) 2997 { 2998 alignmentRequired = true; 2999 3000 // Check the chart area used for alignment 3001 if (this._chartAreas.IndexOf(area.AlignWithChartArea)<0) 3002 { 3003 throw (new InvalidOperationException(SR.ExceptionChartAreaNameReferenceInvalid(area.Name, area.AlignWithChartArea))); 3004 } 3005 } 3006 } 3007 } 3008 3009 return alignmentRequired; 3010 } 3011 3012 /// <summary> 3013 /// Creates a list of the aligned chart areas. 3014 /// </summary> 3015 /// <param name="masterArea">Master chart area.</param> 3016 /// <param name="type">Alignment type.</param> 3017 /// <param name="orientation">Vertical or Horizontal orientation.</param> 3018 /// <returns>List of areas that area aligned to the master area.</returns> GetAlignedAreasGroup(ChartArea masterArea, AreaAlignmentStyles type, AreaAlignmentOrientations orientation)3019 private ArrayList GetAlignedAreasGroup(ChartArea masterArea, AreaAlignmentStyles type, AreaAlignmentOrientations orientation) 3020 { 3021 ArrayList areaList = new ArrayList(); 3022 3023 // Loop throught the chart areas and get the ones aligned with specified master area 3024 foreach(ChartArea area in this.ChartAreas) 3025 { 3026 3027 // Check if chart area is visible 3028 if(area.Visible) 3029 3030 { 3031 if(area.Name != masterArea.Name && 3032 area.AlignWithChartArea == masterArea.Name && 3033 (area.AlignmentStyle & type) == type && 3034 (area.AlignmentOrientation & orientation) == orientation ) 3035 { 3036 // Add "slave" area into the list 3037 areaList.Add(area); 3038 } 3039 } 3040 } 3041 3042 // If list is not empty insert "master" area in the beginning 3043 if(areaList.Count > 0) 3044 { 3045 areaList.Insert(0, masterArea); 3046 } 3047 3048 return areaList; 3049 } 3050 3051 /// <summary> 3052 /// Performs specified type of alignment for the chart areas. 3053 /// </summary> 3054 /// <param name="type">Alignment type required.</param> AlignChartAreas(AreaAlignmentStyles type)3055 internal void AlignChartAreas(AreaAlignmentStyles type) 3056 { 3057 // Check if alignment required 3058 if(IsAreasAlignmentRequired()) 3059 { 3060 // Loop through all chart areas 3061 foreach(ChartArea area in this.ChartAreas) 3062 { 3063 3064 // Check if chart area is visible 3065 if(area.Visible) 3066 3067 { 3068 // Get vertical areas alignment group using current area as a master 3069 ArrayList alignGroup = GetAlignedAreasGroup( 3070 area, 3071 type, 3072 AreaAlignmentOrientations.Vertical); 3073 3074 // Align each area in the group 3075 if(alignGroup.Count > 0) 3076 { 3077 AlignChartAreasPlotPosition(alignGroup, AreaAlignmentOrientations.Vertical); 3078 } 3079 3080 // Get horizontal areas alignment group using current area as a master 3081 alignGroup = GetAlignedAreasGroup( 3082 area, 3083 type, 3084 AreaAlignmentOrientations.Horizontal); 3085 3086 // Align each area in the group 3087 if(alignGroup.Count > 0) 3088 { 3089 AlignChartAreasPlotPosition(alignGroup, AreaAlignmentOrientations.Horizontal); 3090 } 3091 } 3092 } 3093 } 3094 } 3095 3096 /// <summary> 3097 /// Align inner plot position of the chart areas in the group. 3098 /// </summary> 3099 /// <param name="areasGroup">List of areas in the group.</param> 3100 /// <param name="orientation">Group orientation.</param> AlignChartAreasPlotPosition(ArrayList areasGroup, AreaAlignmentOrientations orientation)3101 private void AlignChartAreasPlotPosition(ArrayList areasGroup, AreaAlignmentOrientations orientation) 3102 { 3103 //**************************************************************** 3104 //** Find the smalles size of the inner plot 3105 //**************************************************************** 3106 RectangleF areaPlotPosition = ((ChartArea)areasGroup[0]).PlotAreaPosition.ToRectangleF(); 3107 foreach(ChartArea area in areasGroup) 3108 { 3109 if(area.PlotAreaPosition.X > areaPlotPosition.X) 3110 { 3111 areaPlotPosition.X += area.PlotAreaPosition.X - areaPlotPosition.X; 3112 areaPlotPosition.Width -= area.PlotAreaPosition.X - areaPlotPosition.X; 3113 } 3114 if(area.PlotAreaPosition.Y > areaPlotPosition.Y) 3115 { 3116 areaPlotPosition.Y += area.PlotAreaPosition.Y - areaPlotPosition.Y; 3117 areaPlotPosition.Height -= area.PlotAreaPosition.Y - areaPlotPosition.Y; 3118 } 3119 if(area.PlotAreaPosition.Right < areaPlotPosition.Right) 3120 { 3121 areaPlotPosition.Width -= areaPlotPosition.Right - area.PlotAreaPosition.Right; 3122 if(areaPlotPosition.Width < 5) 3123 { 3124 areaPlotPosition.Width = 5; 3125 } 3126 } 3127 if(area.PlotAreaPosition.Bottom < areaPlotPosition.Bottom) 3128 { 3129 areaPlotPosition.Height -= areaPlotPosition.Bottom - area.PlotAreaPosition.Bottom; 3130 if(areaPlotPosition.Height < 5) 3131 { 3132 areaPlotPosition.Height = 5; 3133 } 3134 } 3135 } 3136 3137 //**************************************************************** 3138 //** Align inner plot position for all areas 3139 //**************************************************************** 3140 foreach(ChartArea area in areasGroup) 3141 { 3142 // Get curretn plot position of the area 3143 RectangleF rect = area.PlotAreaPosition.ToRectangleF(); 3144 3145 // Adjust area position 3146 if( (orientation & AreaAlignmentOrientations.Vertical) == AreaAlignmentOrientations.Vertical) 3147 { 3148 rect.X = areaPlotPosition.X; 3149 rect.Width = areaPlotPosition.Width; 3150 } 3151 if( (orientation & AreaAlignmentOrientations.Horizontal) == AreaAlignmentOrientations.Horizontal) 3152 { 3153 rect.Y = areaPlotPosition.Y; 3154 rect.Height = areaPlotPosition.Height; 3155 } 3156 3157 // Set new plot position in coordinates relative to chart picture 3158 area.PlotAreaPosition.SetPositionNoAuto(rect.X, rect.Y, rect.Width, rect.Height); 3159 3160 // Set new plot position in coordinates relative to chart area position 3161 rect.X = (rect.X - area.Position.X) / area.Position.Width * 100f; 3162 rect.Y = (rect.Y - area.Position.Y) / area.Position.Height * 100f; 3163 rect.Width = rect.Width / area.Position.Width * 100f; 3164 rect.Height = rect.Height / area.Position.Height * 100f; 3165 area.InnerPlotPosition.SetPositionNoAuto(rect.X, rect.Y, rect.Width, rect.Height); 3166 3167 if( (orientation & AreaAlignmentOrientations.Vertical) == AreaAlignmentOrientations.Vertical) 3168 { 3169 area.AxisX2.AdjustLabelFontAtSecondPass(ChartGraph, area.InnerPlotPosition.Auto); 3170 area.AxisX.AdjustLabelFontAtSecondPass(ChartGraph, area.InnerPlotPosition.Auto); 3171 } 3172 if( (orientation & AreaAlignmentOrientations.Horizontal) == AreaAlignmentOrientations.Horizontal) 3173 { 3174 area.AxisY2.AdjustLabelFontAtSecondPass(ChartGraph, area.InnerPlotPosition.Auto); 3175 area.AxisY.AdjustLabelFontAtSecondPass(ChartGraph, area.InnerPlotPosition.Auto); 3176 } 3177 } 3178 3179 } 3180 3181 /// <summary> 3182 /// Aligns positions of the chart areas. 3183 /// </summary> AlignChartAreasPosition()3184 private void AlignChartAreasPosition() 3185 { 3186 // Check if alignment required 3187 if(IsAreasAlignmentRequired()) 3188 { 3189 // Loop through all chart areas 3190 foreach(ChartArea area in this.ChartAreas) 3191 { 3192 3193 // Check if chart area is visible 3194 if(area.Visible) 3195 3196 { 3197 // Check if area is alignd by Position to any other area 3198 if (area.AlignWithChartArea != Constants.NotSetValue && (area.AlignmentStyle & AreaAlignmentStyles.Position) == AreaAlignmentStyles.Position) 3199 { 3200 // Get current area position 3201 RectangleF areaPosition = area.Position.ToRectangleF(); 3202 3203 // Get master chart area 3204 ChartArea masterArea = this.ChartAreas[area.AlignWithChartArea]; 3205 3206 // Vertical alignment 3207 if((area.AlignmentOrientation & AreaAlignmentOrientations.Vertical) == AreaAlignmentOrientations.Vertical) 3208 { 3209 // Align area position 3210 areaPosition.X = masterArea.Position.X; 3211 areaPosition.Width = masterArea.Position.Width; 3212 } 3213 3214 // Horizontal alignment 3215 if((area.AlignmentOrientation & AreaAlignmentOrientations.Horizontal) == AreaAlignmentOrientations.Horizontal) 3216 { 3217 // Align area position 3218 areaPosition.Y = masterArea.Position.Y; 3219 areaPosition.Height = masterArea.Position.Height; 3220 } 3221 3222 // Set new position 3223 area.Position.SetPositionNoAuto(areaPosition.X, areaPosition.Y, areaPosition.Width, areaPosition.Height); 3224 } 3225 } 3226 } 3227 } 3228 } 3229 3230 #if Microsoft_CONTROL 3231 3232 /// <summary> 3233 /// Align chart areas cursor. 3234 /// </summary> 3235 /// <param name="changedArea">Changed chart area.</param> 3236 /// <param name="orientation">Orientation of the changed cursor.</param> 3237 /// <param name="selectionChanged">AxisName of change cursor or selection.</param> AlignChartAreasCursor(ChartArea changedArea, AreaAlignmentOrientations orientation, bool selectionChanged)3238 internal void AlignChartAreasCursor(ChartArea changedArea, AreaAlignmentOrientations orientation, bool selectionChanged) 3239 { 3240 // Check if alignment required 3241 if(IsAreasAlignmentRequired()) 3242 { 3243 // Loop through all chart areas 3244 foreach(ChartArea area in this.ChartAreas) 3245 { 3246 3247 // Check if chart area is visible 3248 if(area.Visible) 3249 3250 { 3251 // Get vertical areas alignment group using current area as a master 3252 ArrayList alignGroup = GetAlignedAreasGroup( 3253 area, 3254 AreaAlignmentStyles.Cursor, 3255 orientation); 3256 3257 // Align each area in the group if it contains changed area 3258 if(alignGroup.Contains(changedArea)) 3259 { 3260 // Set cursor position for all areas in the group 3261 foreach(ChartArea groupArea in alignGroup) 3262 { 3263 groupArea.alignmentInProcess = true; 3264 3265 if(orientation == AreaAlignmentOrientations.Vertical) 3266 { 3267 if(selectionChanged) 3268 { 3269 groupArea.CursorX.SelectionStart = changedArea.CursorX.SelectionStart; 3270 groupArea.CursorX.SelectionEnd = changedArea.CursorX.SelectionEnd; 3271 } 3272 else 3273 { 3274 groupArea.CursorX.Position = changedArea.CursorX.Position; 3275 } 3276 } 3277 if(orientation == AreaAlignmentOrientations.Horizontal) 3278 { 3279 if(selectionChanged) 3280 { 3281 groupArea.CursorY.SelectionStart = changedArea.CursorY.SelectionStart; 3282 groupArea.CursorY.SelectionEnd = changedArea.CursorY.SelectionEnd; 3283 } 3284 else 3285 { 3286 groupArea.CursorY.Position = changedArea.CursorY.Position; 3287 } 3288 } 3289 3290 groupArea.alignmentInProcess = false; 3291 } 3292 } 3293 } 3294 } 3295 } 3296 } 3297 3298 /// <summary> 3299 /// One of the chart areas was zoomed by the user. 3300 /// </summary> 3301 /// <param name="changedArea">Changed chart area.</param> 3302 /// <param name="orientation">Orientation of the changed scaleView.</param> 3303 /// <param name="disposeBufferBitmap">Area double fuffer image must be disposed.</param> AlignChartAreasZoomed(ChartArea changedArea, AreaAlignmentOrientations orientation, bool disposeBufferBitmap)3304 internal void AlignChartAreasZoomed(ChartArea changedArea, AreaAlignmentOrientations orientation, bool disposeBufferBitmap) 3305 { 3306 // Check if alignment required 3307 if(IsAreasAlignmentRequired()) 3308 { 3309 // Loop through all chart areas 3310 foreach(ChartArea area in this.ChartAreas) 3311 { 3312 3313 // Check if chart area is visible 3314 if(area.Visible) 3315 3316 { 3317 // Get vertical areas alignment group using current area as a master 3318 ArrayList alignGroup = GetAlignedAreasGroup( 3319 area, 3320 AreaAlignmentStyles.AxesView, 3321 orientation); 3322 3323 // Align each area in the group if it contains changed area 3324 if(alignGroup.Contains(changedArea)) 3325 { 3326 // Set cursor position for all areas in the group 3327 foreach(ChartArea groupArea in alignGroup) 3328 { 3329 // Clear image buffer 3330 if(groupArea.areaBufferBitmap != null && disposeBufferBitmap) 3331 { 3332 groupArea.areaBufferBitmap.Dispose(); 3333 groupArea.areaBufferBitmap = null; 3334 } 3335 3336 if(orientation == AreaAlignmentOrientations.Vertical) 3337 { 3338 groupArea.CursorX.SelectionStart = double.NaN; 3339 groupArea.CursorX.SelectionEnd = double.NaN; 3340 } 3341 if(orientation == AreaAlignmentOrientations.Horizontal) 3342 { 3343 groupArea.CursorY.SelectionStart = double.NaN; 3344 groupArea.CursorY.SelectionEnd = double.NaN; 3345 } 3346 } 3347 } 3348 } 3349 } 3350 } 3351 } 3352 3353 #endif //Microsoft_CONTROL 3354 3355 /// <summary> 3356 /// Align chart areas axes views. 3357 /// </summary> 3358 /// <param name="changedArea">Changed chart area.</param> 3359 /// <param name="orientation">Orientation of the changed scaleView.</param> AlignChartAreasAxesView(ChartArea changedArea, AreaAlignmentOrientations orientation)3360 internal void AlignChartAreasAxesView(ChartArea changedArea, AreaAlignmentOrientations orientation) 3361 { 3362 // Check if alignment required 3363 if(IsAreasAlignmentRequired()) 3364 { 3365 // Loop through all chart areas 3366 foreach(ChartArea area in this.ChartAreas) 3367 { 3368 3369 // Check if chart area is visible 3370 if(area.Visible) 3371 3372 { 3373 // Get vertical areas alignment group using current area as a master 3374 ArrayList alignGroup = GetAlignedAreasGroup( 3375 area, 3376 AreaAlignmentStyles.AxesView, 3377 orientation); 3378 3379 // Align each area in the group if it contains changed area 3380 if(alignGroup.Contains(changedArea)) 3381 { 3382 // Set cursor position for all areas in the group 3383 foreach(ChartArea groupArea in alignGroup) 3384 { 3385 groupArea.alignmentInProcess = true; 3386 3387 if(orientation == AreaAlignmentOrientations.Vertical) 3388 { 3389 groupArea.AxisX.ScaleView.Position = changedArea.AxisX.ScaleView.Position; 3390 groupArea.AxisX.ScaleView.Size = changedArea.AxisX.ScaleView.Size; 3391 groupArea.AxisX.ScaleView.SizeType = changedArea.AxisX.ScaleView.SizeType; 3392 3393 groupArea.AxisX2.ScaleView.Position = changedArea.AxisX2.ScaleView.Position; 3394 groupArea.AxisX2.ScaleView.Size = changedArea.AxisX2.ScaleView.Size; 3395 groupArea.AxisX2.ScaleView.SizeType = changedArea.AxisX2.ScaleView.SizeType; 3396 } 3397 if(orientation == AreaAlignmentOrientations.Horizontal) 3398 { 3399 groupArea.AxisY.ScaleView.Position = changedArea.AxisY.ScaleView.Position; 3400 groupArea.AxisY.ScaleView.Size = changedArea.AxisY.ScaleView.Size; 3401 groupArea.AxisY.ScaleView.SizeType = changedArea.AxisY.ScaleView.SizeType; 3402 3403 groupArea.AxisY2.ScaleView.Position = changedArea.AxisY2.ScaleView.Position; 3404 groupArea.AxisY2.ScaleView.Size = changedArea.AxisY2.ScaleView.Size; 3405 groupArea.AxisY2.ScaleView.SizeType = changedArea.AxisY2.ScaleView.SizeType; 3406 } 3407 3408 groupArea.alignmentInProcess = false; 3409 } 3410 } 3411 } 3412 } 3413 } 3414 } 3415 3416 #endregion 3417 3418 #region Helper methods 3419 3420 /// <summary> 3421 /// Inspects the chart dimensions. 3422 /// </summary> 3423 /// <param name="width">The width.</param> 3424 /// <param name="height">The height.</param> InspectChartDimensions(int width, int height)3425 internal void InspectChartDimensions(int width, int height) 3426 { 3427 if (this.Chart.IsDesignMode() && ((width * height) > (100 * 1024 *1024))) 3428 { 3429 throw new ArgumentException(SR.ExceptionChartOutOfLimits); 3430 } 3431 if (width < 0) 3432 { 3433 throw new ArgumentException(SR.ExceptionValueMustBeGreaterThan("Width", "0px")); 3434 } 3435 if (height < 0) 3436 { 3437 throw new ArgumentException(SR.ExceptionValueMustBeGreaterThan("Height", "0px")); 3438 } 3439 } 3440 3441 /// <summary> 3442 /// Loads chart appearance template from file. 3443 /// </summary> 3444 /// <param name="name">Template file name to load from.</param> LoadTemplate(string name)3445 public void LoadTemplate(string name) 3446 { 3447 // Check arguments 3448 if (name == null) 3449 throw new ArgumentNullException("name"); 3450 3451 // Load template data into the stream 3452 #if Microsoft_CONTROL 3453 Stream stream = new FileStream(name, FileMode.Open, FileAccess.Read); 3454 #else // Microsoft_CONTROL 3455 Stream stream = LoadTemplateData(name); 3456 #endif // Microsoft_CONTROL 3457 3458 // Load template from stream 3459 LoadTemplate(stream); 3460 3461 // Close tempate stream 3462 stream.Close(); 3463 } 3464 3465 /// <summary> 3466 /// Loads chart appearance template from stream. 3467 /// </summary> 3468 /// <param name="stream">Template stream to load from.</param> LoadTemplate(Stream stream)3469 public void LoadTemplate(Stream stream) 3470 { 3471 // Check arguments 3472 if (stream == null) 3473 throw new ArgumentNullException("stream"); 3474 3475 ChartSerializer serializer = (ChartSerializer)this.Common.container.GetService(typeof(ChartSerializer)); 3476 if (serializer != null) 3477 { 3478 // Save previous serializer properties 3479 string oldSerializableContent = serializer.SerializableContent; 3480 string oldNonSerializableContent = serializer.NonSerializableContent; 3481 SerializationFormat oldFormat = serializer.Format; 3482 bool oldIgnoreUnknownXmlAttributes = serializer.IsUnknownAttributeIgnored; 3483 bool oldTemplateMode = serializer.IsTemplateMode; 3484 3485 // Set serializer properties 3486 serializer.Content = SerializationContents.Appearance; 3487 serializer.SerializableContent += ",Chart.Titles,Chart.Annotations," + 3488 "Chart.Legends,Legend.CellColumns,Legend.CustomItems,LegendItem.Cells," + 3489 "Chart.Series,Series.*Style," + 3490 "Chart.ChartAreas,ChartArea.Axis*," + 3491 "Axis.*Grid,Axis.*TickMark, Axis.*Style," + 3492 "Axis.StripLines, Axis.CustomLabels"; 3493 serializer.Format = SerializationFormat.Xml; 3494 serializer.IsUnknownAttributeIgnored = true; 3495 serializer.IsTemplateMode = true; 3496 3497 try 3498 { 3499 // Load template 3500 serializer.Load(stream); 3501 } 3502 catch (Exception ex) 3503 { 3504 throw (new InvalidOperationException(ex.Message)); 3505 } 3506 finally 3507 { 3508 // Restore previous serializer properties 3509 serializer.SerializableContent = oldSerializableContent; 3510 serializer.NonSerializableContent = oldNonSerializableContent; 3511 serializer.Format = oldFormat; 3512 serializer.IsUnknownAttributeIgnored = oldIgnoreUnknownXmlAttributes; 3513 serializer.IsTemplateMode = oldTemplateMode; 3514 } 3515 } 3516 } 3517 3518 #if !Microsoft_CONTROL 3519 3520 /// <summary> 3521 /// Loads template data from the URL. 3522 /// </summary> 3523 /// <param name="url">Template URL.</param> 3524 /// <returns>Stream with template data or null if error.</returns> LoadTemplateData(string url)3525 private Stream LoadTemplateData(string url) 3526 { 3527 Debug.Assert(url != null, "LoadTemplateData: handed a null url string"); 3528 3529 Stream dataStream = null; 3530 3531 // Try to load as relative URL using the Control object 3532 if(dataStream == null) 3533 { 3534 if (this.Common != null && 3535 this.Common.Chart != null && 3536 this.Common.Chart.Page != null) 3537 { 3538 try 3539 { 3540 dataStream = new FileStream( 3541 this.Common.Chart.Page.MapPath(url), 3542 FileMode.Open); 3543 } 3544 catch (NotSupportedException) 3545 { 3546 dataStream = null; 3547 } 3548 catch (SecurityException) 3549 { 3550 dataStream = null; 3551 } 3552 catch (FileNotFoundException) 3553 { 3554 dataStream = null; 3555 } 3556 catch (DirectoryNotFoundException) 3557 { 3558 dataStream = null; 3559 } 3560 catch (PathTooLongException) 3561 { 3562 dataStream = null; 3563 } 3564 } 3565 } 3566 3567 // Try to load image using the Web Request 3568 if(dataStream == null) 3569 { 3570 Uri templateUri = null; 3571 try 3572 { 3573 // Try to create URI directly from template URL (will work in case of absolute URL) 3574 templateUri = new Uri(url); 3575 } 3576 catch (UriFormatException) 3577 { 3578 templateUri = null; 3579 } 3580 3581 // Make absolute URL using web form document URL 3582 if(templateUri == null) 3583 { 3584 if (this.Common != null && this.Common.Chart != null) 3585 { 3586 string webFormUrl = this.Common.Chart.webFormDocumentURL; 3587 int slashIndex = webFormUrl.LastIndexOf('/'); 3588 if(slashIndex != -1) 3589 { 3590 webFormUrl = webFormUrl.Substring(0, slashIndex + 1); 3591 } 3592 3593 try 3594 { 3595 templateUri = new Uri(new Uri(webFormUrl), url); 3596 } 3597 catch (UriFormatException) 3598 { 3599 templateUri = null; 3600 } 3601 } 3602 } 3603 3604 // Load image from file or web resource 3605 if(templateUri != null) 3606 { 3607 try 3608 { 3609 WebRequest request = WebRequest.Create(templateUri); 3610 dataStream = request.GetResponse().GetResponseStream(); 3611 } 3612 catch (NotSupportedException) 3613 { 3614 dataStream = null; 3615 } 3616 catch (NotImplementedException) 3617 { 3618 dataStream = null; 3619 } 3620 catch (SecurityException) 3621 { 3622 dataStream = null; 3623 } 3624 } 3625 } 3626 3627 // Try to load as file 3628 if(dataStream == null) 3629 { 3630 dataStream = new FileStream(url, FileMode.Open); 3631 } 3632 3633 return dataStream; 3634 } 3635 3636 #endif // Microsoft_CONTROL 3637 3638 3639 3640 #if !Microsoft_CONTROL 3641 3642 3643 /// <summary> 3644 /// Writes chart map tag into the stream. 3645 /// </summary> 3646 /// <param name="output">Html writer to output the data to.</param> 3647 /// <param name="mapName">Chart map name.</param> WriteChartMapTag(HtmlTextWriter output, string mapName)3648 internal void WriteChartMapTag(HtmlTextWriter output, string mapName) 3649 { 3650 output.WriteLine(); 3651 output.AddAttribute(HtmlTextWriterAttribute.Name, mapName); 3652 output.AddAttribute(HtmlTextWriterAttribute.Id, mapName); 3653 output.RenderBeginTag(HtmlTextWriterTag.Map); 3654 3655 //**************************************************** 3656 //** Fire map areas customize event 3657 //**************************************************** 3658 3659 // Make sure only non-custom items are passed into the event handler 3660 MapAreasCollection custCollection = new MapAreasCollection(); 3661 3662 // Move all non-custom items 3663 for (int index = 0; index < _mapAreas.Count; index++) 3664 { 3665 if (!_mapAreas[index].IsCustom) 3666 { 3667 custCollection.Add(_mapAreas[index]); 3668 _mapAreas.RemoveAt(index); 3669 --index; 3670 } 3671 } 3672 3673 // Call a notification event, so that area items collection can be modified by user 3674 Common.Chart.CallOnCustomizeMapAreas(custCollection); 3675 3676 // Add customized items 3677 foreach(MapArea area in custCollection) 3678 { 3679 area.IsCustom = false; 3680 _mapAreas.Add(area); 3681 } 3682 3683 //**************************************************** 3684 //** Add all map areas 3685 //**************************************************** 3686 foreach (MapArea area in _mapAreas) 3687 { 3688 area.RenderTag(output, this.Common.Chart); 3689 } 3690 // if this procedure is enforced to run the image maps have to have at least one map area. 3691 if (_mapAreas.Count == 0) 3692 { 3693 output.Write("<area shape=\"rect\" coords=\"0,0,0,0\" alt=\"\" />"); 3694 } 3695 3696 //**************************************************** 3697 //** End of the map 3698 //**************************************************** 3699 output.RenderEndTag(); 3700 3701 return; 3702 } 3703 3704 #endif 3705 3706 /// <summary> 3707 /// Returns the default title from Titles collection. 3708 /// </summary> 3709 /// <param name="create">Create title if it doesn't exists.</param> 3710 /// <returns>Default title.</returns> GetDefaultTitle(bool create)3711 internal Title GetDefaultTitle(bool create) 3712 { 3713 // Check if default title exists 3714 Title defaultTitle = null; 3715 foreach(Title title in this.Titles) 3716 { 3717 if(title.Name == "Default Title") 3718 { 3719 defaultTitle = title; 3720 } 3721 } 3722 3723 // Create new default title 3724 if(defaultTitle == null && create) 3725 { 3726 defaultTitle = new Title(); 3727 defaultTitle.Name = "Default Title"; 3728 this.Titles.Insert(0, defaultTitle); 3729 } 3730 3731 return defaultTitle; 3732 } 3733 3734 /// <summary> 3735 /// Checks if tooltips are enabled 3736 /// </summary> 3737 /// <returns>true if tooltips enabled</returns> IsToolTipsEnabled()3738 private bool IsToolTipsEnabled() 3739 { 3740 3741 // Data series loop 3742 foreach( Series series in Common.DataManager.Series ) 3743 { 3744 // Check series tooltips 3745 if( series.ToolTip.Length > 0) 3746 { 3747 // ToolTips enabled 3748 return true; 3749 } 3750 3751 // Check series tooltips 3752 if( series.LegendToolTip.Length > 0 || 3753 series.LabelToolTip.Length > 0) 3754 { 3755 // ToolTips enabled 3756 return true; 3757 } 3758 3759 // Check point tooltips only for "non-Fast" chart types 3760 if( !series.IsFastChartType() ) 3761 { 3762 // Data point loop 3763 foreach( DataPoint point in series.Points ) 3764 { 3765 // ToolTip empty 3766 if( point.ToolTip.Length > 0) 3767 { 3768 // ToolTips enabled 3769 return true; 3770 } 3771 // ToolTip empty 3772 if( point.LegendToolTip.Length > 0 || 3773 point.LabelToolTip.Length > 0) 3774 { 3775 // ToolTips enabled 3776 return true; 3777 } 3778 } 3779 } 3780 } 3781 3782 // Legend items loop 3783 foreach( Legend legend in Legends ) 3784 { 3785 foreach( LegendItem legendItem in legend.CustomItems ) 3786 { 3787 // ToolTip empty 3788 if( legendItem.ToolTip.Length > 0 ) 3789 { 3790 return true; 3791 } 3792 } 3793 } 3794 3795 // Title items loop 3796 foreach( Title title in Titles ) 3797 { 3798 // ToolTip empty 3799 if( title.ToolTip.Length > 0 ) 3800 { 3801 return true; 3802 } 3803 } 3804 3805 return false; 3806 } 3807 3808 #endregion 3809 3810 #region IDisposable Members 3811 /// <summary> 3812 /// Releases unmanaged and - optionally - managed resources 3813 /// </summary> 3814 /// <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)3815 protected override void Dispose(bool disposing) 3816 { 3817 if (disposing) 3818 { 3819 // Dispose managed resources 3820 if (ChartGraph != null) 3821 { 3822 ChartGraph.Dispose(); 3823 ChartGraph = null; 3824 } 3825 if (_legends != null) 3826 { 3827 _legends.Dispose(); 3828 _legends = null; 3829 } 3830 if (_titles != null) 3831 { 3832 _titles.Dispose(); 3833 _titles = null; 3834 } 3835 if (_chartAreas != null) 3836 { 3837 _chartAreas.Dispose(); 3838 _chartAreas = null; 3839 } 3840 if (_annotations != null) 3841 { 3842 _annotations.Dispose(); 3843 _annotations = null; 3844 } 3845 if (hotRegionsList != null) 3846 { 3847 hotRegionsList.Dispose(); 3848 hotRegionsList = null; 3849 } 3850 if (_fontCache != null) 3851 { 3852 _fontCache.Dispose(); 3853 _fontCache = null; 3854 } 3855 if (_borderSkin != null) 3856 { 3857 _borderSkin.Dispose(); 3858 _borderSkin = null; 3859 } 3860 #if ! Microsoft_CONTROL 3861 if (_mapAreas != null) 3862 { 3863 _mapAreas.Dispose(); 3864 _mapAreas = null; 3865 } 3866 #endif 3867 3868 #if Microsoft_CONTROL 3869 if (nonTopLevelChartBuffer != null) 3870 { 3871 nonTopLevelChartBuffer.Dispose(); 3872 nonTopLevelChartBuffer = null; 3873 } 3874 #endif 3875 } 3876 base.Dispose(disposing); 3877 } 3878 3879 #endregion 3880 } 3881 3882 /// <summary> 3883 /// Event arguments of Chart paint event. 3884 /// </summary> 3885 #if ASPPERM_35 3886 [AspNetHostingPermission(System.Security.Permissions.SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)] 3887 [AspNetHostingPermission(System.Security.Permissions.SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)] 3888 #endif 3889 public class ChartPaintEventArgs : EventArgs 3890 { 3891 #region Fields 3892 3893 // Private fields 3894 private object _chartElement = null; 3895 private ChartGraphics _chartGraph = null; 3896 private CommonElements _common = null; 3897 private Chart _chart = null; 3898 private ElementPosition _position = null; 3899 3900 #endregion 3901 3902 #region Properties 3903 3904 3905 /// <summary> 3906 /// Gets the chart element of the event. 3907 /// </summary> 3908 /// <value>The chart element.</value> 3909 public object ChartElement 3910 { 3911 get 3912 { 3913 return _chartElement; 3914 } 3915 } 3916 3917 3918 /// <summary> 3919 /// Gets the ChartGraphics object of the event. 3920 /// </summary> 3921 public ChartGraphics ChartGraphics 3922 { 3923 get 3924 { 3925 return _chartGraph; 3926 } 3927 } 3928 3929 /// <summary> 3930 /// Chart Common elements. 3931 /// </summary> 3932 internal CommonElements CommonElements 3933 { 3934 get 3935 { 3936 return _common; 3937 } 3938 } 3939 3940 /// <summary> 3941 /// Chart element position in relative coordinates of the event. 3942 /// </summary> 3943 public ElementPosition Position 3944 { 3945 get 3946 { 3947 return _position; 3948 } 3949 } 3950 3951 /// <summary> 3952 /// Chart object of the event. 3953 /// </summary> 3954 public Chart Chart 3955 { 3956 get 3957 { 3958 if (_chart == null && _common != null) 3959 { 3960 _chart = _common.Chart; 3961 } 3962 3963 return _chart; 3964 } 3965 } 3966 3967 #endregion 3968 3969 #region Methods 3970 3971 /// <summary> 3972 /// Default constructor is not accessible 3973 /// </summary> ChartPaintEventArgs()3974 private ChartPaintEventArgs() 3975 { 3976 } 3977 3978 /// <summary> 3979 /// Paint event arguments constructor. 3980 /// </summary> 3981 /// <param name="chartElement">Chart element.</param> 3982 /// <param name="chartGraph">Chart graphics.</param> 3983 /// <param name="common">Common elements.</param> 3984 /// <param name="position">Position.</param> ChartPaintEventArgs(object chartElement, ChartGraphics chartGraph, CommonElements common, ElementPosition position)3985 internal ChartPaintEventArgs(object chartElement, ChartGraphics chartGraph, CommonElements common, ElementPosition position) 3986 { 3987 this._chartElement = chartElement; 3988 this._chartGraph = chartGraph; 3989 this._common = common; 3990 this._position = position; 3991 } 3992 3993 #endregion 3994 } 3995 3996 /// <summary> 3997 /// Event arguments of localized numbers formatting event. 3998 /// </summary> 3999 #if ASPPERM_35 4000 [AspNetHostingPermission(System.Security.Permissions.SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)] 4001 [AspNetHostingPermission(System.Security.Permissions.SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)] 4002 #endif 4003 public class FormatNumberEventArgs : EventArgs 4004 { 4005 #region Fields 4006 4007 // Private fields 4008 private double _value; 4009 private string _format; 4010 private string _localizedValue; 4011 private ChartValueType _valueType = ChartValueType.Auto; 4012 private object _senderTag; 4013 private ChartElementType _elementType = ChartElementType.Nothing; 4014 4015 #endregion 4016 4017 #region Properties 4018 4019 /// <summary> 4020 /// Value to be formatted. 4021 /// </summary> 4022 public double Value 4023 { 4024 get { return this._value; } 4025 } 4026 4027 /// <summary> 4028 /// Localized text. 4029 /// </summary> 4030 public string LocalizedValue 4031 { 4032 get { return _localizedValue; } 4033 set { _localizedValue = value; } 4034 } 4035 4036 /// <summary> 4037 /// Format string. 4038 /// </summary> 4039 public string Format 4040 { 4041 get { return _format; } 4042 } 4043 4044 /// <summary> 4045 /// Value type. 4046 /// </summary> 4047 public ChartValueType ValueType 4048 { 4049 get { return _valueType; } 4050 } 4051 4052 /// <summary> 4053 /// The sender object of the event. 4054 /// </summary> 4055 public object SenderTag 4056 { 4057 get { return _senderTag; } 4058 } 4059 4060 /// <summary> 4061 /// Chart element type. 4062 /// </summary> 4063 public ChartElementType ElementType 4064 { 4065 get { return _elementType; } 4066 } 4067 4068 #endregion 4069 4070 #region Methods 4071 4072 /// <summary> 4073 /// Default constructor is not accessible 4074 /// </summary> FormatNumberEventArgs()4075 private FormatNumberEventArgs() 4076 { 4077 } 4078 4079 /// <summary> 4080 /// Object constructor. 4081 /// </summary> 4082 /// <param name="value">Value to be formatted.</param> 4083 /// <param name="format">Format string.</param> 4084 /// <param name="valueType">Value type..</param> 4085 /// <param name="localizedValue">Localized value.</param> 4086 /// <param name="senderTag">Chart element object tag.</param> 4087 /// <param name="elementType">Chart element type.</param> FormatNumberEventArgs(double value, string format, ChartValueType valueType, string localizedValue, object senderTag, ChartElementType elementType)4088 internal FormatNumberEventArgs(double value, string format, ChartValueType valueType, string localizedValue, object senderTag, ChartElementType elementType) 4089 { 4090 this._value = value; 4091 this._format = format; 4092 this._valueType = valueType; 4093 this._localizedValue = localizedValue; 4094 this._senderTag = senderTag; 4095 this._elementType = elementType; 4096 } 4097 4098 #endregion 4099 } 4100 4101 #region FontCache 4102 /// <summary> 4103 /// Font cache class helps ChartElements to reuse the Font instances 4104 /// </summary> 4105 internal class FontCache : IDisposable 4106 { 4107 #region Static 4108 4109 // Default font family name 4110 private static string _defaultFamilyName; 4111 4112 /// <summary> 4113 /// Gets the default font family name. 4114 /// </summary> 4115 /// <value>The default font family name.</value> 4116 public static string DefaultFamilyName 4117 { 4118 get 4119 { 4120 if (_defaultFamilyName == null) 4121 { 4122 // Find the "Microsoft Sans Serif" font 4123 foreach (FontFamily fontFamily in FontFamily.Families) 4124 { 4125 if (fontFamily.Name == "Microsoft Sans Serif") 4126 { 4127 _defaultFamilyName = fontFamily.Name; 4128 break; 4129 } 4130 } 4131 // Not found - use the default Sans Serif font 4132 if (_defaultFamilyName == null) 4133 { 4134 _defaultFamilyName = FontFamily.GenericSansSerif.Name; 4135 } 4136 } 4137 return _defaultFamilyName; 4138 } 4139 } 4140 #endregion 4141 4142 #region Fields 4143 4144 // Cached fonts dictionary 4145 private Dictionary<KeyInfo, Font> _fontCache = new Dictionary<KeyInfo, Font>(new KeyInfo.EqualityComparer()); 4146 4147 #endregion // Fields 4148 4149 #region Properties 4150 /// <summary> 4151 /// Gets the default font. 4152 /// </summary> 4153 /// <value>The default font.</value> 4154 public Font DefaultFont 4155 { 4156 get { return this.GetFont(DefaultFamilyName, 8); } 4157 } 4158 4159 /// <summary> 4160 /// Gets the default font. 4161 /// </summary> 4162 /// <value>The default font.</value> 4163 public Font DefaultBoldFont 4164 { 4165 get { return this.GetFont(DefaultFamilyName, 8, FontStyle.Bold); } 4166 } 4167 #endregion 4168 4169 #region Methods 4170 4171 /// <summary> 4172 /// Gets the font. 4173 /// </summary> 4174 /// <param name="familyName">Name of the family.</param> 4175 /// <param name="size">The size.</param> 4176 /// <returns>Font instance</returns> GetFont(string familyName, int size)4177 public Font GetFont(string familyName, int size) 4178 { 4179 KeyInfo key = new KeyInfo(familyName, size); 4180 if (!this._fontCache.ContainsKey(key)) 4181 { 4182 this._fontCache.Add(key, new Font(familyName, size)); 4183 } 4184 return this._fontCache[key]; 4185 } 4186 4187 /// <summary> 4188 /// Gets the font. 4189 /// </summary> 4190 /// <param name="familyName">Name of the family.</param> 4191 /// <param name="size">The size.</param> 4192 /// <param name="style">The style.</param> 4193 /// <returns>Font instance</returns> GetFont(string familyName, float size, FontStyle style)4194 public Font GetFont(string familyName, float size, FontStyle style) 4195 { 4196 KeyInfo key = new KeyInfo(familyName, size, style); 4197 if (!this._fontCache.ContainsKey(key)) 4198 { 4199 this._fontCache.Add(key, new Font(familyName, size, style)); 4200 } 4201 return this._fontCache[key]; 4202 } 4203 4204 /// <summary> 4205 /// Gets the font. 4206 /// </summary> 4207 /// <param name="family">The family.</param> 4208 /// <param name="size">The size.</param> 4209 /// <param name="style">The style.</param> 4210 /// <returns>Font instance</returns> GetFont(FontFamily family, float size, FontStyle style)4211 public Font GetFont(FontFamily family, float size, FontStyle style) 4212 { 4213 KeyInfo key = new KeyInfo(family, size, style); 4214 if (!this._fontCache.ContainsKey(key)) 4215 { 4216 this._fontCache.Add(key, new Font(family, size, style)); 4217 } 4218 return this._fontCache[key]; 4219 } 4220 4221 /// <summary> 4222 /// Gets the font. 4223 /// </summary> 4224 /// <param name="family">The family.</param> 4225 /// <param name="size">The size.</param> 4226 /// <param name="style">The style.</param> 4227 /// <param name="unit">The unit.</param> 4228 /// <returns>Font instance</returns> GetFont(FontFamily family, float size, FontStyle style, GraphicsUnit unit)4229 public Font GetFont(FontFamily family, float size, FontStyle style, GraphicsUnit unit) 4230 { 4231 KeyInfo key = new KeyInfo(family, size, style, unit); 4232 if (!this._fontCache.ContainsKey(key)) 4233 { 4234 this._fontCache.Add(key, new Font(family, size, style, unit)); 4235 } 4236 return this._fontCache[key]; 4237 } 4238 4239 #endregion 4240 4241 #region IDisposable Members 4242 4243 /// <summary> 4244 /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. 4245 /// </summary> Dispose()4246 public void Dispose() 4247 { 4248 foreach (Font font in _fontCache.Values) 4249 { 4250 font.Dispose(); 4251 } 4252 _fontCache.Clear(); 4253 GC.SuppressFinalize(this); 4254 } 4255 4256 #endregion 4257 4258 #region FontKeyInfo struct 4259 /// <summary> 4260 /// Font key info 4261 /// </summary> 4262 private class KeyInfo 4263 { 4264 string _familyName; 4265 float _size = 8; 4266 GraphicsUnit _unit = GraphicsUnit.Point; 4267 FontStyle _style = FontStyle.Regular; 4268 int _gdiCharSet = 1; 4269 4270 /// <summary> 4271 /// Initializes a new instance of the <see cref="KeyInfo"/> class. 4272 /// </summary> 4273 /// <param name="familyName">Name of the family.</param> 4274 /// <param name="size">The size.</param> KeyInfo(string familyName, float size)4275 public KeyInfo(string familyName, float size) 4276 { 4277 this._familyName = familyName; 4278 this._size = size; 4279 } 4280 /// <summary> 4281 /// Initializes a new instance of the <see cref="KeyInfo"/> class. 4282 /// </summary> 4283 /// <param name="familyName">Name of the family.</param> 4284 /// <param name="size">The size.</param> 4285 /// <param name="style">The style.</param> KeyInfo(string familyName, float size, FontStyle style)4286 public KeyInfo(string familyName, float size, FontStyle style) 4287 { 4288 this._familyName = familyName; 4289 this._size = size; 4290 this._style = style; 4291 } 4292 /// <summary> 4293 /// Initializes a new instance of the <see cref="KeyInfo"/> class. 4294 /// </summary> 4295 /// <param name="family">The family.</param> 4296 /// <param name="size">The size.</param> 4297 /// <param name="style">The style.</param> KeyInfo(FontFamily family, float size, FontStyle style)4298 public KeyInfo(FontFamily family, float size, FontStyle style) 4299 { 4300 this._familyName = family.ToString(); 4301 this._size = size; 4302 this._style = style; 4303 } 4304 /// <summary> 4305 /// Initializes a new instance of the <see cref="KeyInfo"/> class. 4306 /// </summary> 4307 /// <param name="family">The family.</param> 4308 /// <param name="size">The size.</param> 4309 /// <param name="style">The style.</param> 4310 /// <param name="unit">The unit.</param> KeyInfo(FontFamily family, float size, FontStyle style, GraphicsUnit unit)4311 public KeyInfo(FontFamily family, float size, FontStyle style, GraphicsUnit unit) 4312 { 4313 this._familyName = family.ToString(); 4314 this._size = size; 4315 this._style = style; 4316 this._unit = unit; 4317 } 4318 4319 #region IEquatable<FontKeyInfo> Members 4320 /// <summary> 4321 /// KeyInfo equality comparer 4322 /// </summary> 4323 internal class EqualityComparer : IEqualityComparer<KeyInfo> 4324 { 4325 /// <summary> 4326 /// Determines whether the specified objects are equal. 4327 /// </summary> 4328 /// <param name="x">The first object of type <paramref name="x"/> to compare.</param> 4329 /// <param name="y">The second object of type <paramref name="y"/> to compare.</param> 4330 /// <returns> 4331 /// true if the specified objects are equal; otherwise, false. 4332 /// </returns> Equals(KeyInfo x, KeyInfo y)4333 public bool Equals(KeyInfo x, KeyInfo y) 4334 { 4335 return 4336 x._size == y._size && 4337 x._familyName == y._familyName && 4338 x._unit == y._unit && 4339 x._style == y._style && 4340 x._gdiCharSet == y._gdiCharSet; 4341 } 4342 4343 /// <summary> 4344 /// Returns a hash code for the specified object. 4345 /// </summary> 4346 /// <param name="obj">The <see cref="T:System.Object"/> for which a hash code is to be returned.</param> 4347 /// <returns>A hash code for the specified object.</returns> 4348 /// <exception cref="T:System.ArgumentNullException">The type of <paramref name="obj"/> is a reference type and <paramref name="obj"/> is null.</exception> GetHashCode(KeyInfo obj)4349 public int GetHashCode(KeyInfo obj) 4350 { 4351 return obj._familyName.GetHashCode() ^ obj._size.GetHashCode(); 4352 } 4353 } 4354 #endregion 4355 } 4356 #endregion 4357 } 4358 #endregion 4359 4360 4361 } 4362