ContinuousView.js 28 KB

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