ContinuousView.js 24 KB

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