BrushTargetManager.js 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343
  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 { each, indexOf, curry, assert, map, createHashMap } from 'zrender/lib/core/util.js';
  41. import * as brushHelper from './brushHelper.js';
  42. import { parseFinder as modelUtilParseFinder, initExtentForUnion } from '../../util/model.js';
  43. import { viewCoordSysCopyBoundingRect, viewCoordSysCopyOverallMatrix } from '../../coord/View.js';
  44. import { boundingRectApplyTransform } from 'zrender/lib/core/BoundingRect.js';
  45. // FIXME
  46. // how to genarialize to more coordinate systems.
  47. var INCLUDE_FINDER_MAIN_TYPES = ['grid', 'xAxis', 'yAxis', 'geo', 'graph', 'polar', 'radiusAxis', 'angleAxis', 'bmap'];
  48. var BrushTargetManager = /** @class */function () {
  49. /**
  50. * @param finder contains Index/Id/Name of xAxis/yAxis/geo/grid
  51. * Each can be {number|Array.<number>}. like: {xAxisIndex: [3, 4]}
  52. * @param opt.include include coordinate system types.
  53. */
  54. function BrushTargetManager(finder, ecModel, opt) {
  55. var _this = this;
  56. this._targetInfoList = [];
  57. var foundCpts = parseFinder(ecModel, finder);
  58. each(targetInfoBuilders, function (builder, type) {
  59. if (!opt || !opt.include || indexOf(opt.include, type) >= 0) {
  60. builder(foundCpts, _this._targetInfoList);
  61. }
  62. });
  63. }
  64. BrushTargetManager.prototype.setOutputRanges = function (areas, ecModel) {
  65. this.matchOutputRanges(areas, ecModel, function (area, coordRange, coordSys) {
  66. (area.coordRanges || (area.coordRanges = [])).push(coordRange);
  67. // area.coordRange is the first of area.coordRanges
  68. if (!area.coordRange) {
  69. area.coordRange = coordRange;
  70. // In 'category' axis, coord to pixel is not reversible, so we can not
  71. // rebuild range by coordRange accrately, which may bring trouble when
  72. // brushing only one item. So we use __rangeOffset to rebuilding range
  73. // by coordRange. And this it only used in brush component so it is no
  74. // need to be adapted to coordRanges.
  75. var result = coordConvert[area.brushType](0, coordSys, coordRange);
  76. area.__rangeOffset = {
  77. offset: diffProcessor[area.brushType](result.values, area.range, [1, 1]),
  78. xyMinMax: result.xyMinMax
  79. };
  80. }
  81. });
  82. return areas;
  83. };
  84. BrushTargetManager.prototype.matchOutputRanges = function (areas, ecModel, cb) {
  85. each(areas, function (area) {
  86. var targetInfo = this.findTargetInfo(area, ecModel);
  87. if (targetInfo && targetInfo !== true) {
  88. each(targetInfo.coordSyses, function (coordSys) {
  89. var result = coordConvert[area.brushType](1, coordSys, area.range, true);
  90. cb(area, result.values, coordSys, ecModel);
  91. });
  92. }
  93. }, this);
  94. };
  95. /**
  96. * the `areas` is `BrushModel.areas`.
  97. * Called in layout stage.
  98. * convert `area.coordRange` to global range and set panelId to `area.range`.
  99. */
  100. BrushTargetManager.prototype.setInputRanges = function (areas, ecModel) {
  101. each(areas, function (area) {
  102. var targetInfo = this.findTargetInfo(area, ecModel);
  103. if (process.env.NODE_ENV !== 'production') {
  104. assert(!targetInfo || targetInfo === true || area.coordRange, 'coordRange must be specified when coord index specified.');
  105. assert(!targetInfo || targetInfo !== true || area.range, 'range must be specified in global brush.');
  106. }
  107. area.range = area.range || [];
  108. // convert coordRange to global range and set panelId.
  109. if (targetInfo && targetInfo !== true) {
  110. area.panelId = targetInfo.panelId;
  111. // (1) area.range should always be calculate from coordRange but does
  112. // not keep its original value, for the sake of the dataZoom scenario,
  113. // where area.coordRange remains unchanged but area.range may be changed.
  114. // (2) Only support converting one coordRange to pixel range in brush
  115. // component. So do not consider `coordRanges`.
  116. // (3) About __rangeOffset, see comment above.
  117. var result = coordConvert[area.brushType](0, targetInfo.coordSys, area.coordRange);
  118. var rangeOffset = area.__rangeOffset;
  119. area.range = rangeOffset ? diffProcessor[area.brushType](result.values, rangeOffset.offset, getScales(result.xyMinMax, rangeOffset.xyMinMax)) : result.values;
  120. }
  121. }, this);
  122. };
  123. BrushTargetManager.prototype.makePanelOpts = function (api, getDefaultBrushType) {
  124. return map(this._targetInfoList, function (targetInfo) {
  125. var rect = targetInfo.getPanelRect();
  126. return {
  127. panelId: targetInfo.panelId,
  128. defaultBrushType: getDefaultBrushType ? getDefaultBrushType(targetInfo) : null,
  129. clipPath: brushHelper.makeRectPanelClipPath(rect),
  130. isTargetByCursor: brushHelper.makeRectIsTargetByCursor(rect, api, targetInfo.coordSysModel),
  131. getLinearBrushOtherExtent: brushHelper.makeLinearBrushOtherExtent(rect)
  132. };
  133. });
  134. };
  135. BrushTargetManager.prototype.controlSeries = function (area, seriesModel, ecModel) {
  136. // Check whether area is bound in coord, and series do not belong to that coord.
  137. // If do not do this check, some brush (like lineX) will controll all axes.
  138. var targetInfo = this.findTargetInfo(area, ecModel);
  139. return targetInfo === true || targetInfo && indexOf(targetInfo.coordSyses, seriesModel.coordinateSystem) >= 0;
  140. };
  141. /**
  142. * If return Object, a coord found.
  143. * If return true, global found.
  144. * Otherwise nothing found.
  145. */
  146. BrushTargetManager.prototype.findTargetInfo = function (area, ecModel) {
  147. var targetInfoList = this._targetInfoList;
  148. var foundCpts = parseFinder(ecModel, area);
  149. for (var i = 0; i < targetInfoList.length; i++) {
  150. var targetInfo = targetInfoList[i];
  151. var areaPanelId = area.panelId;
  152. if (areaPanelId) {
  153. if (targetInfo.panelId === areaPanelId) {
  154. return targetInfo;
  155. }
  156. } else {
  157. for (var j = 0; j < targetInfoMatchers.length; j++) {
  158. if (targetInfoMatchers[j](foundCpts, targetInfo)) {
  159. return targetInfo;
  160. }
  161. }
  162. }
  163. }
  164. return true;
  165. };
  166. return BrushTargetManager;
  167. }();
  168. function formatMinMax(minMax) {
  169. minMax[0] > minMax[1] && minMax.reverse();
  170. return minMax;
  171. }
  172. function parseFinder(ecModel, finder) {
  173. return modelUtilParseFinder(ecModel, finder, {
  174. includeMainTypes: INCLUDE_FINDER_MAIN_TYPES
  175. });
  176. }
  177. var targetInfoBuilders = {
  178. grid: function (foundCpts, targetInfoList) {
  179. var xAxisModels = foundCpts.xAxisModels;
  180. var yAxisModels = foundCpts.yAxisModels;
  181. var gridModels = foundCpts.gridModels;
  182. // Remove duplicated.
  183. var gridModelMap = createHashMap();
  184. var xAxesHas = {};
  185. var yAxesHas = {};
  186. if (!xAxisModels && !yAxisModels && !gridModels) {
  187. return;
  188. }
  189. each(xAxisModels, function (axisModel) {
  190. var gridModel = axisModel.axis.grid.model;
  191. gridModelMap.set(gridModel.id, gridModel);
  192. xAxesHas[gridModel.id] = true;
  193. });
  194. each(yAxisModels, function (axisModel) {
  195. var gridModel = axisModel.axis.grid.model;
  196. gridModelMap.set(gridModel.id, gridModel);
  197. yAxesHas[gridModel.id] = true;
  198. });
  199. each(gridModels, function (gridModel) {
  200. gridModelMap.set(gridModel.id, gridModel);
  201. xAxesHas[gridModel.id] = true;
  202. yAxesHas[gridModel.id] = true;
  203. });
  204. gridModelMap.each(function (gridModel) {
  205. var grid = gridModel.coordinateSystem;
  206. var cartesians = [];
  207. each(grid.getCartesians(), function (cartesian, index) {
  208. if (indexOf(xAxisModels, cartesian.getAxis('x').model) >= 0 || indexOf(yAxisModels, cartesian.getAxis('y').model) >= 0) {
  209. cartesians.push(cartesian);
  210. }
  211. });
  212. targetInfoList.push({
  213. panelId: 'grid--' + gridModel.id,
  214. gridModel: gridModel,
  215. coordSysModel: gridModel,
  216. // Use the first one as the representitive coordSys.
  217. coordSys: cartesians[0],
  218. coordSyses: cartesians,
  219. getPanelRect: panelRectBuilders.grid,
  220. xAxisDeclared: xAxesHas[gridModel.id],
  221. yAxisDeclared: yAxesHas[gridModel.id]
  222. });
  223. });
  224. },
  225. geo: function (foundCpts, targetInfoList) {
  226. each(foundCpts.geoModels, function (geoModel) {
  227. var coordSys = geoModel.coordinateSystem;
  228. targetInfoList.push({
  229. panelId: 'geo--' + geoModel.id,
  230. geoModel: geoModel,
  231. coordSysModel: geoModel,
  232. coordSys: coordSys,
  233. coordSyses: [coordSys],
  234. getPanelRect: panelRectBuilders.geo
  235. });
  236. });
  237. }
  238. };
  239. var targetInfoMatchers = [
  240. // grid
  241. function (foundCpts, targetInfo) {
  242. var xAxisModel = foundCpts.xAxisModel;
  243. var yAxisModel = foundCpts.yAxisModel;
  244. var gridModel = foundCpts.gridModel;
  245. !gridModel && xAxisModel && (gridModel = xAxisModel.axis.grid.model);
  246. !gridModel && yAxisModel && (gridModel = yAxisModel.axis.grid.model);
  247. return gridModel && gridModel === targetInfo.gridModel;
  248. },
  249. // geo
  250. function (foundCpts, targetInfo) {
  251. var geoModel = foundCpts.geoModel;
  252. return geoModel && geoModel === targetInfo.geoModel;
  253. }];
  254. var panelRectBuilders = {
  255. grid: function () {
  256. // grid is not Transformable.
  257. return this.coordSys.master.getRect().clone();
  258. },
  259. geo: function () {
  260. var viewCoordSys = this.coordSys.view;
  261. var rect = viewCoordSysCopyBoundingRect(null, viewCoordSys);
  262. boundingRectApplyTransform(rect, rect, viewCoordSysCopyOverallMatrix(null, viewCoordSys));
  263. return rect;
  264. }
  265. };
  266. var coordConvert = {
  267. lineX: curry(axisConvert, 0),
  268. lineY: curry(axisConvert, 1),
  269. rect: function (to, coordSys, rangeOrCoordRange, clamp) {
  270. var xminymin = to ? coordSys.pointToData([rangeOrCoordRange[0][0], rangeOrCoordRange[1][0]], clamp) : coordSys.dataToPoint([rangeOrCoordRange[0][0], rangeOrCoordRange[1][0]], clamp);
  271. var xmaxymax = to ? coordSys.pointToData([rangeOrCoordRange[0][1], rangeOrCoordRange[1][1]], clamp) : coordSys.dataToPoint([rangeOrCoordRange[0][1], rangeOrCoordRange[1][1]], clamp);
  272. var values = [formatMinMax([xminymin[0], xmaxymax[0]]), formatMinMax([xminymin[1], xmaxymax[1]])];
  273. return {
  274. values: values,
  275. xyMinMax: values
  276. };
  277. },
  278. polygon: function (to, coordSys, rangeOrCoordRange, clamp) {
  279. var xyMinMax = [initExtentForUnion(), initExtentForUnion()];
  280. var values = map(rangeOrCoordRange, function (item) {
  281. var p = to ? coordSys.pointToData(item, clamp) : coordSys.dataToPoint(item, clamp);
  282. xyMinMax[0][0] = Math.min(xyMinMax[0][0], p[0]);
  283. xyMinMax[1][0] = Math.min(xyMinMax[1][0], p[1]);
  284. xyMinMax[0][1] = Math.max(xyMinMax[0][1], p[0]);
  285. xyMinMax[1][1] = Math.max(xyMinMax[1][1], p[1]);
  286. return p;
  287. });
  288. return {
  289. values: values,
  290. xyMinMax: xyMinMax
  291. };
  292. }
  293. };
  294. function axisConvert(axisNameIndex, to, coordSys, rangeOrCoordRange) {
  295. if (process.env.NODE_ENV !== 'production') {
  296. assert(coordSys.type === 'cartesian2d', 'lineX/lineY brush is available only in cartesian2d.');
  297. }
  298. var axis = coordSys.getAxis(['x', 'y'][axisNameIndex]);
  299. var values = formatMinMax(map([0, 1], function (i) {
  300. return to ? axis.coordToData(axis.toLocalCoord(rangeOrCoordRange[i]), true) : axis.toGlobalCoord(axis.dataToCoord(rangeOrCoordRange[i]));
  301. }));
  302. var xyMinMax = [];
  303. xyMinMax[axisNameIndex] = values;
  304. xyMinMax[1 - axisNameIndex] = [NaN, NaN];
  305. return {
  306. values: values,
  307. xyMinMax: xyMinMax
  308. };
  309. }
  310. var diffProcessor = {
  311. lineX: curry(axisDiffProcessor, 0),
  312. lineY: curry(axisDiffProcessor, 1),
  313. rect: function (values, refer, scales) {
  314. return [[values[0][0] - scales[0] * refer[0][0], values[0][1] - scales[0] * refer[0][1]], [values[1][0] - scales[1] * refer[1][0], values[1][1] - scales[1] * refer[1][1]]];
  315. },
  316. polygon: function (values, refer, scales) {
  317. return map(values, function (item, idx) {
  318. return [item[0] - scales[0] * refer[idx][0], item[1] - scales[1] * refer[idx][1]];
  319. });
  320. }
  321. };
  322. function axisDiffProcessor(axisNameIndex, values, refer, scales) {
  323. return [values[0] - scales[axisNameIndex] * refer[0], values[1] - scales[axisNameIndex] * refer[1]];
  324. }
  325. // We have to process scale caused by dataZoom manually,
  326. // although it might be not accurate.
  327. // Return [0~1, 0~1]
  328. function getScales(xyMinMaxCurr, xyMinMaxOrigin) {
  329. var sizeCurr = getSize(xyMinMaxCurr);
  330. var sizeOrigin = getSize(xyMinMaxOrigin);
  331. var scales = [sizeCurr[0] / sizeOrigin[0], sizeCurr[1] / sizeOrigin[1]];
  332. isNaN(scales[0]) && (scales[0] = 1);
  333. isNaN(scales[1]) && (scales[1] = 1);
  334. return scales;
  335. }
  336. function getSize(xyMinMax) {
  337. return xyMinMax ? [xyMinMax[0][1] - xyMinMax[0][0], xyMinMax[1][1] - xyMinMax[1][0]] : [NaN, NaN];
  338. }
  339. export default BrushTargetManager;