Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
半栈学徒
incubator-echarts
提交
f3ed3fab
I
incubator-echarts
项目概览
半栈学徒
/
incubator-echarts
与 Fork 源项目一致
从无法访问的项目Fork
通知
5
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
I
incubator-echarts
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
f3ed3fab
编写于
6月 20, 2020
作者:
P
pissang
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
feat(label): use the new layout algorithm in pie
上级
678a33b9
变更
2
隐藏空白更改
内联
并排
Showing
2 changed file
with
59 addition
and
108 deletion
+59
-108
src/chart/pie/labelLayout.ts
src/chart/pie/labelLayout.ts
+44
-101
src/label/labelLayoutHelper.ts
src/label/labelLayoutHelper.ts
+15
-7
未找到文件。
src/chart/pie/labelLayout.ts
浏览文件 @
f3ed3fab
...
...
@@ -21,18 +21,17 @@
import
{
parsePercent
}
from
'
../../util/number
'
;
import
PieSeriesModel
,
{
PieSeriesOption
,
PieDataItemOption
}
from
'
./PieSeries
'
;
import
{
VectorArray
}
from
'
zrender/src/core/vector
'
;
import
{
HorizontalAlign
,
ZR
RectLike
,
ZR
TextAlign
}
from
'
../../util/types
'
;
import
{
HorizontalAlign
,
ZRTextAlign
}
from
'
../../util/types
'
;
import
{
Sector
,
Polyline
}
from
'
../../util/graphic
'
;
import
ZRText
from
'
zrender/src/graphic/Text
'
;
import
{
RectLike
}
from
'
zrender/src/core/BoundingRect
'
;
import
BoundingRect
,
{
RectLike
}
from
'
zrender/src/core/BoundingRect
'
;
import
{
each
}
from
'
zrender/src/core/util
'
;
import
{
limitTurnAngle
}
from
'
../../label/labelGuideHelper
'
;
import
{
shiftLayoutOnY
}
from
'
../../label/labelLayoutHelper
'
;
const
RADIAN
=
Math
.
PI
/
180
;
interface
LabelLayout
{
x
:
number
y
:
number
label
:
ZRText
,
labelLine
:
Polyline
,
position
:
PieSeriesOption
[
'
label
'
][
'
position
'
],
...
...
@@ -41,12 +40,11 @@ interface LabelLayout {
minTurnAngle
:
number
linePoints
:
VectorArray
[]
textAlign
:
HorizontalAlign
rotation
:
number
,
labelDistance
:
number
,
labelAlignTo
:
PieSeriesOption
[
'
label
'
][
'
alignTo
'
],
labelMargin
:
number
,
bleedMargin
:
PieSeriesOption
[
'
label
'
][
'
bleedMargin
'
],
textRect
:
ZRRectLike
rect
:
BoundingRect
}
function
adjustSingleSide
(
...
...
@@ -65,46 +63,6 @@ function adjustSingleSide(
return
;
}
list
.
sort
(
function
(
a
,
b
)
{
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
++
)
{
list
[
j
].
y
+=
delta
;
adjusted
=
true
;
if
(
j
>
start
&&
j
+
1
<
end
&&
list
[
j
+
1
].
y
>
list
[
j
].
y
+
list
[
j
].
textRect
.
height
)
{
// Shift up so it can be more equaly distributed.
shiftUp
(
j
,
delta
/
2
);
return
;
}
}
shiftUp
(
end
-
1
,
delta
/
2
);
}
function
shiftUp
(
end
:
number
,
delta
:
number
)
{
for
(
let
j
=
end
;
j
>=
0
;
j
--
)
{
list
[
j
].
y
-=
delta
;
adjusted
=
true
;
const
textHeight
=
list
[
j
].
textRect
.
height
;
if
(
list
[
j
].
y
-
textHeight
/
2
<
viewTop
)
{
list
[
j
].
y
=
viewTop
+
textHeight
/
2
;
}
if
(
j
>
0
&&
list
[
j
].
y
>
list
[
j
-
1
].
y
+
list
[
j
-
1
].
textRect
.
height
)
{
break
;
}
}
}
interface
SemiInfo
{
list
:
LabelLayout
[]
...
...
@@ -117,13 +75,13 @@ function adjustSingleSide(
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
);
const
dy
=
Math
.
abs
(
item
.
label
.
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
;
item
.
label
.
x
=
cx
+
(
dx
+
item
.
len2
)
*
dir
;
}
}
...
...
@@ -138,10 +96,10 @@ function adjustSingleSide(
continue
;
}
const
item
=
items
[
i
];
const
semi
=
item
.
y
>
cy
?
bottomSemi
:
topSemi
;
const
dy
=
Math
.
abs
(
item
.
y
-
cy
);
const
semi
=
item
.
label
.
y
>
cy
?
bottomSemi
:
topSemi
;
const
dy
=
Math
.
abs
(
item
.
label
.
y
-
cy
);
if
(
dy
>
semi
.
maxY
)
{
const
dx
=
item
.
x
-
cx
-
item
.
len2
*
dir
;
const
dx
=
item
.
label
.
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.
...
...
@@ -158,30 +116,16 @@ function adjustSingleSide(
recalculateXOnSemiToAlignOnEllipseCurve
(
bottomSemi
);
}
let
lastY
=
0
;
let
delta
;
const
len
=
list
.
length
;
for
(
let
i
=
0
;
i
<
len
;
i
++
)
{
if
(
list
[
i
].
position
===
'
outer
'
&&
list
[
i
].
labelAlignTo
===
'
labelLine
'
)
{
const
dx
=
list
[
i
].
x
-
farthestX
;
const
dx
=
list
[
i
].
label
.
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
);
list
[
i
].
label
.
x
=
farthestX
;
}
lastY
=
list
[
i
].
y
+
list
[
i
].
textRect
.
height
;
}
// PENDING:
// If data is sorted. Left top is usually the small data with a lower priority.
// So shift up and make sure the data on the bottom is always displayed well.
if
(
viewHeight
-
lastY
<
0
)
{
shiftUp
(
len
-
1
,
lastY
-
viewHeight
);
}
if
(
adjusted
)
{
if
(
shiftLayoutOnY
(
list
,
viewTop
,
viewTop
+
viewHeight
)
)
{
recalculateX
(
list
);
}
}
...
...
@@ -201,15 +145,16 @@ function avoidOverlap(
let
leftmostX
=
Number
.
MAX_VALUE
;
let
rightmostX
=
-
Number
.
MAX_VALUE
;
for
(
let
i
=
0
;
i
<
labelLayoutList
.
length
;
i
++
)
{
const
label
=
labelLayoutList
[
i
].
label
;
if
(
isPositionCenter
(
labelLayoutList
[
i
]))
{
continue
;
}
if
(
label
LayoutList
[
i
]
.
x
<
cx
)
{
leftmostX
=
Math
.
min
(
leftmostX
,
label
LayoutList
[
i
]
.
x
);
if
(
label
.
x
<
cx
)
{
leftmostX
=
Math
.
min
(
leftmostX
,
label
.
x
);
leftList
.
push
(
labelLayoutList
[
i
]);
}
else
{
rightmostX
=
Math
.
max
(
rightmostX
,
label
LayoutList
[
i
]
.
x
);
rightmostX
=
Math
.
max
(
rightmostX
,
label
.
x
);
rightList
.
push
(
labelLayoutList
[
i
]);
}
}
...
...
@@ -219,6 +164,7 @@ function avoidOverlap(
for
(
let
i
=
0
;
i
<
labelLayoutList
.
length
;
i
++
)
{
const
layout
=
labelLayoutList
[
i
];
const
label
=
layout
.
label
;
if
(
isPositionCenter
(
layout
))
{
continue
;
}
...
...
@@ -227,10 +173,10 @@ function avoidOverlap(
if
(
linePoints
)
{
const
isAlignToEdge
=
layout
.
labelAlignTo
===
'
edge
'
;
let
realTextWidth
=
layout
.
textR
ect
.
width
;
let
realTextWidth
=
layout
.
r
ect
.
width
;
let
targetTextWidth
;
if
(
isAlignToEdge
)
{
if
(
la
yout
.
x
<
cx
)
{
if
(
la
bel
.
x
<
cx
)
{
targetTextWidth
=
linePoints
[
2
][
0
]
-
layout
.
labelDistance
-
viewLeft
-
layout
.
labelMargin
;
}
...
...
@@ -240,14 +186,14 @@ function avoidOverlap(
}
}
else
{
if
(
la
yout
.
x
<
cx
)
{
targetTextWidth
=
la
yout
.
x
-
viewLeft
-
layout
.
bleedMargin
;
if
(
la
bel
.
x
<
cx
)
{
targetTextWidth
=
la
bel
.
x
-
viewLeft
-
layout
.
bleedMargin
;
}
else
{
targetTextWidth
=
viewLeft
+
viewWidth
-
la
yout
.
x
-
layout
.
bleedMargin
;
targetTextWidth
=
viewLeft
+
viewWidth
-
la
bel
.
x
-
layout
.
bleedMargin
;
}
}
if
(
targetTextWidth
<
layout
.
textR
ect
.
width
)
{
if
(
targetTextWidth
<
layout
.
r
ect
.
width
)
{
// TODOTODO
// layout.text = textContain.truncateText(layout.text, targetTextWidth, layout.font);
layout
.
label
.
style
.
width
=
targetTextWidth
;
...
...
@@ -260,7 +206,7 @@ function avoidOverlap(
const
dist
=
linePoints
[
1
][
0
]
-
linePoints
[
2
][
0
];
if
(
isAlignToEdge
)
{
if
(
la
yout
.
x
<
cx
)
{
if
(
la
bel
.
x
<
cx
)
{
linePoints
[
2
][
0
]
=
viewLeft
+
layout
.
labelMargin
+
realTextWidth
+
layout
.
labelDistance
;
}
else
{
...
...
@@ -269,15 +215,15 @@ function avoidOverlap(
}
}
else
{
if
(
la
yout
.
x
<
cx
)
{
linePoints
[
2
][
0
]
=
la
yout
.
x
+
layout
.
labelDistance
;
if
(
la
bel
.
x
<
cx
)
{
linePoints
[
2
][
0
]
=
la
bel
.
x
+
layout
.
labelDistance
;
}
else
{
linePoints
[
2
][
0
]
=
la
yout
.
x
-
layout
.
labelDistance
;
linePoints
[
2
][
0
]
=
la
bel
.
x
-
layout
.
labelDistance
;
}
linePoints
[
1
][
0
]
=
linePoints
[
2
][
0
]
+
dist
;
}
linePoints
[
1
][
1
]
=
linePoints
[
2
][
1
]
=
la
yout
.
y
;
linePoints
[
1
][
1
]
=
linePoints
[
2
][
1
]
=
la
bel
.
y
;
}
}
}
...
...
@@ -347,12 +293,6 @@ export default function (
cx
=
sectorShape
.
cx
;
cy
=
sectorShape
.
cy
;
const
textRect
=
label
.
getBoundingRect
().
clone
();
// Text has a default 1px stroke. Exclude this.
textRect
.
x
-=
1
;
textRect
.
y
-=
1
;
textRect
.
width
+=
2.1
;
textRect
.
height
+=
2.1
;
const
isLabelInside
=
labelPosition
===
'
inside
'
||
labelPosition
===
'
inner
'
;
if
(
labelPosition
===
'
center
'
)
{
...
...
@@ -407,31 +347,37 @@ export default function (
hasLabelRotate
=
!!
labelRotate
;
label
.
x
=
textX
;
label
.
y
=
textY
;
label
.
rotation
=
labelRotate
;
// Not sectorShape the inside label
if
(
!
isLabelInside
)
{
const
textRect
=
label
.
getBoundingRect
().
clone
();
textRect
.
applyTransform
(
label
.
getComputedTransform
());
// Text has a default 1px stroke. Exclude this.
textRect
.
x
-=
1
;
textRect
.
y
-=
1
;
textRect
.
width
+=
2.1
;
textRect
.
height
+=
2.1
;
labelLayoutList
.
push
({
label
,
labelLine
,
x
:
textX
,
y
:
textY
,
position
:
labelPosition
,
len
:
labelLineLen
,
len2
:
labelLineLen2
,
minTurnAngle
:
labelLineModel
.
get
(
'
minTurnAngle
'
),
linePoints
:
linePoints
,
textAlign
:
textAlign
,
rotation
:
labelRotate
,
labelDistance
:
labelDistance
,
labelAlignTo
:
labelAlignTo
,
labelMargin
:
labelMargin
,
bleedMargin
:
bleedMargin
,
textR
ect
:
textRect
r
ect
:
textRect
});
}
else
{
label
.
x
=
textX
;
label
.
y
=
textY
;
label
.
rotation
=
labelRotate
;
label
.
setStyle
({
align
:
textAlign
,
verticalAlign
:
'
middle
'
...
...
@@ -450,11 +396,8 @@ export default function (
const
layout
=
labelLayoutList
[
i
];
const
label
=
layout
.
label
;
const
labelLine
=
layout
.
labelLine
;
const
notShowLabel
=
isNaN
(
la
yout
.
x
)
||
isNaN
(
layout
.
y
);
const
notShowLabel
=
isNaN
(
la
bel
.
x
)
||
isNaN
(
label
.
y
);
if
(
label
)
{
label
.
x
=
layout
.
x
;
label
.
y
=
layout
.
y
;
label
.
rotation
=
layout
.
rotation
;
label
.
setStyle
({
align
:
layout
.
textAlign
,
verticalAlign
:
'
middle
'
...
...
@@ -465,8 +408,8 @@ export default function (
}
const
selectState
=
label
.
states
.
select
;
if
(
selectState
)
{
selectState
.
x
+=
la
yout
.
x
;
selectState
.
y
+=
la
yout
.
y
;
selectState
.
x
+=
la
bel
.
x
;
selectState
.
y
+=
la
bel
.
y
;
}
}
if
(
labelLine
)
{
...
...
src/label/labelLayoutHelper.ts
浏览文件 @
f3ed3fab
...
...
@@ -91,7 +91,7 @@ export function prepareLayoutList(input: LabelLayoutListPrepareInput[]): LabelLa
}
function
shiftLayout
(
list
:
LabelLayoutInfo
[],
list
:
Pick
<
LabelLayoutInfo
,
'
rect
'
|
'
label
'
>
[],
xyDim
:
'
x
'
|
'
y
'
,
sizeDim
:
'
width
'
|
'
height
'
,
minBound
:
number
,
...
...
@@ -109,6 +109,8 @@ function shiftLayout(
let
lastPos
=
0
;
let
delta
;
let
adjusted
=
false
;
const
shifts
=
[];
let
totalShifts
=
0
;
for
(
let
i
=
0
;
i
<
len
;
i
++
)
{
...
...
@@ -119,6 +121,7 @@ function shiftLayout(
// shiftForward(i, len, -delta);
rect
[
xyDim
]
-=
delta
;
item
.
label
[
xyDim
]
-=
delta
;
adjusted
=
true
;
}
const
shift
=
Math
.
max
(
-
delta
,
0
);
shifts
.
push
(
shift
);
...
...
@@ -170,6 +173,9 @@ function shiftLayout(
}
function
shiftList
(
delta
:
number
,
start
:
number
,
end
:
number
)
{
if
(
delta
!==
0
)
{
adjusted
=
true
;
}
for
(
let
i
=
start
;
i
<
end
;
i
++
)
{
const
item
=
list
[
i
];
const
rect
=
item
.
rect
;
...
...
@@ -236,28 +242,30 @@ function shiftLayout(
}
}
}
return
adjusted
;
}
/**
* Adjust labels on x direction to avoid overlap.
*/
export
function
shiftLayoutOnX
(
list
:
LabelLayoutInfo
[],
list
:
Pick
<
LabelLayoutInfo
,
'
rect
'
|
'
label
'
>
[],
leftBound
:
number
,
rightBound
:
number
)
{
shiftLayout
(
list
,
'
x
'
,
'
width
'
,
leftBound
,
rightBound
);
)
:
boolean
{
return
shiftLayout
(
list
,
'
x
'
,
'
width
'
,
leftBound
,
rightBound
);
}
/**
* Adjust labels on y direction to avoid overlap.
*/
export
function
shiftLayoutOnY
(
list
:
LabelLayoutInfo
[],
list
:
Pick
<
LabelLayoutInfo
,
'
rect
'
|
'
label
'
>
[],
topBound
:
number
,
bottomBound
:
number
)
{
shiftLayout
(
list
,
'
y
'
,
'
height
'
,
topBound
,
bottomBound
);
)
:
boolean
{
return
shiftLayout
(
list
,
'
y
'
,
'
height
'
,
topBound
,
bottomBound
);
}
export
function
hideOverlap
(
labelList
:
LabelLayoutInfo
[])
{
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录