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/01 05:18:39 UTC

[incubator-echarts] branch label-enhancement updated (c11498d -> 5accd25)

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

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


    from c11498d  refact: layout label after render in pie.
     new 4062b9f  feat: support state transition in geo component
     new 5accd25  feat(pie): improve the shape of label layout

The 2 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 src/chart/pie/labelLayout.ts | 130 ++++++++++++++++++++++++-------------------
 src/coord/geo/GeoModel.ts    |   5 +-
 src/echarts.ts               |  13 +++--
 3 files changed, 87 insertions(+), 61 deletions(-)


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


[incubator-echarts] 02/02: feat(pie): improve the shape of label layout

Posted by sh...@apache.org.
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

commit 5accd257d0e77f069c37e826927be7870e0f96f3
Author: pissang <bm...@gmail.com>
AuthorDate: Mon Jun 1 13:17:51 2020 +0800

    feat(pie): improve the shape of label layout
---
 src/chart/pie/labelLayout.ts | 130 ++++++++++++++++++++++++-------------------
 1 file changed, 74 insertions(+), 56 deletions(-)

diff --git a/src/chart/pie/labelLayout.ts b/src/chart/pie/labelLayout.ts
index 90c53e5..ec057ec 100644
--- a/src/chart/pie/labelLayout.ts
+++ b/src/chart/pie/labelLayout.ts
@@ -25,7 +25,6 @@ import { HorizontalAlign, VerticalAlign, ZRRectLike, ZRTextAlign } from '../../u
 import { Sector, Polyline } from '../../util/graphic';
 import ZRText from 'zrender/src/graphic/Text';
 import { RectLike } from 'zrender/src/core/BoundingRect';
-import Displayable from 'zrender/src/graphic/Displayable';
 import { each } from 'zrender/src/core/util';
 
 const RADIAN = Math.PI / 180;
@@ -40,7 +39,6 @@ interface LabelLayout {
     len2: number
     linePoints: VectorArray[]
     textAlign: HorizontalAlign
-    verticalAlign: VerticalAlign,
     rotation: number,
     labelDistance: number,
     labelAlignTo: PieSeriesOption['label']['alignTo'],
@@ -65,13 +63,17 @@ function adjustSingleSide(
         return a.y - b.y;
     });
 
+    let adjusted = false;
+
     function shiftDown(start: number, end: number, delta: number, dir: number) {
         for (let j = start; j < end; j++) {
-            if (list[j].y + delta > viewTop + viewHeight) {
+            if (list[j].y + delta + list[j].textRect.height / 2 > viewTop + viewHeight) {
                 break;
             }
 
             list[j].y += delta;
+            adjusted = true;
+
             if (j > start
                 && j + 1 < end
                 && list[j + 1].y > list[j].y + list[j].textRect.height
@@ -86,11 +88,13 @@ function adjustSingleSide(
 
     function shiftUp(end: number, delta: number) {
         for (let j = end; j >= 0; j--) {
-            if (list[j].y - delta < viewTop) {
+            if (list[j].y - delta - list[j].textRect.height / 2 < viewTop) {
                 break;
             }
 
             list[j].y -= delta;
+            adjusted = true;
+
             if (j > 0
                 && list[j].y > list[j - 1].y + list[j - 1].textRect.height
             ) {
@@ -99,52 +103,61 @@ function adjustSingleSide(
         }
     }
 
-    function changeX(
-        list: LabelLayout[], isDownList: boolean,
-        cx: number, cy: number, r: number,
-        dir: 1 | -1
-    ) {
-        let lastDeltaX = dir > 0
-            ? isDownList                // right-side
-                ? Number.MAX_VALUE      // down
-                : 0                     // up
-            : isDownList                // left-side
-                ? Number.MAX_VALUE      // down
-                : 0;                    // up
-
-        for (let i = 0, l = list.length; i < l; i++) {
-            if (list[i].labelAlignTo !== 'none') {
-                continue;
-            }
+    interface SemiInfo {
+        list: LabelLayout[]
+        rB: number
+        maxY: number
+    };
+
+    function recalculateXOnSemiToAlignOnEllipseCurve(semi: SemiInfo) {
+        const rB = semi.rB;
+        const rB2 = rB * rB;
+        for (let i = 0; i < semi.list.length; i++) {
+            const item = semi.list[i];
+            const dy = Math.abs(item.y - cy);
+            // horizontal r is always same with original r because x is not changed.
+            const rA = r + item.len;
+            const rA2 = rA * rA;
+            // Use ellipse implicit function to calculate x
+            const dx = Math.sqrt((1 - Math.abs(dy * dy / rB2)) * rA2);
+            item.x = cx + (dx + item.len2) * dir;
+        }
+    }
 
-            const deltaY = Math.abs(list[i].y - cy);
-            const length = list[i].len;
-            const length2 = list[i].len2;
-            let deltaX = (deltaY < r + length)
-                ? Math.sqrt(
-                        (r + length + length2) * (r + length + length2)
-                        - deltaY * deltaY
-                    )
-                : Math.abs(list[i].x - cx);
-            if (isDownList && deltaX >= lastDeltaX) {
-                // right-down, left-down
-                deltaX = lastDeltaX - 10;
+    // Adjust X based on the shifted y. Make tight labels aligned on an ellipse curve.
+    function recalculateX(items: LabelLayout[]) {
+        // Extremes of
+        const topSemi = { list: [], maxY: 0} as SemiInfo;
+        const bottomSemi = { list: [], maxY: 0 } as SemiInfo;
+
+        for (let i = 0; i < items.length; i++) {
+            if (items[i].labelAlignTo !== 'none') {
+                continue;
             }
-            if (!isDownList && deltaX <= lastDeltaX) {
-                // right-up, left-up
-                deltaX = lastDeltaX + 10;
+            const item = items[i];
+            const semi = item.y > cy ? bottomSemi : topSemi;
+            const dy = Math.abs(item.y - cy);
+            if (dy > semi.maxY) {
+                const dx = item.x - cx - item.len2 * dir;
+                // horizontal r is always same with original r because x is not changed.
+                const rA = r + item.len;
+                // Canculate rB based on the topest / bottemest label.
+                const rB = dx < rA
+                    ? Math.sqrt(dy * dy / (1 - dx * dx / rA / rA))
+                    : rA;
+                semi.rB = rB;
+                semi.maxY = dy;
             }
-
-            list[i].x = cx + deltaX * dir;
-            lastDeltaX = deltaX;
+            semi.list.push(item);
         }
+
+        recalculateXOnSemiToAlignOnEllipseCurve(topSemi);
+        recalculateXOnSemiToAlignOnEllipseCurve(bottomSemi);
     }
 
     let lastY = 0;
     let delta;
     const len = list.length;
-    const upList = [];
-    const downList = [];
     for (let i = 0; i < len; i++) {
         if (list[i].position === 'outer' && list[i].labelAlignTo === 'labelLine') {
             const dx = list[i].x - farthestX;
@@ -161,16 +174,10 @@ function adjustSingleSide(
     if (viewHeight - lastY < 0) {
         shiftUp(len - 1, lastY - viewHeight);
     }
-    for (let i = 0; i < len; i++) {
-        if (list[i].y >= cy) {
-            downList.push(list[i]);
-        }
-        else {
-            upList.push(list[i]);
-        }
+
+    if (adjusted) {
+        recalculateX(list);
     }
-    changeX(upList, false, cx, cy, r, dir);
-    changeX(downList, true, cx, cy, r, dir);
 }
 
 function avoidOverlap(
@@ -291,6 +298,10 @@ export default function (
     const viewTop = viewRect.y;
     const viewHeight = viewRect.height;
 
+    function setNotShow(el: {ignore: boolean}) {
+        el.ignore = true;
+    }
+
     data.each(function (idx) {
         const sector = data.getItemGraphicEl(idx) as Sector;
         const sectorShape = sector.shape;
@@ -313,6 +324,8 @@ export default function (
         labelLineLen2 = parsePercent(labelLineLen2, viewWidth);
 
         if (Math.abs(sectorShape.endAngle - sectorShape.startAngle) < minShowLabelRadian) {
+            each(label.states, setNotShow);
+            label.ignore = true;
             return;
         }
 
@@ -400,7 +413,6 @@ export default function (
                 len2: labelLineLen2,
                 linePoints: linePoints,
                 textAlign: textAlign,
-                verticalAlign: 'middle',
                 rotation: labelRotate,
                 labelDistance: labelDistance,
                 labelAlignTo: labelAlignTo,
@@ -409,6 +421,15 @@ export default function (
                 textRect: textRect
             });
         }
+        else {
+            label.x = textX;
+            label.y = textY;
+            label.rotation = labelRotate;
+            label.setStyle({
+                align: textAlign,
+                verticalAlign: 'middle'
+            });
+        }
         sector.setTextConfig({
             inside: isLabelInside
         });
@@ -418,10 +439,6 @@ export default function (
         avoidOverlap(labelLayoutList, cx, cy, r, viewWidth, viewHeight, viewLeft, viewTop);
     }
 
-    function setNotShow(el: {ignore: boolean}) {
-        el.ignore = true;
-    }
-
     for (let i = 0; i < labelLayoutList.length; i++) {
         const layout = labelLayoutList[i];
         const label = layout.label;
@@ -430,9 +447,10 @@ export default function (
         if (label) {
             label.x = layout.x;
             label.y = layout.y;
+            label.rotation = layout.rotation;
             label.setStyle({
                 align: layout.textAlign,
-                verticalAlign: layout.verticalAlign
+                verticalAlign: 'middle'
             });
             if (notShowLabel) {
                 each(label.states, setNotShow);


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


[incubator-echarts] 01/02: feat: support state transition in geo component

Posted by sh...@apache.org.
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

commit 4062b9f55960447eb66053dfceaf3e7c7307bf4d
Author: pissang <bm...@gmail.com>
AuthorDate: Fri May 29 09:45:34 2020 +0800

    feat: support state transition in geo component
---
 src/coord/geo/GeoModel.ts |  5 ++++-
 src/echarts.ts            | 13 +++++++++----
 2 files changed, 13 insertions(+), 5 deletions(-)

diff --git a/src/coord/geo/GeoModel.ts b/src/coord/geo/GeoModel.ts
index 6c8dee3..5cd4827 100644
--- a/src/coord/geo/GeoModel.ts
+++ b/src/coord/geo/GeoModel.ts
@@ -32,7 +32,8 @@ import {
     ZRColor,
     LabelOption,
     DisplayState,
-    RoamOptionMixin
+    RoamOptionMixin,
+    AnimationOption
 } from '../../util/types';
 import { NameMap } from './geoTypes';
 import GlobalModel from '../../model/Global';
@@ -98,6 +99,8 @@ export interface GeoOption extends
     };
 
     regions: RegoinOption[];
+
+    stateAnimation?: AnimationOption
 }
 
 const LABEL_FORMATTER_NORMAL = ['label', 'formatter'] as const;
diff --git a/src/echarts.ts b/src/echarts.ts
index 3a68ce7..485e058 100644
--- a/src/echarts.ts
+++ b/src/echarts.ts
@@ -1670,9 +1670,14 @@ class ECharts extends Eventful {
                 const componentModel = componentView.__model;
                 componentView.render(componentModel, ecModel, api, payload);
 
+                clearStates(componentModel, componentView);
+
                 updateZ(componentModel, componentView);
                 updateHoverEmphasisHandler(componentView);
+
+                updateStates(componentModel, componentView);
             });
+
         };
 
         /**
@@ -1827,7 +1832,7 @@ class ECharts extends Eventful {
         };
         // Clear states without animation.
         // TODO States on component.
-        function clearStates(seriesModel: SeriesModel, view: ChartView): void {
+        function clearStates(model: ComponentModel, view: ComponentView | ChartView): void {
             view.group.traverse(function (el: Displayable) {
                 // TODO If el is incremental.
                 if (el.hasState()) {
@@ -1848,9 +1853,9 @@ class ECharts extends Eventful {
             });
         }
 
-        function updateStates(seriesModel: SeriesModel, view: ChartView): void {
-            const stateAnimationModel = seriesModel.getModel('stateAnimation');
-            const enableAnimation = seriesModel.isAnimationEnabled();
+        function updateStates(model: ComponentModel, view: ComponentView | ChartView): void {
+            const stateAnimationModel = (model as SeriesModel).getModel('stateAnimation');
+            const enableAnimation = model.isAnimationEnabled();
             view.group.traverse(function (el: Displayable) {
                 // Only updated on changed element. In case element is incremental and don't wan't to rerender.
                 if (el.__dirty && el.states && el.states.emphasis) {


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