Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
x649585723
incubator-echarts
提交
07b074ae
I
incubator-echarts
项目概览
x649585723
/
incubator-echarts
与 Fork 源项目一致
从无法访问的项目Fork
通知
1
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,体验更适合开发者的 AI 搜索 >>
未验证
提交
07b074ae
编写于
3月 19, 2021
作者:
S
sushuang
提交者:
GitHub
3月 19, 2021
浏览文件
操作
浏览文件
下载
差异文件
Merge pull request #14246 from apache/perf-tooltip
perf(tooltip): improve the performance of tooltip.
上级
88d2ad7a
e88b99f6
变更
3
隐藏空白更改
内联
并排
Showing
3 changed file
with
153 addition
and
73 deletion
+153
-73
src/component/tooltip/TooltipHTMLContent.ts
src/component/tooltip/TooltipHTMLContent.ts
+105
-70
src/component/tooltip/TooltipView.ts
src/component/tooltip/TooltipView.ts
+4
-3
src/component/tooltip/helper.ts
src/component/tooltip/helper.ts
+44
-0
未找到文件。
src/component/tooltip/TooltipHTMLContent.ts
浏览文件 @
07b074ae
...
...
@@ -17,26 +17,36 @@
* under the License.
*/
import
{
isString
,
indexOf
,
map
,
each
,
bind
,
isArray
,
isDom
}
from
'
zrender/src/core/util
'
;
import
{
isString
,
indexOf
,
each
,
bind
,
isArray
,
isDom
}
from
'
zrender/src/core/util
'
;
import
{
toHex
}
from
'
zrender/src/tool/color
'
;
import
{
normalizeEvent
}
from
'
zrender/src/core/event
'
;
import
{
transformLocalCoord
}
from
'
zrender/src/core/dom
'
;
import
env
from
'
zrender/src/core/env
'
;
import
{
convertToColorString
,
toCamelCase
,
normalizeCssArray
}
from
'
../../util/format
'
;
import
ExtensionAPI
from
'
../../core/ExtensionAPI
'
;
import
{
ZRenderType
}
from
'
zrender/src/zrender
'
;
import
{
TooltipOption
}
from
'
./TooltipModel
'
;
import
type
ExtensionAPI
from
'
../../core/ExtensionAPI
'
;
import
type
{
ZRenderType
}
from
'
zrender/src/zrender
'
;
import
type
{
TooltipOption
}
from
'
./TooltipModel
'
;
import
Model
from
'
../../model/Model
'
;
import
{
ZRRawEvent
}
from
'
zrender/src/core/types
'
;
import
{
ColorString
,
ZRColor
}
from
'
../../util/types
'
;
import
CanvasPainter
from
'
zrender/src/canvas/Painter
'
;
import
SVGPainter
from
'
zrender/src/svg/Painter
'
;
import
{
shouldTooltipConfine
}
from
'
./helper
'
;
import
type
{
ZRRawEvent
}
from
'
zrender/src/core/types
'
;
import
type
{
ColorString
,
ZRColor
}
from
'
../../util/types
'
;
import
type
CanvasPainter
from
'
zrender/src/canvas/Painter
'
;
import
type
SVGPainter
from
'
zrender/src/svg/Painter
'
;
import
{
shouldTooltipConfine
,
toCSSVendorPrefix
,
getComputedStyle
,
TRANSFORM_VENDOR
,
TRANSITION_VENDOR
}
from
'
./helper
'
;
import
{
getPaddingFromTooltipModel
}
from
'
./tooltipMarkup
'
;
const
vendors
=
[
'
-ms-
'
,
'
-moz-
'
,
'
-o-
'
,
'
-webkit-
'
,
''
];
/* global document, window */
const
gCssText
=
'
position:absolute;display:block;border-style:solid;white-space:nowrap;z-index:9999999;
'
;
const
CSS_TRANSITION_VENDOR
=
toCSSVendorPrefix
(
TRANSITION_VENDOR
,
'
transition
'
);
const
CSS_TRANSFORM_VENDOR
=
toCSSVendorPrefix
(
TRANSFORM_VENDOR
,
'
transform
'
);
// eslint-disable-next-line
const
gCssText
=
`position:absolute;display:block;border-style:solid;white-space:nowrap;z-index:9999999;
${
env
.
transform3dSupported
?
'
will-change:transform;
'
:
''
}
`
;
function
mirrorPos
(
pos
:
string
):
string
{
pos
=
pos
===
'
left
'
...
...
@@ -60,44 +70,66 @@ function assembleArrow(
borderColor
=
convertToColorString
(
borderColor
);
const
arrowPos
=
mirrorPos
(
arrowPosition
);
let
positionStyle
=
''
;
let
transformStyle
=
'
'
;
let
positionStyle
=
`
${
arrowPos
}
:-6px;`
;
let
transformStyle
=
CSS_TRANSFORM_VENDOR
+
'
:
'
;
if
(
indexOf
([
'
left
'
,
'
right
'
],
arrowPos
)
>
-
1
)
{
positionStyle
=
`
${
arrowPos
}
:-6px;top:50%;`
;
transformStyle
=
`translateY(-50%) rotate(
${
arrowPos
===
'
left
'
?
-
225
:
-
45
}
deg)`
;
positionStyle
+=
'
top:50%
'
;
transformStyle
+
=
`translateY(-50%) rotate(
${
arrowPos
===
'
left
'
?
-
225
:
-
45
}
deg)`
;
}
else
{
positionStyle
=
`
${
arrowPos
}
:-6px;left:50%;`
;
transformStyle
=
`translateX(-50%) rotate(
${
arrowPos
===
'
top
'
?
225
:
45
}
deg)`
;
positionStyle
+=
'
left:50%
'
;
transformStyle
+
=
`translateX(-50%) rotate(
${
arrowPos
===
'
top
'
?
225
:
45
}
deg)`
;
}
transformStyle
=
map
(
vendors
,
function
(
vendorPrefix
)
{
return
vendorPrefix
+
'
transform:
'
+
transformStyle
;
}).
join
(
'
;
'
);
const
borderStyle
=
`
${
borderColor
}
solid 1px;`
;
const
styleCss
=
[
'
position:absolute;width:10px;height:10px;
'
,
`
${
positionStyle
}${
transformStyle
}
;`
,
`border-bottom:
${
borderColor
}
solid 1px;
`
,
`border-right:
${
borderColor
}
solid 1px;
`
,
`background-color:
${
backgroundColor
}
;`
,
'
box-shadow:
8px 8px 16px -3px #000;
'
`
${
positionStyle
}
;
${
transformStyle
}
;`
,
`border-bottom:
${
borderStyle
}
`
,
`border-right:
${
borderStyle
}
`
,
`background-color:
${
backgroundColor
}
;`
,
'
box-shadow:8px 8px 16px -3px #000;
'
];
return
`<div style="
${
styleCss
.
join
(
''
)}
"></div>`
;
}
function
assembleTransition
(
duration
:
number
,
onlyFade
?:
boolean
):
string
{
const
transitionCurve
=
'
cubic-bezier(0.23,
1, 0.32,
1)
'
;
let
transition
Text
=
'
opacity
'
+
(
duration
/
2
)
+
'
s
'
+
transitionCurve
+
'
,
'
+
'
visibility
'
+
(
duration
/
2
)
+
'
s
'
+
transitionCurve
;
const
transitionCurve
=
'
cubic-bezier(0.23,
1,0.32,
1)
'
;
let
transition
Option
=
`
${
duration
/
2
}
s
${
transitionCurve
}
`
;
let
transitionText
=
`opacity
${
transitionOption
}
,visibility
${
transitionOption
}
`
;
if
(
!
onlyFade
)
{
transitionText
+=
'
,left
'
+
duration
+
'
s
'
+
transitionCurve
+
'
,top
'
+
duration
+
'
s
'
+
transitionCurve
;
transitionOption
=
`
${
duration
}
s
${
transitionCurve
}
`
;
transitionText
+=
env
.
transformSupported
?
`,
${
TRANSFORM_VENDOR
}${
transitionOption
}
`
:
`,left
${
transitionOption
}
,top
${
transitionOption
}
`
;
}
return
map
(
vendors
,
function
(
vendorPrefix
)
{
return
vendorPrefix
+
'
transition:
'
+
transitionText
;
}).
join
(
'
;
'
);
return
CSS_TRANSITION_VENDOR
+
'
:
'
+
transitionText
;
}
function
assembleTransform
(
el
:
HTMLElement
,
x
:
number
,
y
:
number
,
toString
?:
boolean
)
{
// If using float on style, the final width of the dom might
// keep changing slightly while mouse move. So `toFixed(0)` them.
let
x0
;
let
y0
;
// not support transform, use `left` and `top` instead.
if
(
!
env
.
transformSupported
)
{
x0
=
x
.
toFixed
(
0
);
y0
=
y
.
toFixed
(
0
);
return
toString
?
`top:
${
y0
}
px;left:
${
x0
}
px;`
:
[[
'
top
'
,
`
${
y0
}
px`
],
[
'
left
'
,
`
${
x0
}
px`
]];
}
// support transform
// FIXME: the padding of parent element will affect the position of tooltip
const
stl
=
getComputedStyle
(
el
.
parentElement
);
x0
=
(
x
-
parseInt
(
stl
.
paddingLeft
,
10
)).
toFixed
(
0
);
y0
=
(
y
-
parseInt
(
stl
.
paddingTop
,
10
)).
toFixed
(
0
);
const
is3d
=
env
.
transform3dSupported
;
const
translate
=
`translate
${
is3d
?
'
3d
'
:
''
}
(
${
x0
}
px,
${
y0
}
px
${
is3d
?
'
,0
'
:
''
}
)`
;
return
toString
?
CSS_TRANSFORM_VENDOR
+
'
:
'
+
translate
+
'
;
'
:
[[
TRANSFORM_VENDOR
,
translate
]];
}
/**
...
...
@@ -153,12 +185,12 @@ function assembleCssText(tooltipModel: Model<TooltipOption>, enableTransition?:
if
(
backgroundColor
)
{
if
(
env
.
canvasSupported
)
{
cssText
.
push
(
'
background-
C
olor:
'
+
backgroundColor
);
cssText
.
push
(
'
background-
c
olor:
'
+
backgroundColor
);
}
else
{
// for ie
cssText
.
push
(
'
background-
C
olor:#
'
+
toHex
(
backgroundColor
)
'
background-
c
olor:#
'
+
toHex
(
backgroundColor
)
);
cssText
.
push
(
'
filter:alpha(opacity=70)
'
);
}
...
...
@@ -272,7 +304,8 @@ class TooltipHTMLContent {
document
.
body
.
appendChild
(
el
);
}
else
{
container
.
appendChild
(
el
);
// PENDING
container
.
prepend
(
el
);
}
this
.
_container
=
container
;
...
...
@@ -324,10 +357,9 @@ class TooltipHTMLContent {
// FIXME
// Move this logic to ec main?
const
container
=
this
.
_container
;
const
stl
=
(
container
as
any
).
currentStyle
||
document
.
defaultView
.
getComputedStyle
(
container
);
const
position
=
getComputedStyle
(
container
,
'
position
'
);
const
domStyle
=
container
.
style
;
if
(
domStyle
.
position
!==
'
absolute
'
&&
stl
.
position
!==
'
absolute
'
)
{
if
(
domStyle
.
position
!==
'
absolute
'
&&
position
!==
'
absolute
'
)
{
domStyle
.
position
=
'
relative
'
;
}
...
...
@@ -347,25 +379,25 @@ class TooltipHTMLContent {
clearTimeout
(
this
.
_hideTimeout
);
clearTimeout
(
this
.
_longHideTimeout
);
const
el
=
this
.
el
;
const
style
=
el
.
style
;
const
styleCoord
=
this
.
_styleCoord
;
const
offset
=
el
.
offsetHeight
/
2
;
nearPointColor
=
convertToColorString
(
nearPointColor
);
el
.
style
.
cssText
=
gCssText
+
assembleCssText
(
tooltipModel
,
!
this
.
_firstShow
,
this
.
_longHide
)
// Because of the reason described in:
// http://stackoverflow.com/questions/21125587/css3-transition-not-working-in-chrome-anymore
// we should set initial value to `left` and `top`.
+
'
;left:
'
+
styleCoord
[
0
]
+
'
px;top:
'
+
(
styleCoord
[
1
]
-
offset
)
+
'
px;
'
+
`border-color:
${
nearPointColor
}
;`
+
(
tooltipModel
.
get
(
'
extraCssText
'
)
||
''
);
el
.
style
.
display
=
el
.
innerHTML
?
'
block
'
:
'
none
'
;
// If mouse occasionally move over the tooltip, a mouseout event will be
// triggered by canvas, and cause some unexpectable result like dragging
// stop, "unfocusAdjacency". Here `pointer-events: none` is used to solve
// it. Although it is not supported by IE8~IE10, fortunately it is a rare
// scenario.
el
.
style
.
pointerEvents
=
this
.
_enterable
?
'
auto
'
:
'
none
'
;
if
(
!
el
.
innerHTML
)
{
style
.
display
=
'
none
'
;
}
else
{
style
.
cssText
=
gCssText
+
assembleCssText
(
tooltipModel
,
!
this
.
_firstShow
,
this
.
_longHide
)
// initial transform
+
assembleTransform
(
el
,
styleCoord
[
0
],
styleCoord
[
1
],
true
)
+
`border-color:
${
convertToColorString
(
nearPointColor
)}
;`
+
(
tooltipModel
.
get
(
'
extraCssText
'
)
||
''
)
// If mouse occasionally move over the tooltip, a mouseout event will be
// triggered by canvas, and cause some unexpectable result like dragging
// stop, "unfocusAdjacency". Here `pointer-events: none` is used to solve
// it. Although it is not supported by IE8~IE10, fortunately it is a rare
// scenario.
+
`;pointer-event:
${
this
.
_enterable
?
'
auto
'
:
'
none
'
}
`
;
}
this
.
_show
=
true
;
this
.
_firstShow
=
false
;
...
...
@@ -421,10 +453,13 @@ class TooltipHTMLContent {
if
(
styleCoord
[
0
]
!=
null
&&
styleCoord
[
1
]
!=
null
)
{
const
style
=
this
.
el
.
style
;
// If using float on style, the final width of the dom might
// keep changing slightly while mouse move. So `toFixed(0)` them.
style
.
left
=
styleCoord
[
0
].
toFixed
(
0
)
+
'
px
'
;
style
.
top
=
styleCoord
[
1
].
toFixed
(
0
)
+
'
px
'
;
const
transforms
=
assembleTransform
(
this
.
el
,
styleCoord
[
0
],
styleCoord
[
1
]
)
as
string
[][];
each
(
transforms
,
(
transform
)
=>
{
style
[
transform
[
0
]
as
any
]
=
transform
[
1
];
});
}
}
...
...
@@ -444,8 +479,10 @@ class TooltipHTMLContent {
}
hide
()
{
this
.
el
.
style
.
visibility
=
'
hidden
'
;
this
.
el
.
style
.
opacity
=
'
0
'
;
const
style
=
this
.
el
.
style
;
style
.
visibility
=
'
hidden
'
;
style
.
opacity
=
'
0
'
;
env
.
transform3dSupported
&&
(
style
.
willChange
=
''
);
this
.
_show
=
false
;
this
.
_longHideTimeout
=
setTimeout
(()
=>
this
.
_longHide
=
true
,
500
)
as
any
;
}
...
...
@@ -478,12 +515,10 @@ class TooltipHTMLContent {
// Consider browser compatibility.
// IE8 does not support getComputedStyle.
if
(
document
.
defaultView
&&
document
.
defaultView
.
getComputedStyle
)
{
const
stl
=
document
.
defaultView
.
getComputedStyle
(
this
.
el
);
if
(
stl
)
{
width
+=
parseInt
(
stl
.
borderLeftWidth
,
10
)
+
parseInt
(
stl
.
borderRightWidth
,
10
);
height
+=
parseInt
(
stl
.
borderTopWidth
,
10
)
+
parseInt
(
stl
.
borderBottomWidth
,
10
);
}
const
stl
=
getComputedStyle
(
this
.
el
);
if
(
stl
)
{
width
+=
parseInt
(
stl
.
borderLeftWidth
,
10
)
+
parseInt
(
stl
.
borderRightWidth
,
10
);
height
+=
parseInt
(
stl
.
borderTopWidth
,
10
)
+
parseInt
(
stl
.
borderBottomWidth
,
10
);
}
return
{
width
:
width
,
height
:
height
};
...
...
src/component/tooltip/TooltipView.ts
浏览文件 @
07b074ae
...
...
@@ -770,6 +770,7 @@ class TooltipView extends ComponentView {
tooltipModel
.
get
(
'
trigger
'
),
tooltipModel
.
get
(
'
borderColor
'
)
);
const
nearPointColor
=
nearPoint
.
color
;
if
(
formatter
&&
zrUtil
.
isString
(
formatter
))
{
const
useUTC
=
tooltipModel
.
ecModel
.
get
(
'
useUTC
'
);
...
...
@@ -784,7 +785,7 @@ class TooltipView extends ComponentView {
else
if
(
zrUtil
.
isFunction
(
formatter
))
{
const
callback
=
bind
(
function
(
cbTicket
:
string
,
html
:
string
|
HTMLElement
[])
{
if
(
cbTicket
===
this
.
_ticket
)
{
tooltipContent
.
setContent
(
html
,
markupStyleCreator
,
tooltipModel
,
nearPoint
.
c
olor
,
positionExpr
);
tooltipContent
.
setContent
(
html
,
markupStyleCreator
,
tooltipModel
,
nearPoint
C
olor
,
positionExpr
);
this
.
_updatePosition
(
tooltipModel
,
positionExpr
,
x
,
y
,
tooltipContent
,
params
,
el
);
...
...
@@ -794,8 +795,8 @@ class TooltipView extends ComponentView {
html
=
formatter
(
params
,
asyncTicket
,
callback
);
}
tooltipContent
.
setContent
(
html
,
markupStyleCreator
,
tooltipModel
,
nearPoint
.
c
olor
,
positionExpr
);
tooltipContent
.
show
(
tooltipModel
,
nearPoint
.
c
olor
);
tooltipContent
.
setContent
(
html
,
markupStyleCreator
,
tooltipModel
,
nearPoint
C
olor
,
positionExpr
);
tooltipContent
.
show
(
tooltipModel
,
nearPoint
C
olor
);
this
.
_updatePosition
(
tooltipModel
,
positionExpr
,
x
,
y
,
tooltipContent
,
params
,
el
);
...
...
src/component/tooltip/helper.ts
浏览文件 @
07b074ae
...
...
@@ -19,6 +19,10 @@
import
{
TooltipOption
}
from
'
./TooltipModel
'
;
import
Model
from
'
../../model/Model
'
;
import
{
toCamelCase
}
from
'
../../util/format
'
;
import
env
from
'
zrender/src/core/env
'
;
/* global document */
export
function
shouldTooltipConfine
(
tooltipModel
:
Model
<
TooltipOption
>
):
boolean
{
const
confineOption
=
tooltipModel
.
get
(
'
confine
'
);
...
...
@@ -27,3 +31,43 @@ export function shouldTooltipConfine(tooltipModel: Model<TooltipOption>): boolea
// In richText mode, the outside part can not be visible.
:
tooltipModel
.
get
(
'
renderMode
'
)
===
'
richText
'
;
}
function
testStyle
(
styleProps
:
string
[]):
string
|
undefined
{
if
(
!
env
.
domSupported
)
{
return
;
}
const
style
=
document
.
documentElement
.
style
;
for
(
let
i
=
0
,
len
=
styleProps
.
length
;
i
<
len
;
i
++
)
{
if
(
styleProps
[
i
]
in
style
)
{
return
styleProps
[
i
];
}
}
}
export
const
TRANSFORM_VENDOR
=
testStyle
(
[
'
transform
'
,
'
webkitTransform
'
,
'
OTransform
'
,
'
MozTransform
'
,
'
msTransform
'
]
);
export
const
TRANSITION_VENDOR
=
testStyle
(
[
'
webkitTransition
'
,
'
transition
'
,
'
OTransition
'
,
'
MozTransition
'
,
'
msTransition
'
]
);
export
function
toCSSVendorPrefix
(
styleVendor
:
string
,
styleProp
:
string
)
{
if
(
!
styleVendor
)
{
return
styleProp
;
}
styleProp
=
toCamelCase
(
styleProp
,
true
);
const
idx
=
styleVendor
.
indexOf
(
styleProp
);
styleVendor
=
idx
===
-
1
?
styleProp
:
`-
${
styleVendor
.
slice
(
0
,
idx
)}
-
${
styleProp
}
`
;
return
styleVendor
.
toLowerCase
();
}
export
function
getComputedStyle
(
el
:
HTMLElement
,
style
?:
string
)
{
const
stl
=
(
el
as
any
).
currentStyle
||
(
document
.
defaultView
&&
document
.
defaultView
.
getComputedStyle
(
el
));
return
stl
?
style
?
stl
[
style
]
:
stl
:
null
;
}
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录