| 
/* 
 | 
* 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. 
 | 
 */ 
 | 
  
 | 
/* 
 | 
* 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. 
 | 
*/ 
 | 
// TODO: move labels out of viewport. 
 | 
import { BoundingRect, updateProps, initProps, isElementRemoved } from '../util/graphic.js'; 
 | 
import { getECData } from '../util/innerStore.js'; 
 | 
import { parsePercent } from '../util/number.js'; 
 | 
import Transformable from 'zrender/lib/core/Transformable.js'; 
 | 
import { updateLabelLinePoints, setLabelLineStyle, getLabelLineStatesModels } from './labelGuideHelper.js'; 
 | 
import { makeInner } from '../util/model.js'; 
 | 
import { retrieve2, each, keys, isFunction, filter, indexOf } from 'zrender/lib/core/util.js'; 
 | 
import { prepareLayoutList, hideOverlap, shiftLayoutOnX, shiftLayoutOnY } from './labelLayoutHelper.js'; 
 | 
import { labelInner, animateLabelValue } from './labelStyle.js'; 
 | 
import { normalizeRadian } from 'zrender/lib/contain/util.js'; 
 | 
function cloneArr(points) { 
 | 
  if (points) { 
 | 
    var newPoints = []; 
 | 
    for (var i = 0; i < points.length; i++) { 
 | 
      newPoints.push(points[i].slice()); 
 | 
    } 
 | 
    return newPoints; 
 | 
  } 
 | 
} 
 | 
function prepareLayoutCallbackParams(labelItem, hostEl) { 
 | 
  var label = labelItem.label; 
 | 
  var labelLine = hostEl && hostEl.getTextGuideLine(); 
 | 
  return { 
 | 
    dataIndex: labelItem.dataIndex, 
 | 
    dataType: labelItem.dataType, 
 | 
    seriesIndex: labelItem.seriesModel.seriesIndex, 
 | 
    text: labelItem.label.style.text, 
 | 
    rect: labelItem.hostRect, 
 | 
    labelRect: labelItem.rect, 
 | 
    // x: labelAttr.x, 
 | 
    // y: labelAttr.y, 
 | 
    align: label.style.align, 
 | 
    verticalAlign: label.style.verticalAlign, 
 | 
    labelLinePoints: cloneArr(labelLine && labelLine.shape.points) 
 | 
  }; 
 | 
} 
 | 
var LABEL_OPTION_TO_STYLE_KEYS = ['align', 'verticalAlign', 'width', 'height', 'fontSize']; 
 | 
var dummyTransformable = new Transformable(); 
 | 
var labelLayoutInnerStore = makeInner(); 
 | 
var labelLineAnimationStore = makeInner(); 
 | 
function extendWithKeys(target, source, keys) { 
 | 
  for (var i = 0; i < keys.length; i++) { 
 | 
    var key = keys[i]; 
 | 
    if (source[key] != null) { 
 | 
      target[key] = source[key]; 
 | 
    } 
 | 
  } 
 | 
} 
 | 
var LABEL_LAYOUT_PROPS = ['x', 'y', 'rotation']; 
 | 
var LabelManager = /** @class */function () { 
 | 
  function LabelManager() { 
 | 
    this._labelList = []; 
 | 
    this._chartViewList = []; 
 | 
  } 
 | 
  LabelManager.prototype.clearLabels = function () { 
 | 
    this._labelList = []; 
 | 
    this._chartViewList = []; 
 | 
  }; 
 | 
  /** 
 | 
   * Add label to manager 
 | 
   */ 
 | 
  LabelManager.prototype._addLabel = function (dataIndex, dataType, seriesModel, label, layoutOption) { 
 | 
    var labelStyle = label.style; 
 | 
    var hostEl = label.__hostTarget; 
 | 
    var textConfig = hostEl.textConfig || {}; 
 | 
    // TODO: If label is in other state. 
 | 
    var labelTransform = label.getComputedTransform(); 
 | 
    var labelRect = label.getBoundingRect().plain(); 
 | 
    BoundingRect.applyTransform(labelRect, labelRect, labelTransform); 
 | 
    if (labelTransform) { 
 | 
      dummyTransformable.setLocalTransform(labelTransform); 
 | 
    } else { 
 | 
      // Identity transform. 
 | 
      dummyTransformable.x = dummyTransformable.y = dummyTransformable.rotation = dummyTransformable.originX = dummyTransformable.originY = 0; 
 | 
      dummyTransformable.scaleX = dummyTransformable.scaleY = 1; 
 | 
    } 
 | 
    dummyTransformable.rotation = normalizeRadian(dummyTransformable.rotation); 
 | 
    var host = label.__hostTarget; 
 | 
    var hostRect; 
 | 
    if (host) { 
 | 
      hostRect = host.getBoundingRect().plain(); 
 | 
      var transform = host.getComputedTransform(); 
 | 
      BoundingRect.applyTransform(hostRect, hostRect, transform); 
 | 
    } 
 | 
    var labelGuide = hostRect && host.getTextGuideLine(); 
 | 
    this._labelList.push({ 
 | 
      label: label, 
 | 
      labelLine: labelGuide, 
 | 
      seriesModel: seriesModel, 
 | 
      dataIndex: dataIndex, 
 | 
      dataType: dataType, 
 | 
      layoutOption: layoutOption, 
 | 
      computedLayoutOption: null, 
 | 
      rect: labelRect, 
 | 
      hostRect: hostRect, 
 | 
      // Label with lower priority will be hidden when overlapped 
 | 
      // Use rect size as default priority 
 | 
      priority: hostRect ? hostRect.width * hostRect.height : 0, 
 | 
      // Save default label attributes. 
 | 
      // For restore if developers want get back to default value in callback. 
 | 
      defaultAttr: { 
 | 
        ignore: label.ignore, 
 | 
        labelGuideIgnore: labelGuide && labelGuide.ignore, 
 | 
        x: dummyTransformable.x, 
 | 
        y: dummyTransformable.y, 
 | 
        scaleX: dummyTransformable.scaleX, 
 | 
        scaleY: dummyTransformable.scaleY, 
 | 
        rotation: dummyTransformable.rotation, 
 | 
        style: { 
 | 
          x: labelStyle.x, 
 | 
          y: labelStyle.y, 
 | 
          align: labelStyle.align, 
 | 
          verticalAlign: labelStyle.verticalAlign, 
 | 
          width: labelStyle.width, 
 | 
          height: labelStyle.height, 
 | 
          fontSize: labelStyle.fontSize 
 | 
        }, 
 | 
        cursor: label.cursor, 
 | 
        attachedPos: textConfig.position, 
 | 
        attachedRot: textConfig.rotation 
 | 
      } 
 | 
    }); 
 | 
  }; 
 | 
  LabelManager.prototype.addLabelsOfSeries = function (chartView) { 
 | 
    var _this = this; 
 | 
    this._chartViewList.push(chartView); 
 | 
    var seriesModel = chartView.__model; 
 | 
    var layoutOption = seriesModel.get('labelLayout'); 
 | 
    /** 
 | 
     * Ignore layouting if it's not specified anything. 
 | 
     */ 
 | 
    if (!(isFunction(layoutOption) || keys(layoutOption).length)) { 
 | 
      return; 
 | 
    } 
 | 
    chartView.group.traverse(function (child) { 
 | 
      if (child.ignore) { 
 | 
        return true; // Stop traverse descendants. 
 | 
      } 
 | 
      // Only support label being hosted on graphic elements. 
 | 
      var textEl = child.getTextContent(); 
 | 
      var ecData = getECData(child); 
 | 
      // Can only attach the text on the element with dataIndex 
 | 
      if (textEl && !textEl.disableLabelLayout) { 
 | 
        _this._addLabel(ecData.dataIndex, ecData.dataType, seriesModel, textEl, layoutOption); 
 | 
      } 
 | 
    }); 
 | 
  }; 
 | 
  LabelManager.prototype.updateLayoutConfig = function (api) { 
 | 
    var width = api.getWidth(); 
 | 
    var height = api.getHeight(); 
 | 
    function createDragHandler(el, labelLineModel) { 
 | 
      return function () { 
 | 
        updateLabelLinePoints(el, labelLineModel); 
 | 
      }; 
 | 
    } 
 | 
    for (var i = 0; i < this._labelList.length; i++) { 
 | 
      var labelItem = this._labelList[i]; 
 | 
      var label = labelItem.label; 
 | 
      var hostEl = label.__hostTarget; 
 | 
      var defaultLabelAttr = labelItem.defaultAttr; 
 | 
      var layoutOption = void 0; 
 | 
      // TODO A global layout option? 
 | 
      if (isFunction(labelItem.layoutOption)) { 
 | 
        layoutOption = labelItem.layoutOption(prepareLayoutCallbackParams(labelItem, hostEl)); 
 | 
      } else { 
 | 
        layoutOption = labelItem.layoutOption; 
 | 
      } 
 | 
      layoutOption = layoutOption || {}; 
 | 
      labelItem.computedLayoutOption = layoutOption; 
 | 
      var degreeToRadian = Math.PI / 180; 
 | 
      // TODO hostEl should always exists. 
 | 
      // Or label should not have parent because the x, y is all in global space. 
 | 
      if (hostEl) { 
 | 
        hostEl.setTextConfig({ 
 | 
          // Force to set local false. 
 | 
          local: false, 
 | 
          // Ignore position and rotation config on the host el if x or y is changed. 
 | 
          position: layoutOption.x != null || layoutOption.y != null ? null : defaultLabelAttr.attachedPos, 
 | 
          // Ignore rotation config on the host el if rotation is changed. 
 | 
          rotation: layoutOption.rotate != null ? layoutOption.rotate * degreeToRadian : defaultLabelAttr.attachedRot, 
 | 
          offset: [layoutOption.dx || 0, layoutOption.dy || 0] 
 | 
        }); 
 | 
      } 
 | 
      var needsUpdateLabelLine = false; 
 | 
      if (layoutOption.x != null) { 
 | 
        // TODO width of chart view. 
 | 
        label.x = parsePercent(layoutOption.x, width); 
 | 
        label.setStyle('x', 0); // Ignore movement in style. TODO: origin. 
 | 
        needsUpdateLabelLine = true; 
 | 
      } else { 
 | 
        label.x = defaultLabelAttr.x; 
 | 
        label.setStyle('x', defaultLabelAttr.style.x); 
 | 
      } 
 | 
      if (layoutOption.y != null) { 
 | 
        // TODO height of chart view. 
 | 
        label.y = parsePercent(layoutOption.y, height); 
 | 
        label.setStyle('y', 0); // Ignore movement in style. 
 | 
        needsUpdateLabelLine = true; 
 | 
      } else { 
 | 
        label.y = defaultLabelAttr.y; 
 | 
        label.setStyle('y', defaultLabelAttr.style.y); 
 | 
      } 
 | 
      if (layoutOption.labelLinePoints) { 
 | 
        var guideLine = hostEl.getTextGuideLine(); 
 | 
        if (guideLine) { 
 | 
          guideLine.setShape({ 
 | 
            points: layoutOption.labelLinePoints 
 | 
          }); 
 | 
          // Not update 
 | 
          needsUpdateLabelLine = false; 
 | 
        } 
 | 
      } 
 | 
      var labelLayoutStore = labelLayoutInnerStore(label); 
 | 
      labelLayoutStore.needsUpdateLabelLine = needsUpdateLabelLine; 
 | 
      label.rotation = layoutOption.rotate != null ? layoutOption.rotate * degreeToRadian : defaultLabelAttr.rotation; 
 | 
      label.scaleX = defaultLabelAttr.scaleX; 
 | 
      label.scaleY = defaultLabelAttr.scaleY; 
 | 
      for (var k = 0; k < LABEL_OPTION_TO_STYLE_KEYS.length; k++) { 
 | 
        var key = LABEL_OPTION_TO_STYLE_KEYS[k]; 
 | 
        label.setStyle(key, layoutOption[key] != null ? layoutOption[key] : defaultLabelAttr.style[key]); 
 | 
      } 
 | 
      if (layoutOption.draggable) { 
 | 
        label.draggable = true; 
 | 
        label.cursor = 'move'; 
 | 
        if (hostEl) { 
 | 
          var hostModel = labelItem.seriesModel; 
 | 
          if (labelItem.dataIndex != null) { 
 | 
            var data = labelItem.seriesModel.getData(labelItem.dataType); 
 | 
            hostModel = data.getItemModel(labelItem.dataIndex); 
 | 
          } 
 | 
          label.on('drag', createDragHandler(hostEl, hostModel.getModel('labelLine'))); 
 | 
        } 
 | 
      } else { 
 | 
        // TODO Other drag functions? 
 | 
        label.off('drag'); 
 | 
        label.cursor = defaultLabelAttr.cursor; 
 | 
      } 
 | 
    } 
 | 
  }; 
 | 
  LabelManager.prototype.layout = function (api) { 
 | 
    var width = api.getWidth(); 
 | 
    var height = api.getHeight(); 
 | 
    var labelList = prepareLayoutList(this._labelList); 
 | 
    var labelsNeedsAdjustOnX = filter(labelList, function (item) { 
 | 
      return item.layoutOption.moveOverlap === 'shiftX'; 
 | 
    }); 
 | 
    var labelsNeedsAdjustOnY = filter(labelList, function (item) { 
 | 
      return item.layoutOption.moveOverlap === 'shiftY'; 
 | 
    }); 
 | 
    shiftLayoutOnX(labelsNeedsAdjustOnX, 0, width); 
 | 
    shiftLayoutOnY(labelsNeedsAdjustOnY, 0, height); 
 | 
    var labelsNeedsHideOverlap = filter(labelList, function (item) { 
 | 
      return item.layoutOption.hideOverlap; 
 | 
    }); 
 | 
    hideOverlap(labelsNeedsHideOverlap); 
 | 
  }; 
 | 
  /** 
 | 
   * Process all labels. Not only labels with layoutOption. 
 | 
   */ 
 | 
  LabelManager.prototype.processLabelsOverall = function () { 
 | 
    var _this = this; 
 | 
    each(this._chartViewList, function (chartView) { 
 | 
      var seriesModel = chartView.__model; 
 | 
      var ignoreLabelLineUpdate = chartView.ignoreLabelLineUpdate; 
 | 
      var animationEnabled = seriesModel.isAnimationEnabled(); 
 | 
      chartView.group.traverse(function (child) { 
 | 
        if (child.ignore && !child.forceLabelAnimation) { 
 | 
          return true; // Stop traverse descendants. 
 | 
        } 
 | 
        var needsUpdateLabelLine = !ignoreLabelLineUpdate; 
 | 
        var label = child.getTextContent(); 
 | 
        if (!needsUpdateLabelLine && label) { 
 | 
          needsUpdateLabelLine = labelLayoutInnerStore(label).needsUpdateLabelLine; 
 | 
        } 
 | 
        if (needsUpdateLabelLine) { 
 | 
          _this._updateLabelLine(child, seriesModel); 
 | 
        } 
 | 
        if (animationEnabled) { 
 | 
          _this._animateLabels(child, seriesModel); 
 | 
        } 
 | 
      }); 
 | 
    }); 
 | 
  }; 
 | 
  LabelManager.prototype._updateLabelLine = function (el, seriesModel) { 
 | 
    // Only support label being hosted on graphic elements. 
 | 
    var textEl = el.getTextContent(); 
 | 
    // Update label line style. 
 | 
    var ecData = getECData(el); 
 | 
    var dataIndex = ecData.dataIndex; 
 | 
    // Only support labelLine on the labels represent data. 
 | 
    if (textEl && dataIndex != null) { 
 | 
      var data = seriesModel.getData(ecData.dataType); 
 | 
      var itemModel = data.getItemModel(dataIndex); 
 | 
      var defaultStyle = {}; 
 | 
      var visualStyle = data.getItemVisual(dataIndex, 'style'); 
 | 
      if (visualStyle) { 
 | 
        var visualType = data.getVisual('drawType'); 
 | 
        // Default to be same with main color 
 | 
        defaultStyle.stroke = visualStyle[visualType]; 
 | 
      } 
 | 
      var labelLineModel = itemModel.getModel('labelLine'); 
 | 
      setLabelLineStyle(el, getLabelLineStatesModels(itemModel), defaultStyle); 
 | 
      updateLabelLinePoints(el, labelLineModel); 
 | 
    } 
 | 
  }; 
 | 
  LabelManager.prototype._animateLabels = function (el, seriesModel) { 
 | 
    var textEl = el.getTextContent(); 
 | 
    var guideLine = el.getTextGuideLine(); 
 | 
    // Animate 
 | 
    if (textEl 
 | 
    // `forceLabelAnimation` has the highest priority 
 | 
    && (el.forceLabelAnimation || !textEl.ignore && !textEl.invisible && !el.disableLabelAnimation && !isElementRemoved(el))) { 
 | 
      var layoutStore = labelLayoutInnerStore(textEl); 
 | 
      var oldLayout = layoutStore.oldLayout; 
 | 
      var ecData = getECData(el); 
 | 
      var dataIndex = ecData.dataIndex; 
 | 
      var newProps = { 
 | 
        x: textEl.x, 
 | 
        y: textEl.y, 
 | 
        rotation: textEl.rotation 
 | 
      }; 
 | 
      var data = seriesModel.getData(ecData.dataType); 
 | 
      if (!oldLayout) { 
 | 
        textEl.attr(newProps); 
 | 
        // Disable fade in animation if value animation is enabled. 
 | 
        if (!labelInner(textEl).valueAnimation) { 
 | 
          var oldOpacity = retrieve2(textEl.style.opacity, 1); 
 | 
          // Fade in animation 
 | 
          textEl.style.opacity = 0; 
 | 
          initProps(textEl, { 
 | 
            style: { 
 | 
              opacity: oldOpacity 
 | 
            } 
 | 
          }, seriesModel, dataIndex); 
 | 
        } 
 | 
      } else { 
 | 
        textEl.attr(oldLayout); 
 | 
        // Make sure the animation from is in the right status. 
 | 
        var prevStates = el.prevStates; 
 | 
        if (prevStates) { 
 | 
          if (indexOf(prevStates, 'select') >= 0) { 
 | 
            textEl.attr(layoutStore.oldLayoutSelect); 
 | 
          } 
 | 
          if (indexOf(prevStates, 'emphasis') >= 0) { 
 | 
            textEl.attr(layoutStore.oldLayoutEmphasis); 
 | 
          } 
 | 
        } 
 | 
        updateProps(textEl, newProps, seriesModel, dataIndex); 
 | 
      } 
 | 
      layoutStore.oldLayout = newProps; 
 | 
      if (textEl.states.select) { 
 | 
        var layoutSelect = layoutStore.oldLayoutSelect = {}; 
 | 
        extendWithKeys(layoutSelect, newProps, LABEL_LAYOUT_PROPS); 
 | 
        extendWithKeys(layoutSelect, textEl.states.select, LABEL_LAYOUT_PROPS); 
 | 
      } 
 | 
      if (textEl.states.emphasis) { 
 | 
        var layoutEmphasis = layoutStore.oldLayoutEmphasis = {}; 
 | 
        extendWithKeys(layoutEmphasis, newProps, LABEL_LAYOUT_PROPS); 
 | 
        extendWithKeys(layoutEmphasis, textEl.states.emphasis, LABEL_LAYOUT_PROPS); 
 | 
      } 
 | 
      animateLabelValue(textEl, dataIndex, data, seriesModel, seriesModel); 
 | 
    } 
 | 
    if (guideLine && !guideLine.ignore && !guideLine.invisible) { 
 | 
      var layoutStore = labelLineAnimationStore(guideLine); 
 | 
      var oldLayout = layoutStore.oldLayout; 
 | 
      var newLayout = { 
 | 
        points: guideLine.shape.points 
 | 
      }; 
 | 
      if (!oldLayout) { 
 | 
        guideLine.setShape(newLayout); 
 | 
        guideLine.style.strokePercent = 0; 
 | 
        initProps(guideLine, { 
 | 
          style: { 
 | 
            strokePercent: 1 
 | 
          } 
 | 
        }, seriesModel); 
 | 
      } else { 
 | 
        guideLine.attr({ 
 | 
          shape: oldLayout 
 | 
        }); 
 | 
        updateProps(guideLine, { 
 | 
          shape: newLayout 
 | 
        }, seriesModel); 
 | 
      } 
 | 
      layoutStore.oldLayout = newLayout; 
 | 
    } 
 | 
  }; 
 | 
  return LabelManager; 
 | 
}(); 
 | 
export default LabelManager; 
 |