ContinuousView.js 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688
  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. import * as zrUtil from 'zrender/lib/core/util.js';
  42. import LinearGradient from 'zrender/lib/graphic/LinearGradient.js';
  43. import * as eventTool from 'zrender/lib/core/event.js';
  44. import VisualMapView from './VisualMapView.js';
  45. import * as graphic from '../../util/graphic.js';
  46. import * as numberUtil from '../../util/number.js';
  47. import sliderMove from '../helper/sliderMove.js';
  48. import * as helper from './helper.js';
  49. import * as modelUtil from '../../util/model.js';
  50. import { parsePercent } from 'zrender/lib/contain/text.js';
  51. import { setAsHighDownDispatcher } from '../../util/states.js';
  52. import { createSymbol } from '../../util/symbol.js';
  53. import ZRImage from 'zrender/lib/graphic/Image.js';
  54. import { getECData } from '../../util/innerStore.js';
  55. import { createTextStyle } from '../../label/labelStyle.js';
  56. import { findEventDispatcher } from '../../util/event.js';
  57. var linearMap = numberUtil.linearMap;
  58. var each = zrUtil.each;
  59. var mathMin = Math.min;
  60. var mathMax = Math.max;
  61. // Arbitrary value
  62. var HOVER_LINK_SIZE = 12;
  63. var HOVER_LINK_OUT = 6;
  64. // Notice:
  65. // Any "interval" should be by the order of [low, high].
  66. // "handle0" (handleIndex === 0) maps to
  67. // low data value: this._dataInterval[0] and has low coord.
  68. // "handle1" (handleIndex === 1) maps to
  69. // high data value: this._dataInterval[1] and has high coord.
  70. // The logic of transform is implemented in this._createBarGroup.
  71. var ContinuousView = /** @class */function (_super) {
  72. __extends(ContinuousView, _super);
  73. function ContinuousView() {
  74. var _this = _super !== null && _super.apply(this, arguments) || this;
  75. _this.type = ContinuousView.type;
  76. _this._shapes = {};
  77. _this._dataInterval = [];
  78. _this._handleEnds = [];
  79. _this._hoverLinkDataIndices = [];
  80. return _this;
  81. }
  82. ContinuousView.prototype.init = function (ecModel, api) {
  83. _super.prototype.init.call(this, ecModel, api);
  84. this._hoverLinkFromSeriesMouseOver = zrUtil.bind(this._hoverLinkFromSeriesMouseOver, this);
  85. this._hideIndicator = zrUtil.bind(this._hideIndicator, this);
  86. };
  87. ContinuousView.prototype.doRender = function (visualMapModel, ecModel, api, payload) {
  88. if (!payload || payload.type !== 'selectDataRange' || payload.from !== this.uid) {
  89. this._buildView();
  90. }
  91. };
  92. ContinuousView.prototype._buildView = function () {
  93. this.group.removeAll();
  94. var visualMapModel = this.visualMapModel;
  95. var thisGroup = this.group;
  96. this._orient = visualMapModel.get('orient');
  97. this._useHandle = visualMapModel.get('calculable');
  98. this._resetInterval();
  99. this._renderBar(thisGroup);
  100. var dataRangeText = visualMapModel.get('text');
  101. this._renderEndsText(thisGroup, dataRangeText, 0);
  102. this._renderEndsText(thisGroup, dataRangeText, 1);
  103. // Do this for background size calculation.
  104. this._updateView(true);
  105. // After updating view, inner shapes is built completely,
  106. // and then background can be rendered.
  107. this.renderBackground(thisGroup);
  108. // Real update view
  109. this._updateView();
  110. this._enableHoverLinkToSeries();
  111. this._enableHoverLinkFromSeries();
  112. this.positionGroup(thisGroup);
  113. };
  114. ContinuousView.prototype._renderEndsText = function (group, dataRangeText, endsIndex) {
  115. if (!dataRangeText) {
  116. return;
  117. }
  118. // Compatible with ec2, text[0] map to high value, text[1] map low value.
  119. var text = dataRangeText[1 - endsIndex];
  120. text = text != null ? text + '' : '';
  121. var visualMapModel = this.visualMapModel;
  122. var textGap = visualMapModel.get('textGap');
  123. var itemSize = visualMapModel.itemSize;
  124. var barGroup = this._shapes.mainGroup;
  125. var position = this._applyTransform([itemSize[0] / 2, endsIndex === 0 ? -textGap : itemSize[1] + textGap], barGroup);
  126. var align = this._applyTransform(endsIndex === 0 ? 'bottom' : 'top', barGroup);
  127. var orient = this._orient;
  128. var textStyleModel = this.visualMapModel.textStyleModel;
  129. this.group.add(new graphic.Text({
  130. style: createTextStyle(textStyleModel, {
  131. x: position[0],
  132. y: position[1],
  133. verticalAlign: orient === 'horizontal' ? 'middle' : align,
  134. align: orient === 'horizontal' ? align : 'center',
  135. text: text
  136. })
  137. }));
  138. };
  139. ContinuousView.prototype._renderBar = function (targetGroup) {
  140. var visualMapModel = this.visualMapModel;
  141. var shapes = this._shapes;
  142. var itemSize = visualMapModel.itemSize;
  143. var orient = this._orient;
  144. var useHandle = this._useHandle;
  145. var itemAlign = helper.getItemAlign(visualMapModel, this.api, itemSize);
  146. var mainGroup = shapes.mainGroup = this._createBarGroup(itemAlign);
  147. var gradientBarGroup = new graphic.Group();
  148. mainGroup.add(gradientBarGroup);
  149. // Bar
  150. gradientBarGroup.add(shapes.outOfRange = createPolygon());
  151. gradientBarGroup.add(shapes.inRange = createPolygon(null, useHandle ? getCursor(this._orient) : null, zrUtil.bind(this._dragHandle, this, 'all', false), zrUtil.bind(this._dragHandle, this, 'all', true)));
  152. // A border radius clip.
  153. gradientBarGroup.setClipPath(new graphic.Rect({
  154. shape: {
  155. x: 0,
  156. y: 0,
  157. width: itemSize[0],
  158. height: itemSize[1],
  159. r: 3
  160. }
  161. }));
  162. var textRect = visualMapModel.textStyleModel.getTextRect('国');
  163. var textSize = mathMax(textRect.width, textRect.height);
  164. // Handle
  165. if (useHandle) {
  166. shapes.handleThumbs = [];
  167. shapes.handleLabels = [];
  168. shapes.handleLabelPoints = [];
  169. this._createHandle(visualMapModel, mainGroup, 0, itemSize, textSize, orient);
  170. this._createHandle(visualMapModel, mainGroup, 1, itemSize, textSize, orient);
  171. }
  172. this._createIndicator(visualMapModel, mainGroup, itemSize, textSize, orient);
  173. targetGroup.add(mainGroup);
  174. };
  175. ContinuousView.prototype._createHandle = function (visualMapModel, mainGroup, handleIndex, itemSize, textSize, orient) {
  176. var onDrift = zrUtil.bind(this._dragHandle, this, handleIndex, false);
  177. var onDragEnd = zrUtil.bind(this._dragHandle, this, handleIndex, true);
  178. var handleSize = parsePercent(visualMapModel.get('handleSize'), itemSize[0]);
  179. var handleThumb = createSymbol(visualMapModel.get('handleIcon'), -handleSize / 2, -handleSize / 2, handleSize, handleSize, null, true);
  180. var cursor = getCursor(this._orient);
  181. handleThumb.attr({
  182. cursor: cursor,
  183. draggable: true,
  184. drift: onDrift,
  185. ondragend: onDragEnd,
  186. onmousemove: function (e) {
  187. eventTool.stop(e.event);
  188. }
  189. });
  190. handleThumb.x = itemSize[0] / 2;
  191. handleThumb.useStyle(visualMapModel.getModel('handleStyle').getItemStyle());
  192. handleThumb.setStyle({
  193. strokeNoScale: true,
  194. strokeFirst: true
  195. });
  196. handleThumb.style.lineWidth *= 2;
  197. handleThumb.ensureState('emphasis').style = visualMapModel.getModel(['emphasis', 'handleStyle']).getItemStyle();
  198. setAsHighDownDispatcher(handleThumb, true);
  199. mainGroup.add(handleThumb);
  200. // Text is always horizontal layout but should not be effected by
  201. // transform (orient/inverse). So label is built separately but not
  202. // use zrender/graphic/helper/RectText, and is located based on view
  203. // group (according to handleLabelPoint) but not barGroup.
  204. var textStyleModel = this.visualMapModel.textStyleModel;
  205. var handleLabel = new graphic.Text({
  206. cursor: cursor,
  207. draggable: true,
  208. drift: onDrift,
  209. onmousemove: function (e) {
  210. // For mobile device, prevent screen slider on the button.
  211. eventTool.stop(e.event);
  212. },
  213. ondragend: onDragEnd,
  214. style: createTextStyle(textStyleModel, {
  215. x: 0,
  216. y: 0,
  217. text: ''
  218. })
  219. });
  220. handleLabel.ensureState('blur').style = {
  221. opacity: 0.1
  222. };
  223. handleLabel.stateTransition = {
  224. duration: 200
  225. };
  226. this.group.add(handleLabel);
  227. var handleLabelPoint = [handleSize, 0];
  228. var shapes = this._shapes;
  229. shapes.handleThumbs[handleIndex] = handleThumb;
  230. shapes.handleLabelPoints[handleIndex] = handleLabelPoint;
  231. shapes.handleLabels[handleIndex] = handleLabel;
  232. };
  233. ContinuousView.prototype._createIndicator = function (visualMapModel, mainGroup, itemSize, textSize, orient) {
  234. var scale = parsePercent(visualMapModel.get('indicatorSize'), itemSize[0]);
  235. var indicator = createSymbol(visualMapModel.get('indicatorIcon'), -scale / 2, -scale / 2, scale, scale, null, true);
  236. indicator.attr({
  237. cursor: 'move',
  238. invisible: true,
  239. silent: true,
  240. x: itemSize[0] / 2
  241. });
  242. var indicatorStyle = visualMapModel.getModel('indicatorStyle').getItemStyle();
  243. if (indicator instanceof ZRImage) {
  244. var pathStyle = indicator.style;
  245. indicator.useStyle(zrUtil.extend({
  246. // TODO other properties like x, y ?
  247. image: pathStyle.image,
  248. x: pathStyle.x,
  249. y: pathStyle.y,
  250. width: pathStyle.width,
  251. height: pathStyle.height
  252. }, indicatorStyle));
  253. } else {
  254. indicator.useStyle(indicatorStyle);
  255. }
  256. mainGroup.add(indicator);
  257. var textStyleModel = this.visualMapModel.textStyleModel;
  258. var indicatorLabel = new graphic.Text({
  259. silent: true,
  260. invisible: true,
  261. style: createTextStyle(textStyleModel, {
  262. x: 0,
  263. y: 0,
  264. text: ''
  265. })
  266. });
  267. this.group.add(indicatorLabel);
  268. var indicatorLabelPoint = [(orient === 'horizontal' ? textSize / 2 : HOVER_LINK_OUT) + itemSize[0] / 2, 0];
  269. var shapes = this._shapes;
  270. shapes.indicator = indicator;
  271. shapes.indicatorLabel = indicatorLabel;
  272. shapes.indicatorLabelPoint = indicatorLabelPoint;
  273. this._firstShowIndicator = true;
  274. };
  275. ContinuousView.prototype._dragHandle = function (handleIndex, isEnd,
  276. // dx is event from ondragend if isEnd is true. It's not used
  277. dx, dy) {
  278. if (!this._useHandle) {
  279. return;
  280. }
  281. this._dragging = !isEnd;
  282. if (!isEnd) {
  283. // Transform dx, dy to bar coordination.
  284. var vertex = this._applyTransform([dx, dy], this._shapes.mainGroup, true);
  285. this._updateInterval(handleIndex, vertex[1]);
  286. this._hideIndicator();
  287. // Considering realtime, update view should be executed
  288. // before dispatch action.
  289. this._updateView();
  290. }
  291. // dragEnd do not dispatch action when realtime.
  292. if (isEnd === !this.visualMapModel.get('realtime')) {
  293. // jshint ignore:line
  294. this.api.dispatchAction({
  295. type: 'selectDataRange',
  296. from: this.uid,
  297. visualMapId: this.visualMapModel.id,
  298. selected: this._dataInterval.slice()
  299. });
  300. }
  301. if (isEnd) {
  302. !this._hovering && this._clearHoverLinkToSeries();
  303. } else if (useHoverLinkOnHandle(this.visualMapModel)) {
  304. this._doHoverLinkToSeries(this._handleEnds[handleIndex], false);
  305. }
  306. };
  307. ContinuousView.prototype._resetInterval = function () {
  308. var visualMapModel = this.visualMapModel;
  309. var dataInterval = this._dataInterval = visualMapModel.getSelected();
  310. var dataExtent = visualMapModel.getExtent();
  311. var sizeExtent = [0, visualMapModel.itemSize[1]];
  312. this._handleEnds = [linearMap(dataInterval[0], dataExtent, sizeExtent, true), linearMap(dataInterval[1], dataExtent, sizeExtent, true)];
  313. };
  314. /**
  315. * @private
  316. * @param {(number|string)} handleIndex 0 or 1 or 'all'
  317. * @param {number} dx
  318. * @param {number} dy
  319. */
  320. ContinuousView.prototype._updateInterval = function (handleIndex, delta) {
  321. delta = delta || 0;
  322. var visualMapModel = this.visualMapModel;
  323. var handleEnds = this._handleEnds;
  324. var sizeExtent = [0, visualMapModel.itemSize[1]];
  325. sliderMove(delta, handleEnds, sizeExtent, handleIndex,
  326. // cross is forbidden
  327. 0);
  328. var dataExtent = visualMapModel.getExtent();
  329. // Update data interval.
  330. this._dataInterval = [linearMap(handleEnds[0], sizeExtent, dataExtent, true), linearMap(handleEnds[1], sizeExtent, dataExtent, true)];
  331. };
  332. ContinuousView.prototype._updateView = function (forSketch) {
  333. var visualMapModel = this.visualMapModel;
  334. var dataExtent = visualMapModel.getExtent();
  335. var shapes = this._shapes;
  336. var outOfRangeHandleEnds = [0, visualMapModel.itemSize[1]];
  337. var inRangeHandleEnds = forSketch ? outOfRangeHandleEnds : this._handleEnds;
  338. var visualInRange = this._createBarVisual(this._dataInterval, dataExtent, inRangeHandleEnds, 'inRange');
  339. var visualOutOfRange = this._createBarVisual(dataExtent, dataExtent, outOfRangeHandleEnds, 'outOfRange');
  340. shapes.inRange.setStyle({
  341. fill: visualInRange.barColor
  342. // opacity: visualInRange.opacity
  343. }).setShape('points', visualInRange.barPoints);
  344. shapes.outOfRange.setStyle({
  345. fill: visualOutOfRange.barColor
  346. // opacity: visualOutOfRange.opacity
  347. }).setShape('points', visualOutOfRange.barPoints);
  348. this._updateHandle(inRangeHandleEnds, visualInRange);
  349. };
  350. ContinuousView.prototype._createBarVisual = function (dataInterval, dataExtent, handleEnds, forceState) {
  351. var opts = {
  352. forceState: forceState,
  353. convertOpacityToAlpha: true
  354. };
  355. var colorStops = this._makeColorGradient(dataInterval, opts);
  356. var symbolSizes = [this.getControllerVisual(dataInterval[0], 'symbolSize', opts), this.getControllerVisual(dataInterval[1], 'symbolSize', opts)];
  357. var barPoints = this._createBarPoints(handleEnds, symbolSizes);
  358. return {
  359. barColor: new LinearGradient(0, 0, 0, 1, colorStops),
  360. barPoints: barPoints,
  361. handlesColor: [colorStops[0].color, colorStops[colorStops.length - 1].color]
  362. };
  363. };
  364. ContinuousView.prototype._makeColorGradient = function (dataInterval, opts) {
  365. // Considering colorHue, which is not linear, so we have to sample
  366. // to calculate gradient color stops, but not only calculate head
  367. // and tail.
  368. var sampleNumber = 100; // Arbitrary value.
  369. var colorStops = [];
  370. var step = (dataInterval[1] - dataInterval[0]) / sampleNumber;
  371. colorStops.push({
  372. color: this.getControllerVisual(dataInterval[0], 'color', opts),
  373. offset: 0
  374. });
  375. for (var i = 1; i < sampleNumber; i++) {
  376. var currValue = dataInterval[0] + step * i;
  377. if (currValue > dataInterval[1]) {
  378. break;
  379. }
  380. colorStops.push({
  381. color: this.getControllerVisual(currValue, 'color', opts),
  382. offset: i / sampleNumber
  383. });
  384. }
  385. colorStops.push({
  386. color: this.getControllerVisual(dataInterval[1], 'color', opts),
  387. offset: 1
  388. });
  389. return colorStops;
  390. };
  391. ContinuousView.prototype._createBarPoints = function (handleEnds, symbolSizes) {
  392. var itemSize = this.visualMapModel.itemSize;
  393. return [[itemSize[0] - symbolSizes[0], handleEnds[0]], [itemSize[0], handleEnds[0]], [itemSize[0], handleEnds[1]], [itemSize[0] - symbolSizes[1], handleEnds[1]]];
  394. };
  395. ContinuousView.prototype._createBarGroup = function (itemAlign) {
  396. var orient = this._orient;
  397. var inverse = this.visualMapModel.get('inverse');
  398. return new graphic.Group(orient === 'horizontal' && !inverse ? {
  399. scaleX: itemAlign === 'bottom' ? 1 : -1,
  400. rotation: Math.PI / 2
  401. } : orient === 'horizontal' && inverse ? {
  402. scaleX: itemAlign === 'bottom' ? -1 : 1,
  403. rotation: -Math.PI / 2
  404. } : orient === 'vertical' && !inverse ? {
  405. scaleX: itemAlign === 'left' ? 1 : -1,
  406. scaleY: -1
  407. } : {
  408. scaleX: itemAlign === 'left' ? 1 : -1
  409. });
  410. };
  411. ContinuousView.prototype._updateHandle = function (handleEnds, visualInRange) {
  412. if (!this._useHandle) {
  413. return;
  414. }
  415. var shapes = this._shapes;
  416. var visualMapModel = this.visualMapModel;
  417. var handleThumbs = shapes.handleThumbs;
  418. var handleLabels = shapes.handleLabels;
  419. var itemSize = visualMapModel.itemSize;
  420. var dataExtent = visualMapModel.getExtent();
  421. each([0, 1], function (handleIndex) {
  422. var handleThumb = handleThumbs[handleIndex];
  423. handleThumb.setStyle('fill', visualInRange.handlesColor[handleIndex]);
  424. handleThumb.y = handleEnds[handleIndex];
  425. var val = linearMap(handleEnds[handleIndex], [0, itemSize[1]], dataExtent, true);
  426. var symbolSize = this.getControllerVisual(val, 'symbolSize');
  427. handleThumb.scaleX = handleThumb.scaleY = symbolSize / itemSize[0];
  428. handleThumb.x = itemSize[0] - symbolSize / 2;
  429. // Update handle label position.
  430. var textPoint = graphic.applyTransform(shapes.handleLabelPoints[handleIndex], graphic.getTransform(handleThumb, this.group));
  431. handleLabels[handleIndex].setStyle({
  432. x: textPoint[0],
  433. y: textPoint[1],
  434. text: visualMapModel.formatValueText(this._dataInterval[handleIndex]),
  435. verticalAlign: 'middle',
  436. align: this._orient === 'vertical' ? this._applyTransform('left', shapes.mainGroup) : 'center'
  437. });
  438. }, this);
  439. };
  440. ContinuousView.prototype._showIndicator = function (cursorValue, textValue, rangeSymbol, halfHoverLinkSize) {
  441. var visualMapModel = this.visualMapModel;
  442. var dataExtent = visualMapModel.getExtent();
  443. var itemSize = visualMapModel.itemSize;
  444. var sizeExtent = [0, itemSize[1]];
  445. var shapes = this._shapes;
  446. var indicator = shapes.indicator;
  447. if (!indicator) {
  448. return;
  449. }
  450. indicator.attr('invisible', false);
  451. var opts = {
  452. convertOpacityToAlpha: true
  453. };
  454. var color = this.getControllerVisual(cursorValue, 'color', opts);
  455. var symbolSize = this.getControllerVisual(cursorValue, 'symbolSize');
  456. var y = linearMap(cursorValue, dataExtent, sizeExtent, true);
  457. var x = itemSize[0] - symbolSize / 2;
  458. var oldIndicatorPos = {
  459. x: indicator.x,
  460. y: indicator.y
  461. };
  462. // Update handle label position.
  463. indicator.y = y;
  464. indicator.x = x;
  465. var textPoint = graphic.applyTransform(shapes.indicatorLabelPoint, graphic.getTransform(indicator, this.group));
  466. var indicatorLabel = shapes.indicatorLabel;
  467. indicatorLabel.attr('invisible', false);
  468. var align = this._applyTransform('left', shapes.mainGroup);
  469. var orient = this._orient;
  470. var isHorizontal = orient === 'horizontal';
  471. indicatorLabel.setStyle({
  472. text: (rangeSymbol ? rangeSymbol : '') + visualMapModel.formatValueText(textValue),
  473. verticalAlign: isHorizontal ? align : 'middle',
  474. align: isHorizontal ? 'center' : align
  475. });
  476. var indicatorNewProps = {
  477. x: x,
  478. y: y,
  479. style: {
  480. fill: color
  481. }
  482. };
  483. var labelNewProps = {
  484. style: {
  485. x: textPoint[0],
  486. y: textPoint[1]
  487. }
  488. };
  489. if (visualMapModel.ecModel.isAnimationEnabled() && !this._firstShowIndicator) {
  490. var animationCfg = {
  491. duration: 100,
  492. easing: 'cubicInOut',
  493. additive: true
  494. };
  495. indicator.x = oldIndicatorPos.x;
  496. indicator.y = oldIndicatorPos.y;
  497. indicator.animateTo(indicatorNewProps, animationCfg);
  498. indicatorLabel.animateTo(labelNewProps, animationCfg);
  499. } else {
  500. indicator.attr(indicatorNewProps);
  501. indicatorLabel.attr(labelNewProps);
  502. }
  503. this._firstShowIndicator = false;
  504. var handleLabels = this._shapes.handleLabels;
  505. if (handleLabels) {
  506. for (var i = 0; i < handleLabels.length; i++) {
  507. // Fade out handle labels.
  508. // NOTE: Must use api enter/leave on emphasis/blur/select state. Or the global states manager will change it.
  509. this.api.enterBlur(handleLabels[i]);
  510. }
  511. }
  512. };
  513. ContinuousView.prototype._enableHoverLinkToSeries = function () {
  514. var self = this;
  515. this._shapes.mainGroup.on('mousemove', function (e) {
  516. self._hovering = true;
  517. if (!self._dragging) {
  518. var itemSize = self.visualMapModel.itemSize;
  519. var pos = self._applyTransform([e.offsetX, e.offsetY], self._shapes.mainGroup, true, true);
  520. // For hover link show when hover handle, which might be
  521. // below or upper than sizeExtent.
  522. pos[1] = mathMin(mathMax(0, pos[1]), itemSize[1]);
  523. self._doHoverLinkToSeries(pos[1], 0 <= pos[0] && pos[0] <= itemSize[0]);
  524. }
  525. }).on('mouseout', function () {
  526. // When mouse is out of handle, hoverLink still need
  527. // to be displayed when realtime is set as false.
  528. self._hovering = false;
  529. !self._dragging && self._clearHoverLinkToSeries();
  530. });
  531. };
  532. ContinuousView.prototype._enableHoverLinkFromSeries = function () {
  533. var zr = this.api.getZr();
  534. if (this.visualMapModel.option.hoverLink) {
  535. zr.on('mouseover', this._hoverLinkFromSeriesMouseOver, this);
  536. zr.on('mouseout', this._hideIndicator, this);
  537. } else {
  538. this._clearHoverLinkFromSeries();
  539. }
  540. };
  541. ContinuousView.prototype._doHoverLinkToSeries = function (cursorPos, hoverOnBar) {
  542. var visualMapModel = this.visualMapModel;
  543. var itemSize = visualMapModel.itemSize;
  544. if (!visualMapModel.option.hoverLink) {
  545. return;
  546. }
  547. var sizeExtent = [0, itemSize[1]];
  548. var dataExtent = visualMapModel.getExtent();
  549. // For hover link show when hover handle, which might be below or upper than sizeExtent.
  550. cursorPos = mathMin(mathMax(sizeExtent[0], cursorPos), sizeExtent[1]);
  551. var halfHoverLinkSize = getHalfHoverLinkSize(visualMapModel, dataExtent, sizeExtent);
  552. var hoverRange = [cursorPos - halfHoverLinkSize, cursorPos + halfHoverLinkSize];
  553. var cursorValue = linearMap(cursorPos, sizeExtent, dataExtent, true);
  554. var valueRange = [linearMap(hoverRange[0], sizeExtent, dataExtent, true), linearMap(hoverRange[1], sizeExtent, dataExtent, true)];
  555. // Consider data range is out of visualMap range, see test/visualMap-continuous.html,
  556. // where china and india has very large population.
  557. hoverRange[0] < sizeExtent[0] && (valueRange[0] = -Infinity);
  558. hoverRange[1] > sizeExtent[1] && (valueRange[1] = Infinity);
  559. // Do not show indicator when mouse is over handle,
  560. // otherwise labels overlap, especially when dragging.
  561. if (hoverOnBar) {
  562. if (valueRange[0] === -Infinity) {
  563. this._showIndicator(cursorValue, valueRange[1], '< ', halfHoverLinkSize);
  564. } else if (valueRange[1] === Infinity) {
  565. this._showIndicator(cursorValue, valueRange[0], '> ', halfHoverLinkSize);
  566. } else {
  567. this._showIndicator(cursorValue, cursorValue, '≈ ', halfHoverLinkSize);
  568. }
  569. }
  570. // When realtime is set as false, handles, which are in barGroup,
  571. // also trigger hoverLink, which help user to realize where they
  572. // focus on when dragging. (see test/heatmap-large.html)
  573. // When realtime is set as true, highlight will not show when hover
  574. // handle, because the label on handle, which displays a exact value
  575. // but not range, might mislead users.
  576. var oldBatch = this._hoverLinkDataIndices;
  577. var newBatch = [];
  578. if (hoverOnBar || useHoverLinkOnHandle(visualMapModel)) {
  579. newBatch = this._hoverLinkDataIndices = visualMapModel.findTargetDataIndices(valueRange);
  580. }
  581. var resultBatches = modelUtil.compressBatches(oldBatch, newBatch);
  582. this._dispatchHighDown('downplay', helper.makeHighDownBatch(resultBatches[0], visualMapModel));
  583. this._dispatchHighDown('highlight', helper.makeHighDownBatch(resultBatches[1], visualMapModel));
  584. };
  585. ContinuousView.prototype._hoverLinkFromSeriesMouseOver = function (e) {
  586. var ecData;
  587. findEventDispatcher(e.target, function (target) {
  588. var currECData = getECData(target);
  589. if (currECData.dataIndex != null) {
  590. ecData = currECData;
  591. return true;
  592. }
  593. }, true);
  594. if (!ecData) {
  595. return;
  596. }
  597. var dataModel = this.ecModel.getSeriesByIndex(ecData.seriesIndex);
  598. var visualMapModel = this.visualMapModel;
  599. if (!visualMapModel.isTargetSeries(dataModel)) {
  600. return;
  601. }
  602. var data = dataModel.getData(ecData.dataType);
  603. var value = data.getStore().get(visualMapModel.getDataDimensionIndex(data), ecData.dataIndex);
  604. if (!isNaN(value)) {
  605. this._showIndicator(value, value);
  606. }
  607. };
  608. ContinuousView.prototype._hideIndicator = function () {
  609. var shapes = this._shapes;
  610. shapes.indicator && shapes.indicator.attr('invisible', true);
  611. shapes.indicatorLabel && shapes.indicatorLabel.attr('invisible', true);
  612. var handleLabels = this._shapes.handleLabels;
  613. if (handleLabels) {
  614. for (var i = 0; i < handleLabels.length; i++) {
  615. // Fade out handle labels.
  616. // NOTE: Must use api enter/leave on emphasis/blur/select state. Or the global states manager will change it.
  617. this.api.leaveBlur(handleLabels[i]);
  618. }
  619. }
  620. };
  621. ContinuousView.prototype._clearHoverLinkToSeries = function () {
  622. this._hideIndicator();
  623. var indices = this._hoverLinkDataIndices;
  624. this._dispatchHighDown('downplay', helper.makeHighDownBatch(indices, this.visualMapModel));
  625. indices.length = 0;
  626. };
  627. ContinuousView.prototype._clearHoverLinkFromSeries = function () {
  628. this._hideIndicator();
  629. var zr = this.api.getZr();
  630. zr.off('mouseover', this._hoverLinkFromSeriesMouseOver);
  631. zr.off('mouseout', this._hideIndicator);
  632. };
  633. ContinuousView.prototype._applyTransform = function (vertex, element, inverse, global) {
  634. var transform = graphic.getTransform(element, global ? null : this.group);
  635. return zrUtil.isArray(vertex) ? graphic.applyTransform(vertex, transform, inverse) : graphic.transformDirection(vertex, transform, inverse);
  636. };
  637. // TODO: TYPE more specified payload types.
  638. ContinuousView.prototype._dispatchHighDown = function (type, batch) {
  639. batch && batch.length && this.api.dispatchAction({
  640. type: type,
  641. batch: batch
  642. });
  643. };
  644. /**
  645. * @override
  646. */
  647. ContinuousView.prototype.dispose = function () {
  648. this._clearHoverLinkFromSeries();
  649. this._clearHoverLinkToSeries();
  650. };
  651. ContinuousView.type = 'visualMap.continuous';
  652. return ContinuousView;
  653. }(VisualMapView);
  654. function createPolygon(points, cursor, onDrift, onDragEnd) {
  655. return new graphic.Polygon({
  656. shape: {
  657. points: points
  658. },
  659. draggable: !!onDrift,
  660. cursor: cursor,
  661. drift: onDrift,
  662. onmousemove: function (e) {
  663. // For mobile device, prevent screen slider on the button.
  664. eventTool.stop(e.event);
  665. },
  666. ondragend: onDragEnd
  667. });
  668. }
  669. function getHalfHoverLinkSize(visualMapModel, dataExtent, sizeExtent) {
  670. var halfHoverLinkSize = HOVER_LINK_SIZE / 2;
  671. var hoverLinkDataSize = visualMapModel.get('hoverLinkDataSize');
  672. if (hoverLinkDataSize) {
  673. halfHoverLinkSize = linearMap(hoverLinkDataSize, dataExtent, sizeExtent, true) / 2;
  674. }
  675. return halfHoverLinkSize;
  676. }
  677. function useHoverLinkOnHandle(visualMapModel) {
  678. var hoverLinkOnHandle = visualMapModel.get('hoverLinkOnHandle');
  679. return !!(hoverLinkOnHandle == null ? visualMapModel.get('realtime') : hoverLinkOnHandle);
  680. }
  681. function getCursor(orient) {
  682. return orient === 'vertical' ? 'ns-resize' : 'ew-resize';
  683. }
  684. export default ContinuousView;