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.effects.effectClasses
13{
14
15import flash.geom.Point;
16import flash.geom.Rectangle;
17
18/**
19 *  The SeriesZoomInstance class implements the instance class
20 *  for the SeriesZoom effect.
21 *  Flex creates an instance of this class when it plays a SeriesZoom effect;
22 *  you do not create one yourself.
23 *
24 *  @see mx.charts.effects.SeriesZoom
25 *
26 *  @langversion 3.0
27 *  @playerversion Flash 9
28 *  @playerversion AIR 1.1
29 *  @productversion Flex 3
30 */
31public class SeriesZoomInstance extends SeriesEffectInstance
32{
33    include "../../../core/Version.as";
34
35    //--------------------------------------------------------------------------
36    //
37    //  Class constants
38    //
39    //--------------------------------------------------------------------------
40
41    /**
42     *  @private
43     */
44    private static var BOTH:uint = 0;
45
46    /**
47     *  @private
48     */
49    private static var HORIZONTAL:uint = 1;
50
51    /**
52     *  @private
53     */
54    private static var VERTICAL:uint = 2;
55
56    //--------------------------------------------------------------------------
57    //
58    //  Constructor
59    //
60    //--------------------------------------------------------------------------
61
62    /**
63     *  Constructor.
64     *
65     *  @param target The target of the effect.
66     *
67     *  @langversion 3.0
68     *  @playerversion Flash 9
69     *  @playerversion AIR 1.1
70     *  @productversion Flex 3
71     */
72    public function SeriesZoomInstance(target:Object)
73    {
74        super(target);
75    }
76
77    //--------------------------------------------------------------------------
78    //
79    //  Variables
80    //
81    //--------------------------------------------------------------------------
82
83    /**
84     *  @private
85     */
86    private var _direction:uint;
87
88    /**
89     *  @private
90     */
91    private var _elementBounds:Array /* of Rectangle */;
92
93    /**
94     *  @private
95     */
96    private var _slideDistance:Number;
97
98    /**
99     *  @private
100     */
101    private var _zoomPoints:Array /* of Point */;
102
103    /**
104     *  @private
105     */
106    private var seriesRenderData:Object;
107
108
109    //--------------------------------------------------------------------------
110    //
111    //  Properties
112    //
113    //--------------------------------------------------------------------------
114
115    //----------------------------------
116    //  horizontalFocus
117    //----------------------------------
118
119    [Inspectable(category="General", enumeration="left,center,right")]
120
121    /**
122     *  Defines the location of the focul point of the zoom.
123     *
124     *  <p>Valid values of <code>horizontalFocus</code> are
125     *  <code>"left"</code>, <code>"center"</code>, <code>"right"</code>,
126     *  and <code>null</code>.</p>
127     *  The default value is <code>"center"</code>.
128     *
129     *  <p>You combine the <code>horizontalFocus</code> and
130     *  <code>verticalFocus</code> properties to define where the data series
131     *  zooms in and out from.
132     *  For example, set <code>horizontalFocus</code> to <code>"left"</code>
133     *  and <code>verticalFocus</code> to <code>"top"</code> to zoom
134     *  the series data to and from the top left corner of either the element
135     *  or the chart (depending on the setting of the
136     *  <code>relativeTo</code> property).</p>
137     *
138     *  <p>If you specify only one of these two properties, then the focus
139     *  is a horizontal or vertical line rather than a point.
140     *  For example, when you set <code>horizontalFocus</code> to
141     *  <code>"left"</code> but <code>verticalFocus</code> to
142     *  <code>null</code>, the element zooms to and from a vertical line
143     *  along the left edge of its bounding box.
144     *  Set <code>verticalFocus</code> to <code>"center"</code> to zoom
145     *  chart elements to and from a horizontal line along the middle
146     *  of the chart's bounding box.</p>
147     *
148     *  @langversion 3.0
149     *  @playerversion Flash 9
150     *  @playerversion AIR 1.1
151     *  @productversion Flex 3
152     */
153    public var horizontalFocus:String;
154
155    //----------------------------------
156    //  relativeTo
157    //----------------------------------
158
159    [Inspectable(category="General", enumeration="series,chart", defaultValue="series")]
160
161    /**
162     *  Controls the bounding box that Flex uses to calculate
163     *  the focal point of the zooms.
164     *
165     *  <p>Valid values for <code>relativeTo</code> are
166     *  <code>"series"</code> and <code>"chart"</code>.
167     *  The default value is <code>"series"</code>.</p>
168     *
169     *  <p>Set to <code>"series"</code> to zoom each element
170     *  relative to itself.
171     *  For example, each column of a ColumnChart zooms from the top left
172     *  of the column, the center of the column, and so on.</p>
173     *
174     *  <p>Set to <code>"chart"</code> to zoom each element
175     *  relative to the chart area.
176     *  For example, each column zooms from the top left of the axes,
177     *  the center of the axes, and so on.</p>
178     *
179     *  @langversion 3.0
180     *  @playerversion Flash 9
181     *  @playerversion AIR 1.1
182     *  @productversion Flex 3
183     */
184    public var relativeTo:String = "series";
185
186    //----------------------------------
187    //  verticalFocus
188    //----------------------------------
189
190    [Inspectable(category="General", enumeration="top,center,bottom")]
191
192    /**
193     *  Defines the location of the focul point of the zoom.
194     *
195     *  <p>Valid values of <code>verticalFocus</code> are
196     *  <code>"top"</code>, <code>"center"</code>, <code>"bottom"</code>,
197     *  and <code>null</code>.
198     *  The default value is <code>"center"</code>.</p>
199     *
200     *  <p>For more information, see the description of the
201     *  <code>horizontalFocus</code> property.</p>
202     *
203     *  @langversion 3.0
204     *  @playerversion Flash 9
205     *  @playerversion AIR 1.1
206     *  @productversion Flex 3
207     */
208    public var verticalFocus:String;
209
210    //--------------------------------------------------------------------------
211    //
212    //  Overridden methods
213    //
214    //--------------------------------------------------------------------------
215
216    /**
217     *  @private
218     */
219    override public function play():void
220    {
221        seriesRenderData = targetSeries.getRenderDataForTransition(type);
222
223        targetSeries.getElementBounds(seriesRenderData);
224        var elementBounds:Array /* of Rectangle */ = _elementBounds =
225            seriesRenderData.elementBounds;
226
227        var activeBounds:Array /* of Rectangle */ = [];
228        var zoomPoints:Array /* of Point */ = [];
229
230        var n:int = elementBounds.length;
231        var i:int;
232        var pt:Point;
233        var v:Rectangle;
234
235        if (relativeTo == "series")
236        {
237            loadSeriesRelativePoints(zoomPoints, elementBounds);
238        }
239        else
240        {
241            loadChartRelativePoints(zoomPoints, elementBounds,
242                                    seriesRenderData.visibleRegion);
243        }
244
245        if (type == "show")
246        {
247            switch (_direction)
248            {
249                case BOTH:
250                {
251                    for (i = 0; i < n; i++)
252                    {
253                        pt = zoomPoints[i];
254                        activeBounds[i] = new Rectangle(pt.x, pt.y, 0, 0);
255                    }
256                    break;
257                }
258
259                case HORIZONTAL:
260                {
261                    for (i = 0; i < n; i++)
262                    {
263                        pt = zoomPoints[i];
264                        v = elementBounds[i];
265                        activeBounds[i] =
266                            new Rectangle(pt.x, v.top, 0, v.height);
267                    }
268                    break;
269                }
270
271                case VERTICAL:
272                {
273                    for (i = 0; i < n; i++)
274                    {
275                        pt = zoomPoints[i];
276                        v = elementBounds[i];
277                        activeBounds[i] =
278                            new Rectangle(v.left, pt.y, v.width, 0);
279                    }
280                    break;
281                }
282            }
283        }
284        else
285        {
286            for (i = 0; i < n; i++)
287            {
288                v = elementBounds[i];
289                activeBounds[i] = elementBounds[i].clone();
290            }
291        }
292
293        seriesRenderData.elementBounds = activeBounds;
294        targetSeries.transitionRenderData = seriesRenderData;
295        _zoomPoints = zoomPoints;
296
297        beginTween(n);
298    }
299
300    /**
301     *  @private
302     */
303    override public function onTweenUpdate(value:Object):void
304    {
305        super.onTweenUpdate(value);
306
307        var elementBounds:Array /* of Rectangle */ = _elementBounds;
308        var activeBounds:Array /* of Rectangle */ = seriesRenderData.elementBounds;
309        var zoomPoints:Array /* of Point */ = _zoomPoints;
310
311        var n:int = elementBounds.length;
312        var base:Number = 0;
313        var scale:Number = 1;
314        var i:int;
315        var v:Rectangle;
316        var pt:Point;
317        var interpolation:Number;
318
319        if (type == "hide")
320        {
321            base = 1;
322            scale = -1;
323        }
324        {
325            switch (_direction)
326            {
327                case BOTH:
328                {
329                    for (i = 0; i < n; i++)
330                    {
331                        interpolation = base + scale * interpolationValues[i];
332                        v = elementBounds[i];
333
334                        pt = zoomPoints[i];
335                        activeBounds[i] = new Rectangle(
336                            pt.x + (v.left - pt.x) * interpolation,
337                            pt.y + (v.top - pt.y) * interpolation,
338                            v.width * interpolation,
339                            v.height * interpolation);
340                    }
341                    break;
342                }
343
344                case HORIZONTAL:
345                {
346                    for (i = 0; i < n; i++)
347                    {
348                        interpolation = base + scale * interpolationValues[i];
349                        v = elementBounds[i];
350
351                        pt = zoomPoints[i];
352                        activeBounds[i] = new Rectangle(
353                            pt.x + (v.left - pt.x) * interpolation, v.top,
354                            v.width *interpolation, v.height);
355                    }
356                    break;
357                }
358
359                case VERTICAL:
360                {
361                    for (i = 0; i < n; i++)
362                    {
363                        interpolation = base + scale * interpolationValues[i];
364                        v = elementBounds[i];
365
366                        pt = zoomPoints[i];
367                        activeBounds[i] = new Rectangle(
368                            v.left, pt.y + (v.top - pt.y) * interpolation,
369                            v.width, v.height * interpolation);
370                    }
371                    break;
372                }
373            }
374        }
375
376        targetSeries.invalidateDisplayList();
377    }
378
379    /**
380     *  @private
381     */
382    override public function onTweenEnd(value:Object):void
383    {
384        super.onTweenEnd(value);
385
386        targetSeries.transitionRenderData = null;
387    }
388
389    //--------------------------------------------------------------------------
390    //
391    //  Methods
392    //
393    //--------------------------------------------------------------------------
394
395    /**
396     *  @private
397     */
398    private function loadChartRelativePoints(zoomPoints:Array /* of Point */,
399                                             elementBounds:Array /* of Rectangle */,
400                                             visibleRegion:Rectangle):void
401    {
402        var n:int = elementBounds.length;
403        var i:int;
404        var pt:Point;
405
406        if (!visibleRegion)
407            visibleRegion = new Rectangle(0, 0,
408                                          targetSeries.width / Math.abs(targetSeries.scaleX),
409                                          targetSeries.height / Math.abs(targetSeries.scaleY));
410
411        switch (horizontalFocus)
412        {
413            case "left":
414            {
415                switch (verticalFocus)
416                {
417                    case "top":
418                    {
419                        _direction = BOTH;
420                        pt = visibleRegion.topLeft;
421                        for (i = 0; i < n; i++)
422                        {
423                            zoomPoints[i] = pt;
424                        }
425                        break;
426                    }
427
428                    case "center":
429                    {
430                        _direction = BOTH;
431                        pt = new Point(visibleRegion.left,
432                                       visibleRegion.top +
433                                       visibleRegion.height / 2);
434                        for (i = 0; i < n; i++)
435                        {
436                            zoomPoints[i] = pt;
437                        }
438                        break;
439                    }
440
441                    case "bottom":
442                    {
443                        _direction = BOTH;
444                        pt = new Point(visibleRegion.left,
445                                       visibleRegion.bottom);
446                        for (i = 0; i < n; i++)
447                        {
448                            zoomPoints[i] = pt;
449                        }
450                        break;
451                    }
452
453                    default:
454                    {
455                        _direction = HORIZONTAL;
456                        pt = new Point(visibleRegion.left, NaN);
457                        for (i = 0; i < n; i++)
458                        {
459                            zoomPoints[i] = pt;
460                        }
461                        break;
462                    }
463                }
464                break;
465            }
466
467            case "right":
468            {
469                switch (verticalFocus)
470                {
471                    case "top":
472                    {
473                        _direction = BOTH;
474                        pt = new Point(visibleRegion.right,
475                                       visibleRegion.top);
476                        for (i = 0; i < n; i++)
477                        {
478                            zoomPoints[i] = pt;
479                        }
480                        break;
481                    }
482
483                    case "center":
484                    {
485                        _direction = BOTH;
486                        pt = new Point(visibleRegion.right,
487                                       visibleRegion.top +
488                                       visibleRegion.height / 2);
489                        for (i = 0; i < n; i++)
490                        {
491                            zoomPoints[i] = pt;
492                        }
493                        break;
494                    }
495
496                    case "bottom":
497                    {
498                        _direction = BOTH;
499                        pt = visibleRegion.bottomRight;
500                        for (i = 0; i < n; i++)
501                        {
502                            zoomPoints[i] = pt;
503                        }
504                        break;
505                    }
506
507                    default:
508                    {
509                        _direction = HORIZONTAL;
510                        pt = new Point(visibleRegion.right, NaN);
511                        for (i = 0; i < n; i++)
512                        {
513                            zoomPoints[i] = pt;
514                        }
515                        break;
516                    }
517                }
518                break;
519            }
520
521            case "center":
522            {
523                switch (verticalFocus)
524                {
525                    case "top":
526                    {
527                        _direction = BOTH;
528                        pt = new Point(visibleRegion.left +
529                                       visibleRegion.width / 2,
530                                       visibleRegion.top);
531                        for (i = 0; i < n; i++)
532                        {
533                            zoomPoints[i] = pt;
534                        }
535                        break;
536                    }
537
538                    case "center":
539                    {
540                        _direction = BOTH;
541                        pt = new Point(visibleRegion.left +
542                                       visibleRegion.width / 2,
543                                       visibleRegion.top +
544                                       visibleRegion.height / 2);
545                        for (i = 0; i < n; i++)
546                        {
547                            zoomPoints[i] = pt;
548                        }
549                        break;
550                    }
551
552                    case "bottom":
553                    {
554                        _direction = BOTH;
555                        pt = new Point(visibleRegion.left +
556                                       visibleRegion.width / 2,
557                                       visibleRegion.bottom);
558                        for (i = 0; i < n; i++)
559                        {
560                            zoomPoints[i] = pt;
561                        }
562                        break;
563                    }
564
565                    default:
566                    {
567                        _direction = HORIZONTAL;
568                        pt = new Point(visibleRegion.left +
569                                       visibleRegion.width / 2,
570                                       NaN);
571                        for (i = 0; i < n; i++)
572                        {
573                            zoomPoints[i] = pt;
574                        }
575                        break;
576                    }
577                }
578                break;
579            }
580
581            default:
582            {
583                switch (verticalFocus)
584                {
585                    case "top":
586                    {
587                        _direction = VERTICAL;
588                        pt = new Point(NaN, visibleRegion.top);
589                        for (i = 0; i < n; i++)
590                        {
591                            zoomPoints[i] = pt;
592                        }
593                        break;
594                    }
595
596                    case "center":
597                    {
598                        _direction = VERTICAL;
599                        pt = new Point(NaN,
600                                       visibleRegion.top +
601                                       visibleRegion.height / 2);
602                        for (i = 0; i < n; i++)
603                        {
604                            zoomPoints[i] = pt;
605                        }
606                        break;
607                    }
608
609                    case "bottom":
610                    {
611                        _direction = VERTICAL;
612                        pt = new Point(NaN, visibleRegion.bottom);
613                        for (i = 0; i < n; i++)
614                        {
615                            zoomPoints[i] = pt;
616                        }
617                        break;
618                    }
619
620                    default:
621                    {
622                        _direction = BOTH;
623                        pt = new Point(visibleRegion.left +
624                                       visibleRegion.width / 2,
625                                       visibleRegion.top +
626                                       visibleRegion.height / 2);
627                        for (i = 0; i < n; i++)
628                        {
629                            zoomPoints[i] = pt;
630                        }
631                        break;
632                    }
633                }
634                break;
635            }
636        }
637    }
638
639    /**
640     *  @private
641     */
642    private function loadSeriesRelativePoints(zoomPoints:Array /* of Point */,
643                                              elementBounds:Array /* of Rectangle */):void
644    {
645        var n:int = elementBounds.length;
646        var i:int;
647        var v:Rectangle;
648        var pt:Point;
649
650        switch (horizontalFocus)
651        {
652            case "left":
653            {
654                switch (verticalFocus)
655                {
656                    case "top":
657                    {
658                        _direction= BOTH;
659                        for (i = 0; i < n; i++)
660                        {
661                            v = elementBounds[i];
662                            zoomPoints[i] = new Point(v.left, v.top);
663                        }
664                        break;
665                    }
666
667                    case "center":
668                    {
669                        _direction = BOTH;
670                        for (i = 0; i < n; i++)
671                        {
672                            v = elementBounds[i];
673                            zoomPoints[i] = new Point(v.left,
674                                                      (v.top + v.bottom) / 2);
675                        }
676                        break;
677                    }
678
679                    case "bottom":
680                    {
681                        _direction = BOTH;
682                        for (i = 0; i < n; i++)
683                        {
684                            v = elementBounds[i];
685                            zoomPoints[i] = new Point(v.left, v.bottom);
686                        }
687                        break;
688                    }
689
690                    default:
691                    {
692                        _direction = HORIZONTAL;
693                        for (i = 0; i < n; i++)
694                        {
695                            v = elementBounds[i];
696                            zoomPoints[i] = new Point(v.left,NaN);
697                        }
698                        break;
699                    }
700                }
701                break;
702            }
703
704            case "right":
705            {
706                switch (verticalFocus)
707                {
708                    case "top":
709                    {
710                        _direction = BOTH;
711                        for (i = 0; i < n; i++)
712                        {
713                            v = elementBounds[i];
714                            zoomPoints[i] = new Point(v.right, v.top);
715                        }
716                        break;
717                    }
718
719                    case "center":
720                    {
721                        _direction = BOTH;
722                        for (i = 0; i < n; i++)
723                        {
724                            v = elementBounds[i];
725                            zoomPoints[i] = new Point(v.right,
726                                                      (v.top + v.bottom) / 2);
727                        }
728                        break;
729                    }
730
731                    case "bottom":
732                    {
733                        _direction = BOTH;
734                        for (i = 0; i < n; i++)
735                        {
736                            v = elementBounds[i];
737                            zoomPoints[i] = new Point(v.right, v.bottom);
738                        }
739                        break;
740                    }
741
742                    default:
743                    {
744                        _direction = HORIZONTAL;
745                        for (i = 0; i < n; i++)
746                        {
747                            v = elementBounds[i];
748                            zoomPoints[i] = new Point(v.right,NaN);
749                        }
750                        break;
751                    }
752                }
753                break;
754            }
755
756            case "center":
757            {
758                switch (verticalFocus)
759                {
760                    case "top":
761                    {
762                        _direction = BOTH;
763                        for (i = 0; i < n; i++)
764                        {
765                            v = elementBounds[i];
766                            zoomPoints[i] = new Point((v.left + v.right) / 2,
767                                                      v.top);
768                        }
769                        break;
770                    }
771
772                    case "center":
773                    {
774                        _direction = BOTH;
775                        for (i = 0; i < n; i++)
776                        {
777                            v = elementBounds[i];
778                            zoomPoints[i] = new Point((v.left + v.right) / 2,
779                                                      (v.top + v.bottom) / 2);
780                        }
781                        break;
782                    }
783
784                    case "bottom":
785                    {
786                        _direction = BOTH;
787                        for (i = 0; i < n; i++)
788                        {
789                            v = elementBounds[i];
790                            zoomPoints[i] = new Point((v.left + v.right) / 2,
791                                                      v.bottom);
792                        }
793                        break;
794                    }
795
796                    default:
797                    {
798                        _direction = HORIZONTAL;
799                        for (i = 0; i < n; i++)
800                        {
801                            v = elementBounds[i];
802                            zoomPoints[i] = new Point((v.right + v.left) / 2,
803                                                      NaN);
804                        }
805                        break;
806                    }
807                }
808                break;
809            }
810
811            default:
812            {
813                switch (verticalFocus)
814                {
815                    case "top":
816                    {
817                        _direction = VERTICAL;
818                        for (i = 0; i < n; i++)
819                        {
820                            v = elementBounds[i];
821                            zoomPoints[i] = new Point(NaN, v.top);
822                        }
823                        break;
824                    }
825
826                    case "center":
827                    {
828                        _direction = VERTICAL;
829                        for (i = 0; i < n; i++)
830                        {
831                            v = elementBounds[i];
832                            zoomPoints[i] = new Point(NaN,
833                                                      (v.top + v.bottom) / 2);
834                        }
835                        break;
836                    }
837
838                    case "bottom":
839                    {
840                        _direction = VERTICAL;
841                        for (i = 0; i < n; i++)
842                        {
843                            v = elementBounds[i];
844                            zoomPoints[i] = new Point(NaN, v.bottom);
845                        }
846                        break;
847                    }
848
849                    default:
850                    {
851                        _direction = BOTH;
852                        for (i = 0; i < n; i++)
853                        {
854                            v = elementBounds[i];
855                            zoomPoints[i] = new Point((v.left + v.right) / 2,
856                                                      (v.top + v.bottom) / 2);
857                        }
858                        break;
859                    }
860                }
861                break;
862            }
863        }
864    }
865}
866
867}
868