| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527 | 
/** Licensed to the Apache Software Foundation (ASF) under one* or more contributor license agreements.  See the NOTICE file* distributed with this work for additional information* regarding copyright ownership.  The ASF licenses this file* to you under the Apache License, Version 2.0 (the* "License"); you may not use this file except in compliance* with the License.  You may obtain a copy of the License at**   http://www.apache.org/licenses/LICENSE-2.0** Unless required by applicable law or agreed to in writing,* software distributed under the License is distributed on an* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY* KIND, either express or implied.  See the License for the* specific language governing permissions and limitations* under the License.*/var zrUtil = require("zrender/lib/core/util");var clazzUtil = require("../../util/clazz");var graphic = require("../../util/graphic");var axisPointerModelHelper = require("./modelHelper");var eventTool = require("zrender/lib/core/event");var throttleUtil = require("../../util/throttle");var _model = require("../../util/model");var makeInner = _model.makeInner;/** Licensed to the Apache Software Foundation (ASF) under one* or more contributor license agreements.  See the NOTICE file* distributed with this work for additional information* regarding copyright ownership.  The ASF licenses this file* to you under the Apache License, Version 2.0 (the* "License"); you may not use this file except in compliance* with the License.  You may obtain a copy of the License at**   http://www.apache.org/licenses/LICENSE-2.0** Unless required by applicable law or agreed to in writing,* software distributed under the License is distributed on an* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY* KIND, either express or implied.  See the License for the* specific language governing permissions and limitations* under the License.*/var inner = makeInner();var clone = zrUtil.clone;var bind = zrUtil.bind;/** * Base axis pointer class in 2D. * Implemenents {module:echarts/component/axis/IAxisPointer}. */function BaseAxisPointer() {}BaseAxisPointer.prototype = {  /**   * @private   */  _group: null,  /**   * @private   */  _lastGraphicKey: null,  /**   * @private   */  _handle: null,  /**   * @private   */  _dragging: false,  /**   * @private   */  _lastValue: null,  /**   * @private   */  _lastStatus: null,  /**   * @private   */  _payloadInfo: null,  /**   * In px, arbitrary value. Do not set too small,   * no animation is ok for most cases.   * @protected   */  animationThreshold: 15,  /**   * @implement   */  render: function (axisModel, axisPointerModel, api, forceRender) {    var value = axisPointerModel.get('value');    var status = axisPointerModel.get('status'); // Bind them to `this`, not in closure, otherwise they will not    // be replaced when user calling setOption in not merge mode.    this._axisModel = axisModel;    this._axisPointerModel = axisPointerModel;    this._api = api; // Optimize: `render` will be called repeatly during mouse move.    // So it is power consuming if performing `render` each time,    // especially on mobile device.    if (!forceRender && this._lastValue === value && this._lastStatus === status) {      return;    }    this._lastValue = value;    this._lastStatus = status;    var group = this._group;    var handle = this._handle;    if (!status || status === 'hide') {      // Do not clear here, for animation better.      group && group.hide();      handle && handle.hide();      return;    }    group && group.show();    handle && handle.show(); // Otherwise status is 'show'    var elOption = {};    this.makeElOption(elOption, value, axisModel, axisPointerModel, api); // Enable change axis pointer type.    var graphicKey = elOption.graphicKey;    if (graphicKey !== this._lastGraphicKey) {      this.clear(api);    }    this._lastGraphicKey = graphicKey;    var moveAnimation = this._moveAnimation = this.determineAnimation(axisModel, axisPointerModel);    if (!group) {      group = this._group = new graphic.Group();      this.createPointerEl(group, elOption, axisModel, axisPointerModel);      this.createLabelEl(group, elOption, axisModel, axisPointerModel);      api.getZr().add(group);    } else {      var doUpdateProps = zrUtil.curry(updateProps, axisPointerModel, moveAnimation);      this.updatePointerEl(group, elOption, doUpdateProps, axisPointerModel);      this.updateLabelEl(group, elOption, doUpdateProps, axisPointerModel);    }    updateMandatoryProps(group, axisPointerModel, true);    this._renderHandle(value);  },  /**   * @implement   */  remove: function (api) {    this.clear(api);  },  /**   * @implement   */  dispose: function (api) {    this.clear(api);  },  /**   * @protected   */  determineAnimation: function (axisModel, axisPointerModel) {    var animation = axisPointerModel.get('animation');    var axis = axisModel.axis;    var isCategoryAxis = axis.type === 'category';    var useSnap = axisPointerModel.get('snap'); // Value axis without snap always do not snap.    if (!useSnap && !isCategoryAxis) {      return false;    }    if (animation === 'auto' || animation == null) {      var animationThreshold = this.animationThreshold;      if (isCategoryAxis && axis.getBandWidth() > animationThreshold) {        return true;      } // It is important to auto animation when snap used. Consider if there is      // a dataZoom, animation will be disabled when too many points exist, while      // it will be enabled for better visual effect when little points exist.      if (useSnap) {        var seriesDataCount = axisPointerModelHelper.getAxisInfo(axisModel).seriesDataCount;        var axisExtent = axis.getExtent(); // Approximate band width        return Math.abs(axisExtent[0] - axisExtent[1]) / seriesDataCount > animationThreshold;      }      return false;    }    return animation === true;  },  /**   * add {pointer, label, graphicKey} to elOption   * @protected   */  makeElOption: function (elOption, value, axisModel, axisPointerModel, api) {// Shoule be implemenented by sub-class.  },  /**   * @protected   */  createPointerEl: function (group, elOption, axisModel, axisPointerModel) {    var pointerOption = elOption.pointer;    if (pointerOption) {      var pointerEl = inner(group).pointerEl = new graphic[pointerOption.type](clone(elOption.pointer));      group.add(pointerEl);    }  },  /**   * @protected   */  createLabelEl: function (group, elOption, axisModel, axisPointerModel) {    if (elOption.label) {      var labelEl = inner(group).labelEl = new graphic.Rect(clone(elOption.label));      group.add(labelEl);      updateLabelShowHide(labelEl, axisPointerModel);    }  },  /**   * @protected   */  updatePointerEl: function (group, elOption, updateProps) {    var pointerEl = inner(group).pointerEl;    if (pointerEl && elOption.pointer) {      pointerEl.setStyle(elOption.pointer.style);      updateProps(pointerEl, {        shape: elOption.pointer.shape      });    }  },  /**   * @protected   */  updateLabelEl: function (group, elOption, updateProps, axisPointerModel) {    var labelEl = inner(group).labelEl;    if (labelEl) {      labelEl.setStyle(elOption.label.style);      updateProps(labelEl, {        // Consider text length change in vertical axis, animation should        // be used on shape, otherwise the effect will be weird.        shape: elOption.label.shape,        position: elOption.label.position      });      updateLabelShowHide(labelEl, axisPointerModel);    }  },  /**   * @private   */  _renderHandle: function (value) {    if (this._dragging || !this.updateHandleTransform) {      return;    }    var axisPointerModel = this._axisPointerModel;    var zr = this._api.getZr();    var handle = this._handle;    var handleModel = axisPointerModel.getModel('handle');    var status = axisPointerModel.get('status');    if (!handleModel.get('show') || !status || status === 'hide') {      handle && zr.remove(handle);      this._handle = null;      return;    }    var isInit;    if (!this._handle) {      isInit = true;      handle = this._handle = graphic.createIcon(handleModel.get('icon'), {        cursor: 'move',        draggable: true,        onmousemove: function (e) {          // Fot mobile devicem, prevent screen slider on the button.          eventTool.stop(e.event);        },        onmousedown: bind(this._onHandleDragMove, this, 0, 0),        drift: bind(this._onHandleDragMove, this),        ondragend: bind(this._onHandleDragEnd, this)      });      zr.add(handle);    }    updateMandatoryProps(handle, axisPointerModel, false); // update style    var includeStyles = ['color', 'borderColor', 'borderWidth', 'opacity', 'shadowColor', 'shadowBlur', 'shadowOffsetX', 'shadowOffsetY'];    handle.setStyle(handleModel.getItemStyle(null, includeStyles)); // update position    var handleSize = handleModel.get('size');    if (!zrUtil.isArray(handleSize)) {      handleSize = [handleSize, handleSize];    }    handle.attr('scale', [handleSize[0] / 2, handleSize[1] / 2]);    throttleUtil.createOrUpdate(this, '_doDispatchAxisPointer', handleModel.get('throttle') || 0, 'fixRate');    this._moveHandleToValue(value, isInit);  },  /**   * @private   */  _moveHandleToValue: function (value, isInit) {    updateProps(this._axisPointerModel, !isInit && this._moveAnimation, this._handle, getHandleTransProps(this.getHandleTransform(value, this._axisModel, this._axisPointerModel)));  },  /**   * @private   */  _onHandleDragMove: function (dx, dy) {    var handle = this._handle;    if (!handle) {      return;    }    this._dragging = true; // Persistent for throttle.    var trans = this.updateHandleTransform(getHandleTransProps(handle), [dx, dy], this._axisModel, this._axisPointerModel);    this._payloadInfo = trans;    handle.stopAnimation();    handle.attr(getHandleTransProps(trans));    inner(handle).lastProp = null;    this._doDispatchAxisPointer();  },  /**   * Throttled method.   * @private   */  _doDispatchAxisPointer: function () {    var handle = this._handle;    if (!handle) {      return;    }    var payloadInfo = this._payloadInfo;    var axisModel = this._axisModel;    this._api.dispatchAction({      type: 'updateAxisPointer',      x: payloadInfo.cursorPoint[0],      y: payloadInfo.cursorPoint[1],      tooltipOption: payloadInfo.tooltipOption,      axesInfo: [{        axisDim: axisModel.axis.dim,        axisIndex: axisModel.componentIndex      }]    });  },  /**   * @private   */  _onHandleDragEnd: function (moveAnimation) {    this._dragging = false;    var handle = this._handle;    if (!handle) {      return;    }    var value = this._axisPointerModel.get('value'); // Consider snap or categroy axis, handle may be not consistent with    // axisPointer. So move handle to align the exact value position when    // drag ended.    this._moveHandleToValue(value); // For the effect: tooltip will be shown when finger holding on handle    // button, and will be hidden after finger left handle button.    this._api.dispatchAction({      type: 'hideTip'    });  },  /**   * Should be implemenented by sub-class if support `handle`.   * @protected   * @param {number} value   * @param {module:echarts/model/Model} axisModel   * @param {module:echarts/model/Model} axisPointerModel   * @return {Object} {position: [x, y], rotation: 0}   */  getHandleTransform: null,  /**   * * Should be implemenented by sub-class if support `handle`.   * @protected   * @param {Object} transform {position, rotation}   * @param {Array.<number>} delta [dx, dy]   * @param {module:echarts/model/Model} axisModel   * @param {module:echarts/model/Model} axisPointerModel   * @return {Object} {position: [x, y], rotation: 0, cursorPoint: [x, y]}   */  updateHandleTransform: null,  /**   * @private   */  clear: function (api) {    this._lastValue = null;    this._lastStatus = null;    var zr = api.getZr();    var group = this._group;    var handle = this._handle;    if (zr && group) {      this._lastGraphicKey = null;      group && zr.remove(group);      handle && zr.remove(handle);      this._group = null;      this._handle = null;      this._payloadInfo = null;    }  },  /**   * @protected   */  doClear: function () {// Implemented by sub-class if necessary.  },  /**   * @protected   * @param {Array.<number>} xy   * @param {Array.<number>} wh   * @param {number} [xDimIndex=0] or 1   */  buildLabel: function (xy, wh, xDimIndex) {    xDimIndex = xDimIndex || 0;    return {      x: xy[xDimIndex],      y: xy[1 - xDimIndex],      width: wh[xDimIndex],      height: wh[1 - xDimIndex]    };  }};BaseAxisPointer.prototype.constructor = BaseAxisPointer;function updateProps(animationModel, moveAnimation, el, props) {  // Animation optimize.  if (!propsEqual(inner(el).lastProp, props)) {    inner(el).lastProp = props;    moveAnimation ? graphic.updateProps(el, props, animationModel) : (el.stopAnimation(), el.attr(props));  }}function propsEqual(lastProps, newProps) {  if (zrUtil.isObject(lastProps) && zrUtil.isObject(newProps)) {    var equals = true;    zrUtil.each(newProps, function (item, key) {      equals = equals && propsEqual(lastProps[key], item);    });    return !!equals;  } else {    return lastProps === newProps;  }}function updateLabelShowHide(labelEl, axisPointerModel) {  labelEl[axisPointerModel.get('label.show') ? 'show' : 'hide']();}function getHandleTransProps(trans) {  return {    position: trans.position.slice(),    rotation: trans.rotation || 0  };}function updateMandatoryProps(group, axisPointerModel, silent) {  var z = axisPointerModel.get('z');  var zlevel = axisPointerModel.get('zlevel');  group && group.traverse(function (el) {    if (el.type !== 'group') {      z != null && (el.z = z);      zlevel != null && (el.zlevel = zlevel);      el.silent = silent;    }  });}clazzUtil.enableClassExtend(BaseAxisPointer);var _default = BaseAxisPointer;module.exports = _default;
 |