states.js 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769
  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 LRU from 'zrender/lib/core/LRU';
  41. import { extend, indexOf, isArrayLike, isObject, keys, isArray, each } from 'zrender/lib/core/util';
  42. import { getECData } from './innerStore';
  43. import * as colorTool from 'zrender/lib/tool/color';
  44. import { queryDataIndex, makeInner } from './model';
  45. import Path from 'zrender/lib/graphic/Path';
  46. import { error } from './log'; // Reserve 0 as default.
  47. var _highlightNextDigit = 1;
  48. var _highlightKeyMap = {};
  49. var getSavedStates = makeInner();
  50. export var HOVER_STATE_NORMAL = 0;
  51. export var HOVER_STATE_BLUR = 1;
  52. export var HOVER_STATE_EMPHASIS = 2;
  53. export var SPECIAL_STATES = ['emphasis', 'blur', 'select'];
  54. export var DISPLAY_STATES = ['normal', 'emphasis', 'blur', 'select'];
  55. export var Z2_EMPHASIS_LIFT = 10;
  56. export var Z2_SELECT_LIFT = 9;
  57. export var HIGHLIGHT_ACTION_TYPE = 'highlight';
  58. export var DOWNPLAY_ACTION_TYPE = 'downplay';
  59. export var SELECT_ACTION_TYPE = 'select';
  60. export var UNSELECT_ACTION_TYPE = 'unselect';
  61. export var TOGGLE_SELECT_ACTION_TYPE = 'toggleSelect';
  62. function hasFillOrStroke(fillOrStroke) {
  63. return fillOrStroke != null && fillOrStroke !== 'none';
  64. } // Most lifted color are duplicated.
  65. var liftedColorCache = new LRU(100);
  66. function liftColor(color) {
  67. if (typeof color !== 'string') {
  68. return color;
  69. }
  70. var liftedColor = liftedColorCache.get(color);
  71. if (!liftedColor) {
  72. liftedColor = colorTool.lift(color, -0.1);
  73. liftedColorCache.put(color, liftedColor);
  74. }
  75. return liftedColor;
  76. }
  77. function doChangeHoverState(el, stateName, hoverStateEnum) {
  78. if (el.onHoverStateChange && (el.hoverState || 0) !== hoverStateEnum) {
  79. el.onHoverStateChange(stateName);
  80. }
  81. el.hoverState = hoverStateEnum;
  82. }
  83. function singleEnterEmphasis(el) {
  84. // Only mark the flag.
  85. // States will be applied in the echarts.ts in next frame.
  86. doChangeHoverState(el, 'emphasis', HOVER_STATE_EMPHASIS);
  87. }
  88. function singleLeaveEmphasis(el) {
  89. // Only mark the flag.
  90. // States will be applied in the echarts.ts in next frame.
  91. if (el.hoverState === HOVER_STATE_EMPHASIS) {
  92. doChangeHoverState(el, 'normal', HOVER_STATE_NORMAL);
  93. }
  94. }
  95. function singleEnterBlur(el) {
  96. doChangeHoverState(el, 'blur', HOVER_STATE_BLUR);
  97. }
  98. function singleLeaveBlur(el) {
  99. if (el.hoverState === HOVER_STATE_BLUR) {
  100. doChangeHoverState(el, 'normal', HOVER_STATE_NORMAL);
  101. }
  102. }
  103. function singleEnterSelect(el) {
  104. el.selected = true;
  105. }
  106. function singleLeaveSelect(el) {
  107. el.selected = false;
  108. }
  109. function updateElementState(el, updater, commonParam) {
  110. updater(el, commonParam);
  111. }
  112. function traverseUpdateState(el, updater, commonParam) {
  113. updateElementState(el, updater, commonParam);
  114. el.isGroup && el.traverse(function (child) {
  115. updateElementState(child, updater, commonParam);
  116. });
  117. }
  118. export function setStatesFlag(el, stateName) {
  119. switch (stateName) {
  120. case 'emphasis':
  121. el.hoverState = HOVER_STATE_EMPHASIS;
  122. break;
  123. case 'normal':
  124. el.hoverState = HOVER_STATE_NORMAL;
  125. break;
  126. case 'blur':
  127. el.hoverState = HOVER_STATE_BLUR;
  128. break;
  129. case 'select':
  130. el.selected = true;
  131. }
  132. }
  133. /**
  134. * If we reuse elements when rerender.
  135. * DONT forget to clearStates before we update the style and shape.
  136. * Or we may update on the wrong state instead of normal state.
  137. */
  138. export function clearStates(el) {
  139. if (el.isGroup) {
  140. el.traverse(function (child) {
  141. child.clearStates();
  142. });
  143. } else {
  144. el.clearStates();
  145. }
  146. }
  147. function getFromStateStyle(el, props, toStateName, defaultValue) {
  148. var style = el.style;
  149. var fromState = {};
  150. for (var i = 0; i < props.length; i++) {
  151. var propName = props[i];
  152. var val = style[propName];
  153. fromState[propName] = val == null ? defaultValue && defaultValue[propName] : val;
  154. }
  155. for (var i = 0; i < el.animators.length; i++) {
  156. var animator = el.animators[i];
  157. if (animator.__fromStateTransition // Dont consider the animation to emphasis state.
  158. && animator.__fromStateTransition.indexOf(toStateName) < 0 && animator.targetName === 'style') {
  159. animator.saveFinalToTarget(fromState, props);
  160. }
  161. }
  162. return fromState;
  163. }
  164. function createEmphasisDefaultState(el, stateName, targetStates, state) {
  165. var hasSelect = targetStates && indexOf(targetStates, 'select') >= 0;
  166. var cloned = false;
  167. if (el instanceof Path) {
  168. var store = getSavedStates(el);
  169. var fromFill = hasSelect ? store.selectFill || store.normalFill : store.normalFill;
  170. var fromStroke = hasSelect ? store.selectStroke || store.normalStroke : store.normalStroke;
  171. if (hasFillOrStroke(fromFill) || hasFillOrStroke(fromStroke)) {
  172. state = state || {};
  173. var emphasisStyle = state.style || {}; // inherit case
  174. if (emphasisStyle.fill === 'inherit') {
  175. cloned = true;
  176. state = extend({}, state);
  177. emphasisStyle = extend({}, emphasisStyle);
  178. emphasisStyle.fill = fromFill;
  179. } // Apply default color lift
  180. else if (!hasFillOrStroke(emphasisStyle.fill) && hasFillOrStroke(fromFill)) {
  181. cloned = true; // Not modify the original value.
  182. state = extend({}, state);
  183. emphasisStyle = extend({}, emphasisStyle); // Already being applied 'emphasis'. DON'T lift color multiple times.
  184. emphasisStyle.fill = liftColor(fromFill);
  185. } // Not highlight stroke if fill has been highlighted.
  186. else if (!hasFillOrStroke(emphasisStyle.stroke) && hasFillOrStroke(fromStroke)) {
  187. if (!cloned) {
  188. state = extend({}, state);
  189. emphasisStyle = extend({}, emphasisStyle);
  190. }
  191. emphasisStyle.stroke = liftColor(fromStroke);
  192. }
  193. state.style = emphasisStyle;
  194. }
  195. }
  196. if (state) {
  197. // TODO Share with textContent?
  198. if (state.z2 == null) {
  199. if (!cloned) {
  200. state = extend({}, state);
  201. }
  202. var z2EmphasisLift = el.z2EmphasisLift;
  203. state.z2 = el.z2 + (z2EmphasisLift != null ? z2EmphasisLift : Z2_EMPHASIS_LIFT);
  204. }
  205. }
  206. return state;
  207. }
  208. function createSelectDefaultState(el, stateName, state) {
  209. // const hasSelect = indexOf(el.currentStates, stateName) >= 0;
  210. if (state) {
  211. // TODO Share with textContent?
  212. if (state.z2 == null) {
  213. state = extend({}, state);
  214. var z2SelectLift = el.z2SelectLift;
  215. state.z2 = el.z2 + (z2SelectLift != null ? z2SelectLift : Z2_SELECT_LIFT);
  216. }
  217. }
  218. return state;
  219. }
  220. function createBlurDefaultState(el, stateName, state) {
  221. var hasBlur = indexOf(el.currentStates, stateName) >= 0;
  222. var currentOpacity = el.style.opacity;
  223. var fromState = !hasBlur ? getFromStateStyle(el, ['opacity'], stateName, {
  224. opacity: 1
  225. }) : null;
  226. state = state || {};
  227. var blurStyle = state.style || {};
  228. if (blurStyle.opacity == null) {
  229. // clone state
  230. state = extend({}, state);
  231. blurStyle = extend({
  232. // Already being applied 'emphasis'. DON'T mul opacity multiple times.
  233. opacity: hasBlur ? currentOpacity : fromState.opacity * 0.1
  234. }, blurStyle);
  235. state.style = blurStyle;
  236. }
  237. return state;
  238. }
  239. function elementStateProxy(stateName, targetStates) {
  240. var state = this.states[stateName];
  241. if (this.style) {
  242. if (stateName === 'emphasis') {
  243. return createEmphasisDefaultState(this, stateName, targetStates, state);
  244. } else if (stateName === 'blur') {
  245. return createBlurDefaultState(this, stateName, state);
  246. } else if (stateName === 'select') {
  247. return createSelectDefaultState(this, stateName, state);
  248. }
  249. }
  250. return state;
  251. }
  252. /**FI
  253. * Set hover style (namely "emphasis style") of element.
  254. * @param el Should not be `zrender/graphic/Group`.
  255. * @param focus 'self' | 'selfInSeries' | 'series'
  256. */
  257. export function setDefaultStateProxy(el) {
  258. el.stateProxy = elementStateProxy;
  259. var textContent = el.getTextContent();
  260. var textGuide = el.getTextGuideLine();
  261. if (textContent) {
  262. textContent.stateProxy = elementStateProxy;
  263. }
  264. if (textGuide) {
  265. textGuide.stateProxy = elementStateProxy;
  266. }
  267. }
  268. export function enterEmphasisWhenMouseOver(el, e) {
  269. !shouldSilent(el, e) // "emphasis" event highlight has higher priority than mouse highlight.
  270. && !el.__highByOuter && traverseUpdateState(el, singleEnterEmphasis);
  271. }
  272. export function leaveEmphasisWhenMouseOut(el, e) {
  273. !shouldSilent(el, e) // "emphasis" event highlight has higher priority than mouse highlight.
  274. && !el.__highByOuter && traverseUpdateState(el, singleLeaveEmphasis);
  275. }
  276. export function enterEmphasis(el, highlightDigit) {
  277. el.__highByOuter |= 1 << (highlightDigit || 0);
  278. traverseUpdateState(el, singleEnterEmphasis);
  279. }
  280. export function leaveEmphasis(el, highlightDigit) {
  281. !(el.__highByOuter &= ~(1 << (highlightDigit || 0))) && traverseUpdateState(el, singleLeaveEmphasis);
  282. }
  283. export function enterBlur(el) {
  284. traverseUpdateState(el, singleEnterBlur);
  285. }
  286. export function leaveBlur(el) {
  287. traverseUpdateState(el, singleLeaveBlur);
  288. }
  289. export function enterSelect(el) {
  290. traverseUpdateState(el, singleEnterSelect);
  291. }
  292. export function leaveSelect(el) {
  293. traverseUpdateState(el, singleLeaveSelect);
  294. }
  295. function shouldSilent(el, e) {
  296. return el.__highDownSilentOnTouch && e.zrByTouch;
  297. }
  298. export function allLeaveBlur(api) {
  299. var model = api.getModel();
  300. model.eachComponent(function (componentType, componentModel) {
  301. var view = componentType === 'series' ? api.getViewOfSeriesModel(componentModel) : api.getViewOfComponentModel(componentModel); // Leave blur anyway
  302. view.group.traverse(function (child) {
  303. singleLeaveBlur(child);
  304. });
  305. });
  306. }
  307. export function blurSeries(targetSeriesIndex, focus, blurScope, api) {
  308. var ecModel = api.getModel();
  309. blurScope = blurScope || 'coordinateSystem';
  310. function leaveBlurOfIndices(data, dataIndices) {
  311. for (var i = 0; i < dataIndices.length; i++) {
  312. var itemEl = data.getItemGraphicEl(dataIndices[i]);
  313. itemEl && leaveBlur(itemEl);
  314. }
  315. }
  316. if (targetSeriesIndex == null) {
  317. return;
  318. }
  319. if (!focus || focus === 'none') {
  320. return;
  321. }
  322. var targetSeriesModel = ecModel.getSeriesByIndex(targetSeriesIndex);
  323. var targetCoordSys = targetSeriesModel.coordinateSystem;
  324. if (targetCoordSys && targetCoordSys.master) {
  325. targetCoordSys = targetCoordSys.master;
  326. }
  327. var blurredSeries = [];
  328. ecModel.eachSeries(function (seriesModel) {
  329. var sameSeries = targetSeriesModel === seriesModel;
  330. var coordSys = seriesModel.coordinateSystem;
  331. if (coordSys && coordSys.master) {
  332. coordSys = coordSys.master;
  333. }
  334. var sameCoordSys = coordSys && targetCoordSys ? coordSys === targetCoordSys : sameSeries; // If there is no coordinate system. use sameSeries instead.
  335. if (!( // Not blur other series if blurScope series
  336. blurScope === 'series' && !sameSeries // Not blur other coordinate system if blurScope is coordinateSystem
  337. || blurScope === 'coordinateSystem' && !sameCoordSys // Not blur self series if focus is series.
  338. || focus === 'series' && sameSeries // TODO blurScope: coordinate system
  339. )) {
  340. var view = api.getViewOfSeriesModel(seriesModel);
  341. view.group.traverse(function (child) {
  342. singleEnterBlur(child);
  343. });
  344. if (isArrayLike(focus)) {
  345. leaveBlurOfIndices(seriesModel.getData(), focus);
  346. } else if (isObject(focus)) {
  347. var dataTypes = keys(focus);
  348. for (var d = 0; d < dataTypes.length; d++) {
  349. leaveBlurOfIndices(seriesModel.getData(dataTypes[d]), focus[dataTypes[d]]);
  350. }
  351. }
  352. blurredSeries.push(seriesModel);
  353. }
  354. });
  355. ecModel.eachComponent(function (componentType, componentModel) {
  356. if (componentType === 'series') {
  357. return;
  358. }
  359. var view = api.getViewOfComponentModel(componentModel);
  360. if (view && view.blurSeries) {
  361. view.blurSeries(blurredSeries, ecModel);
  362. }
  363. });
  364. }
  365. export function blurComponent(componentMainType, componentIndex, api) {
  366. if (componentMainType == null || componentIndex == null) {
  367. return;
  368. }
  369. var componentModel = api.getModel().getComponent(componentMainType, componentIndex);
  370. if (!componentModel) {
  371. return;
  372. }
  373. var view = api.getViewOfComponentModel(componentModel);
  374. if (!view || !view.focusBlurEnabled) {
  375. return;
  376. }
  377. view.group.traverse(function (child) {
  378. singleEnterBlur(child);
  379. });
  380. }
  381. export function blurSeriesFromHighlightPayload(seriesModel, payload, api) {
  382. var seriesIndex = seriesModel.seriesIndex;
  383. var data = seriesModel.getData(payload.dataType);
  384. var dataIndex = queryDataIndex(data, payload); // Pick the first one if there is multiple/none exists.
  385. dataIndex = (isArray(dataIndex) ? dataIndex[0] : dataIndex) || 0;
  386. var el = data.getItemGraphicEl(dataIndex);
  387. if (!el) {
  388. var count = data.count();
  389. var current = 0; // If data on dataIndex is NaN.
  390. while (!el && current < count) {
  391. el = data.getItemGraphicEl(current++);
  392. }
  393. }
  394. if (el) {
  395. var ecData = getECData(el);
  396. blurSeries(seriesIndex, ecData.focus, ecData.blurScope, api);
  397. } else {
  398. // If there is no element put on the data. Try getting it from raw option
  399. // TODO Should put it on seriesModel?
  400. var focus_1 = seriesModel.get(['emphasis', 'focus']);
  401. var blurScope = seriesModel.get(['emphasis', 'blurScope']);
  402. if (focus_1 != null) {
  403. blurSeries(seriesIndex, focus_1, blurScope, api);
  404. }
  405. }
  406. }
  407. export function findComponentHighDownDispatchers(componentMainType, componentIndex, name, api) {
  408. var ret = {
  409. focusSelf: false,
  410. dispatchers: null
  411. };
  412. if (componentMainType == null || componentMainType === 'series' || componentIndex == null || name == null) {
  413. return ret;
  414. }
  415. var componentModel = api.getModel().getComponent(componentMainType, componentIndex);
  416. if (!componentModel) {
  417. return ret;
  418. }
  419. var view = api.getViewOfComponentModel(componentModel);
  420. if (!view || !view.findHighDownDispatchers) {
  421. return ret;
  422. }
  423. var dispatchers = view.findHighDownDispatchers(name); // At presnet, the component (like Geo) only blur inside itself.
  424. // So we do not use `blurScope` in component.
  425. var focusSelf;
  426. for (var i = 0; i < dispatchers.length; i++) {
  427. if (process.env.NODE_ENV !== 'production' && !isHighDownDispatcher(dispatchers[i])) {
  428. error('param should be highDownDispatcher');
  429. }
  430. if (getECData(dispatchers[i]).focus === 'self') {
  431. focusSelf = true;
  432. break;
  433. }
  434. }
  435. return {
  436. focusSelf: focusSelf,
  437. dispatchers: dispatchers
  438. };
  439. }
  440. export function handleGlobalMouseOverForHighDown(dispatcher, e, api) {
  441. if (process.env.NODE_ENV !== 'production' && !isHighDownDispatcher(dispatcher)) {
  442. error('param should be highDownDispatcher');
  443. }
  444. var ecData = getECData(dispatcher);
  445. var _a = findComponentHighDownDispatchers(ecData.componentMainType, ecData.componentIndex, ecData.componentHighDownName, api),
  446. dispatchers = _a.dispatchers,
  447. focusSelf = _a.focusSelf; // If `findHighDownDispatchers` is supported on the component,
  448. // highlight/downplay elements with the same name.
  449. if (dispatchers) {
  450. if (focusSelf) {
  451. blurComponent(ecData.componentMainType, ecData.componentIndex, api);
  452. }
  453. each(dispatchers, function (dispatcher) {
  454. return enterEmphasisWhenMouseOver(dispatcher, e);
  455. });
  456. } else {
  457. // Try blur all in the related series. Then emphasis the hoverred.
  458. // TODO. progressive mode.
  459. blurSeries(ecData.seriesIndex, ecData.focus, ecData.blurScope, api);
  460. if (ecData.focus === 'self') {
  461. blurComponent(ecData.componentMainType, ecData.componentIndex, api);
  462. } // Other than series, component that not support `findHighDownDispatcher` will
  463. // also use it. But in this case, highlight/downplay are only supported in
  464. // mouse hover but not in dispatchAction.
  465. enterEmphasisWhenMouseOver(dispatcher, e);
  466. }
  467. }
  468. export function handleGlboalMouseOutForHighDown(dispatcher, e, api) {
  469. if (process.env.NODE_ENV !== 'production' && !isHighDownDispatcher(dispatcher)) {
  470. error('param should be highDownDispatcher');
  471. }
  472. allLeaveBlur(api);
  473. var ecData = getECData(dispatcher);
  474. var dispatchers = findComponentHighDownDispatchers(ecData.componentMainType, ecData.componentIndex, ecData.componentHighDownName, api).dispatchers;
  475. if (dispatchers) {
  476. each(dispatchers, function (dispatcher) {
  477. return leaveEmphasisWhenMouseOut(dispatcher, e);
  478. });
  479. } else {
  480. leaveEmphasisWhenMouseOut(dispatcher, e);
  481. }
  482. }
  483. export function toggleSelectionFromPayload(seriesModel, payload, api) {
  484. if (!isSelectChangePayload(payload)) {
  485. return;
  486. }
  487. var dataType = payload.dataType;
  488. var data = seriesModel.getData(dataType);
  489. var dataIndex = queryDataIndex(data, payload);
  490. if (!isArray(dataIndex)) {
  491. dataIndex = [dataIndex];
  492. }
  493. seriesModel[payload.type === TOGGLE_SELECT_ACTION_TYPE ? 'toggleSelect' : payload.type === SELECT_ACTION_TYPE ? 'select' : 'unselect'](dataIndex, dataType);
  494. }
  495. export function updateSeriesElementSelection(seriesModel) {
  496. var allData = seriesModel.getAllData();
  497. each(allData, function (_a) {
  498. var data = _a.data,
  499. type = _a.type;
  500. data.eachItemGraphicEl(function (el, idx) {
  501. seriesModel.isSelected(idx, type) ? enterSelect(el) : leaveSelect(el);
  502. });
  503. });
  504. }
  505. export function getAllSelectedIndices(ecModel) {
  506. var ret = [];
  507. ecModel.eachSeries(function (seriesModel) {
  508. var allData = seriesModel.getAllData();
  509. each(allData, function (_a) {
  510. var data = _a.data,
  511. type = _a.type;
  512. var dataIndices = seriesModel.getSelectedDataIndices();
  513. if (dataIndices.length > 0) {
  514. var item = {
  515. dataIndex: dataIndices,
  516. seriesIndex: seriesModel.seriesIndex
  517. };
  518. if (type != null) {
  519. item.dataType = type;
  520. }
  521. ret.push(item);
  522. }
  523. });
  524. });
  525. return ret;
  526. }
  527. /**
  528. * Enable the function that mouseover will trigger the emphasis state.
  529. *
  530. * NOTE:
  531. * This function should be used on the element with dataIndex, seriesIndex.
  532. *
  533. */
  534. export function enableHoverEmphasis(el, focus, blurScope) {
  535. setAsHighDownDispatcher(el, true);
  536. traverseUpdateState(el, setDefaultStateProxy);
  537. enableHoverFocus(el, focus, blurScope);
  538. }
  539. export function enableHoverFocus(el, focus, blurScope) {
  540. var ecData = getECData(el);
  541. if (focus != null) {
  542. // TODO dataIndex may be set after this function. This check is not useful.
  543. // if (ecData.dataIndex == null) {
  544. // if (__DEV__) {
  545. // console.warn('focus can only been set on element with dataIndex');
  546. // }
  547. // }
  548. // else {
  549. ecData.focus = focus;
  550. ecData.blurScope = blurScope; // }
  551. } else if (ecData.focus) {
  552. ecData.focus = null;
  553. }
  554. }
  555. var OTHER_STATES = ['emphasis', 'blur', 'select'];
  556. var defaultStyleGetterMap = {
  557. itemStyle: 'getItemStyle',
  558. lineStyle: 'getLineStyle',
  559. areaStyle: 'getAreaStyle'
  560. };
  561. /**
  562. * Set emphasis/blur/selected states of element.
  563. */
  564. export function setStatesStylesFromModel(el, itemModel, styleType, // default itemStyle
  565. getter) {
  566. styleType = styleType || 'itemStyle';
  567. for (var i = 0; i < OTHER_STATES.length; i++) {
  568. var stateName = OTHER_STATES[i];
  569. var model = itemModel.getModel([stateName, styleType]);
  570. var state = el.ensureState(stateName); // Let it throw error if getterType is not found.
  571. state.style = getter ? getter(model) : model[defaultStyleGetterMap[styleType]]();
  572. }
  573. }
  574. /**
  575. * @parame el
  576. * @param el.highDownSilentOnTouch
  577. * In touch device, mouseover event will be trigger on touchstart event
  578. * (see module:zrender/dom/HandlerProxy). By this mechanism, we can
  579. * conveniently use hoverStyle when tap on touch screen without additional
  580. * code for compatibility.
  581. * But if the chart/component has select feature, which usually also use
  582. * hoverStyle, there might be conflict between 'select-highlight' and
  583. * 'hover-highlight' especially when roam is enabled (see geo for example).
  584. * In this case, `highDownSilentOnTouch` should be used to disable
  585. * hover-highlight on touch device.
  586. * @param asDispatcher If `false`, do not set as "highDownDispatcher".
  587. */
  588. export function setAsHighDownDispatcher(el, asDispatcher) {
  589. var disable = asDispatcher === false;
  590. var extendedEl = el; // Make `highDownSilentOnTouch` and `onStateChange` only work after
  591. // `setAsHighDownDispatcher` called. Avoid it is modified by user unexpectedly.
  592. if (el.highDownSilentOnTouch) {
  593. extendedEl.__highDownSilentOnTouch = el.highDownSilentOnTouch;
  594. } // Simple optimize, since this method might be
  595. // called for each elements of a group in some cases.
  596. if (!disable || extendedEl.__highDownDispatcher) {
  597. // Emphasis, normal can be triggered manually by API or other components like hover link.
  598. // el[method]('emphasis', onElementEmphasisEvent)[method]('normal', onElementNormalEvent);
  599. // Also keep previous record.
  600. extendedEl.__highByOuter = extendedEl.__highByOuter || 0;
  601. extendedEl.__highDownDispatcher = !disable;
  602. }
  603. }
  604. export function isHighDownDispatcher(el) {
  605. return !!(el && el.__highDownDispatcher);
  606. }
  607. /**
  608. * Enable component highlight/downplay features:
  609. * + hover link (within the same name)
  610. * + focus blur in component
  611. */
  612. export function enableComponentHighDownFeatures(el, componentModel, componentHighDownName) {
  613. var ecData = getECData(el);
  614. ecData.componentMainType = componentModel.mainType;
  615. ecData.componentIndex = componentModel.componentIndex;
  616. ecData.componentHighDownName = componentHighDownName;
  617. }
  618. /**
  619. * Support hightlight/downplay record on each elements.
  620. * For the case: hover highlight/downplay (legend, visualMap, ...) and
  621. * user triggerred hightlight/downplay should not conflict.
  622. * Only all of the highlightDigit cleared, return to normal.
  623. * @param {string} highlightKey
  624. * @return {number} highlightDigit
  625. */
  626. export function getHighlightDigit(highlightKey) {
  627. var highlightDigit = _highlightKeyMap[highlightKey];
  628. if (highlightDigit == null && _highlightNextDigit <= 32) {
  629. highlightDigit = _highlightKeyMap[highlightKey] = _highlightNextDigit++;
  630. }
  631. return highlightDigit;
  632. }
  633. export function isSelectChangePayload(payload) {
  634. var payloadType = payload.type;
  635. return payloadType === SELECT_ACTION_TYPE || payloadType === UNSELECT_ACTION_TYPE || payloadType === TOGGLE_SELECT_ACTION_TYPE;
  636. }
  637. export function isHighDownPayload(payload) {
  638. var payloadType = payload.type;
  639. return payloadType === HIGHLIGHT_ACTION_TYPE || payloadType === DOWNPLAY_ACTION_TYPE;
  640. }
  641. export function savePathStates(el) {
  642. var store = getSavedStates(el);
  643. store.normalFill = el.style.fill;
  644. store.normalStroke = el.style.stroke;
  645. var selectState = el.states.select || {};
  646. store.selectFill = selectState.style && selectState.style.fill || null;
  647. store.selectStroke = selectState.style && selectState.style.stroke || null;
  648. }