SelectableLegend.js 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248
  1. /*
  2. Copyright (c) 2004-2012, The Dojo Foundation All Rights Reserved.
  3. Available via Academic Free License >= 2.1 OR the modified BSD license.
  4. see: http://dojotoolkit.org/license for details
  5. */
  6. if(!dojo._hasResource["dojox.charting.widget.SelectableLegend"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
  7. dojo._hasResource["dojox.charting.widget.SelectableLegend"] = true;
  8. dojo.provide("dojox.charting.widget.SelectableLegend");
  9. dojo.require("dojox.charting.widget.Legend");
  10. dojo.require("dijit.form.CheckBox");
  11. dojo.require("dojox.charting.action2d.Highlight");
  12. (function(){
  13. var df = dojox.lang.functional;
  14. dojo.declare("dojox.charting.widget.SelectableLegend", [dojox.charting.widget.Legend], {
  15. // summary:
  16. // An enhanced chart legend supporting interactive events on data series
  17. // theme component
  18. outline: false, // outline of vanished data series
  19. transitionFill: null, // fill of deselected data series
  20. transitionStroke: null, // stroke of deselected data series
  21. postCreate: function(){
  22. this.legends = [];
  23. this.legendAnim = {};
  24. this.inherited(arguments);
  25. },
  26. refresh: function(){
  27. this.legends = [];
  28. this.inherited(arguments);
  29. this._applyEvents();
  30. new dojox.charting.widget._FocusManager(this);
  31. },
  32. _addLabel: function(dyn, label){
  33. this.inherited(arguments);
  34. // create checkbox
  35. var legendNodes = dojo.query("td", this.legendBody);
  36. var currentLegendNode = legendNodes[legendNodes.length - 1];
  37. this.legends.push(currentLegendNode);
  38. var checkbox = new dijit.form.CheckBox({checked: true});
  39. dojo.place(checkbox.domNode, currentLegendNode, "first");
  40. // connect checkbox and existed label
  41. var label = dojo.query("label", currentLegendNode)[0];
  42. dojo.attr(label, "for", checkbox.id);
  43. },
  44. _applyEvents: function(){
  45. // summary:
  46. // Apply click-event on checkbox and hover-event on legend icon,
  47. // highlight data series or toggle it.
  48. dojo.forEach(this.legends, function(legend, i){
  49. var targetData, shapes = [], plotName, seriesName;
  50. if(this._isPie()){
  51. targetData = this.chart.stack[0];
  52. shapes.push(targetData.group.children[i]);
  53. plotName = targetData.name;
  54. seriesName = this.chart.series[0].name;
  55. }else{
  56. targetData = this.chart.series[i];
  57. shapes = targetData.group.children;
  58. plotName = targetData.plot;
  59. seriesName = targetData.name;
  60. }
  61. var originalDyn = {
  62. fills : df.map(shapes, "x.getFill()"),
  63. strokes: df.map(shapes, "x.getStroke()")
  64. };
  65. // toggle action
  66. var legendCheckBox = dojo.query(".dijitCheckBox", legend)[0];
  67. dojo.connect(legendCheckBox, "onclick", this, function(e){
  68. this._toggle(shapes, i, legend.vanished, originalDyn, seriesName, plotName);
  69. legend.vanished = !legend.vanished;
  70. e.stopPropagation();
  71. });
  72. // highlight action
  73. var legendIcon = dojo.query(".dojoxLegendIcon", legend)[0],
  74. iconShape = this._getFilledShape(this._surfaces[i].children);
  75. dojo.forEach(["onmouseenter", "onmouseleave"], function(event){
  76. dojo.connect(legendIcon, event, this, function(e){
  77. this._highlight(e, iconShape, shapes, i, legend.vanished, originalDyn, seriesName, plotName);
  78. });
  79. }, this);
  80. },this);
  81. },
  82. _toggle: function(shapes, index, isOff, dyn, seriesName, plotName){
  83. dojo.forEach(shapes, function(shape, i){
  84. var startFill = dyn.fills[i],
  85. endFill = this._getTransitionFill(plotName),
  86. startStroke = dyn.strokes[i],
  87. endStroke = this.transitionStroke;
  88. if(startFill){
  89. if(endFill && (typeof startFill == "string" || startFill instanceof dojo.Color)){
  90. dojox.gfx.fx.animateFill({
  91. shape: shape,
  92. color: {
  93. start: isOff ? endFill : startFill,
  94. end: isOff ? startFill : endFill
  95. }
  96. }).play();
  97. }else{
  98. shape.setFill(isOff ? startFill : endFill);
  99. }
  100. }
  101. if(startStroke && !this.outline){
  102. shape.setStroke(isOff ? startStroke : endStroke);
  103. }
  104. }, this);
  105. },
  106. _highlight: function(e, iconShape, shapes, index, isOff, dyn, seriesName, plotName){
  107. if(!isOff){
  108. var anim = this._getAnim(plotName),
  109. isPie = this._isPie(),
  110. type = formatEventType(e.type);
  111. // highlight the label icon,
  112. var label = {
  113. shape: iconShape,
  114. index: isPie ? "legend" + index : "legend",
  115. run: {name: seriesName},
  116. type: type
  117. };
  118. anim.process(label);
  119. // highlight the data items
  120. dojo.forEach(shapes, function(shape, i){
  121. shape.setFill(dyn.fills[i]);
  122. var o = {
  123. shape: shape,
  124. index: isPie ? index : i,
  125. run: {name: seriesName},
  126. type: type
  127. };
  128. anim.duration = 100;
  129. anim.process(o);
  130. });
  131. }
  132. },
  133. _getAnim: function(plotName){
  134. if(!this.legendAnim[plotName]){
  135. this.legendAnim[plotName] = new dojox.charting.action2d.Highlight(this.chart, plotName);
  136. }
  137. return this.legendAnim[plotName];
  138. },
  139. _getTransitionFill: function(plotName){
  140. // Since series of stacked charts all start from the base line,
  141. // fill the "front" series with plotarea color to make it disappear .
  142. if(this.chart.stack[this.chart.plots[plotName]].declaredClass.indexOf("dojox.charting.plot2d.Stacked") != -1){
  143. return this.chart.theme.plotarea.fill;
  144. }
  145. return null;
  146. },
  147. _getFilledShape: function(shapes){
  148. // summary:
  149. // Get filled shape in legend icon which would be highlighted when hovered
  150. var i = 0;
  151. while(shapes[i]){
  152. if(shapes[i].getFill())return shapes[i];
  153. i++;
  154. }
  155. },
  156. _isPie: function(){
  157. return this.chart.stack[0].declaredClass == "dojox.charting.plot2d.Pie";
  158. }
  159. });
  160. function formatEventType(type){
  161. if(type == "mouseenter")return "onmouseover";
  162. if(type == "mouseleave")return "onmouseout";
  163. return "on" + type;
  164. }
  165. dojo.declare("dojox.charting.widget._FocusManager", null, {
  166. // summary:
  167. // It will take legend as a tab stop, and using
  168. // cursor keys to navigate labels within the legend.
  169. constructor: function(legend){
  170. this.legend = legend;
  171. this.index = 0;
  172. this.horizontalLength = this._getHrizontalLength();
  173. dojo.forEach(legend.legends, function(item, i){
  174. if(i > 0){
  175. dojo.query("input", item).attr("tabindex", -1);
  176. }
  177. });
  178. this.firstLabel = dojo.query("input", legend.legends[0])[0];
  179. dojo.connect(this.firstLabel, "focus", this, function(){this.legend.active = true;});
  180. dojo.connect(this.legend.legendNode, "keydown", this, "_onKeyEvent");
  181. },
  182. _getHrizontalLength: function(){
  183. var horizontal = this.legend.horizontal;
  184. if(typeof horizontal == "number"){
  185. return Math.min(horizontal, this.legend.legends.length);
  186. }else if(!horizontal){
  187. return 1;
  188. }else{
  189. return this.legend.legends.length;
  190. }
  191. },
  192. _onKeyEvent: function(e){
  193. // if not focused
  194. if(!this.legend.active){
  195. return;
  196. }
  197. // lose focus
  198. if(e.keyCode == dojo.keys.TAB){
  199. this.legend.active = false;
  200. return;
  201. }
  202. // handle with arrow keys
  203. var max = this.legend.legends.length;
  204. switch(e.keyCode){
  205. case dojo.keys.LEFT_ARROW:
  206. this.index--;
  207. if(this.index < 0){
  208. this.index += max;
  209. }
  210. break;
  211. case dojo.keys.RIGHT_ARROW:
  212. this.index++;
  213. if(this.index >= max){
  214. this.index -= max;
  215. }
  216. break;
  217. case dojo.keys.UP_ARROW:
  218. if(this.index - this.horizontalLength >= 0){
  219. this.index -= this.horizontalLength;
  220. }
  221. break;
  222. case dojo.keys.DOWN_ARROW:
  223. if(this.index + this.horizontalLength < max){
  224. this.index += this.horizontalLength;
  225. }
  226. break;
  227. default:
  228. return;
  229. }
  230. this._moveToFocus();
  231. dojo.stopEvent(e);
  232. },
  233. _moveToFocus: function(){
  234. dojo.query("input", this.legend.legends[this.index])[0].focus();
  235. }
  236. });
  237. })();
  238. }