LegendView.js 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291
  1. var _config = require("../../config");
  2. var __DEV__ = _config.__DEV__;
  3. var echarts = require("../../echarts");
  4. var zrUtil = require("zrender/lib/core/util");
  5. var _symbol = require("../../util/symbol");
  6. var createSymbol = _symbol.createSymbol;
  7. var graphic = require("../../util/graphic");
  8. var _listComponent = require("../helper/listComponent");
  9. var makeBackground = _listComponent.makeBackground;
  10. var layoutUtil = require("../../util/layout");
  11. var curry = zrUtil.curry;
  12. var each = zrUtil.each;
  13. var Group = graphic.Group;
  14. var _default = echarts.extendComponentView({
  15. type: 'legend.plain',
  16. newlineDisabled: false,
  17. /**
  18. * @override
  19. */
  20. init: function () {
  21. /**
  22. * @private
  23. * @type {module:zrender/container/Group}
  24. */
  25. this.group.add(this._contentGroup = new Group());
  26. /**
  27. * @private
  28. * @type {module:zrender/Element}
  29. */
  30. this._backgroundEl;
  31. },
  32. /**
  33. * @protected
  34. */
  35. getContentGroup: function () {
  36. return this._contentGroup;
  37. },
  38. /**
  39. * @override
  40. */
  41. render: function (legendModel, ecModel, api) {
  42. this.resetInner();
  43. if (!legendModel.get('show', true)) {
  44. return;
  45. }
  46. var itemAlign = legendModel.get('align');
  47. if (!itemAlign || itemAlign === 'auto') {
  48. itemAlign = legendModel.get('left') === 'right' && legendModel.get('orient') === 'vertical' ? 'right' : 'left';
  49. }
  50. this.renderInner(itemAlign, legendModel, ecModel, api); // Perform layout.
  51. var positionInfo = legendModel.getBoxLayoutParams();
  52. var viewportSize = {
  53. width: api.getWidth(),
  54. height: api.getHeight()
  55. };
  56. var padding = legendModel.get('padding');
  57. var maxSize = layoutUtil.getLayoutRect(positionInfo, viewportSize, padding);
  58. var mainRect = this.layoutInner(legendModel, itemAlign, maxSize); // Place mainGroup, based on the calculated `mainRect`.
  59. var layoutRect = layoutUtil.getLayoutRect(zrUtil.defaults({
  60. width: mainRect.width,
  61. height: mainRect.height
  62. }, positionInfo), viewportSize, padding);
  63. this.group.attr('position', [layoutRect.x - mainRect.x, layoutRect.y - mainRect.y]); // Render background after group is layout.
  64. this.group.add(this._backgroundEl = makeBackground(mainRect, legendModel));
  65. },
  66. /**
  67. * @protected
  68. */
  69. resetInner: function () {
  70. this.getContentGroup().removeAll();
  71. this._backgroundEl && this.group.remove(this._backgroundEl);
  72. },
  73. /**
  74. * @protected
  75. */
  76. renderInner: function (itemAlign, legendModel, ecModel, api) {
  77. var contentGroup = this.getContentGroup();
  78. var legendDrawnMap = zrUtil.createHashMap();
  79. var selectMode = legendModel.get('selectedMode');
  80. each(legendModel.getData(), function (itemModel, dataIndex) {
  81. var name = itemModel.get('name'); // Use empty string or \n as a newline string
  82. if (!this.newlineDisabled && (name === '' || name === '\n')) {
  83. contentGroup.add(new Group({
  84. newline: true
  85. }));
  86. return;
  87. }
  88. var seriesModel = ecModel.getSeriesByName(name)[0];
  89. if (legendDrawnMap.get(name)) {
  90. // Have been drawed
  91. return;
  92. } // Series legend
  93. if (seriesModel) {
  94. var data = seriesModel.getData();
  95. var color = data.getVisual('color'); // If color is a callback function
  96. if (typeof color === 'function') {
  97. // Use the first data
  98. color = color(seriesModel.getDataParams(0));
  99. } // Using rect symbol defaultly
  100. var legendSymbolType = data.getVisual('legendSymbol') || 'roundRect';
  101. var symbolType = data.getVisual('symbol');
  102. var itemGroup = this._createItem(name, dataIndex, itemModel, legendModel, legendSymbolType, symbolType, itemAlign, color, selectMode);
  103. itemGroup.on('click', curry(dispatchSelectAction, name, api)).on('mouseover', curry(dispatchHighlightAction, seriesModel, null, api)).on('mouseout', curry(dispatchDownplayAction, seriesModel, null, api));
  104. legendDrawnMap.set(name, true);
  105. } else {
  106. // Data legend of pie, funnel
  107. ecModel.eachRawSeries(function (seriesModel) {
  108. // In case multiple series has same data name
  109. if (legendDrawnMap.get(name)) {
  110. return;
  111. }
  112. if (seriesModel.legendDataProvider) {
  113. var data = seriesModel.legendDataProvider();
  114. var idx = data.indexOfName(name);
  115. if (idx < 0) {
  116. return;
  117. }
  118. var color = data.getItemVisual(idx, 'color');
  119. var legendSymbolType = 'roundRect';
  120. var itemGroup = this._createItem(name, dataIndex, itemModel, legendModel, legendSymbolType, null, itemAlign, color, selectMode);
  121. itemGroup.on('click', curry(dispatchSelectAction, name, api)) // FIXME Should not specify the series name
  122. .on('mouseover', curry(dispatchHighlightAction, seriesModel, name, api)).on('mouseout', curry(dispatchDownplayAction, seriesModel, name, api));
  123. legendDrawnMap.set(name, true);
  124. }
  125. }, this);
  126. }
  127. }, this);
  128. },
  129. _createItem: function (name, dataIndex, itemModel, legendModel, legendSymbolType, symbolType, itemAlign, color, selectMode) {
  130. var itemWidth = legendModel.get('itemWidth');
  131. var itemHeight = legendModel.get('itemHeight');
  132. var inactiveColor = legendModel.get('inactiveColor');
  133. var isSelected = legendModel.isSelected(name);
  134. var itemGroup = new Group();
  135. var textStyleModel = itemModel.getModel('textStyle');
  136. var itemIcon = itemModel.get('icon');
  137. var tooltipModel = itemModel.getModel('tooltip');
  138. var legendGlobalTooltipModel = tooltipModel.parentModel; // Use user given icon first
  139. legendSymbolType = itemIcon || legendSymbolType;
  140. itemGroup.add(createSymbol(legendSymbolType, 0, 0, itemWidth, itemHeight, isSelected ? color : inactiveColor, true)); // Compose symbols
  141. // PENDING
  142. if (!itemIcon && symbolType // At least show one symbol, can't be all none
  143. && (symbolType !== legendSymbolType || symbolType == 'none')) {
  144. var size = itemHeight * 0.8;
  145. if (symbolType === 'none') {
  146. symbolType = 'circle';
  147. } // Put symbol in the center
  148. itemGroup.add(createSymbol(symbolType, (itemWidth - size) / 2, (itemHeight - size) / 2, size, size, isSelected ? color : inactiveColor));
  149. }
  150. var textX = itemAlign === 'left' ? itemWidth + 5 : -5;
  151. var textAlign = itemAlign;
  152. var formatter = legendModel.get('formatter');
  153. var content = name;
  154. if (typeof formatter === 'string' && formatter) {
  155. content = formatter.replace('{name}', name != null ? name : '');
  156. } else if (typeof formatter === 'function') {
  157. content = formatter(name);
  158. }
  159. itemGroup.add(new graphic.Text({
  160. style: graphic.setTextStyle({}, textStyleModel, {
  161. text: content,
  162. x: textX,
  163. y: itemHeight / 2,
  164. textFill: isSelected ? textStyleModel.getTextColor() : inactiveColor,
  165. textAlign: textAlign,
  166. textVerticalAlign: 'middle'
  167. })
  168. })); // Add a invisible rect to increase the area of mouse hover
  169. var hitRect = new graphic.Rect({
  170. shape: itemGroup.getBoundingRect(),
  171. invisible: true,
  172. tooltip: tooltipModel.get('show') ? zrUtil.extend({
  173. content: name,
  174. // Defaul formatter
  175. formatter: legendGlobalTooltipModel.get('formatter', true) || function () {
  176. return name;
  177. },
  178. formatterParams: {
  179. componentType: 'legend',
  180. legendIndex: legendModel.componentIndex,
  181. name: name,
  182. $vars: ['name']
  183. }
  184. }, tooltipModel.option) : null
  185. });
  186. itemGroup.add(hitRect);
  187. itemGroup.eachChild(function (child) {
  188. child.silent = true;
  189. });
  190. hitRect.silent = !selectMode;
  191. this.getContentGroup().add(itemGroup);
  192. graphic.setHoverStyle(itemGroup);
  193. itemGroup.__legendDataIndex = dataIndex;
  194. return itemGroup;
  195. },
  196. /**
  197. * @protected
  198. */
  199. layoutInner: function (legendModel, itemAlign, maxSize) {
  200. var contentGroup = this.getContentGroup(); // Place items in contentGroup.
  201. layoutUtil.box(legendModel.get('orient'), contentGroup, legendModel.get('itemGap'), maxSize.width, maxSize.height);
  202. var contentRect = contentGroup.getBoundingRect();
  203. contentGroup.attr('position', [-contentRect.x, -contentRect.y]);
  204. return this.group.getBoundingRect();
  205. }
  206. });
  207. function dispatchSelectAction(name, api) {
  208. api.dispatchAction({
  209. type: 'legendToggleSelect',
  210. name: name
  211. });
  212. }
  213. function dispatchHighlightAction(seriesModel, dataName, api) {
  214. // If element hover will move to a hoverLayer.
  215. var el = api.getZr().storage.getDisplayList()[0];
  216. if (!(el && el.useHoverLayer)) {
  217. seriesModel.get('legendHoverLink') && api.dispatchAction({
  218. type: 'highlight',
  219. seriesName: seriesModel.name,
  220. name: dataName
  221. });
  222. }
  223. }
  224. function dispatchDownplayAction(seriesModel, dataName, api) {
  225. // If element hover will move to a hoverLayer.
  226. var el = api.getZr().storage.getDisplayList()[0];
  227. if (!(el && el.useHoverLayer)) {
  228. seriesModel.get('legendHoverLink') && api.dispatchAction({
  229. type: 'downplay',
  230. seriesName: seriesModel.name,
  231. name: dataName
  232. });
  233. }
  234. }
  235. module.exports = _default;