diff options
Diffstat (limited to 'js/dojo/dojox/gauges/AnalogGauge.js')
| -rw-r--r-- | js/dojo/dojox/gauges/AnalogGauge.js | 369 |
1 files changed, 369 insertions, 0 deletions
diff --git a/js/dojo/dojox/gauges/AnalogGauge.js b/js/dojo/dojox/gauges/AnalogGauge.js new file mode 100644 index 0000000..2024615 --- /dev/null +++ b/js/dojo/dojox/gauges/AnalogGauge.js @@ -0,0 +1,369 @@ +//>>built +define("dojox/gauges/AnalogGauge", ["dojo/_base/kernel","dojo/_base/declare","dojo/_base/array","dojo/_base/lang","dojo/_base/html","dojo/_base/event", + "dojox/gfx", "./_Gauge","./AnalogLineIndicator", "dojo/dom-geometry"], + function(dojo, declare, arr, lang, html, event, + gfx, Gauge, AnalogLineIndicator, domGeometry) { + +/*===== + Gauge = dojox.gauges._Gauge; +=====*/ + +return declare("dojox.gauges.AnalogGauge",Gauge,{ + // summary: + // a gauge built using the dojox.gfx package. + // + // description: + // using dojo.gfx (and thus either SVG or VML based on what is supported), this widget + // builds a gauge component, used to display numerical data in a familiar format + // + // example: + // | <script type="text/javascript"> + // | require(["dojox/gauges/AnalogGauge"]); + // | </script> + // | + // | <div dojoType="dojox.gauges.AnalogGauge" + // | id="testGauge" + // | width="300" + // | height="200" + // | cx=150 + // | cy=175 + // | radius=125 + // | image="gaugeOverlay.png" + // | imageOverlay="false" + // | imageWidth="280" + // | imageHeight="155" + // | imageX="12" + // | imageY="38"> + // | </div> + + // startAngle: Number + // angle (in degrees) for start of gauge (default is -90) + startAngle: -90, + + // endAngle: Number + // angle (in degrees) for end of gauge (default is 90) + endAngle: 90, + + // cx: Number + // center of gauge x coordinate (default is gauge width / 2) + cx: 0, + + // cy: Number + // center of gauge x coordinate (default is gauge height / 2) + cy: 0, + + // radius: Number + // radius of gauge (default is smaller of cx-25 or cy-25) + radius: 0, + + // orientation: String + // The orientation of the gauge. The value can be 'clockwise' or 'cclockwise' (default is 'clockwise') + orientation: "clockwise", + + // _defaultIndicator: dojox.gauges._Indicator + // override of dojox.gauges._Gauge._defaultIndicator + _defaultIndicator: AnalogLineIndicator, + + startup: function(){ + // handle settings from HTML by making sure all the options are + // converted correctly to numbers and that we calculate defaults + // for cx, cy and radius + // also connects mouse handling events + + if(this.getChildren){ + arr.forEach(this.getChildren(), function(child){ child.startup(); }); + } + + this.startAngle = Number(this.startAngle); + this.endAngle = Number(this.endAngle); + + this.cx = Number(this.cx); + if(!this.cx){this.cx = this.width/2;} + this.cy = Number(this.cy); + if(!this.cy){this.cy = this.height/2;} + this.radius = Number(this.radius); + if(!this.radius){this.radius = Math.min(this.cx,this.cy) - 25;} + + + this.inherited(arguments); + }, + + _getAngle: function(/*Number*/value){ + // summary: + // This is a helper function used to determine the angle that represents + // a given value on the gauge + // value: Number + // A value to be converted to an angle for this gauge. + + var v = Number(value); + var angle; + if (value == null || isNaN(v) || v <= this.min) + angle = this._mod360(this.startAngle); + else + if (v >= this.max) + angle = this._mod360(this.endAngle); + else { + var startAngle = this._mod360(this.startAngle); + var relativeValue = (v - this.min); + if (this.orientation != 'clockwise') + relativeValue = -relativeValue; + + angle = this._mod360(startAngle + this._getAngleRange() * relativeValue / Math.abs(this.min - this.max)); + } + + return angle; + }, + + _getValueForAngle: function(/*Number*/angle){ + // summary: + // This is a helper function used to determine the value represented by a + // given angle on the gauge + // angle: Number + // A angle to be converted to a value for this gauge. + var startAngle = this._mod360(this.startAngle); + var endAngle = this._mod360(this.endAngle); + + if (!this._angleInRange(angle)){ + + var min1 = this._mod360(startAngle - angle); + var min2 = 360 - min1; + var max1 = this._mod360(endAngle - angle); + var max2 = 360 - max1; + if (Math.min(min1, min2) < Math.min(max1, max2)) + return this.min; + else + return this.max; + } + else { + var range = Math.abs(this.max - this.min); + var relativeAngle = this._mod360(this.orientation == 'clockwise' ? + (angle - startAngle): (-angle + startAngle)); + return this.min + range * relativeAngle / this._getAngleRange(); + } + }, + + _getAngleRange: function(){ + // summary: + // This is a helper function that returns the angle range + // from startAngle to endAngle according to orientation. + var range; + var startAngle = this._mod360(this.startAngle); + var endAngle = this._mod360(this.endAngle); + if (startAngle == endAngle) + return 360; + if (this.orientation == 'clockwise'){ + if (endAngle < startAngle) + range = 360 - (startAngle - endAngle); + else + range = endAngle - startAngle; + } + else { + if (endAngle < startAngle) + range = startAngle - endAngle; + else + range = 360 - (endAngle - startAngle); + } + return range; + }, + + _angleInRange: function(value){ + // summary: + // Test if the angle value is in the startAngle/endAngle range + var startAngle = this._mod360(this.startAngle); + var endAngle = this._mod360(this.endAngle); + if (startAngle == endAngle) + return true; + value = this._mod360(value); + if (this.orientation == "clockwise"){ + if (startAngle < endAngle) + return value >= startAngle && value <= endAngle; + else + return !(value > endAngle && value < startAngle); + } + else { + if (startAngle < endAngle) + return !(value > startAngle && value < endAngle); + else + return value >= endAngle && value <= startAngle; + } + }, + + _isScaleCircular: function(){ + // summary: + // internal method to check if the scale is fully circular + return (this._mod360(this.startAngle) == this._mod360(this.endAngle)); + }, + + _mod360:function(v){ + // summary: + // returns the angle between 0 and 360; + while (v>360) v = v - 360; + while (v<0) v = v + 360; + return v; + }, + + _getRadians: function(/*Number*/angle){ + // summary: + // This is a helper function than converts degrees to radians + // angle: Number + // An angle, in degrees, to be converted to radians. + return angle*Math.PI/180; + }, + + _getDegrees: function(/*Number*/radians){ + // summary: + // This is a helper function that converts radians to degrees + // radians: Number + // An angle, in radians, to be converted to degrees. + return radians*180/Math.PI; + }, + + + drawRange: function(/*dojox.gfx.Group*/ group, /*Object*/range){ + // summary: + // This function is used to draw (or redraw) a range + // description: + // Draws a range (colored area on the background of the gauge) + // based on the given arguments. + // group: + // The GFX group where the range must be drawn. + // range: + // A range is a dojox.gauges.Range or an object + // with similar parameters (low, high, hover, etc.). + var path; + if(range.shape){ + range.shape.parent.remove(range.shape); + range.shape = null; + } + var a1, a2; + if((range.low == this.min) && (range.high == this.max) && ((this._mod360(this.endAngle) == this._mod360(this.startAngle)))){ + path = group.createCircle({cx: this.cx, cy: this.cy, r: this.radius}); + }else{ + + + a1 = this._getRadians(this._getAngle(range.low)); + a2 = this._getRadians(this._getAngle(range.high)); + if (this.orientation == 'cclockwise') + { + var a = a2; + a2 = a1; + a1 = a; + } + + var x1=this.cx+this.radius*Math.sin(a1), + y1=this.cy-this.radius*Math.cos(a1), + x2=this.cx+this.radius*Math.sin(a2), + y2=this.cy-this.radius*Math.cos(a2), + big=0 + ; + + var arange; + if (a1<=a2) + arange = a2-a1; + else + arange = 2*Math.PI-a1+a2; + if(arange>Math.PI){big=1;} + + path = group.createPath(); + if(range.size){ + path.moveTo(this.cx+(this.radius-range.size)*Math.sin(a1), + this.cy-(this.radius-range.size)*Math.cos(a1)); + }else{ + path.moveTo(this.cx,this.cy); + } + path.lineTo(x1,y1); + path.arcTo(this.radius,this.radius,0,big,1,x2,y2); + if(range.size){ + path.lineTo(this.cx+(this.radius-range.size)*Math.sin(a2), + this.cy-(this.radius-range.size)*Math.cos(a2)); + path.arcTo((this.radius-range.size),(this.radius-range.size),0,big,0, + this.cx+(this.radius-range.size)*Math.sin(a1), + this.cy-(this.radius-range.size)*Math.cos(a1)); + } + path.closePath(); + } + + if(lang.isArray(range.color) || lang.isString(range.color)){ + path.setStroke({color: range.color}); + path.setFill(range.color); + }else if(range.color.type){ + // Color is a gradient + a1 = this._getRadians(this._getAngle(range.low)); + a2 = this._getRadians(this._getAngle(range.high)); + range.color.x1 = this.cx+(this.radius*Math.sin(a1))/2; + range.color.x2 = this.cx+(this.radius*Math.sin(a2))/2; + range.color.y1 = this.cy-(this.radius*Math.cos(a1))/2; + range.color.y2 = this.cy-(this.radius*Math.cos(a2))/2; + path.setFill(range.color); + path.setStroke({color: range.color.colors[0].color}); + }else if (gfx.svg){ + // We've defined a style rather than an explicit color + path.setStroke({color: "green"}); // Arbitrary color, just have to indicate + path.setFill("green"); // that we want it filled + path.getEventSource().setAttribute("class", range.color.style); + } + + path.connect("onmouseover", lang.hitch(this, this._handleMouseOverRange, range)); + path.connect("onmouseout", lang.hitch(this, this._handleMouseOutRange, range)); + + range.shape = path; + }, + + getRangeUnderMouse: function(/*Object*/e){ + // summary: + // Determines which range the mouse is currently over + // e: Object + // The event object as received by the mouse handling functions below. + var range = null, + pos = domGeometry.getContentBox(this.gaugeContent), + x = e.clientX - pos.x, + y = e.clientY - pos.y, + r = Math.sqrt((y - this.cy)*(y - this.cy) + (x - this.cx)*(x - this.cx)) + ; + if(r < this.radius){ + var angle = this._getDegrees(Math.atan2(y - this.cy, x - this.cx) + Math.PI/2), + //if(angle > this.endAngle){angle = angle - 360;} + value = this._getValueForAngle(angle) + ; + if(this._rangeData){ + for(var i=0; (i<this._rangeData.length) && !range; i++){ + if((Number(this._rangeData[i].low) <= value) && (Number(this._rangeData[i].high) >= value)){ + range = this._rangeData[i]; + } + } + } + } + return range; + }, + + _dragIndicator: function(/*Object*/ widget, /*Object*/ e){ + // summary: + // Handles the dragging of an indicator to the event position, including moving/re-drawing + // get angle for mouse position + this._dragIndicatorAt(widget, e.pageX, e.pageY); + event.stop(e); + }, + + _dragIndicatorAt: function(/*Object*/ widget, x,y){ + // summary: + // Handles the dragging of an indicator to a specific position, including moving/re-drawing + // get angle for mouse position + var pos = domGeometry.position(widget.gaugeContent, true), + xf = x - pos.x, + yf = y - pos.y, + angle = widget._getDegrees(Math.atan2(yf - widget.cy, xf - widget.cx) + Math.PI/2); + + // get value and restrict to our min/max + var value = widget._getValueForAngle(angle); + value = Math.min(Math.max(value, widget.min), widget.max); + // update the indicator + widget._drag.value = widget._drag.currentValue = value; + // callback + widget._drag.onDragMove(widget._drag); + // rotate indicator + widget._drag.draw(this._indicatorsGroup, true); + widget._drag.valueChanged(); + } + +}); +}); |
