You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@echarts.apache.org by sh...@apache.org on 2020/06/02 06:24:50 UTC

[incubator-echarts] branch label-enhancement updated: feat: add minTurnAngle in labelLine

This is an automated email from the ASF dual-hosted git repository.

shenyi pushed a commit to branch label-enhancement
in repository https://gitbox.apache.org/repos/asf/incubator-echarts.git


The following commit(s) were added to refs/heads/label-enhancement by this push:
     new d8b1f1c  feat: add minTurnAngle in labelLine
d8b1f1c is described below

commit d8b1f1cc5e27b89cfaed54dd88a93809ea989479
Author: pissang <bm...@gmail.com>
AuthorDate: Tue Jun 2 14:24:08 2020 +0800

    feat: add minTurnAngle in labelLine
---
 src/chart/pie/PieSeries.ts    |  1 +
 src/chart/pie/PieView.ts      |  2 +-
 src/chart/pie/labelLayout.ts  | 10 ++++-
 src/label/LabelManager.ts     |  3 +-
 src/label/labelGuideHelper.ts | 91 +++++++++++++++++++++++++++++++++++++++----
 src/util/types.ts             |  3 ++
 6 files changed, 99 insertions(+), 11 deletions(-)

diff --git a/src/chart/pie/PieSeries.ts b/src/chart/pie/PieSeries.ts
index 8e86ed9..e5c398b 100644
--- a/src/chart/pie/PieSeries.ts
+++ b/src/chart/pie/PieSeries.ts
@@ -272,6 +272,7 @@ class PieSeriesModel extends SeriesModel<PieSeriesOption> {
             // 引导线两段中的第二段长度
             length2: 15,
             smooth: false,
+            minTurnAngle: 100,
             lineStyle: {
                 // color: 各异,
                 width: 1,
diff --git a/src/chart/pie/PieView.ts b/src/chart/pie/PieView.ts
index f52c6f7..6241d52 100644
--- a/src/chart/pie/PieView.ts
+++ b/src/chart/pie/PieView.ts
@@ -224,7 +224,7 @@ class PiePiece extends graphic.Sector {
 
         let smooth = labelLineModel.get('smooth');
         if (smooth && smooth === true) {
-            smooth = 0.4;
+            smooth = 0.3;
         }
         labelLine.setShape({
             smooth: smooth as number
diff --git a/src/chart/pie/labelLayout.ts b/src/chart/pie/labelLayout.ts
index ec057ec..693008d 100644
--- a/src/chart/pie/labelLayout.ts
+++ b/src/chart/pie/labelLayout.ts
@@ -26,6 +26,7 @@ import { Sector, Polyline } from '../../util/graphic';
 import ZRText from 'zrender/src/graphic/Text';
 import { RectLike } from 'zrender/src/core/BoundingRect';
 import { each } from 'zrender/src/core/util';
+import { limitTurnAngle } from '../../label/labelGuideHelper';
 
 const RADIAN = Math.PI / 180;
 
@@ -37,6 +38,7 @@ interface LabelLayout {
     position: PieSeriesOption['label']['position'],
     len: number
     len2: number
+    minTurnAngle: number
     linePoints: VectorArray[]
     textAlign: HorizontalAlign
     rotation: number,
@@ -411,6 +413,7 @@ export default function (
                 position: labelPosition,
                 len: labelLineLen,
                 len2: labelLineLen2,
+                minTurnAngle: labelLineModel.get('minTurnAngle'),
                 linePoints: linePoints,
                 textAlign: textAlign,
                 rotation: labelRotate,
@@ -463,11 +466,14 @@ export default function (
             }
         }
         if (labelLine) {
-            labelLine.setShape({ points: layout.linePoints });
-            if (notShowLabel) {
+            if (notShowLabel || !layout.linePoints) {
                 each(labelLine.states, setNotShow);
                 labelLine.ignore = true;
             }
+            else {
+                limitTurnAngle(layout.linePoints, layout.minTurnAngle);
+                labelLine.setShape({ points: layout.linePoints });
+            }
         }
     }
 }
\ No newline at end of file
diff --git a/src/label/LabelManager.ts b/src/label/LabelManager.ts
index 3cbdef5..d3cdfc5 100644
--- a/src/label/LabelManager.ts
+++ b/src/label/LabelManager.ts
@@ -397,7 +397,8 @@ class LabelManager {
                 label,
                 globalRect,
                 label.__hostTarget,
-                labelItem.hostRect
+                labelItem.hostRect,
+                labelItem.seriesModel.getModel(['labelLine'])
             );
         }
     }
diff --git a/src/label/labelGuideHelper.ts b/src/label/labelGuideHelper.ts
index da4848b..ddeba60 100644
--- a/src/label/labelGuideHelper.ts
+++ b/src/label/labelGuideHelper.ts
@@ -27,6 +27,8 @@ import { RectLike } from 'zrender/src/core/BoundingRect';
 import { normalizeRadian } from 'zrender/src/contain/util';
 import { cubicProjectPoint, quadraticProjectPoint } from 'zrender/src/core/curve';
 import Element from 'zrender/src/Element';
+import { LabelGuideLineOption } from '../util/types';
+import Model from '../model/Model';
 
 const PI2 = Math.PI * 2;
 const CMD = PathProxy.CMD;
@@ -144,7 +146,9 @@ function projectPointToArc(
     }
 }
 
-function projectPointToLine(x1: number, y1: number, x2: number, y2: number, x: number, y: number, out: number[]) {
+function projectPointToLine(
+    x1: number, y1: number, x2: number, y2: number, x: number, y: number, out: number[], limitToEnds: boolean
+) {
     const dx = x - x1;
     const dy = y - y1;
 
@@ -157,7 +161,11 @@ function projectPointToLine(x1: number, y1: number, x2: number, y2: number, x: n
 
     // dot product
     const projectedLen = dx * dx1 + dy * dy1;
-    const t = Math.min(Math.max(projectedLen / lineLen, 0), 1);
+    let t = projectedLen / lineLen;
+    if (limitToEnds) {
+        t = Math.min(Math.max(t, 0), 1);
+    }
+    t *= lineLen;
     const ox = out[0] = x1 + t * dx1;
     const oy = out[1] = y1 + t * dy1;
 
@@ -234,7 +242,7 @@ function nearestPointOnPath(pt: Point, path: PathProxy, out: Point) {
                 yi = y0;
                 break;
             case CMD.L:
-                d = projectPointToLine(xi, yi, data[i], data[i + 1], x, y, tmpPt);
+                d = projectPointToLine(xi, yi, data[i], data[i + 1], x, y, tmpPt, true);
                 xi = data[i++];
                 yi = data[i++];
                 break;
@@ -293,7 +301,7 @@ function nearestPointOnPath(pt: Point, path: PathProxy, out: Point) {
                 d = projectPointToRect(x0, y0, width, height, x, y, tmpPt);
                 break;
             case CMD.Z:
-                d = projectPointToLine(xi, yi, x0, y0, x, y, tmpPt);
+                d = projectPointToLine(xi, yi, x0, y0, x, y, tmpPt, true);
 
                 xi = x0;
                 yi = y0;
@@ -309,15 +317,26 @@ function nearestPointOnPath(pt: Point, path: PathProxy, out: Point) {
     return minDist;
 }
 
+// Temporal varible for intermediate usage.
 const pt0 = new Point();
 const pt1 = new Point();
 const pt2 = new Point();
 const dir = new Point();
+const 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 updateLabelGuideLine(
     label: ZRText,
     labelRect: RectLike,
     target: Element,
-    targetRect: RectLike
+    targetRect: RectLike,
+    labelLineModel: Model<LabelGuideLineOption>
 ) {
     if (!target) {
         return;
@@ -356,11 +375,69 @@ export function updateLabelGuideLine(
         // TODO pt2 is in the path
         if (dist < minDist) {
             minDist = dist;
-            pt0.toArray(points[0]);
+            pt2.toArray(points[0]);
             pt1.toArray(points[1]);
-            pt2.toArray(points[2]);
+            pt0.toArray(points[2]);
         }
     }
 
+    limitTurnAngle(points, labelLineModel.get('minTurnAngle'));
+
     labelLine.setShape({ points });
+}
+
+// Temporal variable for the limitTurnAngle function
+const tmpArr: number[] = [];
+const 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: number[][], minTurnAngle: number) {
+    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);
+
+    const len1 = dir.len();
+    const len2 = dir2.len();
+    if (len1 < 1e-3 || len2 < 1e-3) {
+        return;
+    }
+
+    dir.scale(1 / len1);
+    dir2.scale(1 / len2);
+
+    const angleCos = dir.dot(dir2);
+    const minTurnAngleCos = Math.cos(minTurnAngle);
+    if (minTurnAngleCos < angleCos) {    // Smaller than minTurnAngle
+        // Calculate project point of pt0 on pt1-pt2
+        const 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.
+        const t = pt2.x !== pt1.x
+            ? (tmpProjPoint.x - pt1.x) / (pt2.x - pt1.x)
+            : (tmpProjPoint.y - pt1.y) / (pt2.y - pt1.y);
+        if (t < 0) {
+            Point.copy(tmpProjPoint, pt1);
+        }
+        else if (t > 1) {
+            Point.copy(tmpProjPoint, pt2);
+        }
+
+        tmpProjPoint.toArray(linePoints[1]);
+    }
 }
\ No newline at end of file
diff --git a/src/util/types.ts b/src/util/types.ts
index f0eaac1..96a82ad 100644
--- a/src/util/types.ts
+++ b/src/util/types.ts
@@ -804,6 +804,7 @@ export interface LabelGuideLineOption {
     length?: number
     length2?: number
     smooth?: boolean | number
+    minTurnAngle?: number,
     lineStyle?: LineStyleOption
 }
 
@@ -1132,6 +1133,8 @@ export interface SeriesOption extends
      */
     labelLayout?: LabelLayoutOption | LabelLayoutOptionCallback
 
+    labelLine?: LabelGuideLineOption
+
     /**
      * Animation config for state transition.
      */


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@echarts.apache.org
For additional commands, e-mail: commits-help@echarts.apache.org