246 lines
7.5 KiB
JavaScript
246 lines
7.5 KiB
JavaScript
|
//>>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;
|
||
|
});
|