package flare.vis.legend { import flare.display.RectSprite; import flare.display.TextSprite; import flare.scale.IScaleMap; import flare.scale.Scale; import flare.util.Colors; import flare.util.Orientation; import flare.util.Stats; import flare.util.Vectors; import flare.util.palette.ColorPalette; import flash.display.GradientType; import flash.display.Graphics; import flash.display.Shape; import flash.display.Sprite; import flash.geom.Matrix; import flash.geom.Rectangle; import flash.text.TextFormat; /** * A range in a continuous legend, consisting of a continuous * visual scale and value labels. Legend ranges use a * ColorPalette instance for creating a gradient of * color values. If the stats property * is set with the Stats object for a backing data * variable, a histogram of values will also be drawn in the legend * range. To draw only a histogram, set the palette * property to null. */ public class LegendRange extends RectSprite implements IScaleMap { private var _dataField:String; private var _scale:Scale; private var _stats:Stats; private var _palette:ColorPalette; private var _matrix:Matrix = new Matrix(); private var _margin:Number = 5; private var _labels:Sprite; private var _fmt:TextFormat; private var _labelMode:int = TextSprite.BITMAP; private var _range:Shape; private var _rs:Number = 20; private var _borderColor:uint = 0xcccccc; private var _histogramColor:uint = 0x888888; private var _orient:String; private var _vert:Boolean; private var _rev:Boolean; /** The data field described by this legend range. */ public function get dataField():String { return _dataField; } /** Sprite containing the range's labels. */ public function get labels():Sprite { return _labels; } /** Stats object describing the data range. */ public function get stats():Stats { return _stats; } public function set stats(s:Stats):void { _stats = s; dirty(); } /** Text format (font, size, style) of legend range labels. */ public function get labelTextFormat():TextFormat { return _fmt; } public function set labelTextFormat(fmt:TextFormat):void { _fmt = fmt; dirty(); } /** TextFormat (font, size, style) of legend range labels. */ public function get labelTextMode():int { return _labelMode; } public function set labelTextMode(mode:int):void { _labelMode = mode; dirty(); } /** Margin value for padding within the legend item. */ public function get margin():Number { return _margin; } public function set margin(m:Number):void { _margin = m; dirty(); } /** The size of the range, this is either the width or height of * the range, depending on the current orientation. */ public function get rangeSize():Number { return _rs; } public function set rangeSize(s:Number):void { _rs = s; } /** The color of the legend range border. */ public function get borderColor():uint { return _borderColor; } public function set borderColor(c:uint):void { if (c != _borderColor) { _borderColor = c; dirty(); } } /** The color of bars in a generated histogram. */ public function get histogramColor():uint { return _histogramColor; } public function set histogramColor(c:uint):void { if (c == _histogramColor) return; _histogramColor = c; if (_stats) dirty(); } /** The desired orientation of this legend range. */ public function get orientation():String { return _orient; } public function set orientation(o:String):void { _orient = o; _vert = Orientation.isVertical(o); _rev = o==Orientation.RIGHT_TO_LEFT || o==Orientation.BOTTOM_TO_TOP; dirty(); } // -------------------------------------------------------------------- /** * Creates a new LegendRange. * @param dataField the data field described by this range * @param palette the color palette for the data field * @param scale the Scale instance mapping the data field to a visual * variable */ public function LegendRange(dataField:String, scale:Scale, palette:ColorPalette=null, orientation:String=Orientation.LEFT_TO_RIGHT) { _dataField = dataField; _palette = palette; _scale = scale; this.orientation = orientation; addChild(_range = new Shape()); addChild(_labels = new Sprite()); _range.cacheAsBitmap = true; } // -------------------------------------------------------------------- // Lookup /** @inheritDoc */ public function get x1():Number { return _vert || !_rev ? _margin : _w-_margin; } /** @inheritDoc */ public function get x2():Number { return _vert ? _margin+_rs : (_rev ? _margin : _w-_margin); } /** @inheritDoc */ public function get y1():Number { return _vert && !_rev ? _h-_margin : _margin; } /** @inheritDoc */ public function get y2():Number { return _vert ? (_rev ? _h-_margin : _margin) : _margin+_rs; } private var _bounds:Rectangle = new Rectangle(); /** * Bounds for the visual range portion of this legend range. * @return the bounds of the range display */ public function get bounds():Rectangle { _bounds.x = x1; _bounds.y = y1; _bounds.width = x2 - x1; _bounds.height = y2 - y1; return _bounds; } /** @inheritDoc */ public function value(x:Number, y:Number, stayInBounds:Boolean=true):Object { var f:Number; if (_vert) { f = (y-_margin) / (_h - 2*_margin); } else { f = (x-_margin) / (_w - 2*_margin); } // correct bounds if (stayInBounds) { if (f < 0) f = 0; if (f > 1) f = 1; } if (_rev) f = 1-f; // lookup and return value return _scale.lookup(f); } /** @inheritDoc */ public function X(val:Object):Number { return x1 + (_vert ? 0 : _scale.interpolate(val) * (x2 - x1)); } /** @inheritDoc */ public function Y(val:Object):Number { return y1 + (_vert ? _scale.interpolate(val) * (y2-y1) : y1); } // -------------------------------------------------------------------- // Layout and Render /** * Update the labels shown by this legend range. */ public function updateLabels():void { var pts:Vector. = _palette==null ? Vectors.copyFromArray([0,1]) : _palette.keyframes; var n:uint = pts.length; // filter for the needed number of labels for (var i:uint=_labels.numChildren; i=n;) { _labels.removeChildAt(i); } // update and layout the labels for (i=0; i = _stats.values; var ib:int = int(_vert ? h/2 : w/2); var pb:int = (_vert ? h : w) / ib; var d:Number = _vert ? w : h; var i:int, f:Number; var counts:Vector. = new Vector.(ib); for (i=0; i max) max = counts[i]; } max = d / (1.1*max); var g:Graphics = _range.graphics; g.beginFill(_histogramColor, _palette ? 0.5 : 1); for (i=0; i