Upgrade to ExtJS 4.0.2 - Released 06/09/2011
[extjs.git] / src / chart / Mask.js
1 /*
2
3 This file is part of Ext JS 4
4
5 Copyright (c) 2011 Sencha Inc
6
7 Contact:  http://www.sencha.com/contact
8
9 GNU General Public License Usage
10 This file may be used under the terms of the GNU General Public License version 3.0 as published by the Free Software Foundation and appearing in the file LICENSE included in the packaging of this file.  Please review the following information to ensure the GNU General Public License version 3.0 requirements will be met: http://www.gnu.org/copyleft/gpl.html.
11
12 If you are unsure which license is appropriate for your use, please contact the sales department at http://www.sencha.com/contact.
13
14 */
15 /**
16  * @class Ext.chart.Mask
17  *
18  * Defines a mask for a chart's series.
19  * The 'chart' member must be set prior to rendering.
20  *
21  * A Mask can be used to select a certain region in a chart.
22  * When enabled, the `select` event will be triggered when a
23  * region is selected by the mask, allowing the user to perform
24  * other tasks like zooming on that region, etc.
25  *
26  * In order to use the mask one has to set the Chart `mask` option to
27  * `true`, `vertical` or `horizontal`. Then a possible configuration for the
28  * listener could be:
29  *
30         items: {
31             xtype: 'chart',
32             animate: true,
33             store: store1,
34             mask: 'horizontal',
35             listeners: {
36                 select: {
37                     fn: function(me, selection) {
38                         me.setZoom(selection);
39                         me.mask.hide();
40                     }
41                 }
42             },
43
44  * In this example we zoom the chart to that particular region. You can also get
45  * a handle to a mask instance from the chart object. The `chart.mask` element is a
46  * `Ext.Panel`.
47  * 
48  */
49 Ext.define('Ext.chart.Mask', {
50     /**
51      * Creates new Mask.
52      * @param {Object} config (optional) Config object.
53      */
54     constructor: function(config) {
55         var me = this;
56
57         me.addEvents('select');
58
59         if (config) {
60             Ext.apply(me, config);
61         }
62         if (me.mask) {
63             me.on('afterrender', function() {
64                 //create a mask layer component
65                 var comp = Ext.create('Ext.chart.MaskLayer', {
66                     renderTo: me.el
67                 });
68                 comp.el.on({
69                     'mousemove': function(e) {
70                         me.onMouseMove(e);
71                     },
72                     'mouseup': function(e) {
73                         me.resized(e);
74                     }
75                 });
76                 //create a resize handler for the component
77                 var resizeHandler = Ext.create('Ext.resizer.Resizer', {
78                     el: comp.el,
79                     handles: 'all',
80                     pinned: true
81                 });
82                 resizeHandler.on({
83                     'resize': function(e) {
84                         me.resized(e);    
85                     }    
86                 });
87                 comp.initDraggable();
88                 me.maskType = me.mask;
89                 me.mask = comp;
90                 me.maskSprite = me.surface.add({
91                     type: 'path',
92                     path: ['M', 0, 0],
93                     zIndex: 1001,
94                     opacity: 0.7,
95                     hidden: true,
96                     stroke: '#444'
97                 });
98             }, me, { single: true });
99         }
100     },
101     
102     resized: function(e) {
103         var me = this,
104             bbox = me.bbox || me.chartBBox,
105             x = bbox.x,
106             y = bbox.y,
107             width = bbox.width,
108             height = bbox.height,
109             box = me.mask.getBox(true),
110             max = Math.max,
111             min = Math.min,
112             staticX = box.x - x,
113             staticY = box.y - y;
114         
115         staticX = max(staticX, x);
116         staticY = max(staticY, y);
117         staticX = min(staticX, width);
118         staticY = min(staticY, height);
119         box.x = staticX;
120         box.y = staticY;
121         me.fireEvent('select', me, box);
122     },
123
124     onMouseUp: function(e) {
125         var me = this,
126             bbox = me.bbox || me.chartBBox,
127             sel = me.maskSelection;
128         me.maskMouseDown = false;
129         me.mouseDown = false;
130         if (me.mouseMoved) {
131             me.onMouseMove(e);
132             me.mouseMoved = false;
133             me.fireEvent('select', me, {
134                 x: sel.x - bbox.x,
135                 y: sel.y - bbox.y,
136                 width: sel.width,
137                 height: sel.height
138             });
139         }
140     },
141
142     onMouseDown: function(e) {
143         var me = this;
144         me.mouseDown = true;
145         me.mouseMoved = false;
146         me.maskMouseDown = {
147             x: e.getPageX() - me.el.getX(),
148             y: e.getPageY() - me.el.getY()
149         };
150     },
151
152     onMouseMove: function(e) {
153         var me = this,
154             mask = me.maskType,
155             bbox = me.bbox || me.chartBBox,
156             x = bbox.x,
157             y = bbox.y,
158             math = Math,
159             floor = math.floor,
160             abs = math.abs,
161             min = math.min,
162             max = math.max,
163             height = floor(y + bbox.height),
164             width = floor(x + bbox.width),
165             posX = e.getPageX(),
166             posY = e.getPageY(),
167             staticX = posX - me.el.getX(),
168             staticY = posY - me.el.getY(),
169             maskMouseDown = me.maskMouseDown,
170             path;
171         
172         me.mouseMoved = me.mouseDown;
173         staticX = max(staticX, x);
174         staticY = max(staticY, y);
175         staticX = min(staticX, width);
176         staticY = min(staticY, height);
177         if (maskMouseDown && me.mouseDown) {
178             if (mask == 'horizontal') {
179                 staticY = y;
180                 maskMouseDown.y = height;
181                 posY = me.el.getY() + bbox.height + me.insetPadding;
182             }
183             else if (mask == 'vertical') {
184                 staticX = x;
185                 maskMouseDown.x = width;
186             }
187             width = maskMouseDown.x - staticX;
188             height = maskMouseDown.y - staticY;
189             path = ['M', staticX, staticY, 'l', width, 0, 0, height, -width, 0, 'z'];
190             me.maskSelection = {
191                 x: width > 0 ? staticX : staticX + width,
192                 y: height > 0 ? staticY : staticY + height,
193                 width: abs(width),
194                 height: abs(height)
195             };
196             me.mask.updateBox({
197                 x: posX - abs(width),
198                 y: posY - abs(height),
199                 width: abs(width),
200                 height: abs(height)
201             });
202             me.mask.show();
203             me.maskSprite.setAttributes({
204                 hidden: true    
205             }, true);
206         }
207         else {
208             if (mask == 'horizontal') {
209                 path = ['M', staticX, y, 'L', staticX, height];
210             }
211             else if (mask == 'vertical') {
212                 path = ['M', x, staticY, 'L', width, staticY];
213             }
214             else {
215                 path = ['M', staticX, y, 'L', staticX, height, 'M', x, staticY, 'L', width, staticY];
216             }
217             me.maskSprite.setAttributes({
218                 path: path,
219                 fill: me.maskMouseDown ? me.maskSprite.stroke : false,
220                 'stroke-width': mask === true ? 1 : 3,
221                 hidden: false
222             }, true);
223         }
224     },
225
226     onMouseLeave: function(e) {
227         var me = this;
228         me.mouseMoved = false;
229         me.mouseDown = false;
230         me.maskMouseDown = false;
231         me.mask.hide();
232         me.maskSprite.hide(true);
233     }
234 });
235