source: Dev/trunk/src/client/dojox/gauges/AnalogGauge.js @ 532

Last change on this file since 532 was 483, checked in by hendrikvanantwerpen, 11 years ago

Added Dojo 1.9.3 release.

File size: 11.0 KB
Line 
1define(["dojo/_base/kernel","dojo/_base/declare","dojo/_base/array","dojo/_base/lang","dojo/_base/html","dojo/_base/event",
2                "dojox/gfx", "./_Gauge","./AnalogLineIndicator", "dojo/dom-geometry"],
3        function(dojo, declare, arr, lang, html, event,
4                        gfx, Gauge, AnalogLineIndicator, domGeometry) {
5
6return declare("dojox.gauges.AnalogGauge",Gauge,{
7        // summary:
8        //              a gauge built using the dojox.gfx package.
9        //
10        // description:
11        //              using dojo.gfx (and thus either SVG or VML based on what is supported), this widget
12        //              builds a gauge component, used to display numerical data in a familiar format
13        //
14        // example:
15        //      |       <script type="text/javascript">
16        //      |               require(["dojox/gauges/AnalogGauge"]);
17        //      |       </script>
18        //      |
19        //      |       <div    dojoType="dojox.gauges.AnalogGauge"
20        //      |                       id="testGauge"
21        //      |                       width="300"
22        //      |                       height="200"
23        //      |                       cx=150
24        //      |                       cy=175
25        //      |                       radius=125
26        //      |                       image="gaugeOverlay.png"
27        //      |                       imageOverlay="false"
28        //      |                       imageWidth="280"
29        //      |                       imageHeight="155"
30        //      |                       imageX="12"
31        //      |                       imageY="38">
32        //      |       </div>
33
34        // startAngle: Number
35        //              angle (in degrees) for start of gauge (default is -90)
36        startAngle: -90,
37
38        // endAngle: Number
39        //              angle (in degrees) for end of gauge (default is 90)
40        endAngle: 90,
41
42        // cx: Number
43        //              center of gauge x coordinate (default is gauge width / 2)
44        cx: 0,
45
46        // cy: Number
47        //              center of gauge x coordinate (default is gauge height / 2)
48        cy: 0,
49
50        // radius: Number
51        //              radius of gauge (default is smaller of cx-25 or cy-25)
52        radius: 0,
53       
54        // orientation: String
55        //              The orientation of the gauge. The value can be 'clockwise' or 'cclockwise' (default is 'clockwise')
56        orientation: "clockwise",
57
58        // _defaultIndicator: dojox.gauges._Indicator
59        //              override of dojox.gauges._Gauge._defaultIndicator
60        _defaultIndicator: AnalogLineIndicator,
61
62        startup: function(){
63                // handle settings from HTML by making sure all the options are
64                // converted correctly to numbers and that we calculate defaults
65                // for cx, cy and radius
66                // also connects mouse handling events
67
68                if(this.getChildren){
69                        arr.forEach(this.getChildren(), function(child){ child.startup(); });
70                }
71
72                this.startAngle = Number(this.startAngle);
73                this.endAngle = Number(this.endAngle);
74
75                this.cx = Number(this.cx);
76                if(!this.cx){this.cx = this.width/2;}
77                this.cy = Number(this.cy);
78                if(!this.cy){this.cy = this.height/2;}
79                this.radius = Number(this.radius);
80                if(!this.radius){this.radius = Math.min(this.cx,this.cy) - 25;}
81       
82
83                this.inherited(arguments);
84        },
85
86        _getAngle: function(/*Number*/value){
87                // summary:
88                //              This is a helper function used to determine the angle that represents
89                //              a given value on the gauge
90                // value:       Number
91                //              A value to be converted to an angle for this gauge.
92               
93                var v = Number(value);
94                var angle;
95                if (value == null || isNaN(v) || v <= this.min)
96                        angle = this._mod360(this.startAngle);
97                else
98                        if (v >= this.max)
99                                angle = this._mod360(this.endAngle);
100                        else {
101                                var startAngle = this._mod360(this.startAngle);
102                                var relativeValue = (v - this.min);
103                                if (this.orientation != 'clockwise')
104                                        relativeValue = -relativeValue;
105
106                                angle = this._mod360(startAngle + this._getAngleRange() * relativeValue / Math.abs(this.min - this.max));
107                        }
108
109                return angle;
110        },
111
112        _getValueForAngle: function(/*Number*/angle){
113                // summary:
114                //              This is a helper function used to determine the value represented by a
115                //              given angle on the gauge
116                // angle:       Number
117                //              A angle to be converted to a value for this gauge.
118                var startAngle = this._mod360(this.startAngle);
119                var endAngle = this._mod360(this.endAngle);
120
121                if (!this._angleInRange(angle)){
122
123                        var min1 = this._mod360(startAngle - angle);
124                        var min2 = 360 - min1;
125                        var max1 = this._mod360(endAngle - angle);
126                        var max2 = 360 - max1;
127                        if (Math.min(min1, min2) < Math.min(max1, max2))
128                                return this.min;
129                        else
130                                return this.max;
131                }
132                else {
133                        var range = Math.abs(this.max - this.min);
134                        var relativeAngle = this._mod360(this.orientation == 'clockwise' ?
135                                (angle - startAngle): (-angle + startAngle));
136                        return this.min + range * relativeAngle / this._getAngleRange();
137                }
138        },
139
140        _getAngleRange: function(){
141                // summary:
142                //              This is a helper function that returns the angle range
143                //              from startAngle to endAngle according to orientation.
144                var range;
145                var startAngle = this._mod360(this.startAngle);
146                var endAngle = this._mod360(this.endAngle);
147                if (startAngle == endAngle)
148                        return 360;
149                if (this.orientation == 'clockwise'){
150                        if (endAngle < startAngle)
151                                range = 360 - (startAngle - endAngle);
152                        else
153                                range = endAngle - startAngle;
154                }
155                else {
156                        if (endAngle < startAngle)
157                                range = startAngle - endAngle;
158                        else
159                                range = 360 - (endAngle - startAngle);
160                }
161                return range;
162        },
163       
164        _angleInRange: function(value){
165                // summary:
166                //              Test if the angle value is in the startAngle/endAngle range
167                var startAngle = this._mod360(this.startAngle);
168                var endAngle = this._mod360(this.endAngle);
169                if (startAngle == endAngle)
170                        return true;
171                        value = this._mod360(value);
172                if (this.orientation == "clockwise"){
173                        if (startAngle < endAngle)
174                                return value >= startAngle && value <= endAngle;
175                        else
176                                return !(value > endAngle && value < startAngle);
177                }
178                else {
179                        if (startAngle < endAngle)
180                                return !(value > startAngle && value < endAngle);
181                        else
182                                return value >= endAngle && value <= startAngle;
183                }
184        },
185       
186        _isScaleCircular: function(){
187                // summary:
188                //              internal method to check if the scale is fully circular
189                return (this._mod360(this.startAngle) == this._mod360(this.endAngle));
190        },
191       
192        _mod360:function(v){
193                // summary:
194                //              returns the angle between 0 and 360;
195                while (v>360) v = v - 360;
196                while (v<0) v = v + 360;
197                return v;
198        },
199
200        _getRadians: function(/*Number*/angle){
201                // summary:
202                //              This is a helper function than converts degrees to radians
203                // angle:       Number
204                //              An angle, in degrees, to be converted to radians.
205                return angle*Math.PI/180;
206        },
207
208        _getDegrees: function(/*Number*/radians){
209                // summary:
210                //              This is a helper function that converts radians to degrees
211                // radians:     Number
212                //              An angle, in radians, to be converted to degrees.
213                return radians*180/Math.PI;
214        },
215
216
217        drawRange: function(/*dojox.gfx.Group*/ group, /*Object*/range){
218                // summary:
219                //              This function is used to draw (or redraw) a range
220                // description:
221                //              Draws a range (colored area on the background of the gauge)
222                //              based on the given arguments.
223                // group:
224                //              The GFX group where the range must be drawn.
225                // range:
226                //              A range is a dojox.gauges.Range or an object
227                //              with similar parameters (low, high, hover, etc.).
228                var path;
229                if(range.shape){
230                        range.shape.parent.remove(range.shape);
231                        range.shape = null;
232                }
233                var a1, a2;
234                if((range.low == this.min) && (range.high == this.max) && ((this._mod360(this.endAngle) == this._mod360(this.startAngle)))){
235                        path = group.createCircle({cx: this.cx, cy: this.cy, r: this.radius});
236                }else{
237                       
238                       
239                        a1 = this._getRadians(this._getAngle(range.low));
240                        a2 = this._getRadians(this._getAngle(range.high));
241                        if (this.orientation == 'cclockwise')
242                        {
243                                var a = a2;
244                                a2 = a1;
245                                a1 = a;
246                        }
247                       
248                        var x1=this.cx+this.radius*Math.sin(a1),
249                                y1=this.cy-this.radius*Math.cos(a1),
250                                x2=this.cx+this.radius*Math.sin(a2),
251                                y2=this.cy-this.radius*Math.cos(a2),
252                                big=0
253                        ;
254                       
255                        var arange;
256                        if (a1<=a2)
257                           arange = a2-a1;
258                        else
259                           arange = 2*Math.PI-a1+a2;
260                        if(arange>Math.PI){big=1;}
261                       
262                        path = group.createPath();
263                        if(range.size){
264                                path.moveTo(this.cx+(this.radius-range.size)*Math.sin(a1),
265                                                        this.cy-(this.radius-range.size)*Math.cos(a1));
266                        }else{
267                                path.moveTo(this.cx,this.cy);
268                        }
269                        path.lineTo(x1,y1);
270                        path.arcTo(this.radius,this.radius,0,big,1,x2,y2);
271                        if(range.size){
272                                path.lineTo(this.cx+(this.radius-range.size)*Math.sin(a2),
273                                                        this.cy-(this.radius-range.size)*Math.cos(a2));
274                                path.arcTo((this.radius-range.size),(this.radius-range.size),0,big,0,
275                                                        this.cx+(this.radius-range.size)*Math.sin(a1),
276                                                        this.cy-(this.radius-range.size)*Math.cos(a1));
277                        }
278                        path.closePath();
279                }
280
281                if(lang.isArray(range.color) || lang.isString(range.color)){
282                        path.setStroke({color: range.color});
283                        path.setFill(range.color);
284                }else if(range.color.type){
285                        // Color is a gradient
286                        a1 = this._getRadians(this._getAngle(range.low));
287                        a2 = this._getRadians(this._getAngle(range.high));
288                        range.color.x1 = this.cx+(this.radius*Math.sin(a1))/2;
289                        range.color.x2 = this.cx+(this.radius*Math.sin(a2))/2;
290                        range.color.y1 = this.cy-(this.radius*Math.cos(a1))/2;
291                        range.color.y2 = this.cy-(this.radius*Math.cos(a2))/2;
292                        path.setFill(range.color);
293                        path.setStroke({color: range.color.colors[0].color});
294                }else if (gfx.svg){
295                        // We've defined a style rather than an explicit color
296                        path.setStroke({color: "green"});       // Arbitrary color, just have to indicate
297                        path.setFill("green");                          // that we want it filled
298                        path.getEventSource().setAttribute("class", range.color.style);
299                }
300               
301                path.connect("onmouseover", lang.hitch(this, this._handleMouseOverRange, range));
302                path.connect("onmouseout", lang.hitch(this, this._handleMouseOutRange, range));
303       
304                range.shape = path;
305        },
306
307        getRangeUnderMouse: function(/*Object*/e){
308                // summary:
309                //              Determines which range the mouse is currently over
310                // e:   Object
311                //              The event object as received by the mouse handling functions below.
312                var range = null,
313                        pos = domGeometry.getContentBox(this.gaugeContent),
314                        x = e.clientX - pos.x,
315                        y = e.clientY - pos.y,
316                        r = Math.sqrt((y - this.cy)*(y - this.cy) + (x - this.cx)*(x - this.cx))
317                ;
318                if(r < this.radius){
319                        var angle = this._getDegrees(Math.atan2(y - this.cy, x - this.cx) + Math.PI/2),
320                        //if(angle > this.endAngle){angle = angle - 360;}
321                                value = this._getValueForAngle(angle)
322                        ;
323                        if(this._rangeData){
324                                for(var i=0; (i<this._rangeData.length) && !range; i++){
325                                        if((Number(this._rangeData[i].low) <= value) && (Number(this._rangeData[i].high) >= value)){
326                                                range = this._rangeData[i];
327                                        }
328                                }
329                        }
330                }
331                return range;
332        },
333
334        _dragIndicator: function(/*Object*/ widget, /*Object*/ e){
335                // summary:
336                //              Handles the dragging of an indicator to the event position, including moving/re-drawing
337                //              get angle for mouse position
338                this._dragIndicatorAt(widget, e.pageX, e.pageY);
339                event.stop(e);
340        },
341               
342        _dragIndicatorAt: function(/*Object*/ widget, x,y){
343                // summary:
344                //              Handles the dragging of an indicator to a specific position, including moving/re-drawing
345                //              get angle for mouse position
346                var pos = domGeometry.position(widget.gaugeContent, true),
347                        xf = x - pos.x,
348                        yf = y - pos.y,
349                        angle = widget._getDegrees(Math.atan2(yf - widget.cy, xf - widget.cx) + Math.PI/2);
350               
351                // get value and restrict to our min/max
352                var value = widget._getValueForAngle(angle);
353                value = Math.min(Math.max(value, widget.min), widget.max);
354                // update the indicator
355                widget._drag.value = widget._drag.currentValue = value;
356                // callback
357                widget._drag.onDragMove(widget._drag);
358                // rotate indicator
359                widget._drag.draw(this._indicatorsGroup, true);
360                widget._drag.valueChanged();
361        }
362
363});
364});
Note: See TracBrowser for help on using the repository browser.