提交 849b8038 编写于 作者: O Ovilia

feat(pie): two new alignTo layouts

上级 b6732792
......@@ -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位置到圆心的距离与圆半径(环状图为内外半径和)的比例系数
......
......@@ -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
},
......
......@@ -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
......@@ -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
<!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>
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册