1//////////////////////////////////////////////////////////////////////////////// 2// 3// ADOBE SYSTEMS INCORPORATED 4// Copyright 2009 Adobe Systems Incorporated 5// All Rights Reserved. 6// 7// NOTICE: Adobe permits you to use, modify, and distribute this file 8// in accordance with the terms of the license agreement accompanying it. 9// 10//////////////////////////////////////////////////////////////////////////////// 11 12package mx.charts 13{ 14 15import flash.display.Graphics; 16import flash.geom.Rectangle; 17 18import mx.charts.chartClasses.CartesianChart; 19import mx.charts.chartClasses.ChartElement; 20import mx.charts.chartClasses.ChartState; 21import mx.charts.chartClasses.GraphicsUtilities; 22import mx.charts.chartClasses.IAxisRenderer; 23import mx.charts.styles.HaloDefaults; 24import mx.core.IFlexModuleFactory; 25import mx.core.mx_internal; 26import mx.graphics.IFill; 27import mx.graphics.IStroke; 28import mx.graphics.SolidColorStroke; 29import mx.graphics.Stroke; 30import mx.styles.CSSStyleDeclaration; 31 32use namespace mx_internal; 33 34//-------------------------------------- 35// Styles 36//-------------------------------------- 37 38/** 39 * Specifies the direction of the grid lines. 40 * Allowable values are <code>horizontal</code>, 41 * <code>vertical</code>, or <code>both</code>. 42 * The default value is <code>horizontal</code>. 43 * 44 * @langversion 3.0 45 * @playerversion Flash 9 46 * @playerversion AIR 1.1 47 * @productversion Flex 3 48 */ 49[Style(name="gridDirection", type="String", enumeration="horizontal,vertical,both", inherit="no")] 50 51/** 52 * Specifies the fill pattern for alternating horizontal bands 53 * not defined by the <code>fill</code> property. 54 * Use the IFill class to define the properties of the fill 55 * as a child tag in MXML, or create an IFill object in ActionScript. 56 * Set to <code>null</code> to not fill the bands. 57 * The default value is <code>null</code>. 58 * 59 * @langversion 3.0 60 * @playerversion Flash 9 61 * @playerversion AIR 1.1 62 * @productversion Flex 3 63 */ 64[Style(name="horizontalAlternateFill", type="mx.graphics.IFill", inherit="no")] 65 66/** 67 * Specifies the number of tick marks between horizontal grid lines. 68 * Set the <code>horizontalChangeCount</code> property to 3 69 * to draw a grid line at every third tick mark along the axis. 70 * The fill style alternates at each grid line, so a larger 71 * <code>horizontalChangeCount</code> value results 72 * in large alternating bands. 73 * The defaults value is <code>1</code>. 74 * 75 * @langversion 3.0 76 * @playerversion Flash 9 77 * @playerversion AIR 1.1 78 * @productversion Flex 3 79 */ 80[Style(name="horizontalChangeCount", type="int", inherit="no")] 81 82/** 83 * Specifies the fill pattern for every other horizontal band 84 * created by the grid lines. 85 * Use the IFill class to define the properties of the fill 86 * as a child tag in MXML, or create a IFill object in ActionScript. 87 * Set to <code>null</code> to not fill the bands. 88 * The default value is <code>null</code>. 89 * 90 * @langversion 3.0 91 * @playerversion Flash 9 92 * @playerversion AIR 1.1 93 * @productversion Flex 3 94 */ 95[Style(name="horizontalFill", type="mx.graphics.IFill", inherit="no")] 96 97/** 98 * Specifies the line style for the horizontal origin. 99 * Use the Stroke class to define the properties as a child tag in MXML, 100 * or create a Stroke object in ActionScript. 101 * 102 * @langversion 3.0 103 * @playerversion Flash 9 104 * @playerversion AIR 1.1 105 * @productversion Flex 3 106 */ 107[Style(name="horizontalOriginStroke", type="mx.graphics.IStroke", inherit="no")] 108 109/** 110 * Determines whether to draw the horizontal origin. 111 * If <code>true</code>, and the origin falls within the chart bounds, 112 * the grid lines draw it using the <code>horizontalOriginStroke</code> style. 113 * For ColumnChart, LineChart, PlotChart, BubbleChart, and AreaChart 114 * controls, the default value is <code>true</code>. 115 * For BarChart controls, the default value is <code>false</code>. 116 * This property does not apply to PieChart controls. 117 * 118 * @langversion 3.0 119 * @playerversion Flash 9 120 * @playerversion AIR 1.1 121 * @productversion Flex 3 122 */ 123[Style(name="horizontalShowOrigin", type="Boolean", inherit="no")] 124 125/** 126 * Specifies the line style for horizontal grid lines. 127 * Use the Stroke class to define the properties as a child tag in MXML, 128 * or create a Stroke object in ActionScript. 129 * 130 * @langversion 3.0 131 * @playerversion Flash 9 132 * @playerversion AIR 1.1 133 * @productversion Flex 3 134 */ 135[Style(name="horizontalStroke", type="mx.graphics.IStroke", inherit="no")] 136 137/** 138 * Determines whether to align horizontal grid lines with tick marks. 139 * If <code>true</code>, horizontal grid lines are drawn aligned 140 * with the tick marks. 141 * If <code>false</code>, Flex draws them between tick marks. 142 * The default value is <code>true</code>. 143 * 144 * @langversion 3.0 145 * @playerversion Flash 9 146 * @playerversion AIR 1.1 147 * @productversion Flex 3 148 */ 149[Style(name="horizontalTickAligned", type="Boolean", inherit="no")] 150 151/** 152 * Specifies the fill pattern for alternating vertical bands 153 * not defined by the fill property. 154 * Use the IFill class to define the properties of the fill 155 * as a child tag in MXML, or create an IFill object in ActionScript. 156 * Set to <code>null</code> to not fill the bands. 157 * The default value is <code>null</code>. 158 * 159 * @langversion 3.0 160 * @playerversion Flash 9 161 * @playerversion AIR 1.1 162 * @productversion Flex 3 163 */ 164[Style(name="verticalAlternateFill", type="mx.graphics.IFill", inherit="no")] 165 166/** 167 * Specifies the number of tick marks between vertical grid lines. 168 * Set <code>verticalChangeCount</code> to <code>3</code> 169 * to draw a grid line at every third tick mark along the axis. 170 * The fill style alternates at each grid line, so a larger 171 * <code>verticalChangeCount</code> value results in large alternating bands. 172 * The default value is <code>1</code>. 173 * 174 * @langversion 3.0 175 * @playerversion Flash 9 176 * @playerversion AIR 1.1 177 * @productversion Flex 3 178 */ 179[Style(name="verticalChangeCount", type="int", inherit="no")] 180 181/** 182 * Specifies the fill pattern for alternating vertical bands 183 * created by the grid lines. 184 * Use the IFill class to define the properties of the fill 185 * as a child tag in MXML, or create a IFill object in ActionScript. 186 * Set to <code>null</code> to not fill the bands. 187 * The default value is <code>null</code>. 188 * 189 * @langversion 3.0 190 * @playerversion Flash 9 191 * @playerversion AIR 1.1 192 * @productversion Flex 3 193 */ 194[Style(name="verticalFill", type="mx.graphics.IFill", inherit="no")] 195 196/** 197 * Specifies the line style for the vertical origin. 198 * Use the Stroke class to define the properties as a child tag in MXML, 199 * or create a Stroke object in ActionScript. 200 * 201 * @langversion 3.0 202 * @playerversion Flash 9 203 * @playerversion AIR 1.1 204 * @productversion Flex 3 205 */ 206[Style(name="verticalOriginStroke", type="mx.graphics.IStroke", inherit="no")] 207 208/** 209 * Determines whether to draw the vertical Origin. 210 * If <code>true</code>, and the origin falls within the chart bounds, 211 * Flex draws it using the <code>verticalOriginStroke</code> style. 212 * For ColumnChart, LineChart, and AreaChart controls, 213 * the default value is <code>false</code>. 214 * For PlotChart, BubbleChart, and BarChart controls, 215 * the default value is <code>true</code>. 216 * This property does not apply to PieChart controls. 217 * 218 * @langversion 3.0 219 * @playerversion Flash 9 220 * @playerversion AIR 1.1 221 * @productversion Flex 3 222 */ 223[Style(name="verticalShowOrigin", type="Boolean", inherit="no")] 224 225/** 226 * Specifies the line style for vertical grid lines. 227 * Use the Stroke class to define the properties as a child tag in MXML, 228 * or create a Stroke object in ActionScript. 229 * 230 * @langversion 3.0 231 * @playerversion Flash 9 232 * @playerversion AIR 1.1 233 * @productversion Flex 3 234 */ 235[Style(name="verticalStroke", type="mx.graphics.IStroke", inherit="no")] 236 237/** 238 * Determines whether to align vertical grid lines with tick marks. 239 * If <code>true</code>, Flex draws vertical grid lines aligned 240 * with the tick marks. 241 * If <code>false</code>, Flex draws them between tick marks. 242 * The default value is <code>true</code>. 243 * 244 * @langversion 3.0 245 * @playerversion Flash 9 246 * @playerversion AIR 1.1 247 * @productversion Flex 3 248 */ 249[Style(name="verticalTickAligned", type="Boolean", inherit="no")] 250 251/** 252 * The GridLines class draws grid lines inside the data area of the chart. 253 * Flex can draw lines horizontally, vertically, or both. 254 * 255 * <p>Flex draws grid lines aligned to the tick marks of the parent chart. 256 * By default, Flex draws one line for every tick mark 257 * along the appropriate axis.</p> 258 * 259 * <p>You typically use the GridLines class as a child tag 260 * of a chart control's <code>backgroundElements</code> property 261 * or <code>annotationElements</code> property.</p> 262 * 263 * @mxml 264 * 265 * <p>The <code><mx:GridLines></code> tag inherits all the properties 266 * of its parent classes and adds the following properties:</p> 267 * 268 * <pre> 269 * <mx:GridLines 270 * <strong>Styles</strong> 271 * gridDirection="horizontal|vertical|both" 272 * horizontalAlternateFill="null" 273 * horizontalChangeCount="1" 274 * horizontalFill="null" 275 * horizontalOriginStroke="<i>IStroke; No default</i>" 276 * horizontalShowOrigin="<i>Default depends on type of chart</i>" 277 * horizontalStroke="<i>IStroke; No default</i>" 278 * horizontalTickAligned="true|false" 279 * verticalAlternateFill="null" 280 * verticalChangeCount="1" 281 * verticalFill="null" 282 * verticalOriginStroke="<i>IStroke; No default</i>" 283 * verticalShowOrigin="<i>Default depends on type of chart</i>" 284 * verticalStroke="<i>IStroke; No default</i>" 285 * verticalTickAligned="true|false" 286 * /> 287 * </pre> 288 * 289 * @includeExample examples/GridLinesExample.mxml 290 * 291 * @langversion 3.0 292 * @playerversion Flash 9 293 * @playerversion AIR 1.1 294 * @productversion Flex 3 295 */ 296public class GridLines extends ChartElement 297{ 298 include "../core/Version.as"; 299 300 //-------------------------------------------------------------------------- 301 // 302 // Class initialization 303 // 304 //-------------------------------------------------------------------------- 305 306 //-------------------------------------------------------------------------- 307 // 308 // Constructor 309 // 310 //-------------------------------------------------------------------------- 311 312 /** 313 * Constructor. 314 * 315 * @langversion 3.0 316 * @playerversion Flash 9 317 * @playerversion AIR 1.1 318 * @productversion Flex 3 319 */ 320 public function GridLines() 321 { 322 super(); 323 } 324 325 //-------------------------------------------------------------------------- 326 // 327 // Variables 328 // 329 //-------------------------------------------------------------------------- 330 331 /** 332 * @private 333 */ 334 private var _moduleFactoryInitialized:Boolean = false; 335 336 //-------------------------------------------------------------------------- 337 // 338 // Overridden methods: UIComponent 339 // 340 //-------------------------------------------------------------------------- 341 342 /** 343 * @private 344 */ 345 private function initStyles():Boolean 346 { 347 HaloDefaults.init(styleManager); 348 349 var gridLinesStyle:CSSStyleDeclaration = styleManager.getStyleDeclaration("mx.charts.GridLines"); 350 gridLinesStyle.setStyle("horizontalOriginStroke", new SolidColorStroke(0xB0C1D0, 1)); 351 gridLinesStyle.setStyle("horizontalStroke", new SolidColorStroke(0xEEEEEE, 0)); 352 gridLinesStyle.setStyle("verticalOriginStroke", new SolidColorStroke(0xB0C1D0, 1)); 353 gridLinesStyle.setStyle("verticalStroke", new SolidColorStroke(0xEEEEEE, 0)); 354 355 var hgridLinesStyle:CSSStyleDeclaration = styleManager.getStyleDeclaration(".horizontalGridLines"); 356 hgridLinesStyle.setStyle("horizontalFill", null); 357 hgridLinesStyle.setStyle("verticalFill", null); 358 return true; 359 } 360 361 /** 362 * @inheritDoc 363 * 364 * @langversion 3.0 365 * @playerversion Flash 9 366 * @playerversion AIR 1.1 367 * @productversion Flex 3 368 */ 369 override public function set moduleFactory(factory:IFlexModuleFactory):void 370 { 371 super.moduleFactory = factory; 372 373 if (_moduleFactoryInitialized) 374 return; 375 376 _moduleFactoryInitialized = true; 377 378 // our style settings 379 initStyles(); 380 } 381 382 /** 383 * @private 384 */ 385 override protected function updateDisplayList(unscaledWidth:Number, 386 unscaledHeight:Number):void 387 { 388 super.updateDisplayList(unscaledWidth, unscaledHeight); 389 390 var len:int; 391 var c:Object; 392 var stroke:IStroke; 393 var changeCount:int; 394 var ticks:Array /* of Number */; 395 var spacing:Array /* of Number */; 396 var axisLength:Number; 397 var colors:Array /* of IFill */; 398 var rc:Rectangle; 399 var originStroke:IStroke; 400 var addedFirstLine:Boolean; 401 var addedLastLine:Boolean; 402 var n:int; 403 404 if (!chart|| 405 chart.chartState == ChartState.PREPARING_TO_HIDE_DATA || 406 chart.chartState == ChartState.HIDING_DATA) 407 { 408 return; 409 } 410 411 var g:Graphics = graphics; 412 g.clear(); 413 414 var gridDirection:String = getStyle("gridDirection"); 415 if (gridDirection == "horizontal" || gridDirection == "both") 416 { 417 stroke = getStyle("horizontalStroke"); 418 419 changeCount = Math.max(1, getStyle("horizontalChangeCount")); 420 if ((changeCount * 0 != 0) || changeCount <= 1) 421 changeCount = 1; 422 423 var verticalAxisRenderer:IAxisRenderer; 424 425 if (!(CartesianChart(chart).verticalAxisRenderer)) 426 { 427 verticalAxisRenderer = CartesianChart(chart).getLeftMostRenderer(); 428 if (!verticalAxisRenderer) 429 verticalAxisRenderer = CartesianChart(chart).getRightMostRenderer(); 430 } 431 else 432 verticalAxisRenderer = CartesianChart(chart).verticalAxisRenderer; 433 434 ticks = verticalAxisRenderer.ticks; 435 436 if (getStyle("horizontalTickAligned") == false) 437 { 438 len = ticks.length; 439 spacing = []; 440 n = len; 441 for (var i:int = 1; i < n; i++) 442 { 443 spacing[i - 1] = (ticks[i] + ticks[i - 1]) / 2; 444 } 445 } 446 else 447 { 448 spacing = ticks; 449 } 450 451 addedFirstLine = false; 452 addedLastLine = false; 453 454 if (spacing[0] != 0) 455 { 456 addedFirstLine = true; 457 spacing.unshift(0); 458 } 459 460 if (spacing[spacing.length - 1] != 1) 461 { 462 addedLastLine = true; 463 spacing.push(1); 464 } 465 466 axisLength = unscaledHeight; 467 468 colors = [ getStyle("horizontalFill"), 469 getStyle("horizontalAlternateFill") ]; 470 471 len = spacing.length; 472 473 if (spacing[len - 1] < 1) 474 { 475 c = colors[1]; 476 if (c != null) 477 { 478 g.lineStyle(0, 0, 0); 479 GraphicsUtilities.fillRect(g, 0, 480 spacing[len - 1] * axisLength, unscaledWidth, 481 unscaledHeight, c); 482 } 483 } 484 485 n = spacing.length; 486 for (i = 0; i < n; i += changeCount) 487 { 488 var idx:int = len - 1 - i; 489 c = colors[(i / changeCount) % 2]; 490 var bottom:Number = spacing[idx] * axisLength; 491 var top:Number = 492 spacing[Math.max(0, idx - changeCount)] * axisLength; 493 rc = new Rectangle(0, top, unscaledWidth, bottom-top); 494 495 if (c != null) 496 { 497 g.lineStyle(0, 0, 0); 498 GraphicsUtilities.fillRect(g, rc.left, rc.top, 499 rc.right, rc.bottom, c); 500 } 501 502 if (stroke && rc.bottom >= -1) //round off errors 503 { 504 if (addedFirstLine && idx == 0) 505 continue; 506 if (addedLastLine && idx == (spacing.length-1)) 507 continue; 508 509 stroke.apply(g,null,null); 510 g.moveTo(rc.left, rc.bottom); 511 g.lineTo(rc.right, rc.bottom); 512 513 } 514 } 515 } 516 517 if (gridDirection == "vertical" || gridDirection == "both") 518 { 519 520 stroke = getStyle("verticalStroke"); 521 changeCount = Math.max(1,getStyle("verticalChangeCount")); 522 523 if (isNaN(changeCount) || changeCount <= 1) 524 changeCount = 1; 525 526 var horizontalAxisRenderer:IAxisRenderer; 527 528 if (!(CartesianChart(chart).horizontalAxisRenderer)) 529 { 530 horizontalAxisRenderer = CartesianChart(chart).getBottomMostRenderer(); 531 if (!horizontalAxisRenderer) 532 horizontalAxisRenderer = CartesianChart(chart).getTopMostRenderer(); 533 } 534 else 535 horizontalAxisRenderer = CartesianChart(chart).horizontalAxisRenderer; 536 537 ticks = horizontalAxisRenderer.ticks.concat(); 538 539 if (getStyle("verticalTickAligned") == false) 540 { 541 len = ticks.length; 542 spacing = []; 543 n = len; 544 for (i = 1; i < n; i++) 545 { 546 spacing[i - 1] = (ticks[i] + ticks[i - 1]) / 2; 547 } 548 } 549 else 550 { 551 spacing = ticks; 552 } 553 554 addedFirstLine = false; 555 addedLastLine = false; 556 557 if (spacing[0] != 0) 558 { 559 addedFirstLine = true; 560 spacing.unshift(0); 561 } 562 563 if (spacing[spacing.length - 1] != 1) 564 { 565 addedLastLine = true; 566 spacing.push(1); 567 } 568 569 axisLength = unscaledWidth; 570 571 colors = [ getStyle("verticalFill"), 572 getStyle("verticalAlternateFill") ]; 573 574 n = spacing.length; 575 for (i = 0; i < n; i += changeCount) 576 { 577 c = colors[(i / changeCount) % 2]; 578 var left:Number = spacing[i] * axisLength; 579 var right:Number = 580 spacing[Math.min(spacing.length - 1, 581 i + changeCount)] * axisLength; 582 rc = new Rectangle(left, 0, right - left, unscaledHeight); 583 if (c != null) 584 { 585 g.lineStyle(0, 0, 0); 586 GraphicsUtilities.fillRect(g, rc.left, rc.top, 587 rc.right, rc.bottom, c); 588 } 589 590 if (stroke) // round off errors 591 { 592 if (addedFirstLine && i == 0) 593 continue; 594 if (addedLastLine && i == spacing.length-1) 595 continue; 596 597 stroke.apply(g,null,null); 598 g.moveTo(rc.left, rc.top); 599 g.lineTo(rc.left, rc.bottom); 600 } 601 } 602 } 603 604 var horizontalShowOrigin:Object = getStyle("horizontalShowOrigin"); 605 var verticalShowOrigin:Object = getStyle("verticalShowOrigin"); 606 607 if (verticalShowOrigin || horizontalShowOrigin) 608 { 609 var cache:Array /* of Object */ = [ { xOrigin: 0, yOrigin: 0 } ]; 610 var sWidth:Number = 0.5; 611 612 dataTransform.transformCache(cache, "xOrigin", "x", "yOrigin", "y"); 613 614 if (horizontalShowOrigin && 615 cache[0].y > 0 && cache[0].y < unscaledHeight) 616 { 617 originStroke = getStyle("horizontalOriginStroke"); 618 originStroke.apply(g,null,null); 619 g.moveTo(0, cache[0].y - sWidth / 2); 620 g.lineTo($width, cache[0].y - sWidth / 2); 621 } 622 623 if (verticalShowOrigin && 624 cache[0].x > 0 && cache[0].x < unscaledWidth) 625 { 626 originStroke = getStyle("verticalOriginStroke"); 627 originStroke.apply(g,null,null); 628 g.moveTo(cache[0].x - sWidth / 2, 0); 629 g.lineTo(cache[0].x - sWidth / 2, $height); 630 } 631 } 632 } 633 634 //-------------------------------------------------------------------------- 635 // 636 // Overridden methods: ChartElement 637 // 638 //-------------------------------------------------------------------------- 639 640 /** 641 * @private 642 */ 643 override public function mappingChanged():void 644 { 645 invalidateDisplayList(); 646 } 647 648 /** 649 * @private 650 */ 651 override public function chartStateChanged(oldState:uint, 652 newState:uint):void 653 { 654 invalidateDisplayList(); 655 } 656} 657 658} 659