| 
/* 
 | 
* 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. 
 | 
*/ 
 | 
import { Point, Path, Polyline } from '../util/graphic.js'; 
 | 
import PathProxy from 'zrender/lib/core/PathProxy.js'; 
 | 
import { normalizeRadian } from 'zrender/lib/contain/util.js'; 
 | 
import { cubicProjectPoint, quadraticProjectPoint } from 'zrender/lib/core/curve.js'; 
 | 
import { defaults, retrieve2 } from 'zrender/lib/core/util.js'; 
 | 
import { invert } from 'zrender/lib/core/matrix.js'; 
 | 
import * as vector from 'zrender/lib/core/vector.js'; 
 | 
import { DISPLAY_STATES, SPECIAL_STATES } from '../util/states.js'; 
 | 
var PI2 = Math.PI * 2; 
 | 
var CMD = PathProxy.CMD; 
 | 
var DEFAULT_SEARCH_SPACE = ['top', 'right', 'bottom', 'left']; 
 | 
function getCandidateAnchor(pos, distance, rect, outPt, outDir) { 
 | 
  var width = rect.width; 
 | 
  var height = rect.height; 
 | 
  switch (pos) { 
 | 
    case 'top': 
 | 
      outPt.set(rect.x + width / 2, rect.y - distance); 
 | 
      outDir.set(0, -1); 
 | 
      break; 
 | 
    case 'bottom': 
 | 
      outPt.set(rect.x + width / 2, rect.y + height + distance); 
 | 
      outDir.set(0, 1); 
 | 
      break; 
 | 
    case 'left': 
 | 
      outPt.set(rect.x - distance, rect.y + height / 2); 
 | 
      outDir.set(-1, 0); 
 | 
      break; 
 | 
    case 'right': 
 | 
      outPt.set(rect.x + width + distance, rect.y + height / 2); 
 | 
      outDir.set(1, 0); 
 | 
      break; 
 | 
  } 
 | 
} 
 | 
function projectPointToArc(cx, cy, r, startAngle, endAngle, anticlockwise, x, y, out) { 
 | 
  x -= cx; 
 | 
  y -= cy; 
 | 
  var d = Math.sqrt(x * x + y * y); 
 | 
  x /= d; 
 | 
  y /= d; 
 | 
  // Intersect point. 
 | 
  var ox = x * r + cx; 
 | 
  var oy = y * r + cy; 
 | 
  if (Math.abs(startAngle - endAngle) % PI2 < 1e-4) { 
 | 
    // Is a circle 
 | 
    out[0] = ox; 
 | 
    out[1] = oy; 
 | 
    return d - r; 
 | 
  } 
 | 
  if (anticlockwise) { 
 | 
    var tmp = startAngle; 
 | 
    startAngle = normalizeRadian(endAngle); 
 | 
    endAngle = normalizeRadian(tmp); 
 | 
  } else { 
 | 
    startAngle = normalizeRadian(startAngle); 
 | 
    endAngle = normalizeRadian(endAngle); 
 | 
  } 
 | 
  if (startAngle > endAngle) { 
 | 
    endAngle += PI2; 
 | 
  } 
 | 
  var angle = Math.atan2(y, x); 
 | 
  if (angle < 0) { 
 | 
    angle += PI2; 
 | 
  } 
 | 
  if (angle >= startAngle && angle <= endAngle || angle + PI2 >= startAngle && angle + PI2 <= endAngle) { 
 | 
    // Project point is on the arc. 
 | 
    out[0] = ox; 
 | 
    out[1] = oy; 
 | 
    return d - r; 
 | 
  } 
 | 
  var x1 = r * Math.cos(startAngle) + cx; 
 | 
  var y1 = r * Math.sin(startAngle) + cy; 
 | 
  var x2 = r * Math.cos(endAngle) + cx; 
 | 
  var y2 = r * Math.sin(endAngle) + cy; 
 | 
  var d1 = (x1 - x) * (x1 - x) + (y1 - y) * (y1 - y); 
 | 
  var d2 = (x2 - x) * (x2 - x) + (y2 - y) * (y2 - y); 
 | 
  if (d1 < d2) { 
 | 
    out[0] = x1; 
 | 
    out[1] = y1; 
 | 
    return Math.sqrt(d1); 
 | 
  } else { 
 | 
    out[0] = x2; 
 | 
    out[1] = y2; 
 | 
    return Math.sqrt(d2); 
 | 
  } 
 | 
} 
 | 
function projectPointToLine(x1, y1, x2, y2, x, y, out, limitToEnds) { 
 | 
  var dx = x - x1; 
 | 
  var dy = y - y1; 
 | 
  var dx1 = x2 - x1; 
 | 
  var dy1 = y2 - y1; 
 | 
  var lineLen = Math.sqrt(dx1 * dx1 + dy1 * dy1); 
 | 
  dx1 /= lineLen; 
 | 
  dy1 /= lineLen; 
 | 
  // dot product 
 | 
  var projectedLen = dx * dx1 + dy * dy1; 
 | 
  var t = projectedLen / lineLen; 
 | 
  if (limitToEnds) { 
 | 
    t = Math.min(Math.max(t, 0), 1); 
 | 
  } 
 | 
  t *= lineLen; 
 | 
  var ox = out[0] = x1 + t * dx1; 
 | 
  var oy = out[1] = y1 + t * dy1; 
 | 
  return Math.sqrt((ox - x) * (ox - x) + (oy - y) * (oy - y)); 
 | 
} 
 | 
function projectPointToRect(x1, y1, width, height, x, y, out) { 
 | 
  if (width < 0) { 
 | 
    x1 = x1 + width; 
 | 
    width = -width; 
 | 
  } 
 | 
  if (height < 0) { 
 | 
    y1 = y1 + height; 
 | 
    height = -height; 
 | 
  } 
 | 
  var x2 = x1 + width; 
 | 
  var y2 = y1 + height; 
 | 
  var ox = out[0] = Math.min(Math.max(x, x1), x2); 
 | 
  var oy = out[1] = Math.min(Math.max(y, y1), y2); 
 | 
  return Math.sqrt((ox - x) * (ox - x) + (oy - y) * (oy - y)); 
 | 
} 
 | 
var tmpPt = []; 
 | 
function nearestPointOnRect(pt, rect, out) { 
 | 
  var dist = projectPointToRect(rect.x, rect.y, rect.width, rect.height, pt.x, pt.y, tmpPt); 
 | 
  out.set(tmpPt[0], tmpPt[1]); 
 | 
  return dist; 
 | 
} 
 | 
/** 
 | 
 * Calculate min distance corresponding point. 
 | 
 * This method won't evaluate if point is in the path. 
 | 
 */ 
 | 
function nearestPointOnPath(pt, path, out) { 
 | 
  var xi = 0; 
 | 
  var yi = 0; 
 | 
  var x0 = 0; 
 | 
  var y0 = 0; 
 | 
  var x1; 
 | 
  var y1; 
 | 
  var minDist = Infinity; 
 | 
  var data = path.data; 
 | 
  var x = pt.x; 
 | 
  var y = pt.y; 
 | 
  for (var i = 0; i < data.length;) { 
 | 
    var cmd = data[i++]; 
 | 
    if (i === 1) { 
 | 
      xi = data[i]; 
 | 
      yi = data[i + 1]; 
 | 
      x0 = xi; 
 | 
      y0 = yi; 
 | 
    } 
 | 
    var d = minDist; 
 | 
    switch (cmd) { 
 | 
      case CMD.M: 
 | 
        // moveTo 命令重新创建一个新的 subpath, 并且更新新的起点 
 | 
        // 在 closePath 的时候使用 
 | 
        x0 = data[i++]; 
 | 
        y0 = data[i++]; 
 | 
        xi = x0; 
 | 
        yi = y0; 
 | 
        break; 
 | 
      case CMD.L: 
 | 
        d = projectPointToLine(xi, yi, data[i], data[i + 1], x, y, tmpPt, true); 
 | 
        xi = data[i++]; 
 | 
        yi = data[i++]; 
 | 
        break; 
 | 
      case CMD.C: 
 | 
        d = cubicProjectPoint(xi, yi, data[i++], data[i++], data[i++], data[i++], data[i], data[i + 1], x, y, tmpPt); 
 | 
        xi = data[i++]; 
 | 
        yi = data[i++]; 
 | 
        break; 
 | 
      case CMD.Q: 
 | 
        d = quadraticProjectPoint(xi, yi, data[i++], data[i++], data[i], data[i + 1], x, y, tmpPt); 
 | 
        xi = data[i++]; 
 | 
        yi = data[i++]; 
 | 
        break; 
 | 
      case CMD.A: 
 | 
        // TODO Arc 判断的开销比较大 
 | 
        var cx = data[i++]; 
 | 
        var cy = data[i++]; 
 | 
        var rx = data[i++]; 
 | 
        var ry = data[i++]; 
 | 
        var theta = data[i++]; 
 | 
        var dTheta = data[i++]; 
 | 
        // TODO Arc 旋转 
 | 
        i += 1; 
 | 
        var anticlockwise = !!(1 - data[i++]); 
 | 
        x1 = Math.cos(theta) * rx + cx; 
 | 
        y1 = Math.sin(theta) * ry + cy; 
 | 
        // 不是直接使用 arc 命令 
 | 
        if (i <= 1) { 
 | 
          // 第一个命令起点还未定义 
 | 
          x0 = x1; 
 | 
          y0 = y1; 
 | 
        } 
 | 
        // zr 使用scale来模拟椭圆, 这里也对x做一定的缩放 
 | 
        var _x = (x - cx) * ry / rx + cx; 
 | 
        d = projectPointToArc(cx, cy, ry, theta, theta + dTheta, anticlockwise, _x, y, tmpPt); 
 | 
        xi = Math.cos(theta + dTheta) * rx + cx; 
 | 
        yi = Math.sin(theta + dTheta) * ry + cy; 
 | 
        break; 
 | 
      case CMD.R: 
 | 
        x0 = xi = data[i++]; 
 | 
        y0 = yi = data[i++]; 
 | 
        var width = data[i++]; 
 | 
        var height = data[i++]; 
 | 
        d = projectPointToRect(x0, y0, width, height, x, y, tmpPt); 
 | 
        break; 
 | 
      case CMD.Z: 
 | 
        d = projectPointToLine(xi, yi, x0, y0, x, y, tmpPt, true); 
 | 
        xi = x0; 
 | 
        yi = y0; 
 | 
        break; 
 | 
    } 
 | 
    if (d < minDist) { 
 | 
      minDist = d; 
 | 
      out.set(tmpPt[0], tmpPt[1]); 
 | 
    } 
 | 
  } 
 | 
  return minDist; 
 | 
} 
 | 
// Temporal variable for intermediate usage. 
 | 
var pt0 = new Point(); 
 | 
var pt1 = new Point(); 
 | 
var pt2 = new Point(); 
 | 
var dir = new Point(); 
 | 
var dir2 = new Point(); 
 | 
/** 
 | 
 * Calculate a proper guide line based on the label position and graphic element definition 
 | 
 * @param label 
 | 
 * @param labelRect 
 | 
 * @param target 
 | 
 * @param targetRect 
 | 
 */ 
 | 
export function updateLabelLinePoints(target, labelLineModel) { 
 | 
  if (!target) { 
 | 
    return; 
 | 
  } 
 | 
  var labelLine = target.getTextGuideLine(); 
 | 
  var label = target.getTextContent(); 
 | 
  // Needs to create text guide in each charts. 
 | 
  if (!(label && labelLine)) { 
 | 
    return; 
 | 
  } 
 | 
  var labelGuideConfig = target.textGuideLineConfig || {}; 
 | 
  var points = [[0, 0], [0, 0], [0, 0]]; 
 | 
  var searchSpace = labelGuideConfig.candidates || DEFAULT_SEARCH_SPACE; 
 | 
  var labelRect = label.getBoundingRect().clone(); 
 | 
  labelRect.applyTransform(label.getComputedTransform()); 
 | 
  var minDist = Infinity; 
 | 
  var anchorPoint = labelGuideConfig.anchor; 
 | 
  var targetTransform = target.getComputedTransform(); 
 | 
  var targetInversedTransform = targetTransform && invert([], targetTransform); 
 | 
  var len = labelLineModel.get('length2') || 0; 
 | 
  if (anchorPoint) { 
 | 
    pt2.copy(anchorPoint); 
 | 
  } 
 | 
  for (var i = 0; i < searchSpace.length; i++) { 
 | 
    var candidate = searchSpace[i]; 
 | 
    getCandidateAnchor(candidate, 0, labelRect, pt0, dir); 
 | 
    Point.scaleAndAdd(pt1, pt0, dir, len); 
 | 
    // Transform to target coord space. 
 | 
    pt1.transform(targetInversedTransform); 
 | 
    // Note: getBoundingRect will ensure the `path` being created. 
 | 
    var boundingRect = target.getBoundingRect(); 
 | 
    var dist = anchorPoint ? anchorPoint.distance(pt1) : target instanceof Path ? nearestPointOnPath(pt1, target.path, pt2) : nearestPointOnRect(pt1, boundingRect, pt2); 
 | 
    // TODO pt2 is in the path 
 | 
    if (dist < minDist) { 
 | 
      minDist = dist; 
 | 
      // Transform back to global space. 
 | 
      pt1.transform(targetTransform); 
 | 
      pt2.transform(targetTransform); 
 | 
      pt2.toArray(points[0]); 
 | 
      pt1.toArray(points[1]); 
 | 
      pt0.toArray(points[2]); 
 | 
    } 
 | 
  } 
 | 
  limitTurnAngle(points, labelLineModel.get('minTurnAngle')); 
 | 
  labelLine.setShape({ 
 | 
    points: points 
 | 
  }); 
 | 
} 
 | 
// Temporal variable for the limitTurnAngle function 
 | 
var tmpArr = []; 
 | 
var tmpProjPoint = new Point(); 
 | 
/** 
 | 
 * Reduce the line segment attached to the label to limit the turn angle between two segments. 
 | 
 * @param linePoints 
 | 
 * @param minTurnAngle Radian of minimum turn angle. 0 - 180 
 | 
 */ 
 | 
export function limitTurnAngle(linePoints, minTurnAngle) { 
 | 
  if (!(minTurnAngle <= 180 && minTurnAngle > 0)) { 
 | 
    return; 
 | 
  } 
 | 
  minTurnAngle = minTurnAngle / 180 * Math.PI; 
 | 
  // The line points can be 
 | 
  //      /pt1----pt2 (label) 
 | 
  //     / 
 | 
  // pt0/ 
 | 
  pt0.fromArray(linePoints[0]); 
 | 
  pt1.fromArray(linePoints[1]); 
 | 
  pt2.fromArray(linePoints[2]); 
 | 
  Point.sub(dir, pt0, pt1); 
 | 
  Point.sub(dir2, pt2, pt1); 
 | 
  var len1 = dir.len(); 
 | 
  var len2 = dir2.len(); 
 | 
  if (len1 < 1e-3 || len2 < 1e-3) { 
 | 
    return; 
 | 
  } 
 | 
  dir.scale(1 / len1); 
 | 
  dir2.scale(1 / len2); 
 | 
  var angleCos = dir.dot(dir2); 
 | 
  var minTurnAngleCos = Math.cos(minTurnAngle); 
 | 
  if (minTurnAngleCos < angleCos) { 
 | 
    // Smaller than minTurnAngle 
 | 
    // Calculate project point of pt0 on pt1-pt2 
 | 
    var d = projectPointToLine(pt1.x, pt1.y, pt2.x, pt2.y, pt0.x, pt0.y, tmpArr, false); 
 | 
    tmpProjPoint.fromArray(tmpArr); 
 | 
    // Calculate new projected length with limited minTurnAngle and get the new connect point 
 | 
    tmpProjPoint.scaleAndAdd(dir2, d / Math.tan(Math.PI - minTurnAngle)); 
 | 
    // Limit the new calculated connect point between pt1 and pt2. 
 | 
    var t = pt2.x !== pt1.x ? (tmpProjPoint.x - pt1.x) / (pt2.x - pt1.x) : (tmpProjPoint.y - pt1.y) / (pt2.y - pt1.y); 
 | 
    if (isNaN(t)) { 
 | 
      return; 
 | 
    } 
 | 
    if (t < 0) { 
 | 
      Point.copy(tmpProjPoint, pt1); 
 | 
    } else if (t > 1) { 
 | 
      Point.copy(tmpProjPoint, pt2); 
 | 
    } 
 | 
    tmpProjPoint.toArray(linePoints[1]); 
 | 
  } 
 | 
} 
 | 
/** 
 | 
 * Limit the angle of line and the surface 
 | 
 * @param maxSurfaceAngle Radian of minimum turn angle. 0 - 180. 0 is same direction to normal. 180 is opposite 
 | 
 */ 
 | 
export function limitSurfaceAngle(linePoints, surfaceNormal, maxSurfaceAngle) { 
 | 
  if (!(maxSurfaceAngle <= 180 && maxSurfaceAngle > 0)) { 
 | 
    return; 
 | 
  } 
 | 
  maxSurfaceAngle = maxSurfaceAngle / 180 * Math.PI; 
 | 
  pt0.fromArray(linePoints[0]); 
 | 
  pt1.fromArray(linePoints[1]); 
 | 
  pt2.fromArray(linePoints[2]); 
 | 
  Point.sub(dir, pt1, pt0); 
 | 
  Point.sub(dir2, pt2, pt1); 
 | 
  var len1 = dir.len(); 
 | 
  var len2 = dir2.len(); 
 | 
  if (len1 < 1e-3 || len2 < 1e-3) { 
 | 
    return; 
 | 
  } 
 | 
  dir.scale(1 / len1); 
 | 
  dir2.scale(1 / len2); 
 | 
  var angleCos = dir.dot(surfaceNormal); 
 | 
  var maxSurfaceAngleCos = Math.cos(maxSurfaceAngle); 
 | 
  if (angleCos < maxSurfaceAngleCos) { 
 | 
    // Calculate project point of pt0 on pt1-pt2 
 | 
    var d = projectPointToLine(pt1.x, pt1.y, pt2.x, pt2.y, pt0.x, pt0.y, tmpArr, false); 
 | 
    tmpProjPoint.fromArray(tmpArr); 
 | 
    var HALF_PI = Math.PI / 2; 
 | 
    var angle2 = Math.acos(dir2.dot(surfaceNormal)); 
 | 
    var newAngle = HALF_PI + angle2 - maxSurfaceAngle; 
 | 
    if (newAngle >= HALF_PI) { 
 | 
      // parallel 
 | 
      Point.copy(tmpProjPoint, pt2); 
 | 
    } else { 
 | 
      // Calculate new projected length with limited minTurnAngle and get the new connect point 
 | 
      tmpProjPoint.scaleAndAdd(dir2, d / Math.tan(Math.PI / 2 - newAngle)); 
 | 
      // Limit the new calculated connect point between pt1 and pt2. 
 | 
      var t = pt2.x !== pt1.x ? (tmpProjPoint.x - pt1.x) / (pt2.x - pt1.x) : (tmpProjPoint.y - pt1.y) / (pt2.y - pt1.y); 
 | 
      if (isNaN(t)) { 
 | 
        return; 
 | 
      } 
 | 
      if (t < 0) { 
 | 
        Point.copy(tmpProjPoint, pt1); 
 | 
      } else if (t > 1) { 
 | 
        Point.copy(tmpProjPoint, pt2); 
 | 
      } 
 | 
    } 
 | 
    tmpProjPoint.toArray(linePoints[1]); 
 | 
  } 
 | 
} 
 | 
function setLabelLineState(labelLine, ignore, stateName, stateModel) { 
 | 
  var isNormal = stateName === 'normal'; 
 | 
  var stateObj = isNormal ? labelLine : labelLine.ensureState(stateName); 
 | 
  // Make sure display. 
 | 
  stateObj.ignore = ignore; 
 | 
  // Set smooth 
 | 
  var smooth = stateModel.get('smooth'); 
 | 
  if (smooth && smooth === true) { 
 | 
    smooth = 0.3; 
 | 
  } 
 | 
  stateObj.shape = stateObj.shape || {}; 
 | 
  if (smooth > 0) { 
 | 
    stateObj.shape.smooth = smooth; 
 | 
  } 
 | 
  var styleObj = stateModel.getModel('lineStyle').getLineStyle(); 
 | 
  isNormal ? labelLine.useStyle(styleObj) : stateObj.style = styleObj; 
 | 
} 
 | 
function buildLabelLinePath(path, shape) { 
 | 
  var smooth = shape.smooth; 
 | 
  var points = shape.points; 
 | 
  if (!points) { 
 | 
    return; 
 | 
  } 
 | 
  path.moveTo(points[0][0], points[0][1]); 
 | 
  if (smooth > 0 && points.length >= 3) { 
 | 
    var len1 = vector.dist(points[0], points[1]); 
 | 
    var len2 = vector.dist(points[1], points[2]); 
 | 
    if (!len1 || !len2) { 
 | 
      path.lineTo(points[1][0], points[1][1]); 
 | 
      path.lineTo(points[2][0], points[2][1]); 
 | 
      return; 
 | 
    } 
 | 
    var moveLen = Math.min(len1, len2) * smooth; 
 | 
    var midPoint0 = vector.lerp([], points[1], points[0], moveLen / len1); 
 | 
    var midPoint2 = vector.lerp([], points[1], points[2], moveLen / len2); 
 | 
    var midPoint1 = vector.lerp([], midPoint0, midPoint2, 0.5); 
 | 
    path.bezierCurveTo(midPoint0[0], midPoint0[1], midPoint0[0], midPoint0[1], midPoint1[0], midPoint1[1]); 
 | 
    path.bezierCurveTo(midPoint2[0], midPoint2[1], midPoint2[0], midPoint2[1], points[2][0], points[2][1]); 
 | 
  } else { 
 | 
    for (var i = 1; i < points.length; i++) { 
 | 
      path.lineTo(points[i][0], points[i][1]); 
 | 
    } 
 | 
  } 
 | 
} 
 | 
/** 
 | 
 * Create a label line if necessary and set it's style. 
 | 
 */ 
 | 
export function setLabelLineStyle(targetEl, statesModels, defaultStyle) { 
 | 
  var labelLine = targetEl.getTextGuideLine(); 
 | 
  var label = targetEl.getTextContent(); 
 | 
  if (!label) { 
 | 
    // Not show label line if there is no label. 
 | 
    if (labelLine) { 
 | 
      targetEl.removeTextGuideLine(); 
 | 
    } 
 | 
    return; 
 | 
  } 
 | 
  var normalModel = statesModels.normal; 
 | 
  var showNormal = normalModel.get('show'); 
 | 
  var labelIgnoreNormal = label.ignore; 
 | 
  for (var i = 0; i < DISPLAY_STATES.length; i++) { 
 | 
    var stateName = DISPLAY_STATES[i]; 
 | 
    var stateModel = statesModels[stateName]; 
 | 
    var isNormal = stateName === 'normal'; 
 | 
    if (stateModel) { 
 | 
      var stateShow = stateModel.get('show'); 
 | 
      var isLabelIgnored = isNormal ? labelIgnoreNormal : retrieve2(label.states[stateName] && label.states[stateName].ignore, labelIgnoreNormal); 
 | 
      if (isLabelIgnored // Not show when label is not shown in this state. 
 | 
      || !retrieve2(stateShow, showNormal) // Use normal state by default if not set. 
 | 
      ) { 
 | 
        var stateObj = isNormal ? labelLine : labelLine && labelLine.states[stateName]; 
 | 
        if (stateObj) { 
 | 
          stateObj.ignore = true; 
 | 
        } 
 | 
        if (!!labelLine) { 
 | 
          setLabelLineState(labelLine, true, stateName, stateModel); 
 | 
        } 
 | 
        continue; 
 | 
      } 
 | 
      // Create labelLine if not exists 
 | 
      if (!labelLine) { 
 | 
        labelLine = new Polyline(); 
 | 
        targetEl.setTextGuideLine(labelLine); 
 | 
        // Reset state of normal because it's new created. 
 | 
        // NOTE: NORMAL should always been the first! 
 | 
        if (!isNormal && (labelIgnoreNormal || !showNormal)) { 
 | 
          setLabelLineState(labelLine, true, 'normal', statesModels.normal); 
 | 
        } 
 | 
        // Use same state proxy. 
 | 
        if (targetEl.stateProxy) { 
 | 
          labelLine.stateProxy = targetEl.stateProxy; 
 | 
        } 
 | 
      } 
 | 
      setLabelLineState(labelLine, false, stateName, stateModel); 
 | 
    } 
 | 
  } 
 | 
  if (labelLine) { 
 | 
    defaults(labelLine.style, defaultStyle); 
 | 
    // Not fill. 
 | 
    labelLine.style.fill = null; 
 | 
    var showAbove = normalModel.get('showAbove'); 
 | 
    var labelLineConfig = targetEl.textGuideLineConfig = targetEl.textGuideLineConfig || {}; 
 | 
    labelLineConfig.showAbove = showAbove || false; 
 | 
    // Custom the buildPath. 
 | 
    labelLine.buildPath = buildLabelLinePath; 
 | 
  } 
 | 
} 
 | 
export function getLabelLineStatesModels(itemModel, labelLineName) { 
 | 
  labelLineName = labelLineName || 'labelLine'; 
 | 
  var statesModels = { 
 | 
    normal: itemModel.getModel(labelLineName) 
 | 
  }; 
 | 
  for (var i = 0; i < SPECIAL_STATES.length; i++) { 
 | 
    var stateName = SPECIAL_STATES[i]; 
 | 
    statesModels[stateName] = itemModel.getModel([stateName, labelLineName]); 
 | 
  } 
 | 
  return statesModels; 
 | 
} 
 |