MarkAreaView.js 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362
  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 { __extends } from "tslib";
  41. // TODO Optimize on polar
  42. import * as colorUtil from 'zrender/lib/tool/color.js';
  43. import SeriesData from '../../data/SeriesData.js';
  44. import * as numberUtil from '../../util/number.js';
  45. import * as graphic from '../../util/graphic.js';
  46. import { toggleHoverEmphasis, setStatesStylesFromModel } from '../../util/states.js';
  47. import * as markerHelper from './markerHelper.js';
  48. import MarkerView from './MarkerView.js';
  49. import { retrieve, mergeAll, map, curry, filter, extend, isString } from 'zrender/lib/core/util.js';
  50. import { isCoordinateSystemType } from '../../coord/CoordinateSystem.js';
  51. import MarkerModel from './MarkerModel.js';
  52. import { makeInner } from '../../util/model.js';
  53. import { getVisualFromData } from '../../visual/helper.js';
  54. import { setLabelStyle, getLabelStatesModels } from '../../label/labelStyle.js';
  55. import { getECData } from '../../util/innerStore.js';
  56. import { parseDataValue } from '../../data/helper/dataValueHelper.js';
  57. var inner = makeInner();
  58. var markAreaTransform = function (seriesModel, coordSys, maModel, item) {
  59. // item may be null
  60. var item0 = item[0];
  61. var item1 = item[1];
  62. if (!item0 || !item1) {
  63. return;
  64. }
  65. var lt = markerHelper.dataTransform(seriesModel, item0);
  66. var rb = markerHelper.dataTransform(seriesModel, item1);
  67. // FIXME make sure lt is less than rb
  68. var ltCoord = lt.coord;
  69. var rbCoord = rb.coord;
  70. ltCoord[0] = retrieve(ltCoord[0], -Infinity);
  71. ltCoord[1] = retrieve(ltCoord[1], -Infinity);
  72. rbCoord[0] = retrieve(rbCoord[0], Infinity);
  73. rbCoord[1] = retrieve(rbCoord[1], Infinity);
  74. // Merge option into one
  75. var result = mergeAll([{}, lt, rb]);
  76. result.coord = [lt.coord, rb.coord];
  77. result.x0 = lt.x;
  78. result.y0 = lt.y;
  79. result.x1 = rb.x;
  80. result.y1 = rb.y;
  81. return result;
  82. };
  83. function isInfinity(val) {
  84. return !isNaN(val) && !isFinite(val);
  85. }
  86. // If a markArea has one dim
  87. function ifMarkAreaHasOnlyDim(dimIndex, fromCoord, toCoord, coordSys) {
  88. var otherDimIndex = 1 - dimIndex;
  89. return isInfinity(fromCoord[otherDimIndex]) && isInfinity(toCoord[otherDimIndex]);
  90. }
  91. function markAreaFilter(coordSys, item) {
  92. var fromCoord = item.coord[0];
  93. var toCoord = item.coord[1];
  94. var item0 = {
  95. coord: fromCoord,
  96. x: item.x0,
  97. y: item.y0
  98. };
  99. var item1 = {
  100. coord: toCoord,
  101. x: item.x1,
  102. y: item.y1
  103. };
  104. if (isCoordinateSystemType(coordSys, 'cartesian2d')) {
  105. // In case
  106. // {
  107. // markArea: {
  108. // data: [{ yAxis: 2 }]
  109. // }
  110. // }
  111. if (fromCoord && toCoord && (ifMarkAreaHasOnlyDim(1, fromCoord, toCoord, coordSys) || ifMarkAreaHasOnlyDim(0, fromCoord, toCoord, coordSys))) {
  112. return true;
  113. }
  114. // Directly returning true may also do the work,
  115. // because markArea will not be shown automatically
  116. // when it's not included in coordinate system.
  117. // But filtering ahead can avoid keeping rendering markArea
  118. // when there are too many of them.
  119. return markerHelper.zoneFilter(coordSys, item0, item1);
  120. }
  121. return markerHelper.dataFilter(coordSys, item0) || markerHelper.dataFilter(coordSys, item1);
  122. }
  123. // dims can be ['x0', 'y0'], ['x1', 'y1'], ['x0', 'y1'], ['x1', 'y0']
  124. function getSingleMarkerEndPoint(data, idx, dims, seriesModel, api) {
  125. var coordSys = seriesModel.coordinateSystem;
  126. var itemModel = data.getItemModel(idx);
  127. var point;
  128. var xPx = numberUtil.parsePercent(itemModel.get(dims[0]), api.getWidth());
  129. var yPx = numberUtil.parsePercent(itemModel.get(dims[1]), api.getHeight());
  130. if (!isNaN(xPx) && !isNaN(yPx)) {
  131. point = [xPx, yPx];
  132. } else {
  133. // Chart like bar may have there own marker positioning logic
  134. if (seriesModel.getMarkerPosition) {
  135. // Consider the case that user input the right-bottom point first
  136. // Pick the larger x and y as 'x1' and 'y1'
  137. var pointValue0 = data.getValues(['x0', 'y0'], idx);
  138. var pointValue1 = data.getValues(['x1', 'y1'], idx);
  139. var clampPointValue0 = coordSys.clampData(pointValue0);
  140. var clampPointValue1 = coordSys.clampData(pointValue1);
  141. var pointValue = [];
  142. if (dims[0] === 'x0') {
  143. pointValue[0] = clampPointValue0[0] > clampPointValue1[0] ? pointValue1[0] : pointValue0[0];
  144. } else {
  145. pointValue[0] = clampPointValue0[0] > clampPointValue1[0] ? pointValue0[0] : pointValue1[0];
  146. }
  147. if (dims[1] === 'y0') {
  148. pointValue[1] = clampPointValue0[1] > clampPointValue1[1] ? pointValue1[1] : pointValue0[1];
  149. } else {
  150. pointValue[1] = clampPointValue0[1] > clampPointValue1[1] ? pointValue0[1] : pointValue1[1];
  151. }
  152. // Use the getMarkerPosition
  153. point = seriesModel.getMarkerPosition(pointValue, dims, true);
  154. } else {
  155. var x = data.get(dims[0], idx);
  156. var y = data.get(dims[1], idx);
  157. var pt = [x, y];
  158. coordSys.clampData && coordSys.clampData(pt, pt);
  159. point = coordSys.dataToPoint(pt, true);
  160. }
  161. if (isCoordinateSystemType(coordSys, 'cartesian2d')) {
  162. // TODO: TYPE ts@4.1 may still infer it as Axis instead of Axis2D. Not sure if it's a bug
  163. var xAxis = coordSys.getAxis('x');
  164. var yAxis = coordSys.getAxis('y');
  165. var x = data.get(dims[0], idx);
  166. var y = data.get(dims[1], idx);
  167. if (isInfinity(x)) {
  168. point[0] = xAxis.toGlobalCoord(xAxis.getExtent()[dims[0] === 'x0' ? 0 : 1]);
  169. } else if (isInfinity(y)) {
  170. point[1] = yAxis.toGlobalCoord(yAxis.getExtent()[dims[1] === 'y0' ? 0 : 1]);
  171. }
  172. }
  173. // Use x, y if has any
  174. if (!isNaN(xPx)) {
  175. point[0] = xPx;
  176. }
  177. if (!isNaN(yPx)) {
  178. point[1] = yPx;
  179. }
  180. }
  181. return point;
  182. }
  183. export var dimPermutations = [['x0', 'y0'], ['x1', 'y0'], ['x1', 'y1'], ['x0', 'y1']];
  184. var MarkAreaView = /** @class */function (_super) {
  185. __extends(MarkAreaView, _super);
  186. function MarkAreaView() {
  187. var _this = _super !== null && _super.apply(this, arguments) || this;
  188. _this.type = MarkAreaView.type;
  189. return _this;
  190. }
  191. MarkAreaView.prototype.updateTransform = function (markAreaModel, ecModel, api) {
  192. ecModel.eachSeries(function (seriesModel) {
  193. var maModel = MarkerModel.getMarkerModelFromSeries(seriesModel, 'markArea');
  194. if (maModel) {
  195. var areaData_1 = maModel.getData();
  196. areaData_1.each(function (idx) {
  197. var points = map(dimPermutations, function (dim) {
  198. return getSingleMarkerEndPoint(areaData_1, idx, dim, seriesModel, api);
  199. });
  200. // Layout
  201. areaData_1.setItemLayout(idx, points);
  202. var el = areaData_1.getItemGraphicEl(idx);
  203. el.setShape('points', points);
  204. });
  205. }
  206. }, this);
  207. };
  208. MarkAreaView.prototype.renderSeries = function (seriesModel, maModel, ecModel, api) {
  209. var coordSys = seriesModel.coordinateSystem;
  210. var seriesId = seriesModel.id;
  211. var seriesData = seriesModel.getData();
  212. var areaGroupMap = this.markerGroupMap;
  213. var polygonGroup = areaGroupMap.get(seriesId) || areaGroupMap.set(seriesId, {
  214. group: new graphic.Group()
  215. });
  216. this.group.add(polygonGroup.group);
  217. this.markKeep(polygonGroup);
  218. var areaData = createList(coordSys, seriesModel, maModel);
  219. // Line data for tooltip and formatter
  220. maModel.setData(areaData);
  221. // Update visual and layout of line
  222. areaData.each(function (idx) {
  223. // Layout
  224. var points = map(dimPermutations, function (dim) {
  225. return getSingleMarkerEndPoint(areaData, idx, dim, seriesModel, api);
  226. });
  227. var xAxisScale = coordSys.getAxis('x').scale;
  228. var yAxisScale = coordSys.getAxis('y').scale;
  229. var xAxisExtent = xAxisScale.getExtent();
  230. var yAxisExtent = yAxisScale.getExtent();
  231. var xPointExtent = [xAxisScale.parse(areaData.get('x0', idx)), xAxisScale.parse(areaData.get('x1', idx))];
  232. var yPointExtent = [yAxisScale.parse(areaData.get('y0', idx)), yAxisScale.parse(areaData.get('y1', idx))];
  233. numberUtil.asc(xPointExtent);
  234. numberUtil.asc(yPointExtent);
  235. var overlapped = !(xAxisExtent[0] > xPointExtent[1] || xAxisExtent[1] < xPointExtent[0] || yAxisExtent[0] > yPointExtent[1] || yAxisExtent[1] < yPointExtent[0]);
  236. // If none of the area is inside coordSys, allClipped is set to be true
  237. // in layout so that label will not be displayed. See #12591
  238. var allClipped = !overlapped;
  239. areaData.setItemLayout(idx, {
  240. points: points,
  241. allClipped: allClipped
  242. });
  243. var style = areaData.getItemModel(idx).getModel('itemStyle').getItemStyle();
  244. var color = getVisualFromData(seriesData, 'color');
  245. if (!style.fill) {
  246. style.fill = color;
  247. if (isString(style.fill)) {
  248. style.fill = colorUtil.modifyAlpha(style.fill, 0.4);
  249. }
  250. }
  251. if (!style.stroke) {
  252. style.stroke = color;
  253. }
  254. // Visual
  255. areaData.setItemVisual(idx, 'style', style);
  256. });
  257. areaData.diff(inner(polygonGroup).data).add(function (idx) {
  258. var layout = areaData.getItemLayout(idx);
  259. if (!layout.allClipped) {
  260. var polygon = new graphic.Polygon({
  261. shape: {
  262. points: layout.points
  263. }
  264. });
  265. areaData.setItemGraphicEl(idx, polygon);
  266. polygonGroup.group.add(polygon);
  267. }
  268. }).update(function (newIdx, oldIdx) {
  269. var polygon = inner(polygonGroup).data.getItemGraphicEl(oldIdx);
  270. var layout = areaData.getItemLayout(newIdx);
  271. if (!layout.allClipped) {
  272. if (polygon) {
  273. graphic.updateProps(polygon, {
  274. shape: {
  275. points: layout.points
  276. }
  277. }, maModel, newIdx);
  278. } else {
  279. polygon = new graphic.Polygon({
  280. shape: {
  281. points: layout.points
  282. }
  283. });
  284. }
  285. areaData.setItemGraphicEl(newIdx, polygon);
  286. polygonGroup.group.add(polygon);
  287. } else if (polygon) {
  288. polygonGroup.group.remove(polygon);
  289. }
  290. }).remove(function (idx) {
  291. var polygon = inner(polygonGroup).data.getItemGraphicEl(idx);
  292. polygonGroup.group.remove(polygon);
  293. }).execute();
  294. areaData.eachItemGraphicEl(function (polygon, idx) {
  295. var itemModel = areaData.getItemModel(idx);
  296. var style = areaData.getItemVisual(idx, 'style');
  297. polygon.useStyle(areaData.getItemVisual(idx, 'style'));
  298. setLabelStyle(polygon, getLabelStatesModels(itemModel), {
  299. labelFetcher: maModel,
  300. labelDataIndex: idx,
  301. defaultText: areaData.getName(idx) || '',
  302. inheritColor: isString(style.fill) ? colorUtil.modifyAlpha(style.fill, 1) : '#000'
  303. });
  304. setStatesStylesFromModel(polygon, itemModel);
  305. toggleHoverEmphasis(polygon, null, null, itemModel.get(['emphasis', 'disabled']));
  306. getECData(polygon).dataModel = maModel;
  307. });
  308. inner(polygonGroup).data = areaData;
  309. polygonGroup.group.silent = maModel.get('silent') || seriesModel.get('silent');
  310. };
  311. MarkAreaView.type = 'markArea';
  312. return MarkAreaView;
  313. }(MarkerView);
  314. function createList(coordSys, seriesModel, maModel) {
  315. var areaData;
  316. var dataDims;
  317. var dims = ['x0', 'y0', 'x1', 'y1'];
  318. if (coordSys) {
  319. var coordDimsInfos_1 = map(coordSys && coordSys.dimensions, function (coordDim) {
  320. var data = seriesModel.getData();
  321. var info = data.getDimensionInfo(data.mapDimension(coordDim)) || {};
  322. // In map series data don't have lng and lat dimension. Fallback to same with coordSys
  323. return extend(extend({}, info), {
  324. name: coordDim,
  325. // DON'T use ordinalMeta to parse and collect ordinal.
  326. ordinalMeta: null
  327. });
  328. });
  329. dataDims = map(dims, function (dim, idx) {
  330. return {
  331. name: dim,
  332. type: coordDimsInfos_1[idx % 2].type
  333. };
  334. });
  335. areaData = new SeriesData(dataDims, maModel);
  336. } else {
  337. dataDims = [{
  338. name: 'value',
  339. type: 'float'
  340. }];
  341. areaData = new SeriesData(dataDims, maModel);
  342. }
  343. var optData = map(maModel.get('data'), curry(markAreaTransform, seriesModel, coordSys, maModel));
  344. if (coordSys) {
  345. optData = filter(optData, curry(markAreaFilter, coordSys));
  346. }
  347. var dimValueGetter = coordSys ? function (item, dimName, dataIndex, dimIndex) {
  348. // TODO should convert to ParsedValue?
  349. var rawVal = item.coord[Math.floor(dimIndex / 2)][dimIndex % 2];
  350. return parseDataValue(rawVal, dataDims[dimIndex]);
  351. } : function (item, dimName, dataIndex, dimIndex) {
  352. return parseDataValue(item.value, dataDims[dimIndex]);
  353. };
  354. areaData.initData(optData, null, dimValueGetter);
  355. areaData.hasItemOption = true;
  356. return areaData;
  357. }
  358. export default MarkAreaView;