visualEncoding.js 12 KB

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