提交 c003487f 编写于 作者: P pissang

feat(label): add maxSurfaceAngle limit in pie

上级 bf6c1441
......@@ -51,18 +51,26 @@ interface PieLabelOption extends Omit<LabelOption, 'rotate' | 'position'> {
position?: LabelOption['position'] | 'outer' | 'inner' | 'center'
}
interface PieLabelLineOption extends LabelLineOption {
/**
* Max angle between labelLine and surface normal.
* 0 - 180
*/
maxSurfaceAngle?: number
}
export interface PieDataItemOption extends
OptionDataItemObject<OptionDataValueNumeric>,
SelectableTarget {
itemStyle?: ItemStyleOption
label?: PieLabelOption
labelLine?: LabelLineOption
labelLine?: PieLabelLineOption
emphasis?: {
itemStyle?: ItemStyleOption
label?: PieLabelOption
labelLine?: LabelLineOption
labelLine?: PieLabelLineOption
}
}
export interface PieSeriesOption extends
......@@ -81,7 +89,7 @@ export interface PieSeriesOption extends
// TODO: TYPE Color Callback
itemStyle?: ItemStyleOption
label?: PieLabelOption
labelLine?: LabelLineOption
labelLine?: PieLabelLineOption
clockwise?: boolean
startAngle?: number
......@@ -99,7 +107,7 @@ export interface PieSeriesOption extends
emphasis?: {
itemStyle?: ItemStyleOption
label?: PieLabelOption
labelLine?: LabelLineOption
labelLine?: PieLabelLineOption
}
animationType?: 'expansion' | 'scale'
......@@ -272,7 +280,8 @@ class PieSeriesModel extends SeriesModel<PieSeriesOption> {
// 引导线两段中的第二段长度
length2: 15,
smooth: false,
minTurnAngle: 100,
minTurnAngle: 90,
maxSurfaceAngle: 90,
lineStyle: {
// color: 各异,
width: 1,
......
......@@ -26,7 +26,7 @@ import { Sector, Polyline, Point } from '../../util/graphic';
import ZRText from 'zrender/src/graphic/Text';
import BoundingRect, {RectLike} from 'zrender/src/core/BoundingRect';
import { each } from 'zrender/src/core/util';
import { limitTurnAngle } from '../../label/labelGuideHelper';
import { limitTurnAngle, limitSurfaceAngle } from '../../label/labelGuideHelper';
import { shiftLayoutOnY } from '../../label/labelLayoutHelper';
const RADIAN = Math.PI / 180;
......@@ -38,6 +38,8 @@ interface LabelLayout {
len: number
len2: number
minTurnAngle: number
maxSurfaceAngle: number
surfaceNormal: Point
linePoints: VectorArray[]
textAlign: HorizontalAlign
labelDistance: number,
......@@ -281,8 +283,8 @@ export default function (
}
const midAngle = (sectorShape.startAngle + sectorShape.endAngle) / 2;
const dx = Math.cos(midAngle);
const dy = Math.sin(midAngle);
const nx = Math.cos(midAngle);
const ny = Math.sin(midAngle);
let textX;
let textY;
......@@ -300,27 +302,27 @@ export default function (
textAlign = 'center';
}
else {
const x1 = (isLabelInside ? (sectorShape.r + sectorShape.r0) / 2 * dx : sectorShape.r * dx) + cx;
const y1 = (isLabelInside ? (sectorShape.r + sectorShape.r0) / 2 * dy : sectorShape.r * dy) + cy;
const x1 = (isLabelInside ? (sectorShape.r + sectorShape.r0) / 2 * nx : sectorShape.r * nx) + cx;
const y1 = (isLabelInside ? (sectorShape.r + sectorShape.r0) / 2 * ny : sectorShape.r * ny) + cy;
textX = x1 + dx * 3;
textY = y1 + dy * 3;
textX = x1 + nx * 3;
textY = y1 + ny * 3;
if (!isLabelInside) {
// For roseType
const x2 = x1 + dx * (labelLineLen + r - sectorShape.r);
const y2 = y1 + dy * (labelLineLen + r - sectorShape.r);
const x3 = x2 + ((dx < 0 ? -1 : 1) * labelLineLen2);
const x2 = x1 + nx * (labelLineLen + r - sectorShape.r);
const y2 = y1 + ny * (labelLineLen + r - sectorShape.r);
const x3 = x2 + ((nx < 0 ? -1 : 1) * labelLineLen2);
const y3 = y2;
if (labelAlignTo === 'edge') {
// Adjust textX because text align of edge is opposite
textX = dx < 0
textX = nx < 0
? viewLeft + edgeDistance
: viewLeft + viewWidth - edgeDistance;
}
else {
textX = x3 + (dx < 0 ? -labelDistance : labelDistance);
textX = x3 + (nx < 0 ? -labelDistance : labelDistance);
}
textY = y3;
linePoints = [[x1, y1], [x2, y2], [x3, y3]];
......@@ -329,8 +331,8 @@ export default function (
textAlign = isLabelInside
? 'center'
: (labelAlignTo === 'edge'
? (dx > 0 ? 'right' : 'left')
: (dx > 0 ? 'left' : 'right'));
? (nx > 0 ? 'right' : 'left')
: (nx > 0 ? 'left' : 'right'));
}
let labelRotate;
......@@ -340,7 +342,7 @@ export default function (
}
else {
labelRotate = rotate
? (dx < 0 ? -midAngle + Math.PI : -midAngle)
? (nx < 0 ? -midAngle + Math.PI : -midAngle)
: 0;
}
......@@ -368,6 +370,8 @@ export default function (
len: labelLineLen,
len2: labelLineLen2,
minTurnAngle: labelLineModel.get('minTurnAngle'),
maxSurfaceAngle: labelLineModel.get('maxSurfaceAngle'),
surfaceNormal: new Point(nx, ny),
linePoints: linePoints,
textAlign: textAlign,
labelDistance: labelDistance,
......@@ -420,6 +424,8 @@ export default function (
}
else {
limitTurnAngle(linePoints, layout.minTurnAngle);
limitSurfaceAngle(linePoints, layout.surfaceNormal, layout.maxSurfaceAngle);
labelLine.setShape({ points: linePoints });
// Set the anchor to the midpoint of sector
......
......@@ -444,6 +444,10 @@ export function limitTurnAngle(linePoints: number[][], minTurnAngle: number) {
const 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);
}
......@@ -455,6 +459,71 @@ export function limitTurnAngle(linePoints: number[][], minTurnAngle: number) {
}
}
/**
* 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: vector.VectorArray[], surfaceNormal: Point, maxSurfaceAngle: number) {
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);
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(surfaceNormal);
const maxSurfaceAngleCos = Math.cos(maxSurfaceAngle);
if (angleCos < maxSurfaceAngleCos) {
// 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);
const HALF_PI = Math.PI / 2;
const angle2 = Math.acos(dir2.dot(surfaceNormal));
const 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.
const 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]);
}
}
type LabelLineModel = Model<LabelLineOption>;
......
......@@ -688,7 +688,7 @@ under the License.
minTurnAngle: 110
},
label: {
margin: 25,
edgeDistance: 25,
bleedMargin: 10,
alignTo: 'none',
overflow: 'truncate'
......@@ -699,7 +699,7 @@ under the License.
chart.setOption({
series: {
label: Object.assign({}, config.label, {
margin: config.label.margin + '%'
edgeDistance: config.label.edgeDistance + '%'
}),
labelLine: config.labelLine
}
......@@ -712,7 +712,7 @@ under the License.
labelLineFolder.open();
labelFolder.add(config.label, 'alignTo', ['none', 'edge', 'labelLine']).onChange(update);
labelFolder.add(config.label, 'overflow', ['truncate', 'break', 'breakAll']).onChange(update);
labelFolder.add(config.label, 'margin', 0, 50).onChange(update);
labelFolder.add(config.label, 'edgeDistance', 0, 50).onChange(update);
labelFolder.add(config.label, 'bleedMargin', 0, 500).onChange(update);
labelLineFolder.add(config.labelLine, 'length', 0, 500).onChange(update);
labelLineFolder.add(config.labelLine, 'length2', 0, 500).onChange(update);
......
......@@ -28,6 +28,7 @@ under the License.
<script src="lib/jquery.min.js"></script>
<script src="lib/facePrint.js"></script>
<script src="lib/testHelper.js"></script>
<script src="lib/dat.gui.min.js"></script>
<link rel="stylesheet" href="lib/reset.css" />
</head>
<body>
......@@ -46,6 +47,9 @@ under the License.
background-color: #fff;
text-align: left;
}
.dg {
text-align: left;
}
</style>
......@@ -73,7 +77,7 @@ under the License.
{ name: '其它', value: 3.8 }
],
////////////////////////////////////////
// ////////////////////////////////////////
[
{ name: '银河帝国5:迈向基地', value: 3.8 },
{ name: '俞军产品方法论', value: 2.3 },
......@@ -94,6 +98,8 @@ under the License.
]
];
const charts = [];
datas.forEach(function (data) {
const dom = document.createElement('div');
dom.classList.add('chart');
......@@ -133,7 +139,8 @@ under the License.
},
labelLine: {
length: 15,
length2: 0
length2: 0,
maxSurfaceAngle: 80
},
labelLayout: function (params) {
const isLeft = params.labelRect.x < chart.getWidth() / 2;
......@@ -150,7 +157,41 @@ under the License.
data: data
}]
});
charts.push(chart);
});
const gui = new dat.GUI();
const config = {
labelLine: {
smooth: 0,
maxSurfaceAngle: 80
},
label: {
edgeDistance: 10
}
};
function update() {
charts.forEach(function (chart) {
chart.setOption({
series: {
label: Object.assign({}, config.label, {
edgeDistance: config.label.edgeDistance
}),
labelLine: config.labelLine
}
});
});
}
const labelFolder = gui.addFolder('label');
const labelLineFolder = gui.addFolder('labelLine');
labelFolder.open();
labelLineFolder.open();
labelFolder.add(config.label, 'edgeDistance', 0, 50).onChange(update);
labelLineFolder.add(config.labelLine, 'maxSurfaceAngle', 0, 90).onChange(update);
labelLineFolder.add(config.labelLine, 'smooth', 0, 1).onChange(update);
});
</script>
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册