summaryrefslogtreecommitdiff
path: root/js/dojo/dojox/charting/widget/SelectableLegend.js
diff options
context:
space:
mode:
Diffstat (limited to 'js/dojo/dojox/charting/widget/SelectableLegend.js')
-rw-r--r--js/dojo/dojox/charting/widget/SelectableLegend.js245
1 files changed, 245 insertions, 0 deletions
diff --git a/js/dojo/dojox/charting/widget/SelectableLegend.js b/js/dojo/dojox/charting/widget/SelectableLegend.js
new file mode 100644
index 0000000..2836679
--- /dev/null
+++ b/js/dojo/dojox/charting/widget/SelectableLegend.js
@@ -0,0 +1,245 @@
+//>>built
+define("dojox/charting/widget/SelectableLegend", ["dojo/_base/lang", "dojo/_base/array", "dojo/_base/declare", "dojo/query", "dojo/_base/html",
+ "dojo/_base/connect", "dojo/_base/Color", "./Legend", "dijit/form/CheckBox", "../action2d/Highlight",
+ "dojox/lang/functional", "dojox/gfx/fx", "dojo/keys", "dojo/_base/event", "dojo/dom-construct",
+ "dojo/dom-prop"],
+ function(lang, arrayUtil, declare, query, html, hub, Color, Legend, CheckBox,
+ Highlight, df, fx, keys, event, dom, domProp){
+/*=====
+var Legend = dojox.charting.widget.Legend;
+=====*/
+ var FocusManager = declare(null, {
+ // summary:
+ // It will take legend as a tab stop, and using
+ // cursor keys to navigate labels within the legend.
+ constructor: function(legend){
+ this.legend = legend;
+ this.index = 0;
+ this.horizontalLength = this._getHrizontalLength();
+ arrayUtil.forEach(legend.legends, function(item, i){
+ if(i > 0){
+ query("input", item).attr("tabindex", -1);
+ }
+ });
+ this.firstLabel = query("input", legend.legends[0])[0];
+ hub.connect(this.firstLabel, "focus", this, function(){this.legend.active = true;});
+ hub.connect(this.legend.domNode, "keydown", this, "_onKeyEvent");
+ },
+ _getHrizontalLength: function(){
+ var horizontal = this.legend.horizontal;
+ if(typeof horizontal == "number"){
+ return Math.min(horizontal, this.legend.legends.length);
+ }else if(!horizontal){
+ return 1;
+ }else{
+ return this.legend.legends.length;
+ }
+ },
+ _onKeyEvent: function(e){
+ // if not focused
+ if(!this.legend.active){
+ return;
+ }
+ // lose focus
+ if(e.keyCode == keys.TAB){
+ this.legend.active = false;
+ return;
+ }
+ // handle with arrow keys
+ var max = this.legend.legends.length;
+ switch(e.keyCode){
+ case keys.LEFT_ARROW:
+ this.index--;
+ if(this.index < 0){
+ this.index += max;
+ }
+ break;
+ case keys.RIGHT_ARROW:
+ this.index++;
+ if(this.index >= max){
+ this.index -= max;
+ }
+ break;
+ case keys.UP_ARROW:
+ if(this.index - this.horizontalLength >= 0){
+ this.index -= this.horizontalLength;
+ }
+ break;
+ case keys.DOWN_ARROW:
+ if(this.index + this.horizontalLength < max){
+ this.index += this.horizontalLength;
+ }
+ break;
+ default:
+ return;
+ }
+ this._moveToFocus();
+ Event.stop(e);
+ },
+ _moveToFocus: function(){
+ query("input", this.legend.legends[this.index])[0].focus();
+ }
+ });
+
+ declare("dojox.charting.widget.SelectableLegend", Legend, {
+ // summary:
+ // An enhanced chart legend supporting interactive events on data series
+
+ // theme component
+ outline: false, // outline of vanished data series
+ transitionFill: null, // fill of deselected data series
+ transitionStroke: null, // stroke of deselected data series
+
+ postCreate: function(){
+ this.legends = [];
+ this.legendAnim = {};
+ this.inherited(arguments);
+ },
+ refresh: function(){
+ this.legends = [];
+ this.inherited(arguments);
+ this._applyEvents();
+ new FocusManager(this);
+ },
+ _addLabel: function(dyn, label){
+ this.inherited(arguments);
+ // create checkbox
+ var legendNodes = query("td", this.legendBody);
+ var currentLegendNode = legendNodes[legendNodes.length - 1];
+ this.legends.push(currentLegendNode);
+ var checkbox = new CheckBox({checked: true});
+ dom.place(checkbox.domNode, currentLegendNode, "first");
+ // connect checkbox and existed label
+ var label = query("label", currentLegendNode)[0];
+ domProp.set(label, "for", checkbox.id);
+ },
+ _applyEvents: function(){
+ // summary:
+ // Apply click-event on checkbox and hover-event on legend icon,
+ // highlight data series or toggle it.
+ // if the chart has not yet been refreshed it will crash here (targetData.group == null)
+ if(this.chart.dirty){
+ return;
+ }
+ arrayUtil.forEach(this.legends, function(legend, i){
+ var targetData, shapes = [], plotName, seriesName;
+ if(this._isPie()){
+ targetData = this.chart.stack[0];
+ shapes.push(targetData.group.children[i]);
+ plotName = targetData.name;
+ seriesName = this.chart.series[0].name;
+ }else{
+ targetData = this.chart.series[i];
+ shapes = targetData.group.children;
+ plotName = targetData.plot;
+ seriesName = targetData.name;
+ }
+ var originalDyn = {
+ fills : df.map(shapes, "x.getFill()"),
+ strokes: df.map(shapes, "x.getStroke()")
+ };
+ // toggle action
+ var legendCheckBox = query(".dijitCheckBox", legend)[0];
+ hub.connect(legendCheckBox, "onclick", this, function(e){
+ this._toggle(shapes, i, legend.vanished, originalDyn, seriesName, plotName);
+ legend.vanished = !legend.vanished;
+ e.stopPropagation();
+ });
+
+ // highlight action
+ var legendIcon = query(".dojoxLegendIcon", legend)[0],
+ iconShape = this._getFilledShape(this._surfaces[i].children);
+ arrayUtil.forEach(["onmouseenter", "onmouseleave"], function(event){
+ hub.connect(legendIcon, event, this, function(e){
+ this._highlight(e, iconShape, shapes, i, legend.vanished, originalDyn, seriesName, plotName);
+ });
+ }, this);
+ },this);
+ },
+ _toggle: function(shapes, index, isOff, dyn, seriesName, plotName){
+ arrayUtil.forEach(shapes, function(shape, i){
+ var startFill = dyn.fills[i],
+ endFill = this._getTransitionFill(plotName),
+ startStroke = dyn.strokes[i],
+ endStroke = this.transitionStroke;
+ if(startFill){
+ if(endFill && (typeof startFill == "string" || startFill instanceof Color)){
+ fx.animateFill({
+ shape: shape,
+ color: {
+ start: isOff ? endFill : startFill,
+ end: isOff ? startFill : endFill
+ }
+ }).play();
+ }else{
+ shape.setFill(isOff ? startFill : endFill);
+ }
+ }
+ if(startStroke && !this.outline){
+ shape.setStroke(isOff ? startStroke : endStroke);
+ }
+ }, this);
+ },
+ _highlight: function(e, iconShape, shapes, index, isOff, dyn, seriesName, plotName){
+ if(!isOff){
+ var anim = this._getAnim(plotName),
+ isPie = this._isPie(),
+ type = formatEventType(e.type);
+ // highlight the label icon,
+ var label = {
+ shape: iconShape,
+ index: isPie ? "legend" + index : "legend",
+ run: {name: seriesName},
+ type: type
+ };
+ anim.process(label);
+ // highlight the data items
+ arrayUtil.forEach(shapes, function(shape, i){
+ shape.setFill(dyn.fills[i]);
+ var o = {
+ shape: shape,
+ index: isPie ? index : i,
+ run: {name: seriesName},
+ type: type
+ };
+ anim.duration = 100;
+ anim.process(o);
+ });
+ }
+ },
+ _getAnim: function(plotName){
+ if(!this.legendAnim[plotName]){
+ this.legendAnim[plotName] = new Highlight(this.chart, plotName);
+ }
+ return this.legendAnim[plotName];
+ },
+ _getTransitionFill: function(plotName){
+ // Since series of stacked charts all start from the base line,
+ // fill the "front" series with plotarea color to make it disappear .
+ if(this.chart.stack[this.chart.plots[plotName]].declaredClass.indexOf("dojox.charting.plot2d.Stacked") != -1){
+ return this.chart.theme.plotarea.fill;
+ }
+ return null;
+ },
+ _getFilledShape: function(shapes){
+ // summary:
+ // Get filled shape in legend icon which would be highlighted when hovered
+ var i = 0;
+ while(shapes[i]){
+ if(shapes[i].getFill())return shapes[i];
+ i++;
+ }
+ },
+ _isPie: function(){
+ return this.chart.stack[0].declaredClass == "dojox.charting.plot2d.Pie";
+ }
+ });
+
+ function formatEventType(type){
+ if(type == "mouseenter")return "onmouseover";
+ if(type == "mouseleave")return "onmouseout";
+ return "on" + type;
+ }
+
+ return dojox.charting.widget.SelectableLegend;
+});