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

ovilia pushed a commit to branch fix-pie-align
in repository https://gitbox.apache.org/repos/asf/incubator-echarts.git

commit 070f591ffb252bcc8e6b48ae03372b835f744060
Author: Ovilia <zwl.s...@gmail.com>
AuthorDate: Tue Nov 26 18:16:46 2019 +0800

    feat(pie): two new alignTo layouts
---
 src/chart/pie/PieSeries.js   |  15 ++-
 src/chart/pie/PieView.js     |   2 +-
 src/chart/pie/labelLayout.js | 134 ++++++++++++++++++----
 src/chart/pie/pieLayout.js   |  27 +++--
 test/pie-alignTo.html        | 262 +++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 409 insertions(+), 31 deletions(-)

diff --git a/src/chart/pie/PieSeries.js b/src/chart/pie/PieSeries.js
index 42a44e6..6844eec 100644
--- a/src/chart/pie/PieSeries.js
+++ b/src/chart/pie/PieSeries.js
@@ -142,12 +142,25 @@ var PieSeries = echarts.extendSeriesModel({
 
         // cursor: null,
 
+        left: 0,
+        top: 0,
+        right: 0,
+        bottom: 0,
+        width: null,
+        height: null,
+
         label: {
             // If rotate around circle
             rotate: false,
             show: true,
             // 'outer', 'inside', 'center'
-            position: 'outer'
+            position: 'outer',
+            // 'none', 'labelLine', 'edge'. Works only when position is 'outer'
+            alignTo: 'none',
+            // Closest distance between label and chart edge.
+            // Works only position is 'outer' and alignTo is 'labelLine' or 
'edge'.
+            margin: '25%',
+            padding: 5,
             // formatter: 标签文本格式器,同Tooltip.formatter,不支持异步回调
             // 默认使用全局文本样式,详见TEXTSTYLE
             // distance: 当position为inner时有效,为label位置到圆心的距离与圆半径(环状图为内外半径和)的比例系数
diff --git a/src/chart/pie/PieView.js b/src/chart/pie/PieView.js
index 69e6903..6df30b3 100644
--- a/src/chart/pie/PieView.js
+++ b/src/chart/pie/PieView.js
@@ -273,7 +273,7 @@ piePieceProto._updateLabel = function (data, idx, 
withAnimation) {
         {
             labelFetcher: data.hostModel,
             labelDataIndex: idx,
-            defaultText: data.getName(idx),
+            defaultText: labelLayout.text,
             autoColor: visualColor,
             useInsideStyle: !!labelLayout.inside
         },
diff --git a/src/chart/pie/labelLayout.js b/src/chart/pie/labelLayout.js
index f2492fe..67f1dac 100644
--- a/src/chart/pie/labelLayout.js
+++ b/src/chart/pie/labelLayout.js
@@ -20,16 +20,21 @@
 // FIXME emphasis label position is not same with normal label position
 
 import * as textContain from 'zrender/src/contain/text';
+import {parsePercent} from '../../util/number';
 
 var RADIAN = Math.PI / 180;
 
-function adjustSingleSide(list, cx, cy, r, dir, viewWidth, viewHeight) {
+function adjustSingleSide(list, cx, cy, r, dir, viewWidth, viewHeight, 
viewLeft, viewTop, farthestX) {
     list.sort(function (a, b) {
         return a.y - b.y;
     });
 
     function shiftDown(start, end, delta, dir) {
         for (var j = start; j < end; j++) {
+            if (list[j].y + delta > viewTop + viewHeight) {
+                break;
+            }
+
             list[j].y += delta;
             if (j > start
                 && j + 1 < end
@@ -45,6 +50,10 @@ function adjustSingleSide(list, cx, cy, r, dir, viewWidth, 
viewHeight) {
 
     function shiftUp(end, delta) {
         for (var j = end; j >= 0; j--) {
+            if (list[j].y - delta < viewTop) {
+                break;
+            }
+
             list[j].y -= delta;
             if (j > 0
                 && list[j].y > list[j - 1].y + list[j - 1].height
@@ -64,6 +73,10 @@ function adjustSingleSide(list, cx, cy, r, dir, viewWidth, 
viewHeight) {
                 : 0;                    // up
 
         for (var i = 0, l = list.length; i < l; i++) {
+            if (list[i].labelAlignTo !== 'none') {
+                continue;
+            }
+
             var deltaY = Math.abs(list[i].y - cy);
             var length = list[i].len;
             var length2 = list[i].len2;
@@ -93,6 +106,12 @@ function adjustSingleSide(list, cx, cy, r, dir, viewWidth, 
viewHeight) {
     var upList = [];
     var downList = [];
     for (var i = 0; i < len; i++) {
+        if (list[i].position === 'outer' && list[i].labelAlignTo === 
'labelLine') {
+            var dx = list[i].x - farthestX;
+            list[i].linePoints[1][0] += dx;
+            list[i].x = farthestX;
+        }
+
         delta = list[i].y - lastY;
         if (delta < 0) {
             shiftDown(i, len, -delta, dir);
@@ -114,39 +133,87 @@ function adjustSingleSide(list, cx, cy, r, dir, 
viewWidth, viewHeight) {
     changeX(downList, true, cx, cy, r, dir);
 }
 
-function avoidOverlap(labelLayoutList, cx, cy, r, viewWidth, viewHeight) {
+function avoidOverlap(labelLayoutList, cx, cy, r, viewWidth, viewHeight, 
viewLeft, viewTop) {
     var leftList = [];
     var rightList = [];
+    var leftmostX = Number.MAX_VALUE;
+    var rightmostX = -Number.MAX_VALUE;
     for (var i = 0; i < labelLayoutList.length; i++) {
         if (isPositionCenter(labelLayoutList[i])) {
             continue;
         }
         if (labelLayoutList[i].x < cx) {
+            leftmostX = Math.min(leftmostX, labelLayoutList[i].x);
             leftList.push(labelLayoutList[i]);
         }
         else {
+            rightmostX = Math.max(rightmostX, labelLayoutList[i].x);
             rightList.push(labelLayoutList[i]);
         }
     }
 
-    adjustSingleSide(rightList, cx, cy, r, 1, viewWidth, viewHeight);
-    adjustSingleSide(leftList, cx, cy, r, -1, viewWidth, viewHeight);
+    adjustSingleSide(rightList, cx, cy, r, 1, viewWidth, viewHeight, viewLeft, 
viewTop, rightmostX);
+    adjustSingleSide(leftList, cx, cy, r, -1, viewWidth, viewHeight, viewLeft, 
viewTop, leftmostX);
 
     for (var i = 0; i < labelLayoutList.length; i++) {
-        if (isPositionCenter(labelLayoutList[i])) {
+        var layout = labelLayoutList[i];
+        if (isPositionCenter(layout)) {
             continue;
         }
-        var linePoints = labelLayoutList[i].linePoints;
+
+        var linePoints = layout.linePoints;
         if (linePoints) {
+            var isAlignToEdge = layout.labelAlignTo === 'edge';
+
+            var realTextWidth = layout.textRect.width;
+            var targetTextWidth;
+            if (isAlignToEdge) {
+                // debugger;
+                // targetTextWidth = Math.abs(layout.x - linePoints[2][0]) - 
layout.labelPadding;
+                if (layout.x < cx) {
+                    targetTextWidth = linePoints[2][0] - layout.labelPadding - 
viewLeft - layout.labelMargin;
+                }
+                else {
+                    targetTextWidth = viewLeft + viewWidth - 
layout.labelMargin - linePoints[2][0] - layout.labelPadding;
+                }
+            }
+            else {
+                if (layout.x < cx) {
+                    targetTextWidth = layout.x - viewLeft - layout.labelMargin;
+                }
+                else {
+                    targetTextWidth = viewLeft + viewWidth - layout.x - 
layout.labelMargin;
+                }
+            }
+            if (targetTextWidth < layout.textRect.width) {
+                layout.text = textContain.truncateText(layout.text, 
targetTextWidth, layout.font);
+                if (layout.labelAlignTo === 'edge') {
+                    realTextWidth = textContain.getWidth(layout.text, 
layout.font);
+                }
+            }
+
             var dist = linePoints[1][0] - linePoints[2][0];
-            if (labelLayoutList[i].x < cx) {
-                linePoints[2][0] = labelLayoutList[i].x + 3;
+            if (isAlignToEdge) {
+                if (layout.x < cx) {
+                    linePoints[2][0] = viewLeft + layout.labelMargin + 
realTextWidth + layout.labelPadding;
+                }
+                else {
+                    linePoints[2][0] = viewLeft + viewWidth - 
layout.labelMargin
+                            - realTextWidth - layout.labelPadding;
+                }
             }
             else {
-                linePoints[2][0] = labelLayoutList[i].x - 3;
+                if (layout.x < cx) {
+                    linePoints[2][0] = layout.x + layout.labelPadding;
+                    layout.x += layout.labelPadding;
+                }
+                else {
+                    linePoints[2][0] = layout.x - layout.labelPadding;
+                    layout.x -= layout.labelPadding;
+                }
+                linePoints[1][0] = linePoints[2][0] + dist;
             }
-            linePoints[1][1] = linePoints[2][1] = labelLayoutList[i].y;
-            linePoints[1][0] = linePoints[2][0] + dist;
+            linePoints[1][1] = linePoints[2][1] = layout.y;
         }
     }
 }
@@ -156,7 +223,7 @@ function isPositionCenter(layout) {
     return layout.position === 'center';
 }
 
-export default function (seriesModel, r, viewWidth, viewHeight, sum) {
+export default function (seriesModel, r, viewWidth, viewHeight, viewLeft, 
viewTop) {
     var data = seriesModel.getData();
     var labelLayoutList = [];
     var cx;
@@ -171,10 +238,16 @@ export default function (seriesModel, r, viewWidth, 
viewHeight, sum) {
         var labelModel = itemModel.getModel('label');
         // Use position in normal or emphasis
         var labelPosition = labelModel.get('position') || 
itemModel.get('emphasis.label.position');
+        var labelPadding = labelModel.get('padding');
+        var labelAlignTo = labelModel.get('alignTo');
+        var labelMargin = parsePercent(labelModel.get('margin'), viewWidth);
+        var font = labelModel.getFont();
 
         var labelLineModel = itemModel.getModel('labelLine');
         var labelLineLen = labelLineModel.get('length');
+        labelLineLen = parsePercent(labelLineLen, viewWidth);
         var labelLineLen2 = labelLineModel.get('length2');
+        labelLineLen2 = parsePercent(labelLineLen2, viewWidth);
 
         if (layout.angle < minShowLabelRadian) {
             return;
@@ -192,6 +265,12 @@ export default function (seriesModel, r, viewWidth, 
viewHeight, sum) {
         cx = layout.cx;
         cy = layout.cy;
 
+        var text = seriesModel.getFormattedLabel(idx, 'normal')
+                || data.getName(idx);
+        var textRect = textContain.getBoundingRect(
+            text, font, textAlign, 'top'
+        );
+
         var isLabelInside = labelPosition === 'inside' || labelPosition === 
'inner';
         if (labelPosition === 'center') {
             textX = layout.cx;
@@ -212,14 +291,23 @@ export default function (seriesModel, r, viewWidth, 
viewHeight, sum) {
                 var x3 = x2 + ((dx < 0 ? -1 : 1) * labelLineLen2);
                 var y3 = y2;
 
-                textX = x3 + (dx < 0 ? -5 : 5);
+                if (labelAlignTo === 'edge') {
+                    // Adjust textX because text align of edge is opposite
+                    textX = dx < 0 ? viewLeft + labelMargin - labelPadding : 
viewLeft + viewWidth - labelMargin + labelPadding;
+                }
+                else {
+                    textX = x3 + (dx < 0 ? -labelPadding : labelPadding);
+                }
                 textY = y3;
                 linePoints = [[x1, y1], [x2, y2], [x3, y3]];
             }
 
-            textAlign = isLabelInside ? 'center' : (dx > 0 ? 'left' : 'right');
+            textAlign = isLabelInside
+                ? 'center'
+                : (labelAlignTo === 'edge'
+                    ? (dx > 0 ? 'right' : 'left')
+                    : (dx > 0 ? 'left' : 'right'));
         }
-        var font = labelModel.getFont();
 
         var labelRotate;
         var rotate = labelModel.get('rotate');
@@ -231,11 +319,7 @@ export default function (seriesModel, r, viewWidth, 
viewHeight, sum) {
                 ? (dx < 0 ? -midAngle + Math.PI : -midAngle)
                 : 0;
         }
-        var text = seriesModel.getFormattedLabel(idx, 'normal')
-                    || data.getName(idx);
-        var textRect = textContain.getBoundingRect(
-            text, font, textAlign, 'top'
-        );
+
         hasLabelRotate = !!labelRotate;
         layout.label = {
             x: textX,
@@ -248,7 +332,13 @@ export default function (seriesModel, r, viewWidth, 
viewHeight, sum) {
             textAlign: textAlign,
             verticalAlign: 'middle',
             rotation: labelRotate,
-            inside: isLabelInside
+            inside: isLabelInside,
+            labelPadding: labelPadding,
+            labelAlignTo: labelAlignTo,
+            labelMargin:labelMargin,
+            textRect: textRect,
+            text: text,
+            font: font
         };
 
         // Not layout the inside label
@@ -257,6 +347,6 @@ export default function (seriesModel, r, viewWidth, 
viewHeight, sum) {
         }
     });
     if (!hasLabelRotate && seriesModel.get('avoidLabelOverlap')) {
-        avoidOverlap(labelLayoutList, cx, cy, r, viewWidth, viewHeight);
+        avoidOverlap(labelLayoutList, cx, cy, r, viewWidth, viewHeight, 
viewLeft, viewTop);
     }
 }
\ No newline at end of file
diff --git a/src/chart/pie/pieLayout.js b/src/chart/pie/pieLayout.js
index e72c218..e8e25b6 100644
--- a/src/chart/pie/pieLayout.js
+++ b/src/chart/pie/pieLayout.js
@@ -19,16 +19,27 @@
 
 
 import {parsePercent, linearMap} from '../../util/number';
+import * as layout from '../../util/layout';
 import labelLayout from './labelLayout';
 import * as zrUtil from 'zrender/src/core/util';
 
 var PI2 = Math.PI * 2;
 var RADIAN = Math.PI / 180;
 
+export function getViewRect(seriesModel, api) {
+    return layout.getLayoutRect(
+        seriesModel.getBoxLayoutParams(), {
+            width: api.getWidth(),
+            height: api.getHeight()
+        }
+    );
+}
+
 export default function (seriesType, ecModel, api, payload) {
     ecModel.eachSeriesByType(seriesType, function (seriesModel) {
         var data = seriesModel.getData();
         var valueDim = data.mapDimension('value');
+        var viewRect = getViewRect(seriesModel, api);
 
         var center = seriesModel.get('center');
         var radius = seriesModel.get('radius');
@@ -40,11 +51,11 @@ export default function (seriesType, ecModel, api, payload) 
{
             center = [center, center];
         }
 
-        var width = api.getWidth();
-        var height = api.getHeight();
+        var width = parsePercent(viewRect.width, api.getWidth());
+        var height = parsePercent(viewRect.height, api.getHeight());
         var size = Math.min(width, height);
-        var cx = parsePercent(center[0], width);
-        var cy = parsePercent(center[1], height);
+        var cx = parsePercent(center[0], width) + viewRect.x;
+        var cy = parsePercent(center[1], height) + viewRect.y;
         var r0 = parsePercent(radius[0], size / 2);
         var r = parsePercent(radius[1], size / 2);
 
@@ -90,7 +101,8 @@ export default function (seriesType, ecModel, api, payload) {
                     r0: r0,
                     r: roseType
                         ? NaN
-                        : r
+                        : r,
+                    viewRect: viewRect
                 });
                 return;
             }
@@ -123,7 +135,8 @@ export default function (seriesType, ecModel, api, payload) 
{
                 r0: r0,
                 r: roseType
                     ? linearMap(value, extent, [r0, r])
-                    : r
+                    : r,
+                viewRect: viewRect
             });
 
             currentAngle = endAngle;
@@ -161,6 +174,6 @@ export default function (seriesType, ecModel, api, payload) 
{
             }
         }
 
-        labelLayout(seriesModel, r, width, height);
+        labelLayout(seriesModel, r, viewRect.width, viewRect.height, 
viewRect.x, viewRect.y);
     });
 }
\ No newline at end of file
diff --git a/test/pie-alignTo.html b/test/pie-alignTo.html
new file mode 100644
index 0000000..698cc6e
--- /dev/null
+++ b/test/pie-alignTo.html
@@ -0,0 +1,262 @@
+<!DOCTYPE html>
+<!--
+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.
+-->
+
+
+<html>
+    <head>
+        <meta charset="utf-8">
+        <meta name="viewport" content="width=device-width, initial-scale=1" />
+        <script src="lib/esl.js"></script>
+        <script src="lib/config.js"></script>
+        <script src="lib/jquery.min.js"></script>
+        <script src="lib/facePrint.js"></script>
+        <script src="lib/testHelper.js"></script>
+        <!-- <script src="ut/lib/canteen.js"></script> -->
+        <script src="lib/dat.gui.min.js"></script>
+        <link rel="stylesheet" href="lib/reset.css" />
+    </head>
+    <body>
+        <style>
+        </style>
+
+
+
+        <div id="main-none"></div>
+        <div id="main0"></div>
+        <div id="main1"></div>
+        <div id="main2"></div>
+
+
+
+
+
+
+
+
+        <script>
+        require(['echarts'], function (echarts) {
+            var count = 20;
+            var data = [];
+            var text = '';
+            for (var i = 0; i < count; i++) {
+                text += 'XY';
+                data.push({
+                    name: text + i,
+                    value: Math.random()
+                });
+            }
+
+            var optionNone = {
+                series: [{
+                    type: 'pie',
+                    radius: '50%',
+                    data: data,
+                    animation: false,
+                    labelLine: {
+                        length2: 15
+                    },
+                    label: {
+                        margin: 20,
+                        position: 'outer'
+                    }
+                }]
+            };
+
+            var option0 = {
+                series: [{
+                    type: 'pie',
+                    radius: '50%',
+                    data: data,
+                    animation: false,
+                    labelLine: {
+                        length2: 15
+                    },
+                    label: {
+                        margin: 20,
+                        position: 'outer',
+                        alignTo: 'labelLine'
+                    }
+                }]
+            };
+
+            var option1 = {
+                series: [{
+                    type: 'pie',
+                    radius: '50%',
+                    data: data,
+                    animation: false,
+                    labelLine: {
+                        length2: 15
+                    },
+                    label: {
+                        margin: 20,
+                        position: 'outer',
+                        alignTo: 'edge'
+                    }
+                }]
+            };
+
+            var option2 = {
+                series: [{
+                    type: 'pie',
+                    radius: '25%',
+                    center: ['50%', '50%'],
+                    data: data,
+                    animation: false,
+                    labelLine: {
+                        length2: 15
+                    },
+                    label: {
+                        position: 'outer',
+                        alignTo: 'edge'
+                    },
+                    left: 0,
+                    right: '50%',
+                    top: 0,
+                    bottom: '50%'
+                }, {
+                    type: 'pie',
+                    radius: '25%',
+                    center: ['50%', '50%'],
+                    data: data,
+                    animation: false,
+                    labelLine: {
+                        length2: 15
+                    },
+                    label: {
+                        margin: 20,
+                        position: 'outer',
+                        alignTo: 'labelLine'
+                    },
+                    left: '50%',
+                    right: 0,
+                    top: 0,
+                    bottom: '50%'
+                }, {
+                    type: 'pie',
+                    radius: '25%',
+                    center: ['50%', '50%'],
+                    data: data,
+                    animation: false,
+                    labelLine: {
+                        length2: 15
+                    },
+                    label: {
+                        position: 'outer',
+                        alignTo: 'edge'
+                    },
+                    left: 0,
+                    right: '50%',
+                    top: '50%',
+                    bottom: 0
+                }, {
+                    type: 'pie',
+                    radius: '25%',
+                    center: ['50%', '50%'],
+                    data: data,
+                    animation: false,
+                    labelLine: {
+                        length2: 15
+                    },
+                    label: {
+                        margin: 20,
+                        position: 'outer',
+                        alignTo: 'labelLine'
+                    },
+                    left: '50%',
+                    right: 0,
+                    top: '50%',
+                    bottom: 0
+                }]
+            };
+
+            var chartNone = testHelper.create(echarts, 'main-none', {
+                title: 'alignTo: "none"',
+                option: optionNone
+            });
+
+            var chart0 = testHelper.create(echarts, 'main0', {
+                title: 'alignTo: "labelLine"',
+                option: option0
+            });
+
+            var chart1 = testHelper.create(echarts, 'main1', {
+                title: 'alignTo: "edge"',
+                option: option1
+            });
+
+            var chart2 = testHelper.create(echarts, 'main2', {
+                title: 'Multiple charts',
+                option: option2
+            });
+
+            var gui = new dat.GUI({
+            });
+            var config = {
+                length2: 15,
+                margin: 20
+            };
+
+            gui
+                .add(config, 'length2', 0, 300)
+                .onChange(function (value) {
+                    option0.series[0].labelLine.length2 = value;
+                    option1.series[0].labelLine.length2 = value;
+                    optionNone.series[0].labelLine.length2 = value;
+                    chart0.setOption(option0);
+                    chart1.setOption(option1);
+                    chartNone.setOption(optionNone);
+
+                    for (var i = 0; i < 4; ++i) {
+                        option2.series[i].labelLine.length2 = value;
+                    }
+                    chart2.setOption(option2);
+                });
+
+            gui
+                .add(config, 'margin', 0, 300)
+                .onChange(function (value) {
+                    option0.series[0].label.margin = value;
+                    option1.series[0].label.margin = value;
+                    optionNone.series[0].label.margin = value;
+                    chart0.setOption(option0);
+                    chart1.setOption(option1);
+                    chartNone.setOption(optionNone);
+
+                    for (var i = 0; i < 4; ++i) {
+                        option2.series[i].label.margin = value;
+                    }
+                    chart2.setOption(option2);
+                });
+            });
+
+            window.onresize = function () {
+                if (chart0) {
+                    chart0.resize();
+                    chart1.resize();
+                    chart2.resize();
+                }
+            };
+        </script>
+
+
+    </body>
+</html>
+


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

Reply via email to