LegendModel.js 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351
  1. /*
  2. * Licensed to the Apache Software Foundation (ASF) under one
  3. * or more contributor license agreements. See the NOTICE file
  4. * distributed with this work for additional information
  5. * regarding copyright ownership. The ASF licenses this file
  6. * to you under the Apache License, Version 2.0 (the
  7. * "License"); you may not use this file except in compliance
  8. * with the License. You may obtain a copy of the License at
  9. *
  10. * http://www.apache.org/licenses/LICENSE-2.0
  11. *
  12. * Unless required by applicable law or agreed to in writing,
  13. * software distributed under the License is distributed on an
  14. * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  15. * KIND, either express or implied. See the License for the
  16. * specific language governing permissions and limitations
  17. * under the License.
  18. */
  19. var echarts = require("../../echarts");
  20. var zrUtil = require("zrender/lib/core/util");
  21. var Model = require("../../model/Model");
  22. var _model = require("../../util/model");
  23. var isNameSpecified = _model.isNameSpecified;
  24. var lang = require("../../lang");
  25. /*
  26. * Licensed to the Apache Software Foundation (ASF) under one
  27. * or more contributor license agreements. See the NOTICE file
  28. * distributed with this work for additional information
  29. * regarding copyright ownership. The ASF licenses this file
  30. * to you under the Apache License, Version 2.0 (the
  31. * "License"); you may not use this file except in compliance
  32. * with the License. You may obtain a copy of the License at
  33. *
  34. * http://www.apache.org/licenses/LICENSE-2.0
  35. *
  36. * Unless required by applicable law or agreed to in writing,
  37. * software distributed under the License is distributed on an
  38. * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  39. * KIND, either express or implied. See the License for the
  40. * specific language governing permissions and limitations
  41. * under the License.
  42. */
  43. var langSelector = lang.legend.selector;
  44. var defaultSelectorOption = {
  45. all: {
  46. type: 'all',
  47. title: zrUtil.clone(langSelector.all)
  48. },
  49. inverse: {
  50. type: 'inverse',
  51. title: zrUtil.clone(langSelector.inverse)
  52. }
  53. };
  54. var LegendModel = echarts.extendComponentModel({
  55. type: 'legend.plain',
  56. dependencies: ['series'],
  57. layoutMode: {
  58. type: 'box',
  59. // legend.width/height are maxWidth/maxHeight actually,
  60. // whereas realy width/height is calculated by its content.
  61. // (Setting {left: 10, right: 10} does not make sense).
  62. // So consider the case:
  63. // `setOption({legend: {left: 10});`
  64. // then `setOption({legend: {right: 10});`
  65. // The previous `left` should be cleared by setting `ignoreSize`.
  66. ignoreSize: true
  67. },
  68. init: function (option, parentModel, ecModel) {
  69. this.mergeDefaultAndTheme(option, ecModel);
  70. option.selected = option.selected || {};
  71. this._updateSelector(option);
  72. },
  73. mergeOption: function (option) {
  74. LegendModel.superCall(this, 'mergeOption', option);
  75. this._updateSelector(option);
  76. },
  77. _updateSelector: function (option) {
  78. var selector = option.selector;
  79. if (selector === true) {
  80. selector = option.selector = ['all', 'inverse'];
  81. }
  82. if (zrUtil.isArray(selector)) {
  83. zrUtil.each(selector, function (item, index) {
  84. zrUtil.isString(item) && (item = {
  85. type: item
  86. });
  87. selector[index] = zrUtil.merge(item, defaultSelectorOption[item.type]);
  88. });
  89. }
  90. },
  91. optionUpdated: function () {
  92. this._updateData(this.ecModel);
  93. var legendData = this._data; // If selectedMode is single, try to select one
  94. if (legendData[0] && this.get('selectedMode') === 'single') {
  95. var hasSelected = false; // If has any selected in option.selected
  96. for (var i = 0; i < legendData.length; i++) {
  97. var name = legendData[i].get('name');
  98. if (this.isSelected(name)) {
  99. // Force to unselect others
  100. this.select(name);
  101. hasSelected = true;
  102. break;
  103. }
  104. } // Try select the first if selectedMode is single
  105. !hasSelected && this.select(legendData[0].get('name'));
  106. }
  107. },
  108. _updateData: function (ecModel) {
  109. var potentialData = [];
  110. var availableNames = [];
  111. ecModel.eachRawSeries(function (seriesModel) {
  112. var seriesName = seriesModel.name;
  113. availableNames.push(seriesName);
  114. var isPotential;
  115. if (seriesModel.legendVisualProvider) {
  116. var provider = seriesModel.legendVisualProvider;
  117. var names = provider.getAllNames();
  118. if (!ecModel.isSeriesFiltered(seriesModel)) {
  119. availableNames = availableNames.concat(names);
  120. }
  121. if (names.length) {
  122. potentialData = potentialData.concat(names);
  123. } else {
  124. isPotential = true;
  125. }
  126. } else {
  127. isPotential = true;
  128. }
  129. if (isPotential && isNameSpecified(seriesModel)) {
  130. potentialData.push(seriesModel.name);
  131. }
  132. });
  133. /**
  134. * @type {Array.<string>}
  135. * @private
  136. */
  137. this._availableNames = availableNames; // If legend.data not specified in option, use availableNames as data,
  138. // which is convinient for user preparing option.
  139. var rawData = this.get('data') || potentialData;
  140. var legendData = zrUtil.map(rawData, function (dataItem) {
  141. // Can be string or number
  142. if (typeof dataItem === 'string' || typeof dataItem === 'number') {
  143. dataItem = {
  144. name: dataItem
  145. };
  146. }
  147. return new Model(dataItem, this, this.ecModel);
  148. }, this);
  149. /**
  150. * @type {Array.<module:echarts/model/Model>}
  151. * @private
  152. */
  153. this._data = legendData;
  154. },
  155. /**
  156. * @return {Array.<module:echarts/model/Model>}
  157. */
  158. getData: function () {
  159. return this._data;
  160. },
  161. /**
  162. * @param {string} name
  163. */
  164. select: function (name) {
  165. var selected = this.option.selected;
  166. var selectedMode = this.get('selectedMode');
  167. if (selectedMode === 'single') {
  168. var data = this._data;
  169. zrUtil.each(data, function (dataItem) {
  170. selected[dataItem.get('name')] = false;
  171. });
  172. }
  173. selected[name] = true;
  174. },
  175. /**
  176. * @param {string} name
  177. */
  178. unSelect: function (name) {
  179. if (this.get('selectedMode') !== 'single') {
  180. this.option.selected[name] = false;
  181. }
  182. },
  183. /**
  184. * @param {string} name
  185. */
  186. toggleSelected: function (name) {
  187. var selected = this.option.selected; // Default is true
  188. if (!selected.hasOwnProperty(name)) {
  189. selected[name] = true;
  190. }
  191. this[selected[name] ? 'unSelect' : 'select'](name);
  192. },
  193. allSelect: function () {
  194. var data = this._data;
  195. var selected = this.option.selected;
  196. zrUtil.each(data, function (dataItem) {
  197. selected[dataItem.get('name', true)] = true;
  198. });
  199. },
  200. inverseSelect: function () {
  201. var data = this._data;
  202. var selected = this.option.selected;
  203. zrUtil.each(data, function (dataItem) {
  204. var name = dataItem.get('name', true); // Initially, default value is true
  205. if (!selected.hasOwnProperty(name)) {
  206. selected[name] = true;
  207. }
  208. selected[name] = !selected[name];
  209. });
  210. },
  211. /**
  212. * @param {string} name
  213. */
  214. isSelected: function (name) {
  215. var selected = this.option.selected;
  216. return !(selected.hasOwnProperty(name) && !selected[name]) && zrUtil.indexOf(this._availableNames, name) >= 0;
  217. },
  218. getOrient: function () {
  219. return this.get('orient') === 'vertical' ? {
  220. index: 1,
  221. name: 'vertical'
  222. } : {
  223. index: 0,
  224. name: 'horizontal'
  225. };
  226. },
  227. defaultOption: {
  228. // 一级层叠
  229. zlevel: 0,
  230. // 二级层叠
  231. z: 4,
  232. show: true,
  233. // 布局方式,默认为水平布局,可选为:
  234. // 'horizontal' | 'vertical'
  235. orient: 'horizontal',
  236. left: 'center',
  237. // right: 'center',
  238. top: 0,
  239. // bottom: null,
  240. // 水平对齐
  241. // 'auto' | 'left' | 'right'
  242. // 默认为 'auto', 根据 x 的位置判断是左对齐还是右对齐
  243. align: 'auto',
  244. backgroundColor: 'rgba(0,0,0,0)',
  245. // 图例边框颜色
  246. borderColor: '#ccc',
  247. borderRadius: 0,
  248. // 图例边框线宽,单位px,默认为0(无边框)
  249. borderWidth: 0,
  250. // 图例内边距,单位px,默认各方向内边距为5,
  251. // 接受数组分别设定上右下左边距,同css
  252. padding: 5,
  253. // 各个item之间的间隔,单位px,默认为10,
  254. // 横向布局时为水平间隔,纵向布局时为纵向间隔
  255. itemGap: 10,
  256. // the width of legend symbol
  257. itemWidth: 25,
  258. // the height of legend symbol
  259. itemHeight: 14,
  260. // the color of unselected legend symbol
  261. inactiveColor: '#ccc',
  262. // the borderColor of unselected legend symbol
  263. inactiveBorderColor: '#ccc',
  264. itemStyle: {
  265. // the default borderWidth of legend symbol
  266. borderWidth: 0
  267. },
  268. textStyle: {
  269. // 图例文字颜色
  270. color: '#333'
  271. },
  272. // formatter: '',
  273. // 选择模式,默认开启图例开关
  274. selectedMode: true,
  275. // 配置默认选中状态,可配合LEGEND.SELECTED事件做动态数据载入
  276. // selected: null,
  277. // 图例内容(详见legend.data,数组中每一项代表一个item
  278. // data: [],
  279. // Usage:
  280. // selector: [{type: 'all or inverse', title: xxx}]
  281. // or
  282. // selector: true
  283. // or
  284. // selector: ['all', 'inverse']
  285. selector: false,
  286. selectorLabel: {
  287. show: true,
  288. borderRadius: 10,
  289. padding: [3, 5, 3, 5],
  290. fontSize: 12,
  291. fontFamily: ' sans-serif',
  292. color: '#666',
  293. borderWidth: 1,
  294. borderColor: '#666'
  295. },
  296. emphasis: {
  297. selectorLabel: {
  298. show: true,
  299. color: '#eee',
  300. backgroundColor: '#666'
  301. }
  302. },
  303. // Value can be 'start' or 'end'
  304. selectorPosition: 'auto',
  305. selectorItemGap: 7,
  306. selectorButtonGap: 10,
  307. // Tooltip 相关配置
  308. tooltip: {
  309. show: false
  310. }
  311. }
  312. });
  313. var _default = LegendModel;
  314. module.exports = _default;