Upgrade to ExtJS 4.0.7 - Released 10/19/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     require: ['Ext.chart.MaskLayer'],
51     /**
52      * Creates new Mask.
53      * @param {Object} config (optional) Config object.
54      */
55     constructor: function(config) {
56         var me = this;
57
58         me.addEvents('select');
59
60         if (config) {
61             Ext.apply(me, config);
62         }
63         if (me.mask) {
64             me.on('afterrender', function() {
65                 //create a mask layer component
66                 var comp = Ext.create('Ext.chart.MaskLayer', {
67                     renderTo: me.el
68                 });
69                 comp.el.on({
70                     'mousemove': function(e) {
71                         me.onMouseMove(e);
72                     },
73                     'mouseup': function(e) {
74                         me.resized(e);
75                     }
76                 });
77                 //create a resize handler for the component
78                 var resizeHandler = Ext.create('Ext.resizer.Resizer', {
79                     el: comp.el,
80                     handles: 'all',
81                     pinned: true
82                 });
83                 resizeHandler.on({
84                     'resize': function(e) {
85                         me.resized(e);    
86                     }    
87                 });
88                 comp.initDraggable();
89                 me.maskType = me.mask;
90                 me.mask = comp;
91                 me.maskSprite = me.surface.add({
92                     type: 'path',
93                     path: ['M', 0, 0],
94                     zIndex: 1001,
95                     opacity: 0.7,
96                     hidden: true,
97                     stroke: '#444'
98                 });
99             }, me, { single: true });
100         }
101     },
102     
103     resized: function(e) {
104         var me = this,
105             bbox = me.bbox || me.chartBBox,
106             x = bbox.x,
107             y = bbox.y,
108             width = bbox.width,
109             height = bbox.height,
110             box = me.mask.getBox(true),
111             max = Math.max,
112             min = Math.min,
113             staticX = box.x - x,
114             staticY = box.y - y;
115         
116         staticX = max(staticX, x);
117         staticY = max(staticY, y);
118         staticX = min(staticX, width);
119         staticY = min(staticY, height);
120         box.x = staticX;
121         box.y = staticY;
122         me.fireEvent('select', me, box);
123     },
124
125     onMouseUp: function(e) {
126         var me = this,
127             bbox = me.bbox || me.chartBBox,
128             sel = me.maskSelection;
129         me.maskMouseDown = false;
130         me.mouseDown = false;
131         if (me.mouseMoved) {
132             me.onMouseMove(e);
133             me.mouseMoved = false;
134             me.fireEvent('select', me, {
135                 x: sel.x - bbox.x,
136                 y: sel.y - bbox.y,
137                 width: sel.width,
138                 height: sel.height
139             });
140         }
141     },
142
143     onMouseDown: function(e) {
144         var me = this;
145         me.mouseDown = true;
146         me.mouseMoved = false;
147         me.maskMouseDown = {
148             x: e.getPageX() - me.el.getX(),
149             y: e.getPageY() - me.el.getY()
150         };
151     },
152
153     onMouseMove: function(e) {
154         var me = this,
155             mask = me.maskType,
156             bbox = me.bbox || me.chartBBox,
157             x = bbox.x,
158             y = bbox.y,
159             math = Math,
160             floor = math.floor,
161             abs = math.abs,
162             min = math.min,
163             max = math.max,
164             height = floor(y + bbox.height),
165             width = floor(x + bbox.width),
166             posX = e.getPageX(),
167             posY = e.getPageY(),
168             staticX = posX - me.el.getX(),
169             staticY = posY - me.el.getY(),
170             maskMouseDown = me.maskMouseDown,
171             path;
172         
173         me.mouseMoved = me.mouseDown;
174         staticX = max(staticX, x);
175         staticY = max(staticY, y);
176         staticX = min(staticX, width);
177         staticY = min(staticY, height);
178         if (maskMouseDown && me.mouseDown) {
179             if (mask == 'horizontal') {
180                 staticY = y;
181                 maskMouseDown.y = height;
182                 posY = me.el.getY() + bbox.height + me.insetPadding;
183             }
184             else if (mask == 'vertical') {
185                 staticX = x;
186                 maskMouseDown.x = width;
187             }
188             width = maskMouseDown.x - staticX;
189             height = maskMouseDown.y - staticY;
190             path = ['M', staticX, staticY, 'l', width, 0, 0, height, -width, 0, 'z'];
191             me.maskSelection = {
192                 x: width > 0 ? staticX : staticX + width,
193                 y: height > 0 ? staticY : staticY + height,
194                 width: abs(width),
195                 height: abs(height)
196             };
197             me.mask.updateBox(me.maskSelection);
198             me.mask.show();
199             me.maskSprite.setAttributes({
200                 hidden: true    
201             }, true);
202         }
203         else {
204             if (mask == 'horizontal') {
205                 path = ['M', staticX, y, 'L', staticX, height];
206             }
207             else if (mask == 'vertical') {
208                 path = ['M', x, staticY, 'L', width, staticY];
209             }
210             else {
211                 path = ['M', staticX, y, 'L', staticX, height, 'M', x, staticY, 'L', width, staticY];
212             }
213             me.maskSprite.setAttributes({
214                 path: path,
215                 fill: me.maskMouseDown ? me.maskSprite.stroke : false,
216                 'stroke-width': mask === true ? 1 : 3,
217                 hidden: false
218             }, true);
219         }
220     },
221
222     onMouseLeave: function(e) {
223         var me = this;
224         me.mouseMoved = false;
225         me.mouseDown = false;
226         me.maskMouseDown = false;
227         me.mask.hide();
228         me.maskSprite.hide(true);
229     }
230 });
231