| 
/* 
 | 
* 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. 
 | 
*/ 
 | 
  
 | 
  
 | 
/** 
 | 
 * AUTO-GENERATED FILE. DO NOT MODIFY. 
 | 
 */ 
 | 
  
 | 
import { __extends } from "tslib"; 
 | 
/* 
 | 
* 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. 
 | 
*/ 
 | 
import { bind, each, clone, trim, isString, isFunction, isArray, isObject, extend } from 'zrender/lib/core/util.js'; 
 | 
import env from 'zrender/lib/core/env.js'; 
 | 
import TooltipHTMLContent from './TooltipHTMLContent.js'; 
 | 
import TooltipRichContent from './TooltipRichContent.js'; 
 | 
import { convertToColorString, encodeHTML, formatTpl } from '../../util/format.js'; 
 | 
import { parsePercent } from '../../util/number.js'; 
 | 
import { Rect } from '../../util/graphic.js'; 
 | 
import findPointFromSeries from '../axisPointer/findPointFromSeries.js'; 
 | 
import { getLayoutRect } from '../../util/layout.js'; 
 | 
import Model from '../../model/Model.js'; 
 | 
import * as globalListener from '../axisPointer/globalListener.js'; 
 | 
import * as axisHelper from '../../coord/axisHelper.js'; 
 | 
import * as axisPointerViewHelper from '../axisPointer/viewHelper.js'; 
 | 
import { getTooltipRenderMode, preParseFinder, queryReferringComponents } from '../../util/model.js'; 
 | 
import ComponentView from '../../view/Component.js'; 
 | 
import { format as timeFormat } from '../../util/time.js'; 
 | 
import { getECData } from '../../util/innerStore.js'; 
 | 
import { shouldTooltipConfine } from './helper.js'; 
 | 
import { normalizeTooltipFormatResult } from '../../model/mixin/dataFormat.js'; 
 | 
import { createTooltipMarkup, buildTooltipMarkup, TooltipMarkupStyleCreator } from './tooltipMarkup.js'; 
 | 
import { findEventDispatcher } from '../../util/event.js'; 
 | 
import { clear, createOrUpdate } from '../../util/throttle.js'; 
 | 
var proxyRect = new Rect({ 
 | 
  shape: { 
 | 
    x: -1, 
 | 
    y: -1, 
 | 
    width: 2, 
 | 
    height: 2 
 | 
  } 
 | 
}); 
 | 
var TooltipView = /** @class */function (_super) { 
 | 
  __extends(TooltipView, _super); 
 | 
  function TooltipView() { 
 | 
    var _this = _super !== null && _super.apply(this, arguments) || this; 
 | 
    _this.type = TooltipView.type; 
 | 
    return _this; 
 | 
  } 
 | 
  TooltipView.prototype.init = function (ecModel, api) { 
 | 
    if (env.node || !api.getDom()) { 
 | 
      return; 
 | 
    } 
 | 
    var tooltipModel = ecModel.getComponent('tooltip'); 
 | 
    var renderMode = this._renderMode = getTooltipRenderMode(tooltipModel.get('renderMode')); 
 | 
    this._tooltipContent = renderMode === 'richText' ? new TooltipRichContent(api) : new TooltipHTMLContent(api, { 
 | 
      appendTo: tooltipModel.get('appendToBody', true) ? 'body' : tooltipModel.get('appendTo', true) 
 | 
    }); 
 | 
  }; 
 | 
  TooltipView.prototype.render = function (tooltipModel, ecModel, api) { 
 | 
    if (env.node || !api.getDom()) { 
 | 
      return; 
 | 
    } 
 | 
    // Reset 
 | 
    this.group.removeAll(); 
 | 
    this._tooltipModel = tooltipModel; 
 | 
    this._ecModel = ecModel; 
 | 
    this._api = api; 
 | 
    var tooltipContent = this._tooltipContent; 
 | 
    tooltipContent.update(tooltipModel); 
 | 
    tooltipContent.setEnterable(tooltipModel.get('enterable')); 
 | 
    this._initGlobalListener(); 
 | 
    this._keepShow(); 
 | 
    // PENDING 
 | 
    // `mousemove` event will be triggered very frequently when the mouse moves fast, 
 | 
    // which causes that the `updatePosition` function was also called frequently. 
 | 
    // In Chrome with devtools open and Firefox, tooltip looks laggy and shakes. See #14695 #16101 
 | 
    // To avoid frequent triggering, 
 | 
    // consider throttling it in 50ms when transition is enabled 
 | 
    if (this._renderMode !== 'richText' && tooltipModel.get('transitionDuration')) { 
 | 
      createOrUpdate(this, '_updatePosition', 50, 'fixRate'); 
 | 
    } else { 
 | 
      clear(this, '_updatePosition'); 
 | 
    } 
 | 
  }; 
 | 
  TooltipView.prototype._initGlobalListener = function () { 
 | 
    var tooltipModel = this._tooltipModel; 
 | 
    var triggerOn = tooltipModel.get('triggerOn'); 
 | 
    globalListener.register('itemTooltip', this._api, bind(function (currTrigger, e, dispatchAction) { 
 | 
      // If 'none', it is not controlled by mouse totally. 
 | 
      if (triggerOn !== 'none') { 
 | 
        if (triggerOn.indexOf(currTrigger) >= 0) { 
 | 
          this._tryShow(e, dispatchAction); 
 | 
        } else if (currTrigger === 'leave') { 
 | 
          this._hide(dispatchAction); 
 | 
        } 
 | 
      } 
 | 
    }, this)); 
 | 
  }; 
 | 
  TooltipView.prototype._keepShow = function () { 
 | 
    var tooltipModel = this._tooltipModel; 
 | 
    var ecModel = this._ecModel; 
 | 
    var api = this._api; 
 | 
    var triggerOn = tooltipModel.get('triggerOn'); 
 | 
    // Try to keep the tooltip show when refreshing 
 | 
    if (this._lastX != null && this._lastY != null 
 | 
    // When user is willing to control tooltip totally using API, 
 | 
    // self.manuallyShowTip({x, y}) might cause tooltip hide, 
 | 
    // which is not expected. 
 | 
    && triggerOn !== 'none' && triggerOn !== 'click') { 
 | 
      var self_1 = this; 
 | 
      clearTimeout(this._refreshUpdateTimeout); 
 | 
      this._refreshUpdateTimeout = setTimeout(function () { 
 | 
        // Show tip next tick after other charts are rendered 
 | 
        // In case highlight action has wrong result 
 | 
        // FIXME 
 | 
        !api.isDisposed() && self_1.manuallyShowTip(tooltipModel, ecModel, api, { 
 | 
          x: self_1._lastX, 
 | 
          y: self_1._lastY, 
 | 
          dataByCoordSys: self_1._lastDataByCoordSys 
 | 
        }); 
 | 
      }); 
 | 
    } 
 | 
  }; 
 | 
  /** 
 | 
   * Show tip manually by 
 | 
   * dispatchAction({ 
 | 
   *     type: 'showTip', 
 | 
   *     x: 10, 
 | 
   *     y: 10 
 | 
   * }); 
 | 
   * Or 
 | 
   * dispatchAction({ 
 | 
   *      type: 'showTip', 
 | 
   *      seriesIndex: 0, 
 | 
   *      dataIndex or dataIndexInside or name 
 | 
   * }); 
 | 
   * 
 | 
   *  TODO Batch 
 | 
   */ 
 | 
  TooltipView.prototype.manuallyShowTip = function (tooltipModel, ecModel, api, payload) { 
 | 
    if (payload.from === this.uid || env.node || !api.getDom()) { 
 | 
      return; 
 | 
    } 
 | 
    var dispatchAction = makeDispatchAction(payload, api); 
 | 
    // Reset ticket 
 | 
    this._ticket = ''; 
 | 
    // When triggered from axisPointer. 
 | 
    var dataByCoordSys = payload.dataByCoordSys; 
 | 
    var cmptRef = findComponentReference(payload, ecModel, api); 
 | 
    if (cmptRef) { 
 | 
      var rect = cmptRef.el.getBoundingRect().clone(); 
 | 
      rect.applyTransform(cmptRef.el.transform); 
 | 
      this._tryShow({ 
 | 
        offsetX: rect.x + rect.width / 2, 
 | 
        offsetY: rect.y + rect.height / 2, 
 | 
        target: cmptRef.el, 
 | 
        position: payload.position, 
 | 
        // When manully trigger, the mouse is not on the el, so we'd better to 
 | 
        // position tooltip on the bottom of the el and display arrow is possible. 
 | 
        positionDefault: 'bottom' 
 | 
      }, dispatchAction); 
 | 
    } else if (payload.tooltip && payload.x != null && payload.y != null) { 
 | 
      var el = proxyRect; 
 | 
      el.x = payload.x; 
 | 
      el.y = payload.y; 
 | 
      el.update(); 
 | 
      getECData(el).tooltipConfig = { 
 | 
        name: null, 
 | 
        option: payload.tooltip 
 | 
      }; 
 | 
      // Manually show tooltip while view is not using zrender elements. 
 | 
      this._tryShow({ 
 | 
        offsetX: payload.x, 
 | 
        offsetY: payload.y, 
 | 
        target: el 
 | 
      }, dispatchAction); 
 | 
    } else if (dataByCoordSys) { 
 | 
      this._tryShow({ 
 | 
        offsetX: payload.x, 
 | 
        offsetY: payload.y, 
 | 
        position: payload.position, 
 | 
        dataByCoordSys: dataByCoordSys, 
 | 
        tooltipOption: payload.tooltipOption 
 | 
      }, dispatchAction); 
 | 
    } else if (payload.seriesIndex != null) { 
 | 
      if (this._manuallyAxisShowTip(tooltipModel, ecModel, api, payload)) { 
 | 
        return; 
 | 
      } 
 | 
      var pointInfo = findPointFromSeries(payload, ecModel); 
 | 
      var cx = pointInfo.point[0]; 
 | 
      var cy = pointInfo.point[1]; 
 | 
      if (cx != null && cy != null) { 
 | 
        this._tryShow({ 
 | 
          offsetX: cx, 
 | 
          offsetY: cy, 
 | 
          target: pointInfo.el, 
 | 
          position: payload.position, 
 | 
          // When manully trigger, the mouse is not on the el, so we'd better to 
 | 
          // position tooltip on the bottom of the el and display arrow is possible. 
 | 
          positionDefault: 'bottom' 
 | 
        }, dispatchAction); 
 | 
      } 
 | 
    } else if (payload.x != null && payload.y != null) { 
 | 
      // FIXME 
 | 
      // should wrap dispatchAction like `axisPointer/globalListener` ? 
 | 
      api.dispatchAction({ 
 | 
        type: 'updateAxisPointer', 
 | 
        x: payload.x, 
 | 
        y: payload.y 
 | 
      }); 
 | 
      this._tryShow({ 
 | 
        offsetX: payload.x, 
 | 
        offsetY: payload.y, 
 | 
        position: payload.position, 
 | 
        target: api.getZr().findHover(payload.x, payload.y).target 
 | 
      }, dispatchAction); 
 | 
    } 
 | 
  }; 
 | 
  TooltipView.prototype.manuallyHideTip = function (tooltipModel, ecModel, api, payload) { 
 | 
    var tooltipContent = this._tooltipContent; 
 | 
    if (this._tooltipModel) { 
 | 
      tooltipContent.hideLater(this._tooltipModel.get('hideDelay')); 
 | 
    } 
 | 
    this._lastX = this._lastY = this._lastDataByCoordSys = null; 
 | 
    if (payload.from !== this.uid) { 
 | 
      this._hide(makeDispatchAction(payload, api)); 
 | 
    } 
 | 
  }; 
 | 
  // Be compatible with previous design, that is, when tooltip.type is 'axis' and 
 | 
  // dispatchAction 'showTip' with seriesIndex and dataIndex will trigger axis pointer 
 | 
  // and tooltip. 
 | 
  TooltipView.prototype._manuallyAxisShowTip = function (tooltipModel, ecModel, api, payload) { 
 | 
    var seriesIndex = payload.seriesIndex; 
 | 
    var dataIndex = payload.dataIndex; 
 | 
    // @ts-ignore 
 | 
    var coordSysAxesInfo = ecModel.getComponent('axisPointer').coordSysAxesInfo; 
 | 
    if (seriesIndex == null || dataIndex == null || coordSysAxesInfo == null) { 
 | 
      return; 
 | 
    } 
 | 
    var seriesModel = ecModel.getSeriesByIndex(seriesIndex); 
 | 
    if (!seriesModel) { 
 | 
      return; 
 | 
    } 
 | 
    var data = seriesModel.getData(); 
 | 
    var tooltipCascadedModel = buildTooltipModel([data.getItemModel(dataIndex), seriesModel, (seriesModel.coordinateSystem || {}).model], this._tooltipModel); 
 | 
    if (tooltipCascadedModel.get('trigger') !== 'axis') { 
 | 
      return; 
 | 
    } 
 | 
    api.dispatchAction({ 
 | 
      type: 'updateAxisPointer', 
 | 
      seriesIndex: seriesIndex, 
 | 
      dataIndex: dataIndex, 
 | 
      position: payload.position 
 | 
    }); 
 | 
    return true; 
 | 
  }; 
 | 
  TooltipView.prototype._tryShow = function (e, dispatchAction) { 
 | 
    var el = e.target; 
 | 
    var tooltipModel = this._tooltipModel; 
 | 
    if (!tooltipModel) { 
 | 
      return; 
 | 
    } 
 | 
    // Save mouse x, mouse y. So we can try to keep showing the tip if chart is refreshed 
 | 
    this._lastX = e.offsetX; 
 | 
    this._lastY = e.offsetY; 
 | 
    var dataByCoordSys = e.dataByCoordSys; 
 | 
    if (dataByCoordSys && dataByCoordSys.length) { 
 | 
      this._showAxisTooltip(dataByCoordSys, e); 
 | 
    } else if (el) { 
 | 
      var ecData = getECData(el); 
 | 
      if (ecData.ssrType === 'legend') { 
 | 
        // Don't trigger tooltip for legend tooltip item 
 | 
        return; 
 | 
      } 
 | 
      this._lastDataByCoordSys = null; 
 | 
      var seriesDispatcher_1; 
 | 
      var cmptDispatcher_1; 
 | 
      findEventDispatcher(el, function (target) { 
 | 
        // Always show item tooltip if mouse is on the element with dataIndex 
 | 
        if (getECData(target).dataIndex != null) { 
 | 
          seriesDispatcher_1 = target; 
 | 
          return true; 
 | 
        } 
 | 
        // Tooltip provided directly. Like legend. 
 | 
        if (getECData(target).tooltipConfig != null) { 
 | 
          cmptDispatcher_1 = target; 
 | 
          return true; 
 | 
        } 
 | 
      }, true); 
 | 
      if (seriesDispatcher_1) { 
 | 
        this._showSeriesItemTooltip(e, seriesDispatcher_1, dispatchAction); 
 | 
      } else if (cmptDispatcher_1) { 
 | 
        this._showComponentItemTooltip(e, cmptDispatcher_1, dispatchAction); 
 | 
      } else { 
 | 
        this._hide(dispatchAction); 
 | 
      } 
 | 
    } else { 
 | 
      this._lastDataByCoordSys = null; 
 | 
      this._hide(dispatchAction); 
 | 
    } 
 | 
  }; 
 | 
  TooltipView.prototype._showOrMove = function (tooltipModel, cb) { 
 | 
    // showDelay is used in this case: tooltip.enterable is set 
 | 
    // as true. User intent to move mouse into tooltip and click 
 | 
    // something. `showDelay` makes it easier to enter the content 
 | 
    // but tooltip do not move immediately. 
 | 
    var delay = tooltipModel.get('showDelay'); 
 | 
    cb = bind(cb, this); 
 | 
    clearTimeout(this._showTimout); 
 | 
    delay > 0 ? this._showTimout = setTimeout(cb, delay) : cb(); 
 | 
  }; 
 | 
  TooltipView.prototype._showAxisTooltip = function (dataByCoordSys, e) { 
 | 
    var ecModel = this._ecModel; 
 | 
    var globalTooltipModel = this._tooltipModel; 
 | 
    var point = [e.offsetX, e.offsetY]; 
 | 
    var singleTooltipModel = buildTooltipModel([e.tooltipOption], globalTooltipModel); 
 | 
    var renderMode = this._renderMode; 
 | 
    var cbParamsList = []; 
 | 
    var articleMarkup = createTooltipMarkup('section', { 
 | 
      blocks: [], 
 | 
      noHeader: true 
 | 
    }); 
 | 
    // Only for legacy: `Serise['formatTooltip']` returns a string. 
 | 
    var markupTextArrLegacy = []; 
 | 
    var markupStyleCreator = new TooltipMarkupStyleCreator(); 
 | 
    each(dataByCoordSys, function (itemCoordSys) { 
 | 
      each(itemCoordSys.dataByAxis, function (axisItem) { 
 | 
        var axisModel = ecModel.getComponent(axisItem.axisDim + 'Axis', axisItem.axisIndex); 
 | 
        var axisValue = axisItem.value; 
 | 
        if (!axisModel || axisValue == null) { 
 | 
          return; 
 | 
        } 
 | 
        var axisValueLabel = axisPointerViewHelper.getValueLabel(axisValue, axisModel.axis, ecModel, axisItem.seriesDataIndices, axisItem.valueLabelOpt); 
 | 
        var axisSectionMarkup = createTooltipMarkup('section', { 
 | 
          header: axisValueLabel, 
 | 
          noHeader: !trim(axisValueLabel), 
 | 
          sortBlocks: true, 
 | 
          blocks: [] 
 | 
        }); 
 | 
        articleMarkup.blocks.push(axisSectionMarkup); 
 | 
        each(axisItem.seriesDataIndices, function (idxItem) { 
 | 
          var series = ecModel.getSeriesByIndex(idxItem.seriesIndex); 
 | 
          var dataIndex = idxItem.dataIndexInside; 
 | 
          var cbParams = series.getDataParams(dataIndex); 
 | 
          // Can't find data. 
 | 
          if (cbParams.dataIndex < 0) { 
 | 
            return; 
 | 
          } 
 | 
          cbParams.axisDim = axisItem.axisDim; 
 | 
          cbParams.axisIndex = axisItem.axisIndex; 
 | 
          cbParams.axisType = axisItem.axisType; 
 | 
          cbParams.axisId = axisItem.axisId; 
 | 
          cbParams.axisValue = axisHelper.getAxisRawValue(axisModel.axis, { 
 | 
            value: axisValue 
 | 
          }); 
 | 
          cbParams.axisValueLabel = axisValueLabel; 
 | 
          // Pre-create marker style for makers. Users can assemble richText 
 | 
          // text in `formatter` callback and use those markers style. 
 | 
          cbParams.marker = markupStyleCreator.makeTooltipMarker('item', convertToColorString(cbParams.color), renderMode); 
 | 
          var seriesTooltipResult = normalizeTooltipFormatResult(series.formatTooltip(dataIndex, true, null)); 
 | 
          var frag = seriesTooltipResult.frag; 
 | 
          if (frag) { 
 | 
            var valueFormatter = buildTooltipModel([series], globalTooltipModel).get('valueFormatter'); 
 | 
            axisSectionMarkup.blocks.push(valueFormatter ? extend({ 
 | 
              valueFormatter: valueFormatter 
 | 
            }, frag) : frag); 
 | 
          } 
 | 
          if (seriesTooltipResult.text) { 
 | 
            markupTextArrLegacy.push(seriesTooltipResult.text); 
 | 
          } 
 | 
          cbParamsList.push(cbParams); 
 | 
        }); 
 | 
      }); 
 | 
    }); 
 | 
    // In most cases, the second axis is displays upper on the first one. 
 | 
    // So we reverse it to look better. 
 | 
    articleMarkup.blocks.reverse(); 
 | 
    markupTextArrLegacy.reverse(); 
 | 
    var positionExpr = e.position; 
 | 
    var orderMode = singleTooltipModel.get('order'); 
 | 
    var builtMarkupText = buildTooltipMarkup(articleMarkup, markupStyleCreator, renderMode, orderMode, ecModel.get('useUTC'), singleTooltipModel.get('textStyle')); 
 | 
    builtMarkupText && markupTextArrLegacy.unshift(builtMarkupText); 
 | 
    var blockBreak = renderMode === 'richText' ? '\n\n' : '<br/>'; 
 | 
    var allMarkupText = markupTextArrLegacy.join(blockBreak); 
 | 
    this._showOrMove(singleTooltipModel, function () { 
 | 
      if (this._updateContentNotChangedOnAxis(dataByCoordSys, cbParamsList)) { 
 | 
        this._updatePosition(singleTooltipModel, positionExpr, point[0], point[1], this._tooltipContent, cbParamsList); 
 | 
      } else { 
 | 
        this._showTooltipContent(singleTooltipModel, allMarkupText, cbParamsList, Math.random() + '', point[0], point[1], positionExpr, null, markupStyleCreator); 
 | 
      } 
 | 
    }); 
 | 
    // Do not trigger events here, because this branch only be entered 
 | 
    // from dispatchAction. 
 | 
  }; 
 | 
  TooltipView.prototype._showSeriesItemTooltip = function (e, dispatcher, dispatchAction) { 
 | 
    var ecModel = this._ecModel; 
 | 
    var ecData = getECData(dispatcher); 
 | 
    // Use dataModel in element if possible 
 | 
    // Used when mouseover on a element like markPoint or edge 
 | 
    // In which case, the data is not main data in series. 
 | 
    var seriesIndex = ecData.seriesIndex; 
 | 
    var seriesModel = ecModel.getSeriesByIndex(seriesIndex); 
 | 
    // For example, graph link. 
 | 
    var dataModel = ecData.dataModel || seriesModel; 
 | 
    var dataIndex = ecData.dataIndex; 
 | 
    var dataType = ecData.dataType; 
 | 
    var data = dataModel.getData(dataType); 
 | 
    var renderMode = this._renderMode; 
 | 
    var positionDefault = e.positionDefault; 
 | 
    var tooltipModel = buildTooltipModel([data.getItemModel(dataIndex), dataModel, seriesModel && (seriesModel.coordinateSystem || {}).model], this._tooltipModel, positionDefault ? { 
 | 
      position: positionDefault 
 | 
    } : null); 
 | 
    var tooltipTrigger = tooltipModel.get('trigger'); 
 | 
    if (tooltipTrigger != null && tooltipTrigger !== 'item') { 
 | 
      return; 
 | 
    } 
 | 
    var params = dataModel.getDataParams(dataIndex, dataType); 
 | 
    var markupStyleCreator = new TooltipMarkupStyleCreator(); 
 | 
    // Pre-create marker style for makers. Users can assemble richText 
 | 
    // text in `formatter` callback and use those markers style. 
 | 
    params.marker = markupStyleCreator.makeTooltipMarker('item', convertToColorString(params.color), renderMode); 
 | 
    var seriesTooltipResult = normalizeTooltipFormatResult(dataModel.formatTooltip(dataIndex, false, dataType)); 
 | 
    var orderMode = tooltipModel.get('order'); 
 | 
    var valueFormatter = tooltipModel.get('valueFormatter'); 
 | 
    var frag = seriesTooltipResult.frag; 
 | 
    var markupText = frag ? buildTooltipMarkup(valueFormatter ? extend({ 
 | 
      valueFormatter: valueFormatter 
 | 
    }, frag) : frag, markupStyleCreator, renderMode, orderMode, ecModel.get('useUTC'), tooltipModel.get('textStyle')) : seriesTooltipResult.text; 
 | 
    var asyncTicket = 'item_' + dataModel.name + '_' + dataIndex; 
 | 
    this._showOrMove(tooltipModel, function () { 
 | 
      this._showTooltipContent(tooltipModel, markupText, params, asyncTicket, e.offsetX, e.offsetY, e.position, e.target, markupStyleCreator); 
 | 
    }); 
 | 
    // FIXME 
 | 
    // duplicated showtip if manuallyShowTip is called from dispatchAction. 
 | 
    dispatchAction({ 
 | 
      type: 'showTip', 
 | 
      dataIndexInside: dataIndex, 
 | 
      dataIndex: data.getRawIndex(dataIndex), 
 | 
      seriesIndex: seriesIndex, 
 | 
      from: this.uid 
 | 
    }); 
 | 
  }; 
 | 
  TooltipView.prototype._showComponentItemTooltip = function (e, el, dispatchAction) { 
 | 
    var isHTMLRenderMode = this._renderMode === 'html'; 
 | 
    var ecData = getECData(el); 
 | 
    var tooltipConfig = ecData.tooltipConfig; 
 | 
    var tooltipOpt = tooltipConfig.option || {}; 
 | 
    var encodeHTMLContent = tooltipOpt.encodeHTMLContent; 
 | 
    if (isString(tooltipOpt)) { 
 | 
      var content = tooltipOpt; 
 | 
      tooltipOpt = { 
 | 
        content: content, 
 | 
        // Fixed formatter 
 | 
        formatter: content 
 | 
      }; 
 | 
      // when `tooltipConfig.option` is a string rather than an object, 
 | 
      // we can't know if the content needs to be encoded 
 | 
      // for the sake of security, encode it by default. 
 | 
      encodeHTMLContent = true; 
 | 
    } 
 | 
    if (encodeHTMLContent && isHTMLRenderMode && tooltipOpt.content) { 
 | 
      // clone might be unnecessary? 
 | 
      tooltipOpt = clone(tooltipOpt); 
 | 
      tooltipOpt.content = encodeHTML(tooltipOpt.content); 
 | 
    } 
 | 
    var tooltipModelCascade = [tooltipOpt]; 
 | 
    var cmpt = this._ecModel.getComponent(ecData.componentMainType, ecData.componentIndex); 
 | 
    if (cmpt) { 
 | 
      tooltipModelCascade.push(cmpt); 
 | 
    } 
 | 
    // In most cases, component tooltip formatter has different params with series tooltip formatter, 
 | 
    // so that they cannot share the same formatter. Since the global tooltip formatter is used for series 
 | 
    // by convention, we do not use it as the default formatter for component. 
 | 
    tooltipModelCascade.push({ 
 | 
      formatter: tooltipOpt.content 
 | 
    }); 
 | 
    var positionDefault = e.positionDefault; 
 | 
    var subTooltipModel = buildTooltipModel(tooltipModelCascade, this._tooltipModel, positionDefault ? { 
 | 
      position: positionDefault 
 | 
    } : null); 
 | 
    var defaultHtml = subTooltipModel.get('content'); 
 | 
    var asyncTicket = Math.random() + ''; 
 | 
    // PENDING: this case do not support richText style yet. 
 | 
    var markupStyleCreator = new TooltipMarkupStyleCreator(); 
 | 
    // Do not check whether `trigger` is 'none' here, because `trigger` 
 | 
    // only works on coordinate system. In fact, we have not found case 
 | 
    // that requires setting `trigger` nothing on component yet. 
 | 
    this._showOrMove(subTooltipModel, function () { 
 | 
      // Use formatterParams from element defined in component 
 | 
      // Avoid users modify it. 
 | 
      var formatterParams = clone(subTooltipModel.get('formatterParams') || {}); 
 | 
      this._showTooltipContent(subTooltipModel, defaultHtml, formatterParams, asyncTicket, e.offsetX, e.offsetY, e.position, el, markupStyleCreator); 
 | 
    }); 
 | 
    // If not dispatch showTip, tip may be hide triggered by axis. 
 | 
    dispatchAction({ 
 | 
      type: 'showTip', 
 | 
      from: this.uid 
 | 
    }); 
 | 
  }; 
 | 
  TooltipView.prototype._showTooltipContent = function ( 
 | 
  // Use Model<TooltipOption> insteadof TooltipModel because this model may be from series or other options. 
 | 
  // Instead of top level tooltip. 
 | 
  tooltipModel, defaultHtml, params, asyncTicket, x, y, positionExpr, el, markupStyleCreator) { 
 | 
    // Reset ticket 
 | 
    this._ticket = ''; 
 | 
    if (!tooltipModel.get('showContent') || !tooltipModel.get('show')) { 
 | 
      return; 
 | 
    } 
 | 
    var tooltipContent = this._tooltipContent; 
 | 
    tooltipContent.setEnterable(tooltipModel.get('enterable')); 
 | 
    var formatter = tooltipModel.get('formatter'); 
 | 
    positionExpr = positionExpr || tooltipModel.get('position'); 
 | 
    var html = defaultHtml; 
 | 
    var nearPoint = this._getNearestPoint([x, y], params, tooltipModel.get('trigger'), tooltipModel.get('borderColor')); 
 | 
    var nearPointColor = nearPoint.color; 
 | 
    if (formatter) { 
 | 
      if (isString(formatter)) { 
 | 
        var useUTC = tooltipModel.ecModel.get('useUTC'); 
 | 
        var params0 = isArray(params) ? params[0] : params; 
 | 
        var isTimeAxis = params0 && params0.axisType && params0.axisType.indexOf('time') >= 0; 
 | 
        html = formatter; 
 | 
        if (isTimeAxis) { 
 | 
          html = timeFormat(params0.axisValue, html, useUTC); 
 | 
        } 
 | 
        html = formatTpl(html, params, true); 
 | 
      } else if (isFunction(formatter)) { 
 | 
        var callback = bind(function (cbTicket, html) { 
 | 
          if (cbTicket === this._ticket) { 
 | 
            tooltipContent.setContent(html, markupStyleCreator, tooltipModel, nearPointColor, positionExpr); 
 | 
            this._updatePosition(tooltipModel, positionExpr, x, y, tooltipContent, params, el); 
 | 
          } 
 | 
        }, this); 
 | 
        this._ticket = asyncTicket; 
 | 
        html = formatter(params, asyncTicket, callback); 
 | 
      } else { 
 | 
        html = formatter; 
 | 
      } 
 | 
    } 
 | 
    tooltipContent.setContent(html, markupStyleCreator, tooltipModel, nearPointColor, positionExpr); 
 | 
    tooltipContent.show(tooltipModel, nearPointColor); 
 | 
    this._updatePosition(tooltipModel, positionExpr, x, y, tooltipContent, params, el); 
 | 
  }; 
 | 
  TooltipView.prototype._getNearestPoint = function (point, tooltipDataParams, trigger, borderColor) { 
 | 
    if (trigger === 'axis' || isArray(tooltipDataParams)) { 
 | 
      return { 
 | 
        color: borderColor || (this._renderMode === 'html' ? '#fff' : 'none') 
 | 
      }; 
 | 
    } 
 | 
    if (!isArray(tooltipDataParams)) { 
 | 
      return { 
 | 
        color: borderColor || tooltipDataParams.color || tooltipDataParams.borderColor 
 | 
      }; 
 | 
    } 
 | 
  }; 
 | 
  TooltipView.prototype._updatePosition = function (tooltipModel, positionExpr, x, 
 | 
  // Mouse x 
 | 
  y, 
 | 
  // Mouse y 
 | 
  content, params, el) { 
 | 
    var viewWidth = this._api.getWidth(); 
 | 
    var viewHeight = this._api.getHeight(); 
 | 
    positionExpr = positionExpr || tooltipModel.get('position'); 
 | 
    var contentSize = content.getSize(); 
 | 
    var align = tooltipModel.get('align'); 
 | 
    var vAlign = tooltipModel.get('verticalAlign'); 
 | 
    var rect = el && el.getBoundingRect().clone(); 
 | 
    el && rect.applyTransform(el.transform); 
 | 
    if (isFunction(positionExpr)) { 
 | 
      // Callback of position can be an array or a string specify the position 
 | 
      positionExpr = positionExpr([x, y], params, content.el, rect, { 
 | 
        viewSize: [viewWidth, viewHeight], 
 | 
        contentSize: contentSize.slice() 
 | 
      }); 
 | 
    } 
 | 
    if (isArray(positionExpr)) { 
 | 
      x = parsePercent(positionExpr[0], viewWidth); 
 | 
      y = parsePercent(positionExpr[1], viewHeight); 
 | 
    } else if (isObject(positionExpr)) { 
 | 
      var boxLayoutPosition = positionExpr; 
 | 
      boxLayoutPosition.width = contentSize[0]; 
 | 
      boxLayoutPosition.height = contentSize[1]; 
 | 
      var layoutRect = getLayoutRect(boxLayoutPosition, { 
 | 
        width: viewWidth, 
 | 
        height: viewHeight 
 | 
      }); 
 | 
      x = layoutRect.x; 
 | 
      y = layoutRect.y; 
 | 
      align = null; 
 | 
      // When positionExpr is left/top/right/bottom, 
 | 
      // align and verticalAlign will not work. 
 | 
      vAlign = null; 
 | 
    } 
 | 
    // Specify tooltip position by string 'top' 'bottom' 'left' 'right' around graphic element 
 | 
    else if (isString(positionExpr) && el) { 
 | 
      var pos = calcTooltipPosition(positionExpr, rect, contentSize, tooltipModel.get('borderWidth')); 
 | 
      x = pos[0]; 
 | 
      y = pos[1]; 
 | 
    } else { 
 | 
      var pos = refixTooltipPosition(x, y, content, viewWidth, viewHeight, align ? null : 20, vAlign ? null : 20); 
 | 
      x = pos[0]; 
 | 
      y = pos[1]; 
 | 
    } 
 | 
    align && (x -= isCenterAlign(align) ? contentSize[0] / 2 : align === 'right' ? contentSize[0] : 0); 
 | 
    vAlign && (y -= isCenterAlign(vAlign) ? contentSize[1] / 2 : vAlign === 'bottom' ? contentSize[1] : 0); 
 | 
    if (shouldTooltipConfine(tooltipModel)) { 
 | 
      var pos = confineTooltipPosition(x, y, content, viewWidth, viewHeight); 
 | 
      x = pos[0]; 
 | 
      y = pos[1]; 
 | 
    } 
 | 
    content.moveTo(x, y); 
 | 
  }; 
 | 
  // FIXME 
 | 
  // Should we remove this but leave this to user? 
 | 
  TooltipView.prototype._updateContentNotChangedOnAxis = function (dataByCoordSys, cbParamsList) { 
 | 
    var lastCoordSys = this._lastDataByCoordSys; 
 | 
    var lastCbParamsList = this._cbParamsList; 
 | 
    var contentNotChanged = !!lastCoordSys && lastCoordSys.length === dataByCoordSys.length; 
 | 
    contentNotChanged && each(lastCoordSys, function (lastItemCoordSys, indexCoordSys) { 
 | 
      var lastDataByAxis = lastItemCoordSys.dataByAxis || []; 
 | 
      var thisItemCoordSys = dataByCoordSys[indexCoordSys] || {}; 
 | 
      var thisDataByAxis = thisItemCoordSys.dataByAxis || []; 
 | 
      contentNotChanged = contentNotChanged && lastDataByAxis.length === thisDataByAxis.length; 
 | 
      contentNotChanged && each(lastDataByAxis, function (lastItem, indexAxis) { 
 | 
        var thisItem = thisDataByAxis[indexAxis] || {}; 
 | 
        var lastIndices = lastItem.seriesDataIndices || []; 
 | 
        var newIndices = thisItem.seriesDataIndices || []; 
 | 
        contentNotChanged = contentNotChanged && lastItem.value === thisItem.value && lastItem.axisType === thisItem.axisType && lastItem.axisId === thisItem.axisId && lastIndices.length === newIndices.length; 
 | 
        contentNotChanged && each(lastIndices, function (lastIdxItem, j) { 
 | 
          var newIdxItem = newIndices[j]; 
 | 
          contentNotChanged = contentNotChanged && lastIdxItem.seriesIndex === newIdxItem.seriesIndex && lastIdxItem.dataIndex === newIdxItem.dataIndex; 
 | 
        }); 
 | 
        // check is cbParams data value changed 
 | 
        lastCbParamsList && each(lastItem.seriesDataIndices, function (idxItem) { 
 | 
          var seriesIdx = idxItem.seriesIndex; 
 | 
          var cbParams = cbParamsList[seriesIdx]; 
 | 
          var lastCbParams = lastCbParamsList[seriesIdx]; 
 | 
          if (cbParams && lastCbParams && lastCbParams.data !== cbParams.data) { 
 | 
            contentNotChanged = false; 
 | 
          } 
 | 
        }); 
 | 
      }); 
 | 
    }); 
 | 
    this._lastDataByCoordSys = dataByCoordSys; 
 | 
    this._cbParamsList = cbParamsList; 
 | 
    return !!contentNotChanged; 
 | 
  }; 
 | 
  TooltipView.prototype._hide = function (dispatchAction) { 
 | 
    // Do not directly hideLater here, because this behavior may be prevented 
 | 
    // in dispatchAction when showTip is dispatched. 
 | 
    // FIXME 
 | 
    // duplicated hideTip if manuallyHideTip is called from dispatchAction. 
 | 
    this._lastDataByCoordSys = null; 
 | 
    dispatchAction({ 
 | 
      type: 'hideTip', 
 | 
      from: this.uid 
 | 
    }); 
 | 
  }; 
 | 
  TooltipView.prototype.dispose = function (ecModel, api) { 
 | 
    if (env.node || !api.getDom()) { 
 | 
      return; 
 | 
    } 
 | 
    clear(this, '_updatePosition'); 
 | 
    this._tooltipContent.dispose(); 
 | 
    globalListener.unregister('itemTooltip', api); 
 | 
  }; 
 | 
  TooltipView.type = 'tooltip'; 
 | 
  return TooltipView; 
 | 
}(ComponentView); 
 | 
/** 
 | 
 * From top to bottom. (the last one should be globalTooltipModel); 
 | 
 */ 
 | 
function buildTooltipModel(modelCascade, globalTooltipModel, defaultTooltipOption) { 
 | 
  // Last is always tooltip model. 
 | 
  var ecModel = globalTooltipModel.ecModel; 
 | 
  var resultModel; 
 | 
  if (defaultTooltipOption) { 
 | 
    resultModel = new Model(defaultTooltipOption, ecModel, ecModel); 
 | 
    resultModel = new Model(globalTooltipModel.option, resultModel, ecModel); 
 | 
  } else { 
 | 
    resultModel = globalTooltipModel; 
 | 
  } 
 | 
  for (var i = modelCascade.length - 1; i >= 0; i--) { 
 | 
    var tooltipOpt = modelCascade[i]; 
 | 
    if (tooltipOpt) { 
 | 
      if (tooltipOpt instanceof Model) { 
 | 
        tooltipOpt = tooltipOpt.get('tooltip', true); 
 | 
      } 
 | 
      // In each data item tooltip can be simply write: 
 | 
      // { 
 | 
      //  value: 10, 
 | 
      //  tooltip: 'Something you need to know' 
 | 
      // } 
 | 
      if (isString(tooltipOpt)) { 
 | 
        tooltipOpt = { 
 | 
          formatter: tooltipOpt 
 | 
        }; 
 | 
      } 
 | 
      if (tooltipOpt) { 
 | 
        resultModel = new Model(tooltipOpt, resultModel, ecModel); 
 | 
      } 
 | 
    } 
 | 
  } 
 | 
  return resultModel; 
 | 
} 
 | 
function makeDispatchAction(payload, api) { 
 | 
  return payload.dispatchAction || bind(api.dispatchAction, api); 
 | 
} 
 | 
function refixTooltipPosition(x, y, content, viewWidth, viewHeight, gapH, gapV) { 
 | 
  var size = content.getSize(); 
 | 
  var width = size[0]; 
 | 
  var height = size[1]; 
 | 
  if (gapH != null) { 
 | 
    // Add extra 2 pixels for this case: 
 | 
    // At present the "values" in default tooltip are using CSS `float: right`. 
 | 
    // When the right edge of the tooltip box is on the right side of the 
 | 
    // viewport, the `float` layout might push the "values" to the second line. 
 | 
    if (x + width + gapH + 2 > viewWidth) { 
 | 
      x -= width + gapH; 
 | 
    } else { 
 | 
      x += gapH; 
 | 
    } 
 | 
  } 
 | 
  if (gapV != null) { 
 | 
    if (y + height + gapV > viewHeight) { 
 | 
      y -= height + gapV; 
 | 
    } else { 
 | 
      y += gapV; 
 | 
    } 
 | 
  } 
 | 
  return [x, y]; 
 | 
} 
 | 
function confineTooltipPosition(x, y, content, viewWidth, viewHeight) { 
 | 
  var size = content.getSize(); 
 | 
  var width = size[0]; 
 | 
  var height = size[1]; 
 | 
  x = Math.min(x + width, viewWidth) - width; 
 | 
  y = Math.min(y + height, viewHeight) - height; 
 | 
  x = Math.max(x, 0); 
 | 
  y = Math.max(y, 0); 
 | 
  return [x, y]; 
 | 
} 
 | 
function calcTooltipPosition(position, rect, contentSize, borderWidth) { 
 | 
  var domWidth = contentSize[0]; 
 | 
  var domHeight = contentSize[1]; 
 | 
  var offset = Math.ceil(Math.SQRT2 * borderWidth) + 8; 
 | 
  var x = 0; 
 | 
  var y = 0; 
 | 
  var rectWidth = rect.width; 
 | 
  var rectHeight = rect.height; 
 | 
  switch (position) { 
 | 
    case 'inside': 
 | 
      x = rect.x + rectWidth / 2 - domWidth / 2; 
 | 
      y = rect.y + rectHeight / 2 - domHeight / 2; 
 | 
      break; 
 | 
    case 'top': 
 | 
      x = rect.x + rectWidth / 2 - domWidth / 2; 
 | 
      y = rect.y - domHeight - offset; 
 | 
      break; 
 | 
    case 'bottom': 
 | 
      x = rect.x + rectWidth / 2 - domWidth / 2; 
 | 
      y = rect.y + rectHeight + offset; 
 | 
      break; 
 | 
    case 'left': 
 | 
      x = rect.x - domWidth - offset; 
 | 
      y = rect.y + rectHeight / 2 - domHeight / 2; 
 | 
      break; 
 | 
    case 'right': 
 | 
      x = rect.x + rectWidth + offset; 
 | 
      y = rect.y + rectHeight / 2 - domHeight / 2; 
 | 
  } 
 | 
  return [x, y]; 
 | 
} 
 | 
function isCenterAlign(align) { 
 | 
  return align === 'center' || align === 'middle'; 
 | 
} 
 | 
/** 
 | 
 * Find target component by payload like: 
 | 
 * ```js 
 | 
 * { legendId: 'some_id', name: 'xxx' } 
 | 
 * { toolboxIndex: 1, name: 'xxx' } 
 | 
 * { geoName: 'some_name', name: 'xxx' } 
 | 
 * ``` 
 | 
 * PENDING: at present only 
 | 
 * 
 | 
 * If not found, return null/undefined. 
 | 
 */ 
 | 
function findComponentReference(payload, ecModel, api) { 
 | 
  var queryOptionMap = preParseFinder(payload).queryOptionMap; 
 | 
  var componentMainType = queryOptionMap.keys()[0]; 
 | 
  if (!componentMainType || componentMainType === 'series') { 
 | 
    return; 
 | 
  } 
 | 
  var queryResult = queryReferringComponents(ecModel, componentMainType, queryOptionMap.get(componentMainType), { 
 | 
    useDefault: false, 
 | 
    enableAll: false, 
 | 
    enableNone: false 
 | 
  }); 
 | 
  var model = queryResult.models[0]; 
 | 
  if (!model) { 
 | 
    return; 
 | 
  } 
 | 
  var view = api.getViewOfComponentModel(model); 
 | 
  var el; 
 | 
  view.group.traverse(function (subEl) { 
 | 
    var tooltipConfig = getECData(subEl).tooltipConfig; 
 | 
    if (tooltipConfig && tooltipConfig.name === payload.name) { 
 | 
      el = subEl; 
 | 
      return true; // stop 
 | 
    } 
 | 
  }); 
 | 
  if (el) { 
 | 
    return { 
 | 
      componentMainType: componentMainType, 
 | 
      componentIndex: model.componentIndex, 
 | 
      el: el 
 | 
    }; 
 | 
  } 
 | 
} 
 | 
export default TooltipView; 
 |