visualEncoding.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257
  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 * as zrUtil from 'zrender/lib/core/util.js';
  41. import BoundingRect from 'zrender/lib/core/BoundingRect.js';
  42. import * as visualSolution from '../../visual/visualSolution.js';
  43. import { makeBrushCommonSelectorForSeries } from './selector.js';
  44. import * as throttleUtil from '../../util/throttle.js';
  45. import BrushTargetManager from '../helper/BrushTargetManager.js';
  46. var STATE_LIST = ['inBrush', 'outOfBrush'];
  47. var DISPATCH_METHOD = '__ecBrushSelect';
  48. var DISPATCH_FLAG = '__ecInBrushSelectEvent';
  49. ;
  50. export function layoutCovers(ecModel) {
  51. ecModel.eachComponent({
  52. mainType: 'brush'
  53. }, function (brushModel) {
  54. var brushTargetManager = brushModel.brushTargetManager = new BrushTargetManager(brushModel.option, ecModel);
  55. brushTargetManager.setInputRanges(brushModel.areas, ecModel);
  56. });
  57. }
  58. /**
  59. * Register the visual encoding if this modules required.
  60. */
  61. export default function brushVisual(ecModel, api, payload) {
  62. var brushSelected = [];
  63. var throttleType;
  64. var throttleDelay;
  65. ecModel.eachComponent({
  66. mainType: 'brush'
  67. }, function (brushModel) {
  68. payload && payload.type === 'takeGlobalCursor' && brushModel.setBrushOption(payload.key === 'brush' ? payload.brushOption : {
  69. brushType: false
  70. });
  71. });
  72. layoutCovers(ecModel);
  73. ecModel.eachComponent({
  74. mainType: 'brush'
  75. }, function (brushModel, brushIndex) {
  76. var thisBrushSelected = {
  77. brushId: brushModel.id,
  78. brushIndex: brushIndex,
  79. brushName: brushModel.name,
  80. areas: zrUtil.clone(brushModel.areas),
  81. selected: []
  82. };
  83. // Every brush component exists in event params, convenient
  84. // for user to find by index.
  85. brushSelected.push(thisBrushSelected);
  86. var brushOption = brushModel.option;
  87. var brushLink = brushOption.brushLink;
  88. var linkedSeriesMap = [];
  89. var selectedDataIndexForLink = [];
  90. var rangeInfoBySeries = [];
  91. var hasBrushExists = false;
  92. if (!brushIndex) {
  93. // Only the first throttle setting works.
  94. throttleType = brushOption.throttleType;
  95. throttleDelay = brushOption.throttleDelay;
  96. }
  97. // Add boundingRect and selectors to range.
  98. var areas = zrUtil.map(brushModel.areas, function (area) {
  99. var builder = boundingRectBuilders[area.brushType];
  100. var selectableArea = zrUtil.defaults({
  101. boundingRect: builder ? builder(area) : void 0
  102. }, area);
  103. selectableArea.selectors = makeBrushCommonSelectorForSeries(selectableArea);
  104. return selectableArea;
  105. });
  106. var visualMappings = visualSolution.createVisualMappings(brushModel.option, STATE_LIST, function (mappingOption) {
  107. mappingOption.mappingMethod = 'fixed';
  108. });
  109. zrUtil.isArray(brushLink) && zrUtil.each(brushLink, function (seriesIndex) {
  110. linkedSeriesMap[seriesIndex] = 1;
  111. });
  112. function linkOthers(seriesIndex) {
  113. return brushLink === 'all' || !!linkedSeriesMap[seriesIndex];
  114. }
  115. // If no supported brush or no brush on the series,
  116. // all visuals should be in original state.
  117. function brushed(rangeInfoList) {
  118. return !!rangeInfoList.length;
  119. }
  120. /**
  121. * Logic for each series: (If the logic has to be modified one day, do it carefully!)
  122. *
  123. * ( brushed ┬ && ┬hasBrushExist ┬ && linkOthers ) => StepA: ┬record, ┬ StepB: ┬visualByRecord.
  124. * !brushed┘ ├hasBrushExist ┤ └nothing,┘ ├visualByRecord.
  125. * └!hasBrushExist┘ └nothing.
  126. * ( !brushed && ┬hasBrushExist ┬ && linkOthers ) => StepA: nothing, StepB: ┬visualByRecord.
  127. * └!hasBrushExist┘ └nothing.
  128. * ( brushed ┬ && !linkOthers ) => StepA: nothing, StepB: ┬visualByCheck.
  129. * !brushed┘ └nothing.
  130. * ( !brushed && !linkOthers ) => StepA: nothing, StepB: nothing.
  131. */
  132. // Step A
  133. ecModel.eachSeries(function (seriesModel, seriesIndex) {
  134. var rangeInfoList = rangeInfoBySeries[seriesIndex] = [];
  135. seriesModel.subType === 'parallel' ? stepAParallel(seriesModel, seriesIndex) : stepAOthers(seriesModel, seriesIndex, rangeInfoList);
  136. });
  137. function stepAParallel(seriesModel, seriesIndex) {
  138. var coordSys = seriesModel.coordinateSystem;
  139. hasBrushExists = hasBrushExists || coordSys.hasAxisBrushed();
  140. linkOthers(seriesIndex) && coordSys.eachActiveState(seriesModel.getData(), function (activeState, dataIndex) {
  141. activeState === 'active' && (selectedDataIndexForLink[dataIndex] = 1);
  142. });
  143. }
  144. function stepAOthers(seriesModel, seriesIndex, rangeInfoList) {
  145. if (!seriesModel.brushSelector || brushModelNotControll(brushModel, seriesIndex)) {
  146. return;
  147. }
  148. zrUtil.each(areas, function (area) {
  149. if (brushModel.brushTargetManager.controlSeries(area, seriesModel, ecModel)) {
  150. rangeInfoList.push(area);
  151. }
  152. hasBrushExists = hasBrushExists || brushed(rangeInfoList);
  153. });
  154. if (linkOthers(seriesIndex) && brushed(rangeInfoList)) {
  155. var data_1 = seriesModel.getData();
  156. data_1.each(function (dataIndex) {
  157. if (checkInRange(seriesModel, rangeInfoList, data_1, dataIndex)) {
  158. selectedDataIndexForLink[dataIndex] = 1;
  159. }
  160. });
  161. }
  162. }
  163. // Step B
  164. ecModel.eachSeries(function (seriesModel, seriesIndex) {
  165. var seriesBrushSelected = {
  166. seriesId: seriesModel.id,
  167. seriesIndex: seriesIndex,
  168. seriesName: seriesModel.name,
  169. dataIndex: []
  170. };
  171. // Every series exists in event params, convenient
  172. // for user to find series by seriesIndex.
  173. thisBrushSelected.selected.push(seriesBrushSelected);
  174. var rangeInfoList = rangeInfoBySeries[seriesIndex];
  175. var data = seriesModel.getData();
  176. var getValueState = linkOthers(seriesIndex) ? function (dataIndex) {
  177. return selectedDataIndexForLink[dataIndex] ? (seriesBrushSelected.dataIndex.push(data.getRawIndex(dataIndex)), 'inBrush') : 'outOfBrush';
  178. } : function (dataIndex) {
  179. return checkInRange(seriesModel, rangeInfoList, data, dataIndex) ? (seriesBrushSelected.dataIndex.push(data.getRawIndex(dataIndex)), 'inBrush') : 'outOfBrush';
  180. };
  181. // If no supported brush or no brush, all visuals are in original state.
  182. (linkOthers(seriesIndex) ? hasBrushExists : brushed(rangeInfoList)) && visualSolution.applyVisual(STATE_LIST, visualMappings, data, getValueState);
  183. });
  184. });
  185. dispatchAction(api, throttleType, throttleDelay, brushSelected, payload);
  186. }
  187. ;
  188. function dispatchAction(api, throttleType, throttleDelay, brushSelected, payload) {
  189. // This event will not be triggered when `setOpion`, otherwise dead lock may
  190. // triggered when do `setOption` in event listener, which we do not find
  191. // satisfactory way to solve yet. Some considered resolutions:
  192. // (a) Diff with prevoius selected data ant only trigger event when changed.
  193. // But store previous data and diff precisely (i.e., not only by dataIndex, but
  194. // also detect value changes in selected data) might bring complexity or fragility.
  195. // (b) Use spectial param like `silent` to suppress event triggering.
  196. // But such kind of volatile param may be weird in `setOption`.
  197. if (!payload) {
  198. return;
  199. }
  200. var zr = api.getZr();
  201. if (zr[DISPATCH_FLAG]) {
  202. return;
  203. }
  204. if (!zr[DISPATCH_METHOD]) {
  205. zr[DISPATCH_METHOD] = doDispatch;
  206. }
  207. var fn = throttleUtil.createOrUpdate(zr, DISPATCH_METHOD, throttleDelay, throttleType);
  208. fn(api, brushSelected);
  209. }
  210. function doDispatch(api, brushSelected) {
  211. if (!api.isDisposed()) {
  212. var zr = api.getZr();
  213. zr[DISPATCH_FLAG] = true;
  214. api.dispatchAction({
  215. type: 'brushSelect',
  216. batch: brushSelected
  217. });
  218. zr[DISPATCH_FLAG] = false;
  219. }
  220. }
  221. function checkInRange(seriesModel, rangeInfoList, data, dataIndex) {
  222. for (var i = 0, len = rangeInfoList.length; i < len; i++) {
  223. var area = rangeInfoList[i];
  224. if (seriesModel.brushSelector(dataIndex, data, area.selectors, area)) {
  225. return true;
  226. }
  227. }
  228. }
  229. function brushModelNotControll(brushModel, seriesIndex) {
  230. var seriesIndices = brushModel.option.seriesIndex;
  231. return seriesIndices != null && seriesIndices !== 'all' && (zrUtil.isArray(seriesIndices) ? zrUtil.indexOf(seriesIndices, seriesIndex) < 0 : seriesIndex !== seriesIndices);
  232. }
  233. var boundingRectBuilders = {
  234. rect: function (area) {
  235. return getBoundingRectFromMinMax(area.range);
  236. },
  237. polygon: function (area) {
  238. var minMax;
  239. var range = area.range;
  240. for (var i = 0, len = range.length; i < len; i++) {
  241. minMax = minMax || [[Infinity, -Infinity], [Infinity, -Infinity]];
  242. var rg = range[i];
  243. rg[0] < minMax[0][0] && (minMax[0][0] = rg[0]);
  244. rg[0] > minMax[0][1] && (minMax[0][1] = rg[0]);
  245. rg[1] < minMax[1][0] && (minMax[1][0] = rg[1]);
  246. rg[1] > minMax[1][1] && (minMax[1][1] = rg[1]);
  247. }
  248. return minMax && getBoundingRectFromMinMax(minMax);
  249. }
  250. };
  251. function getBoundingRectFromMinMax(minMax) {
  252. return new BoundingRect(minMax[0][0], minMax[1][0], minMax[0][1] - minMax[0][0], minMax[1][1] - minMax[1][0]);
  253. }