BaseAxisPointer.js 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469
  1. /*
  2. * Licensed to the Apache Software Foundation (ASF) under one
  3. * or more contributor license agreements. See the NOTICE file
  4. * distributed with this work for additional information
  5. * regarding copyright ownership. The ASF licenses this file
  6. * to you under the Apache License, Version 2.0 (the
  7. * "License"); you may not use this file except in compliance
  8. * with the License. You may obtain a copy of the License at
  9. *
  10. * http://www.apache.org/licenses/LICENSE-2.0
  11. *
  12. * Unless required by applicable law or agreed to in writing,
  13. * software distributed under the License is distributed on an
  14. * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  15. * KIND, either express or implied. See the License for the
  16. * specific language governing permissions and limitations
  17. * under the License.
  18. */
  19. /**
  20. * AUTO-GENERATED FILE. DO NOT MODIFY.
  21. */
  22. /*
  23. * Licensed to the Apache Software Foundation (ASF) under one
  24. * or more contributor license agreements. See the NOTICE file
  25. * distributed with this work for additional information
  26. * regarding copyright ownership. The ASF licenses this file
  27. * to you under the Apache License, Version 2.0 (the
  28. * "License"); you may not use this file except in compliance
  29. * with the License. You may obtain a copy of the License at
  30. *
  31. * http://www.apache.org/licenses/LICENSE-2.0
  32. *
  33. * Unless required by applicable law or agreed to in writing,
  34. * software distributed under the License is distributed on an
  35. * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  36. * KIND, either express or implied. See the License for the
  37. * specific language governing permissions and limitations
  38. * under the License.
  39. */
  40. import * as zrUtil from 'zrender/lib/core/util.js';
  41. import * as graphic from '../../util/graphic.js';
  42. import * as axisPointerModelHelper from './modelHelper.js';
  43. import * as eventTool from 'zrender/lib/core/event.js';
  44. import * as throttleUtil from '../../util/throttle.js';
  45. import { makeInner } from '../../util/model.js';
  46. var inner = makeInner();
  47. var clone = zrUtil.clone;
  48. var bind = zrUtil.bind;
  49. /**
  50. * Base axis pointer class in 2D.
  51. */
  52. var BaseAxisPointer =
  53. /** @class */
  54. function () {
  55. function BaseAxisPointer() {
  56. this._dragging = false;
  57. /**
  58. * In px, arbitrary value. Do not set too small,
  59. * no animation is ok for most cases.
  60. */
  61. this.animationThreshold = 15;
  62. }
  63. /**
  64. * @implement
  65. */
  66. BaseAxisPointer.prototype.render = function (axisModel, axisPointerModel, api, forceRender) {
  67. var value = axisPointerModel.get('value');
  68. var status = axisPointerModel.get('status'); // Bind them to `this`, not in closure, otherwise they will not
  69. // be replaced when user calling setOption in not merge mode.
  70. this._axisModel = axisModel;
  71. this._axisPointerModel = axisPointerModel;
  72. this._api = api; // Optimize: `render` will be called repeatedly during mouse move.
  73. // So it is power consuming if performing `render` each time,
  74. // especially on mobile device.
  75. if (!forceRender && this._lastValue === value && this._lastStatus === status) {
  76. return;
  77. }
  78. this._lastValue = value;
  79. this._lastStatus = status;
  80. var group = this._group;
  81. var handle = this._handle;
  82. if (!status || status === 'hide') {
  83. // Do not clear here, for animation better.
  84. group && group.hide();
  85. handle && handle.hide();
  86. return;
  87. }
  88. group && group.show();
  89. handle && handle.show(); // Otherwise status is 'show'
  90. var elOption = {};
  91. this.makeElOption(elOption, value, axisModel, axisPointerModel, api); // Enable change axis pointer type.
  92. var graphicKey = elOption.graphicKey;
  93. if (graphicKey !== this._lastGraphicKey) {
  94. this.clear(api);
  95. }
  96. this._lastGraphicKey = graphicKey;
  97. var moveAnimation = this._moveAnimation = this.determineAnimation(axisModel, axisPointerModel);
  98. if (!group) {
  99. group = this._group = new graphic.Group();
  100. this.createPointerEl(group, elOption, axisModel, axisPointerModel);
  101. this.createLabelEl(group, elOption, axisModel, axisPointerModel);
  102. api.getZr().add(group);
  103. } else {
  104. var doUpdateProps = zrUtil.curry(updateProps, axisPointerModel, moveAnimation);
  105. this.updatePointerEl(group, elOption, doUpdateProps);
  106. this.updateLabelEl(group, elOption, doUpdateProps, axisPointerModel);
  107. }
  108. updateMandatoryProps(group, axisPointerModel, true);
  109. this._renderHandle(value);
  110. };
  111. /**
  112. * @implement
  113. */
  114. BaseAxisPointer.prototype.remove = function (api) {
  115. this.clear(api);
  116. };
  117. /**
  118. * @implement
  119. */
  120. BaseAxisPointer.prototype.dispose = function (api) {
  121. this.clear(api);
  122. };
  123. /**
  124. * @protected
  125. */
  126. BaseAxisPointer.prototype.determineAnimation = function (axisModel, axisPointerModel) {
  127. var animation = axisPointerModel.get('animation');
  128. var axis = axisModel.axis;
  129. var isCategoryAxis = axis.type === 'category';
  130. var useSnap = axisPointerModel.get('snap'); // Value axis without snap always do not snap.
  131. if (!useSnap && !isCategoryAxis) {
  132. return false;
  133. }
  134. if (animation === 'auto' || animation == null) {
  135. var animationThreshold = this.animationThreshold;
  136. if (isCategoryAxis && axis.getBandWidth() > animationThreshold) {
  137. return true;
  138. } // It is important to auto animation when snap used. Consider if there is
  139. // a dataZoom, animation will be disabled when too many points exist, while
  140. // it will be enabled for better visual effect when little points exist.
  141. if (useSnap) {
  142. var seriesDataCount = axisPointerModelHelper.getAxisInfo(axisModel).seriesDataCount;
  143. var axisExtent = axis.getExtent(); // Approximate band width
  144. return Math.abs(axisExtent[0] - axisExtent[1]) / seriesDataCount > animationThreshold;
  145. }
  146. return false;
  147. }
  148. return animation === true;
  149. };
  150. /**
  151. * add {pointer, label, graphicKey} to elOption
  152. * @protected
  153. */
  154. BaseAxisPointer.prototype.makeElOption = function (elOption, value, axisModel, axisPointerModel, api) {// Should be implemenented by sub-class.
  155. };
  156. /**
  157. * @protected
  158. */
  159. BaseAxisPointer.prototype.createPointerEl = function (group, elOption, axisModel, axisPointerModel) {
  160. var pointerOption = elOption.pointer;
  161. if (pointerOption) {
  162. var pointerEl = inner(group).pointerEl = new graphic[pointerOption.type](clone(elOption.pointer));
  163. group.add(pointerEl);
  164. }
  165. };
  166. /**
  167. * @protected
  168. */
  169. BaseAxisPointer.prototype.createLabelEl = function (group, elOption, axisModel, axisPointerModel) {
  170. if (elOption.label) {
  171. var labelEl = inner(group).labelEl = new graphic.Text(clone(elOption.label));
  172. group.add(labelEl);
  173. updateLabelShowHide(labelEl, axisPointerModel);
  174. }
  175. };
  176. /**
  177. * @protected
  178. */
  179. BaseAxisPointer.prototype.updatePointerEl = function (group, elOption, updateProps) {
  180. var pointerEl = inner(group).pointerEl;
  181. if (pointerEl && elOption.pointer) {
  182. pointerEl.setStyle(elOption.pointer.style);
  183. updateProps(pointerEl, {
  184. shape: elOption.pointer.shape
  185. });
  186. }
  187. };
  188. /**
  189. * @protected
  190. */
  191. BaseAxisPointer.prototype.updateLabelEl = function (group, elOption, updateProps, axisPointerModel) {
  192. var labelEl = inner(group).labelEl;
  193. if (labelEl) {
  194. labelEl.setStyle(elOption.label.style);
  195. updateProps(labelEl, {
  196. // Consider text length change in vertical axis, animation should
  197. // be used on shape, otherwise the effect will be weird.
  198. // TODOTODO
  199. // shape: elOption.label.shape,
  200. x: elOption.label.x,
  201. y: elOption.label.y
  202. });
  203. updateLabelShowHide(labelEl, axisPointerModel);
  204. }
  205. };
  206. /**
  207. * @private
  208. */
  209. BaseAxisPointer.prototype._renderHandle = function (value) {
  210. if (this._dragging || !this.updateHandleTransform) {
  211. return;
  212. }
  213. var axisPointerModel = this._axisPointerModel;
  214. var zr = this._api.getZr();
  215. var handle = this._handle;
  216. var handleModel = axisPointerModel.getModel('handle');
  217. var status = axisPointerModel.get('status');
  218. if (!handleModel.get('show') || !status || status === 'hide') {
  219. handle && zr.remove(handle);
  220. this._handle = null;
  221. return;
  222. }
  223. var isInit;
  224. if (!this._handle) {
  225. isInit = true;
  226. handle = this._handle = graphic.createIcon(handleModel.get('icon'), {
  227. cursor: 'move',
  228. draggable: true,
  229. onmousemove: function (e) {
  230. // For mobile device, prevent screen slider on the button.
  231. eventTool.stop(e.event);
  232. },
  233. onmousedown: bind(this._onHandleDragMove, this, 0, 0),
  234. drift: bind(this._onHandleDragMove, this),
  235. ondragend: bind(this._onHandleDragEnd, this)
  236. });
  237. zr.add(handle);
  238. }
  239. updateMandatoryProps(handle, axisPointerModel, false); // update style
  240. handle.setStyle(handleModel.getItemStyle(null, ['color', 'borderColor', 'borderWidth', 'opacity', 'shadowColor', 'shadowBlur', 'shadowOffsetX', 'shadowOffsetY'])); // update position
  241. var handleSize = handleModel.get('size');
  242. if (!zrUtil.isArray(handleSize)) {
  243. handleSize = [handleSize, handleSize];
  244. }
  245. handle.scaleX = handleSize[0] / 2;
  246. handle.scaleY = handleSize[1] / 2;
  247. throttleUtil.createOrUpdate(this, '_doDispatchAxisPointer', handleModel.get('throttle') || 0, 'fixRate');
  248. this._moveHandleToValue(value, isInit);
  249. };
  250. BaseAxisPointer.prototype._moveHandleToValue = function (value, isInit) {
  251. updateProps(this._axisPointerModel, !isInit && this._moveAnimation, this._handle, getHandleTransProps(this.getHandleTransform(value, this._axisModel, this._axisPointerModel)));
  252. };
  253. BaseAxisPointer.prototype._onHandleDragMove = function (dx, dy) {
  254. var handle = this._handle;
  255. if (!handle) {
  256. return;
  257. }
  258. this._dragging = true; // Persistent for throttle.
  259. var trans = this.updateHandleTransform(getHandleTransProps(handle), [dx, dy], this._axisModel, this._axisPointerModel);
  260. this._payloadInfo = trans;
  261. handle.stopAnimation();
  262. handle.attr(getHandleTransProps(trans));
  263. inner(handle).lastProp = null;
  264. this._doDispatchAxisPointer();
  265. };
  266. /**
  267. * Throttled method.
  268. */
  269. BaseAxisPointer.prototype._doDispatchAxisPointer = function () {
  270. var handle = this._handle;
  271. if (!handle) {
  272. return;
  273. }
  274. var payloadInfo = this._payloadInfo;
  275. var axisModel = this._axisModel;
  276. this._api.dispatchAction({
  277. type: 'updateAxisPointer',
  278. x: payloadInfo.cursorPoint[0],
  279. y: payloadInfo.cursorPoint[1],
  280. tooltipOption: payloadInfo.tooltipOption,
  281. axesInfo: [{
  282. axisDim: axisModel.axis.dim,
  283. axisIndex: axisModel.componentIndex
  284. }]
  285. });
  286. };
  287. BaseAxisPointer.prototype._onHandleDragEnd = function () {
  288. this._dragging = false;
  289. var handle = this._handle;
  290. if (!handle) {
  291. return;
  292. }
  293. var value = this._axisPointerModel.get('value'); // Consider snap or categroy axis, handle may be not consistent with
  294. // axisPointer. So move handle to align the exact value position when
  295. // drag ended.
  296. this._moveHandleToValue(value); // For the effect: tooltip will be shown when finger holding on handle
  297. // button, and will be hidden after finger left handle button.
  298. this._api.dispatchAction({
  299. type: 'hideTip'
  300. });
  301. };
  302. /**
  303. * @private
  304. */
  305. BaseAxisPointer.prototype.clear = function (api) {
  306. this._lastValue = null;
  307. this._lastStatus = null;
  308. var zr = api.getZr();
  309. var group = this._group;
  310. var handle = this._handle;
  311. if (zr && group) {
  312. this._lastGraphicKey = null;
  313. group && zr.remove(group);
  314. handle && zr.remove(handle);
  315. this._group = null;
  316. this._handle = null;
  317. this._payloadInfo = null;
  318. }
  319. throttleUtil.clear(this, '_doDispatchAxisPointer');
  320. };
  321. /**
  322. * @protected
  323. */
  324. BaseAxisPointer.prototype.doClear = function () {// Implemented by sub-class if necessary.
  325. };
  326. BaseAxisPointer.prototype.buildLabel = function (xy, wh, xDimIndex) {
  327. xDimIndex = xDimIndex || 0;
  328. return {
  329. x: xy[xDimIndex],
  330. y: xy[1 - xDimIndex],
  331. width: wh[xDimIndex],
  332. height: wh[1 - xDimIndex]
  333. };
  334. };
  335. return BaseAxisPointer;
  336. }();
  337. function updateProps(animationModel, moveAnimation, el, props) {
  338. // Animation optimize.
  339. if (!propsEqual(inner(el).lastProp, props)) {
  340. inner(el).lastProp = props;
  341. moveAnimation ? graphic.updateProps(el, props, animationModel) : (el.stopAnimation(), el.attr(props));
  342. }
  343. }
  344. function propsEqual(lastProps, newProps) {
  345. if (zrUtil.isObject(lastProps) && zrUtil.isObject(newProps)) {
  346. var equals_1 = true;
  347. zrUtil.each(newProps, function (item, key) {
  348. equals_1 = equals_1 && propsEqual(lastProps[key], item);
  349. });
  350. return !!equals_1;
  351. } else {
  352. return lastProps === newProps;
  353. }
  354. }
  355. function updateLabelShowHide(labelEl, axisPointerModel) {
  356. labelEl[axisPointerModel.get(['label', 'show']) ? 'show' : 'hide']();
  357. }
  358. function getHandleTransProps(trans) {
  359. return {
  360. x: trans.x || 0,
  361. y: trans.y || 0,
  362. rotation: trans.rotation || 0
  363. };
  364. }
  365. function updateMandatoryProps(group, axisPointerModel, silent) {
  366. var z = axisPointerModel.get('z');
  367. var zlevel = axisPointerModel.get('zlevel');
  368. group && group.traverse(function (el) {
  369. if (el.type !== 'group') {
  370. z != null && (el.z = z);
  371. zlevel != null && (el.zlevel = zlevel);
  372. el.silent = silent;
  373. }
  374. });
  375. }
  376. export default BaseAxisPointer;