modelHelper.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295
  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. /**
  20. * AUTO-GENERATED FILE. DO NOT MODIFY.
  21. */
  22. /*
  23. * Licensed to the Apache Software Foundation (ASF) under one
  24. * or more contributor license agreements. See the NOTICE file
  25. * distributed with this work for additional information
  26. * regarding copyright ownership. The ASF licenses this file
  27. * to you under the Apache License, Version 2.0 (the
  28. * "License"); you may not use this file except in compliance
  29. * with the License. You may obtain a copy of the License at
  30. *
  31. * http://www.apache.org/licenses/LICENSE-2.0
  32. *
  33. * Unless required by applicable law or agreed to in writing,
  34. * software distributed under the License is distributed on an
  35. * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  36. * KIND, either express or implied. See the License for the
  37. * specific language governing permissions and limitations
  38. * under the License.
  39. */
  40. import Model from '../../model/Model.js';
  41. import { each, curry, clone, defaults, isArray, indexOf } from 'zrender/lib/core/util.js';
  42. // Build axisPointerModel, mergin tooltip.axisPointer model for each axis.
  43. // allAxesInfo should be updated when setOption performed.
  44. export function collect(ecModel, api) {
  45. var result = {
  46. /**
  47. * key: makeKey(axis.model)
  48. * value: {
  49. * axis,
  50. * coordSys,
  51. * axisPointerModel,
  52. * triggerTooltip,
  53. * triggerEmphasis,
  54. * involveSeries,
  55. * snap,
  56. * seriesModels,
  57. * seriesDataCount
  58. * }
  59. */
  60. axesInfo: {},
  61. seriesInvolved: false,
  62. /**
  63. * key: makeKey(coordSys.model)
  64. * value: Object: key makeKey(axis.model), value: axisInfo
  65. */
  66. coordSysAxesInfo: {},
  67. coordSysMap: {}
  68. };
  69. collectAxesInfo(result, ecModel, api);
  70. // Check seriesInvolved for performance, in case too many series in some chart.
  71. result.seriesInvolved && collectSeriesInfo(result, ecModel);
  72. return result;
  73. }
  74. function collectAxesInfo(result, ecModel, api) {
  75. var globalTooltipModel = ecModel.getComponent('tooltip');
  76. var globalAxisPointerModel = ecModel.getComponent('axisPointer');
  77. // links can only be set on global.
  78. var linksOption = globalAxisPointerModel.get('link', true) || [];
  79. var linkGroups = [];
  80. // Collect axes info.
  81. each(api.getCoordinateSystems(), function (coordSys) {
  82. // Some coordinate system do not support axes, like geo.
  83. if (!coordSys.axisPointerEnabled) {
  84. return;
  85. }
  86. var coordSysKey = makeKey(coordSys.model);
  87. var axesInfoInCoordSys = result.coordSysAxesInfo[coordSysKey] = {};
  88. result.coordSysMap[coordSysKey] = coordSys;
  89. // Set tooltip (like 'cross') is a convenient way to show axisPointer
  90. // for user. So we enable setting tooltip on coordSys model.
  91. var coordSysModel = coordSys.model;
  92. var baseTooltipModel = coordSysModel.getModel('tooltip', globalTooltipModel);
  93. each(coordSys.getAxes(), curry(saveTooltipAxisInfo, false, null));
  94. // If axis tooltip used, choose tooltip axis for each coordSys.
  95. // Notice this case: coordSys is `grid` but not `cartesian2D` here.
  96. if (coordSys.getTooltipAxes && globalTooltipModel
  97. // If tooltip.showContent is set as false, tooltip will not
  98. // show but axisPointer will show as normal.
  99. && baseTooltipModel.get('show')) {
  100. // Compatible with previous logic. But series.tooltip.trigger: 'axis'
  101. // or series.data[n].tooltip.trigger: 'axis' are not support any more.
  102. var triggerAxis = baseTooltipModel.get('trigger') === 'axis';
  103. var cross = baseTooltipModel.get(['axisPointer', 'type']) === 'cross';
  104. var tooltipAxes = coordSys.getTooltipAxes(baseTooltipModel.get(['axisPointer', 'axis']));
  105. if (triggerAxis || cross) {
  106. each(tooltipAxes.baseAxes, curry(saveTooltipAxisInfo, cross ? 'cross' : true, triggerAxis));
  107. }
  108. if (cross) {
  109. each(tooltipAxes.otherAxes, curry(saveTooltipAxisInfo, 'cross', false));
  110. }
  111. }
  112. // fromTooltip: true | false | 'cross'
  113. // triggerTooltip: true | false | null
  114. function saveTooltipAxisInfo(fromTooltip, triggerTooltip, axis) {
  115. var axisPointerModel = axis.model.getModel('axisPointer', globalAxisPointerModel);
  116. var axisPointerShow = axisPointerModel.get('show');
  117. if (!axisPointerShow || axisPointerShow === 'auto' && !fromTooltip && !isHandleTrigger(axisPointerModel)) {
  118. return;
  119. }
  120. if (triggerTooltip == null) {
  121. triggerTooltip = axisPointerModel.get('triggerTooltip');
  122. }
  123. axisPointerModel = fromTooltip ? makeAxisPointerModel(axis, baseTooltipModel, globalAxisPointerModel, ecModel, fromTooltip, triggerTooltip) : axisPointerModel;
  124. var snap = axisPointerModel.get('snap');
  125. var triggerEmphasis = axisPointerModel.get('triggerEmphasis');
  126. var axisKey = makeKey(axis.model);
  127. var involveSeries = triggerTooltip || snap || axis.type === 'category';
  128. // If result.axesInfo[key] exist, override it (tooltip has higher priority).
  129. var axisInfo = result.axesInfo[axisKey] = {
  130. key: axisKey,
  131. axis: axis,
  132. coordSys: coordSys,
  133. axisPointerModel: axisPointerModel,
  134. triggerTooltip: triggerTooltip,
  135. triggerEmphasis: triggerEmphasis,
  136. involveSeries: involveSeries,
  137. snap: snap,
  138. useHandle: isHandleTrigger(axisPointerModel),
  139. seriesModels: [],
  140. linkGroup: null
  141. };
  142. axesInfoInCoordSys[axisKey] = axisInfo;
  143. result.seriesInvolved = result.seriesInvolved || involveSeries;
  144. var groupIndex = getLinkGroupIndex(linksOption, axis);
  145. if (groupIndex != null) {
  146. var linkGroup = linkGroups[groupIndex] || (linkGroups[groupIndex] = {
  147. axesInfo: {}
  148. });
  149. linkGroup.axesInfo[axisKey] = axisInfo;
  150. linkGroup.mapper = linksOption[groupIndex].mapper;
  151. axisInfo.linkGroup = linkGroup;
  152. }
  153. }
  154. });
  155. }
  156. function makeAxisPointerModel(axis, baseTooltipModel, globalAxisPointerModel, ecModel, fromTooltip, triggerTooltip) {
  157. var tooltipAxisPointerModel = baseTooltipModel.getModel('axisPointer');
  158. var fields = ['type', 'snap', 'lineStyle', 'shadowStyle', 'label', 'animation', 'animationDurationUpdate', 'animationEasingUpdate', 'z'];
  159. var volatileOption = {};
  160. each(fields, function (field) {
  161. volatileOption[field] = clone(tooltipAxisPointerModel.get(field));
  162. });
  163. // category axis do not auto snap, otherwise some tick that do not
  164. // has value can not be hovered. value/time/log axis default snap if
  165. // triggered from tooltip and trigger tooltip.
  166. volatileOption.snap = axis.type !== 'category' && !!triggerTooltip;
  167. // Compatible with previous behavior, tooltip axis does not show label by default.
  168. // Only these properties can be overridden from tooltip to axisPointer.
  169. if (tooltipAxisPointerModel.get('type') === 'cross') {
  170. volatileOption.type = 'line';
  171. }
  172. var labelOption = volatileOption.label || (volatileOption.label = {});
  173. // Follow the convention, do not show label when triggered by tooltip by default.
  174. labelOption.show == null && (labelOption.show = false);
  175. if (fromTooltip === 'cross') {
  176. // When 'cross', both axes show labels.
  177. var tooltipAxisPointerLabelShow = tooltipAxisPointerModel.get(['label', 'show']);
  178. labelOption.show = tooltipAxisPointerLabelShow != null ? tooltipAxisPointerLabelShow : true;
  179. // If triggerTooltip, this is a base axis, which should better not use cross style
  180. // (cross style is dashed by default)
  181. if (!triggerTooltip) {
  182. var crossStyle = volatileOption.lineStyle = tooltipAxisPointerModel.get('crossStyle');
  183. crossStyle && defaults(labelOption, crossStyle.textStyle);
  184. }
  185. }
  186. return axis.model.getModel('axisPointer', new Model(volatileOption, globalAxisPointerModel, ecModel));
  187. }
  188. function collectSeriesInfo(result, ecModel) {
  189. // Prepare data for axis trigger
  190. ecModel.eachSeries(function (seriesModel) {
  191. // Notice this case: this coordSys is `cartesian2D` but not `grid`.
  192. var coordSys = seriesModel.coordinateSystem;
  193. var seriesTooltipTrigger = seriesModel.get(['tooltip', 'trigger'], true);
  194. var seriesTooltipShow = seriesModel.get(['tooltip', 'show'], true);
  195. if (!coordSys || seriesTooltipTrigger === 'none' || seriesTooltipTrigger === false || seriesTooltipTrigger === 'item' || seriesTooltipShow === false || seriesModel.get(['axisPointer', 'show'], true) === false) {
  196. return;
  197. }
  198. each(result.coordSysAxesInfo[makeKey(coordSys.model)], function (axisInfo) {
  199. var axis = axisInfo.axis;
  200. if (coordSys.getAxis(axis.dim) === axis) {
  201. axisInfo.seriesModels.push(seriesModel);
  202. axisInfo.seriesDataCount == null && (axisInfo.seriesDataCount = 0);
  203. axisInfo.seriesDataCount += seriesModel.getData().count();
  204. }
  205. });
  206. });
  207. }
  208. /**
  209. * For example:
  210. * {
  211. * axisPointer: {
  212. * links: [{
  213. * xAxisIndex: [2, 4],
  214. * yAxisIndex: 'all'
  215. * }, {
  216. * xAxisId: ['a5', 'a7'],
  217. * xAxisName: 'xxx'
  218. * }]
  219. * }
  220. * }
  221. */
  222. function getLinkGroupIndex(linksOption, axis) {
  223. var axisModel = axis.model;
  224. var dim = axis.dim;
  225. for (var i = 0; i < linksOption.length; i++) {
  226. var linkOption = linksOption[i] || {};
  227. if (checkPropInLink(linkOption[dim + 'AxisId'], axisModel.id) || checkPropInLink(linkOption[dim + 'AxisIndex'], axisModel.componentIndex) || checkPropInLink(linkOption[dim + 'AxisName'], axisModel.name)) {
  228. return i;
  229. }
  230. }
  231. }
  232. function checkPropInLink(linkPropValue, axisPropValue) {
  233. return linkPropValue === 'all' || isArray(linkPropValue) && indexOf(linkPropValue, axisPropValue) >= 0 || linkPropValue === axisPropValue;
  234. }
  235. export function fixValue(axisModel) {
  236. var axisInfo = getAxisInfo(axisModel);
  237. if (!axisInfo) {
  238. return;
  239. }
  240. var axisPointerModel = axisInfo.axisPointerModel;
  241. var scale = axisInfo.axis.scale;
  242. var option = axisPointerModel.option;
  243. var status = axisPointerModel.get('status');
  244. var value = axisPointerModel.get('value');
  245. // Parse init value for category and time axis.
  246. if (value != null) {
  247. value = scale.parse(value);
  248. }
  249. var useHandle = isHandleTrigger(axisPointerModel);
  250. // If `handle` used, `axisPointer` will always be displayed, so value
  251. // and status should be initialized.
  252. if (status == null) {
  253. option.status = useHandle ? 'show' : 'hide';
  254. }
  255. var extent = scale.getExtent().slice();
  256. extent[0] > extent[1] && extent.reverse();
  257. if (
  258. // Pick a value on axis when initializing.
  259. value == null
  260. // If both `handle` and `dataZoom` are used, value may be out of axis extent,
  261. // where we should re-pick a value to keep `handle` displaying normally.
  262. || value > extent[1]) {
  263. // Make handle displayed on the end of the axis when init, which looks better.
  264. value = extent[1];
  265. }
  266. if (value < extent[0]) {
  267. value = extent[0];
  268. }
  269. option.value = value;
  270. if (useHandle) {
  271. option.status = axisInfo.axis.scale.isBlank() ? 'hide' : 'show';
  272. }
  273. }
  274. export function getAxisInfo(axisModel) {
  275. var coordSysAxesInfo = (axisModel.ecModel.getComponent('axisPointer') || {}).coordSysAxesInfo;
  276. return coordSysAxesInfo && coordSysAxesInfo.axesInfo[makeKey(axisModel)];
  277. }
  278. export function getAxisPointerModel(axisModel) {
  279. var axisInfo = getAxisInfo(axisModel);
  280. return axisInfo && axisInfo.axisPointerModel;
  281. }
  282. function isHandleTrigger(axisPointerModel) {
  283. return !!axisPointerModel.get(['handle', 'show']);
  284. }
  285. /**
  286. * @param {module:echarts/model/Model} model
  287. * @return {string} unique key
  288. */
  289. export function makeKey(model) {
  290. return model.type + '||' + model.id;
  291. }