Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
半栈学徒
incubator-echarts
提交
abdb25cf
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,体验更适合开发者的 AI 搜索 >>
提交
abdb25cf
编写于
3月 14, 2016
作者:
P
pah100
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
treemap drill down (part I)
上级
a63ac125
变更
8
隐藏空白更改
内联
并排
Showing
8 changed file
with
452 addition
and
153 deletion
+452
-153
src/chart/treemap/Breadcrumb.js
src/chart/treemap/Breadcrumb.js
+1
-0
src/chart/treemap/TreemapSeries.js
src/chart/treemap/TreemapSeries.js
+69
-36
src/chart/treemap/TreemapView.js
src/chart/treemap/TreemapView.js
+150
-74
src/chart/treemap/helper.js
src/chart/treemap/helper.js
+35
-11
src/chart/treemap/treemapAction.js
src/chart/treemap/treemapAction.js
+31
-3
src/chart/treemap/treemapLayout.js
src/chart/treemap/treemapLayout.js
+45
-29
test/treemap-disk.html
test/treemap-disk.html
+17
-0
test/treemap-option.html
test/treemap-option.html
+104
-0
未找到文件。
src/chart/treemap/Breadcrumb.js
浏览文件 @
abdb25cf
...
...
@@ -127,6 +127,7 @@
textFont
:
textStyleModel
.
getFont
()
}
),
z
:
10
,
onclick
:
zrUtil
.
bind
(
this
.
_onSelect
,
this
,
item
.
node
)
}));
...
...
src/chart/treemap/TreemapSeries.js
浏览文件 @
abdb25cf
...
...
@@ -5,6 +5,7 @@ define(function(require) {
var
zrUtil
=
require
(
'
zrender/core/util
'
);
var
Model
=
require
(
'
../../model/Model
'
);
var
formatUtil
=
require
(
'
../../util/format
'
);
var
helper
=
require
(
'
./helper
'
);
var
encodeHTML
=
formatUtil
.
encodeHTML
;
var
addCommas
=
formatUtil
.
addCommas
;
...
...
@@ -15,9 +16,14 @@ define(function(require) {
dependencies
:
[
'
grid
'
,
'
polar
'
],
/**
* @type {module:echarts/data/Tree~Node}
*/
_viewRoot
:
null
,
defaultOption
:
{
// center: ['50%', '50%'],
// not supported in ec3.
// size: ['80%', '80%'],
// deprecated, compatible with ec2.
// center: ['50%', '50%'], // not supported in ec3.
// size: ['80%', '80%'], // deprecated, compatible with ec2.
left
:
'
center
'
,
top
:
'
middle
'
,
right
:
null
,
...
...
@@ -26,15 +32,20 @@ define(function(require) {
height
:
'
80%
'
,
sort
:
true
,
// Can be null or false or true
// (order by desc default, asc not supported yet (strange effect))
clipWindow
:
'
origin
'
,
//
缩放时窗口大小。
'origin' or 'fullscreen'
clipWindow
:
'
origin
'
,
//
Size of clipped window when zooming.
'origin' or 'fullscreen'
squareRatio
:
0.5
*
(
1
+
Math
.
sqrt
(
5
)),
// golden ratio
root
:
null
,
// default: tree root. This feature doesnt work unless node have id.
leafDepth
:
null
,
// Nodes on depth from root are regarded as leaves.
// Count from zero (zero represents only view root).
visualDimension
:
0
,
// Can be 0, 1, 2, 3.
zoomToNodeRatio
:
0.32
*
0.32
,
// zoom to node时 node占可视区域的面积比例。
roam
:
true
,
// true, false, 'scale' or 'zoom', 'move'
nodeClick
:
'
zoomToNode
'
,
// 'zoomToNode', 'link', false
zoomToNodeRatio
:
0.32
*
0.32
,
// Be effective when using zoomToNode. Specify the proportion of the
// target node area in the view area.
roam
:
true
,
// true, false, 'scale' or 'zoom', 'move'.
nodeClick
:
'
zoomToNode
'
,
// Leaf node click behaviour: 'zoomToNode', 'link', false.
// If leafDepth is set and clicking a node which has children but
// be on left depth, the behaviour would be changing root. Otherwise
// use behavious defined above.
animation
:
true
,
animationDurationUpdate
:
15
00
,
animationDurationUpdate
:
9
00
,
animationEasing
:
'
quinticInOut
'
,
breadcrumb
:
{
show
:
true
,
...
...
@@ -43,7 +54,7 @@ define(function(require) {
top
:
'
bottom
'
,
// right
// bottom
emptyItemWidth
:
25
,
// 空节点宽度
emptyItemWidth
:
25
,
// Width of empty node.
itemStyle
:
{
normal
:
{
color
:
'
rgba(0,0,0,0.7)
'
,
//'#5793f3',
...
...
@@ -65,7 +76,7 @@ define(function(require) {
label
:
{
normal
:
{
show
:
true
,
position
:
[
'
50%
'
,
'
50%
'
],
// 可以是 5 '5%'
'insideTopLeft', ...
position
:
[
'
50%
'
,
'
50%
'
],
// Can be 5, '5%' or position stirng like
'insideTopLeft', ...
textStyle
:
{
align
:
'
center
'
,
baseline
:
'
middle
'
,
...
...
@@ -76,30 +87,35 @@ define(function(require) {
},
itemStyle
:
{
normal
:
{
color
:
null
,
// 各异 如不需,可设为'none'
colorAlpha
:
null
,
// 默认不设置 如不需,可设为'none'
colorSaturation
:
null
,
// 默认不设置 如不需,可设为'none'
color
:
null
,
// Can be 'none' if not necessary.
colorAlpha
:
null
,
// Can be 'none' if not necessary.
colorSaturation
:
null
,
// Can be 'none' if not necessary.
borderWidth
:
0
,
gapWidth
:
0
,
borderColor
:
'
#fff
'
,
borderColorSaturation
:
null
// 如果设置,则borderColor的设置无效,而是取当前节点计算出的颜色,再经由borderColorSaturation处理。
borderColorSaturation
:
null
// If specified, borderColor will be ineffective, and the
// border color is evaluated by color of current node and
// borderColorSaturation.
},
emphasis
:
{}
emphasis
:
{
}
},
color
:
'
none
'
,
// 为数组,表示同一level的color 选取列表。默认空,在level[0].color中取系统color列表。
colorAlpha
:
null
,
// 为数组,表示同一level的color alpha 选取范围。
colorSaturation
:
null
,
// 为数组,表示同一level的color alpha 选取范围。
colorMappingBy
:
'
index
'
,
// 'value' or 'index' or 'id'.
visibleMin
:
10
,
// If area less than this threshold (unit: pixel^2), node will not be rendered.
// Only works when sort is 'asc' or 'desc'.
childrenVisibleMin
:
null
,
// If area of a node less than this threshold (unit: pixel^2),
// grandchildren will not show.
// Why grandchildren? If not grandchildren but children,
// some siblings show children and some not,
// the appearance may be mess and not consistent,
levels
:
[]
// Each item: {
// visibleMin, itemStyle, visualDimension, label
// }
color
:
'
none
'
,
// Array. Specify color list of each level.
// level[0].color would be global color list.
colorAlpha
:
null
,
// Array. Specify color alpha range of each level, like [0.2, 0.8]
colorSaturation
:
null
,
// Array. Specify color saturation of each level, like [0.2, 0.5]
colorMappingBy
:
'
index
'
,
// 'value' or 'index' or 'id'.
visibleMin
:
10
,
// If area less than this threshold (unit: pixel^2), node will not
// be rendered. Only works when sort is 'asc' or 'desc'.
childrenVisibleMin
:
null
,
// If area of a node less than this threshold (unit: pixel^2),
// grandchildren will not show.
// Why grandchildren? If not grandchildren but children,
// some siblings show children and some not,
// the appearance may be mess and not consistent,
levels
:
[]
// Each item: {
// visibleMin, itemStyle, visualDimension, label
// }
// data: {
// value: [],
// children: [],
...
...
@@ -134,13 +150,8 @@ define(function(require) {
return
Tree
.
createTree
(
root
,
this
,
levels
).
data
;
},
/**
* @public
*/
getViewRoot
:
function
()
{
var
optionRoot
=
this
.
option
.
root
;
var
treeRoot
=
this
.
getData
().
tree
.
root
;
return
optionRoot
&&
treeRoot
.
getNodeById
(
optionRoot
)
||
treeRoot
;
optionUpdated
:
function
()
{
this
.
resetViewRoot
();
},
/**
...
...
@@ -239,6 +250,28 @@ define(function(require) {
}
return
index
;
},
getViewRoot
:
function
()
{
return
this
.
_viewRoot
;
},
/**
* @param {module:echarts/data/Tree~Node} [viewRoot]
* @return {string} direction 'drilldown' or 'rollup'
*/
resetViewRoot
:
function
(
viewRoot
)
{
viewRoot
?
(
this
.
_viewRoot
=
viewRoot
)
:
(
viewRoot
=
this
.
_viewRoot
);
var
root
=
this
.
getData
().
tree
.
root
;
if
(
!
viewRoot
||
(
viewRoot
!==
root
&&
!
root
.
contains
(
viewRoot
))
)
{
this
.
_viewRoot
=
root
;
}
}
});
...
...
src/chart/treemap/TreemapView.js
浏览文件 @
abdb25cf
...
...
@@ -84,21 +84,36 @@
this
.
api
=
api
;
this
.
ecModel
=
ecModel
;
var
targetInfo
=
helper
.
retrieveTargetInfo
(
payload
,
seriesModel
);
var
payloadType
=
payload
&&
payload
.
type
;
var
layoutInfo
=
seriesModel
.
layoutInfo
;
var
isInit
=
!
this
.
_oldTree
;
var
thisStorage
=
this
.
_storage
;
// Mark new root when action is treemapRootToNode.
var
reRoot
=
(
payloadType
===
'
treemapRootToNode
'
&&
targetInfo
&&
thisStorage
)
?
{
rootNodeGroup
:
thisStorage
.
nodeGroup
[
targetInfo
.
node
.
getRawIndex
()],
direction
:
payload
.
direction
}
:
null
;
var
containerGroup
=
this
.
_giveContainerGroup
(
layoutInfo
);
var
renderResult
=
this
.
_doRender
(
containerGroup
,
seriesModel
);
var
renderResult
=
this
.
_doRender
(
containerGroup
,
seriesModel
,
reRoot
);
(
!
isInit
&&
(
!
payloadType
||
payloadType
===
'
treemapZoomToNode
'
))
?
this
.
_doAnimation
(
containerGroup
,
renderResult
,
seriesModel
)
(
!
isInit
&&
(
!
payloadType
||
payloadType
===
'
treemapZoomToNode
'
||
payloadType
===
'
treemapRootToNode
'
)
)
?
this
.
_doAnimation
(
containerGroup
,
renderResult
,
seriesModel
,
reRoot
)
:
renderResult
.
renderFinally
();
this
.
_resetController
(
api
);
var
targetInfo
=
helper
.
retrieveTargetInfo
(
payload
,
seriesModel
);
this
.
_renderBreadcrumb
(
seriesModel
,
api
,
targetInfo
);
},
...
...
@@ -122,7 +137,7 @@
/**
* @private
*/
_doRender
:
function
(
containerGroup
,
seriesModel
)
{
_doRender
:
function
(
containerGroup
,
seriesModel
,
reRoot
)
{
var
thisTree
=
seriesModel
.
getData
().
tree
;
var
oldTree
=
this
.
_oldTree
;
...
...
@@ -135,9 +150,11 @@
var
willDeleteEls
=
[];
var
renderNode
=
bind
(
this
.
_renderNode
,
this
,
thisStorage
,
oldStorage
,
lastsForAnimation
,
willInvisibleEls
,
willVisibleEls
thisStorage
,
oldStorage
,
reRoot
,
lastsForAnimation
,
willInvisibleEls
,
willVisibleEls
);
var
viewRoot
=
seriesModel
.
getViewRoot
();
var
viewPath
=
helper
.
getPathToRoot
(
viewRoot
);
// Notice: when thisTree and oldTree are the same tree (see list.cloneShadow),
// the oldTree is actually losted, so we can not find all of the old graphic
...
...
@@ -149,7 +166,7 @@
(
oldTree
&&
oldTree
.
root
)
?
[
oldTree
.
root
]
:
[],
containerGroup
,
thisTree
===
oldTree
||
!
oldTree
,
viewRoot
===
thisTree
.
root
0
);
// Process all removing.
...
...
@@ -164,7 +181,7 @@
renderFinally
:
renderFinally
};
function
dualTravel
(
thisViewChildren
,
oldViewChildren
,
parentGroup
,
sameTree
,
inView
)
{
function
dualTravel
(
thisViewChildren
,
oldViewChildren
,
parentGroup
,
sameTree
,
viewPathIndex
)
{
// When 'render' is triggered by action,
// 'this' and 'old' may be the same tree,
// we use rawIndex in that case.
...
...
@@ -194,10 +211,14 @@
var
oldNode
=
oldIndex
!=
null
?
oldViewChildren
[
oldIndex
]
:
null
;
// Whether under viewRoot.
var
subInView
=
inView
||
thisNode
===
viewRoot
;
// If not under viewRoot, only remove.
if
(
!
subInView
)
{
thisNode
=
null
;
if
(
!
thisNode
||
isNaN
(
viewPathIndex
)
||
(
viewPathIndex
<
viewPath
.
length
&&
viewPath
[
viewPathIndex
]
!==
thisNode
)
)
{
// Deleting nodes will be performed finally. This method just find
// element from old storage, or create new element, set them to new
// storage, and set styles.
return
;
}
var
group
=
renderNode
(
thisNode
,
oldNode
,
parentGroup
);
...
...
@@ -207,7 +228,7 @@
oldNode
&&
oldNode
.
viewChildren
||
[],
group
,
sameTree
,
subInView
viewPathIndex
+
1
);
}
}
...
...
@@ -235,6 +256,7 @@
el
.
invisible
=
true
;
// Setting invisible is for optimizing, so no need to set dirty,
// just mark as invisible.
el
.
dirty
();
});
each
(
willVisibleEls
,
function
(
el
)
{
el
.
invisible
=
false
;
...
...
@@ -248,19 +270,13 @@
* @private
*/
_renderNode
:
function
(
thisStorage
,
oldStorage
,
lastsForAnimation
,
willInvisibleEls
,
willVisibleEls
,
thisStorage
,
oldStorage
,
reRoot
,
lastsForAnimation
,
willInvisibleEls
,
willVisibleEls
,
thisNode
,
oldNode
,
parentGroup
)
{
var
thisRawIndex
=
thisNode
&&
thisNode
.
getRawIndex
();
var
oldRawIndex
=
oldNode
&&
oldNode
.
getRawIndex
();
// Deleting things will performed finally. This method just find element from
// old storage, or create new element, set them to new storage, and set styles.
if
(
!
thisNode
)
{
return
;
}
var
layout
=
thisNode
.
getLayout
();
var
thisWidth
=
layout
.
width
;
var
thisHeight
=
layout
.
height
;
...
...
@@ -277,7 +293,7 @@
group
.
__tmNodeHeight
=
thisHeight
;
// Background
var
bg
=
giveGraphic
(
'
background
'
,
Rect
);
var
bg
=
giveGraphic
(
'
background
'
,
Rect
,
0
);
if
(
bg
)
{
bg
.
setShape
({
x
:
0
,
y
:
0
,
width
:
thisWidth
,
height
:
thisHeight
});
updateStyle
(
bg
,
{
fill
:
thisNode
.
getVisual
(
'
borderColor
'
,
true
)});
...
...
@@ -289,13 +305,13 @@
// No children, render content.
if
(
!
thisViewChildren
||
!
thisViewChildren
.
length
)
{
var
borderWidth
=
layout
.
borderWidth
;
var
content
=
giveGraphic
(
'
content
'
,
Rect
);
var
content
=
giveGraphic
(
'
content
'
,
Rect
,
3
);
if
(
content
)
{
var
contentWidth
=
Math
.
max
(
thisWidth
-
2
*
borderWidth
,
0
);
var
contentHeight
=
Math
.
max
(
thisHeight
-
2
*
borderWidth
,
0
);
var
labelModel
=
thisNode
.
getModel
(
'
label.normal
'
);
var
textStyleModel
=
thisNode
.
getModel
(
'
label.normal.textStyle
'
);
var
hoverStyle
=
thisNode
.
getModel
(
'
itemStyle.emphasis
'
).
getItemStyle
();
var
text
=
thisNode
.
getModel
().
get
(
'
name
'
);
var
textRect
=
textStyleModel
.
getTextRect
(
text
);
var
showLabel
=
labelModel
.
get
(
'
show
'
);
...
...
@@ -308,6 +324,8 @@
?
textStyleModel
.
ellipsis
(
text
,
contentWidth
)
:
''
;
}
graphic
.
setHoverStyle
(
content
,
hoverStyle
);
// For tooltip.
content
.
dataIndex
=
thisNode
.
dataIndex
;
content
.
seriesIndex
=
this
.
seriesModel
.
seriesIndex
;
...
...
@@ -319,6 +337,7 @@
width
:
contentWidth
,
height
:
contentHeight
});
updateStyle
(
content
,
{
fill
:
thisNode
.
getVisual
(
'
color
'
,
true
),
text
:
text
,
...
...
@@ -334,7 +353,7 @@
return
group
;
function
giveGraphic
(
storageName
,
Ctor
)
{
function
giveGraphic
(
storageName
,
Ctor
,
z
)
{
var
element
=
oldRawIndex
!=
null
&&
oldStorage
[
storageName
][
oldRawIndex
];
var
lasts
=
lastsForAnimation
[
storageName
];
...
...
@@ -345,7 +364,7 @@
}
// If invisible and no old element, do not create new element (for optimizing).
else
if
(
!
invisible
)
{
element
=
new
Ctor
();
element
=
new
Ctor
(
{
z
:
z
}
);
prepareAnimationWhenNoOld
(
lasts
,
element
,
storageName
);
}
...
...
@@ -356,9 +375,9 @@
function
prepareAnimationWhenHasOld
(
lasts
,
element
,
storageName
)
{
var
lastCfg
=
lasts
[
thisRawIndex
]
=
{};
lastCfg
.
old
=
storageName
===
'
nodeGroup
'
?
element
.
position
.
slice
()
:
zrUtil
.
extend
({},
element
.
shape
);
}
?
element
.
position
.
slice
()
:
zrUtil
.
extend
({},
element
.
shape
);
}
// If a element is new, we need to find the animation start point carefully,
// otherwise it will looks strange when 'zoomToNode'.
...
...
@@ -370,23 +389,25 @@
willVisibleEls
.
push
(
element
);
}
else
{
var
lastCfg
=
lasts
[
thisRawIndex
]
=
{};
var
parentNode
=
thisNode
.
parentNode
;
var
parentOldBg
;
var
parentOldX
=
0
;
var
parentOldY
=
0
;
// For convenient, get old bounding rect from background.
if
(
parentNode
&&
(
parentOldBg
=
lastsForAnimation
.
background
[
parentNode
.
getRawIndex
()]
))
{
parentOldX
=
parentOldBg
.
old
.
width
;
parentOldY
=
parentOldBg
.
old
.
height
;
if
(
parentNode
&&
(
!
reRoot
||
reRoot
.
direction
===
'
drilldown
'
))
{
var
parentOldX
=
0
;
var
parentOldY
=
0
;
// For convenience, get old bounding rect from background.
var
parentOldBg
=
lastsForAnimation
.
background
[
parentNode
.
getRawIndex
()];
if
(
parentOldBg
&&
parentOldBg
.
old
)
{
parentOldX
=
parentOldBg
.
old
.
width
/
2
;
// Devided by 2 for reRoot effect.
parentOldY
=
parentOldBg
.
old
.
height
/
2
;
}
// When no parent old shape found, its parent is new too,
// so we can just use {x:0, y:0}.
lastCfg
.
old
=
storageName
===
'
nodeGroup
'
?
[
parentOldX
,
parentOldY
]
:
{
x
:
parentOldX
,
y
:
parentOldY
,
width
:
0
,
height
:
0
};
}
// When no parent old shape found, its parent is new too,
// so we can just use {x:0, y:0}.
var
lastCfg
=
lasts
[
thisRawIndex
]
=
{};
lastCfg
.
old
=
storageName
===
'
nodeGroup
'
?
[
parentOldX
,
parentOldY
]
:
{
x
:
parentOldX
,
y
:
parentOldY
,
width
:
0
,
height
:
0
};
// Fade in, user can be aware that these nodes are new.
lastCfg
.
fadein
=
storageName
!==
'
nodeGroup
'
;
...
...
@@ -414,56 +435,87 @@
/**
* @private
*/
_doAnimation
:
function
(
containerGroup
,
renderResult
,
seriesModel
)
{
_doAnimation
:
function
(
containerGroup
,
renderResult
,
seriesModel
,
reRoot
)
{
if
(
!
seriesModel
.
get
(
'
animation
'
))
{
return
;
}
var
duration
=
seriesModel
.
get
(
'
animationDurationUpdate
'
);
var
easing
=
seriesModel
.
get
(
'
animationEasing
'
);
var
animationWrap
=
animationUtil
.
createWrap
();
// Make delete animations.
var
viewRoot
=
this
.
seriesModel
.
getViewRoot
();
var
rootGroup
=
this
.
_storage
.
nodeGroup
[
viewRoot
.
getRawIndex
()];
rootGroup
&&
rootGroup
.
traverse
(
function
(
el
)
{
var
storageName
;
if
(
el
.
invisible
||
!
(
storageName
=
el
.
__tmWillDelete
))
{
return
;
}
var
targetX
=
0
;
var
targetY
=
0
;
var
parent
=
el
.
parent
;
// Always has parent, and parent is nodeGroup.
if
(
!
parent
.
__tmWillDelete
)
{
// Let node animate to right-bottom corner, cooperating with fadeout,
// which is perfect for user understanding.
targetX
=
parent
.
__tmNodeWidth
;
targetY
=
parent
.
__tmNodeHeight
;
}
var
target
=
storageName
===
'
nodeGroup
'
?
{
position
:
[
targetX
,
targetY
],
style
:
{
opacity
:
0
}}
:
{
shape
:
{
x
:
targetX
,
y
:
targetY
,
width
:
0
,
height
:
0
},
style
:
{
opacity
:
0
}};
animationWrap
.
add
(
el
,
target
,
duration
,
easing
);
each
(
renderResult
.
willDeleteEls
,
function
(
store
,
storageName
)
{
each
(
store
,
function
(
el
,
rawIndex
)
{
var
storageName
;
if
(
el
.
invisible
||
!
(
storageName
=
el
.
__tmWillDelete
))
{
return
;
}
var
parent
=
el
.
parent
;
// Always has parent, and parent is nodeGroup.
var
target
;
if
(
reRoot
&&
reRoot
.
direction
===
'
drilldown
'
)
{
if
(
parent
===
reRoot
.
rootNodeGroup
)
{
// Only 'content' will enter this branch, but not nodeGroup.
target
=
{
shape
:
{
x
:
0
,
y
:
0
,
width
:
parent
.
__tmNodeWidth
,
height
:
parent
.
__tmNodeHeight
}
};
el
.
z
=
2
;
}
else
{
target
=
{
style
:
{
opacity
:
0
}};
el
.
z
=
1
;
}
}
else
{
var
targetX
=
0
;
var
targetY
=
0
;
if
(
!
parent
.
__tmWillDelete
)
{
// Let node animate to right-bottom corner, cooperating with fadeout,
// which is appropriate for user understanding.
// Divided by 2 for reRoot rollup effect.
targetX
=
parent
.
__tmNodeWidth
/
2
;
targetY
=
parent
.
__tmNodeHeight
/
2
;
}
target
=
storageName
===
'
nodeGroup
'
?
{
position
:
[
targetX
,
targetY
],
style
:
{
opacity
:
0
}}
:
{
shape
:
{
x
:
targetX
,
y
:
targetY
,
width
:
0
,
height
:
0
},
style
:
{
opacity
:
0
}
};
}
target
&&
animationWrap
.
add
(
el
,
target
,
duration
,
easing
);
});
});
// Make other animations
each
(
this
.
_storage
,
function
(
store
,
storageName
)
{
each
(
store
,
function
(
el
,
rawIndex
)
{
var
last
=
renderResult
.
lastsForAnimation
[
storageName
][
rawIndex
];
var
target
;
var
target
=
{}
;
if
(
!
last
)
{
return
;
}
if
(
storageName
===
'
nodeGroup
'
)
{
target
=
{
position
:
el
.
position
.
slice
()};
el
.
position
=
last
.
old
;
if
(
last
.
old
)
{
target
.
position
=
el
.
position
.
slice
();
el
.
position
=
last
.
old
;
}
}
else
{
target
=
{
shape
:
zrUtil
.
extend
({},
el
.
shape
)};
el
.
setShape
(
last
.
old
);
if
(
last
.
old
)
{
target
.
shape
=
zrUtil
.
extend
({},
el
.
shape
);
el
.
setShape
(
last
.
old
);
}
if
(
last
.
fadein
)
{
el
.
setStyle
(
'
opacity
'
,
0
);
...
...
@@ -631,12 +683,19 @@
var
targetInfo
=
this
.
findTarget
(
e
.
offsetX
,
e
.
offsetY
);
if
(
targetInfo
)
{
if
(
!
targetInfo
)
{
return
;
}
var
node
=
targetInfo
.
node
;
if
(
node
.
getLayout
().
isLeafRoot
)
{
this
.
_rootToNode
(
targetInfo
);
}
else
{
if
(
nodeClick
===
'
zoomToNode
'
)
{
this
.
_zoomToNode
(
targetInfo
);
}
else
if
(
nodeClick
===
'
link
'
)
{
var
node
=
targetInfo
.
node
;
var
itemModel
=
node
.
hostTree
.
data
.
getItemModel
(
node
.
dataIndex
);
var
link
=
itemModel
.
get
(
'
link
'
,
true
);
var
linkTarget
=
itemModel
.
get
(
'
target
'
,
true
)
||
'
blank
'
;
...
...
@@ -663,7 +722,11 @@
.
render
(
seriesModel
,
api
,
targetInfo
.
node
);
function
onSelect
(
node
)
{
this
.
_zoomToNode
({
node
:
node
});
if
(
this
.
_state
!==
'
animating
'
)
{
helper
.
aboveViewRoot
(
seriesModel
.
getViewRoot
(),
node
)
?
this
.
_rootToNode
({
node
:
node
})
:
this
.
_zoomToNode
({
node
:
node
});
}
}
},
...
...
@@ -694,6 +757,18 @@
});
},
/**
* @private
*/
_rootToNode
:
function
(
targetInfo
)
{
this
.
api
.
dispatchAction
({
type
:
'
treemapRootToNode
'
,
from
:
this
.
uid
,
seriesId
:
this
.
seriesModel
.
id
,
targetNode
:
targetInfo
.
node
});
},
/**
* @public
* @param {number} x Global coord x.
...
...
@@ -736,4 +811,5 @@
function
createStorage
()
{
return
{
nodeGroup
:
[],
background
:
[],
content
:
[]};
}
});
\ No newline at end of file
src/chart/treemap/helper.js
浏览文件 @
abdb25cf
define
(
function
(
require
)
{
var
zrUtil
=
require
(
'
zrender/core/util
'
);
var
helper
=
{
retrieveTargetInfo
:
function
(
payload
,
seriesModel
)
{
if
(
!
payload
||
payload
.
type
!==
'
treemapZoomToNode
'
)
{
return
;
}
if
(
payload
&&
(
payload
.
type
===
'
treemapZoomToNode
'
||
payload
.
type
===
'
treemapRootToNode
'
)
)
{
var
root
=
seriesModel
.
getData
().
tree
.
root
;
var
targetNode
=
payload
.
targetNode
;
if
(
targetNode
&&
root
.
contains
(
targetNode
))
{
return
{
node
:
targetNode
};
}
var
root
=
seriesModel
.
getData
().
tree
.
root
;
var
targetNode
=
payload
.
targetNode
;
if
(
targetNode
&&
root
.
contains
(
targetNode
))
{
return
{
node
:
targetNode
};
var
targetNodeId
=
payload
.
targetNodeId
;
if
(
targetNodeId
!=
null
&&
(
targetNode
=
root
.
getNodeById
(
targetNodeId
)))
{
return
{
node
:
targetNode
};
}
}
},
var
targetNodeId
=
payload
.
targetNodeId
;
if
(
targetNodeId
!=
null
&&
(
targetNode
=
root
.
getNodeById
(
targetNodeId
)))
{
return
{
node
:
targetNode
};
getPathToRoot
:
function
(
node
)
{
var
path
=
[];
while
(
node
)
{
path
.
push
(
node
);
node
=
node
.
parentNode
;
}
return
path
.
reverse
();
},
aboveViewRoot
:
function
(
viewRoot
,
node
)
{
var
viewPath
=
helper
.
getPathToRoot
(
viewRoot
);
return
helper
.
aboveViewRootByViewPath
(
viewPath
,
node
);
},
return
null
;
// viewPath should obtained from getPathToRoot(viewRoot)
aboveViewRootByViewPath
:
function
(
viewPath
,
node
)
{
var
index
=
zrUtil
.
indexOf
(
viewPath
,
node
);
// The last one is viewRoot
return
index
>=
0
&&
index
!==
viewPath
.
length
-
1
;
}
};
...
...
src/chart/treemap/treemapAction.js
浏览文件 @
abdb25cf
...
...
@@ -4,11 +4,39 @@
define
(
function
(
require
)
{
var
echarts
=
require
(
'
../../echarts
'
);
var
helper
=
require
(
'
./helper
'
);
var
noop
=
function
()
{};
echarts
.
registerAction
({
type
:
'
treemapZoomToNode
'
,
update
:
'
updateView
'
},
noop
);
echarts
.
registerAction
({
type
:
'
treemapRender
'
,
update
:
'
updateView
'
},
noop
);
echarts
.
registerAction
({
type
:
'
treemapMove
'
,
update
:
'
updateView
'
},
noop
);
var
actionTypes
=
[
'
treemapZoomToNode
'
,
'
treemapRender
'
,
'
treemapMove
'
];
for
(
var
i
=
0
;
i
<
actionTypes
.
length
;
i
++
)
{
echarts
.
registerAction
({
type
:
actionTypes
[
i
],
update
:
'
updateView
'
},
noop
);
}
echarts
.
registerAction
(
{
type
:
'
treemapRootToNode
'
,
update
:
'
updateView
'
},
function
(
payload
,
ecModel
)
{
ecModel
.
eachComponent
(
{
mainType
:
'
series
'
,
subType
:
'
treemap
'
,
query
:
payload
},
function
(
model
,
index
)
{
var
targetInfo
=
helper
.
retrieveTargetInfo
(
payload
,
model
);
if
(
targetInfo
)
{
var
originViewRoot
=
model
.
getViewRoot
();
if
(
originViewRoot
)
{
payload
.
direction
=
helper
.
aboveViewRoot
(
originViewRoot
,
targetInfo
.
node
)
?
'
rollup
'
:
'
drilldown
'
;
}
model
.
resetViewRoot
(
targetInfo
.
node
);
}
}
);
}
);
});
\ No newline at end of file
src/chart/treemap/treemapLayout.js
浏览文件 @
abdb25cf
...
...
@@ -5,6 +5,7 @@ define(function (require) {
var
zrUtil
=
require
(
'
zrender/core/util
'
);
var
numberUtil
=
require
(
'
../../util/number
'
);
var
layout
=
require
(
'
../../util/layout
'
);
var
helper
=
require
(
'
./helper
'
);
var
parsePercent
=
numberUtil
.
parsePercent
;
var
retrieveValue
=
zrUtil
.
retrieve
;
var
BoundingRect
=
require
(
'
zrender/core/BoundingRect
'
);
...
...
@@ -21,14 +22,15 @@ define(function (require) {
var
ecWidth
=
api
.
getWidth
();
var
ecHeight
=
api
.
getHeight
();
var
seriesOption
=
seriesModel
.
option
;
var
size
=
series
Model
.
get
(
'
size
'
)
||
[];
// Compatible with ec2.
var
size
=
series
Option
.
size
||
[];
// Compatible with ec2.
var
containerWidth
=
parsePercent
(
retrieveValue
(
series
Model
.
get
(
'
width
'
)
,
size
[
0
]),
retrieveValue
(
series
Option
.
width
,
size
[
0
]),
ecWidth
);
var
containerHeight
=
parsePercent
(
retrieveValue
(
series
Model
.
get
(
'
height
'
)
,
size
[
1
]),
retrieveValue
(
series
Option
.
height
,
size
[
1
]),
ecHeight
);
...
...
@@ -49,18 +51,21 @@ define(function (require) {
if
(
payloadType
!==
'
treemapMove
'
)
{
var
rootSize
=
payloadType
===
'
treemapZoomToNode
'
?
estimateRootSize
(
seriesModel
,
targetInfo
,
containerWidth
,
containerHeight
)
?
estimateRootSize
(
seriesModel
,
targetInfo
,
viewRoot
,
containerWidth
,
containerHeight
)
:
rootRect
?
[
rootRect
.
width
,
rootRect
.
height
]
:
[
containerWidth
,
containerHeight
];
var
sort
=
series
Model
.
get
(
'
sort
'
)
;
var
sort
=
series
Option
.
sort
;
if
(
sort
&&
sort
!==
'
asc
'
&&
sort
!==
'
desc
'
)
{
sort
=
'
desc
'
;
}
var
options
=
{
squareRatio
:
seriesModel
.
get
(
'
squareRatio
'
),
sort
:
sort
squareRatio
:
seriesOption
.
squareRatio
,
sort
:
sort
,
leafDepth
:
seriesOption
.
leafDepth
};
viewRoot
.
setLayout
({
...
...
@@ -69,7 +74,7 @@ define(function (require) {
area
:
rootSize
[
0
]
*
rootSize
[
1
]
});
squarify
(
viewRoot
,
options
);
squarify
(
viewRoot
,
options
,
false
,
0
);
}
// Set root position
...
...
@@ -84,8 +89,10 @@ define(function (require) {
// FIXME
// 现在没有clip功能,暂时取ec高宽。
prunning
(
viewRoot
,
new
BoundingRect
(
-
layoutInfo
.
x
,
-
layoutInfo
.
y
,
ecWidth
,
ecHeight
)
seriesModel
.
getData
().
tree
.
root
,
// Transform to base element coordinate system.
new
BoundingRect
(
-
layoutInfo
.
x
,
-
layoutInfo
.
y
,
ecWidth
,
ecHeight
),
helper
.
getPathToRoot
(
viewRoot
)
);
});
...
...
@@ -100,10 +107,11 @@ define(function (require) {
* @param {module:echarts/data/Tree~TreeNode} node
* @param {Object} options
* @param {string} options.sort 'asc' or 'desc'
* @param {boolean} options.hideChildren
* @param {number} options.squareRatio
* @param {boolean} hideChildren
* @param {number} depth
*/
function
squarify
(
node
,
options
)
{
function
squarify
(
node
,
options
,
hideChildren
,
depth
)
{
var
width
;
var
height
;
...
...
@@ -128,7 +136,9 @@ define(function (require) {
height
=
mathMax
(
height
-
2
*
layoutOffset
,
0
);
var
totalArea
=
width
*
height
;
var
viewChildren
=
initChildren
(
node
,
nodeModel
,
totalArea
,
options
);
var
viewChildren
=
initChildren
(
node
,
nodeModel
,
totalArea
,
options
,
hideChildren
,
depth
);
if
(
!
viewChildren
.
length
)
{
return
;
...
...
@@ -166,9 +176,7 @@ define(function (require) {
position
(
row
,
rowFixedLength
,
rect
,
halfGapWidth
,
true
);
}
// Update option carefully.
var
hideChildren
;
if
(
!
options
.
hideChildren
)
{
if
(
!
hideChildren
)
{
var
childrenVisibleMin
=
nodeModel
.
get
(
'
childrenVisibleMin
'
);
if
(
childrenVisibleMin
!=
null
&&
totalArea
<
childrenVisibleMin
)
{
hideChildren
=
true
;
...
...
@@ -176,23 +184,22 @@ define(function (require) {
}
for
(
var
i
=
0
,
len
=
viewChildren
.
length
;
i
<
len
;
i
++
)
{
var
childOption
=
zrUtil
.
extend
({
hideChildren
:
hideChildren
},
options
);
squarify
(
viewChildren
[
i
],
childOption
);
squarify
(
viewChildren
[
i
],
options
,
hideChildren
,
depth
+
1
);
}
}
/**
* Set area to each child, and calculate data extent for visual coding.
*/
function
initChildren
(
node
,
nodeModel
,
totalArea
,
options
)
{
function
initChildren
(
node
,
nodeModel
,
totalArea
,
options
,
hideChildren
,
depth
)
{
var
viewChildren
=
node
.
children
||
[];
var
orderBy
=
options
.
sort
;
orderBy
!==
'
asc
'
&&
orderBy
!==
'
desc
'
&&
(
orderBy
=
null
);
if
(
options
.
hideChildren
)
{
var
overLeafDepth
=
options
.
leafDepth
!=
null
&&
options
.
leafDepth
<=
depth
;
// leafDepth has higher priority.
if
(
hideChildren
&&
!
overLeafDepth
)
{
return
(
node
.
viewChildren
=
[]);
}
...
...
@@ -222,6 +229,11 @@ define(function (require) {
viewChildren
[
i
].
setLayout
({
area
:
area
});
}
if
(
overLeafDepth
)
{
viewChildren
.
length
&&
node
.
setLayout
({
isLeafRoot
:
true
},
true
);
viewChildren
.
length
=
0
;
}
node
.
viewChildren
=
viewChildren
;
node
.
setLayout
({
dataExtent
:
info
.
dataExtent
},
true
);
...
...
@@ -393,19 +405,19 @@ define(function (require) {
}
// Return [containerWidth, containerHeight] as defualt.
function
estimateRootSize
(
seriesModel
,
targetInfo
,
containerWidth
,
containerHeight
)
{
function
estimateRootSize
(
seriesModel
,
targetInfo
,
viewRoot
,
containerWidth
,
containerHeight
)
{
// If targetInfo.node exists, we zoom to the node,
// so estimate whold width and heigth by target node.
var
currNode
=
(
targetInfo
||
{}).
node
;
var
defaultSize
=
[
containerWidth
,
containerHeight
];
if
(
!
currNode
||
currNode
===
seriesModel
.
getViewRoot
()
)
{
if
(
!
currNode
||
currNode
===
viewRoot
)
{
return
defaultSize
;
}
var
parent
;
var
viewArea
=
containerWidth
*
containerHeight
;
var
area
=
viewArea
*
seriesModel
.
get
(
'
zoomToNodeRatio
'
)
;
var
area
=
viewArea
*
seriesModel
.
option
.
zoomToNodeRatio
;
while
(
parent
=
currNode
.
parentNode
)
{
// jshint ignore:line
var
sum
=
0
;
...
...
@@ -478,10 +490,14 @@ define(function (require) {
// Mark invisible nodes for prunning when visual coding and rendering.
// Prunning depends on layout and root position, so we have to do it after them.
function
prunning
(
node
,
clipRect
)
{
function
prunning
(
node
,
clipRect
,
viewPath
)
{
var
nodeLayout
=
node
.
getLayout
();
node
.
setLayout
({
invisible
:
!
clipRect
.
intersect
(
nodeLayout
)},
true
);
node
.
setLayout
({
invisible
:
nodeLayout
?
!
clipRect
.
intersect
(
nodeLayout
)
:
!
helper
.
aboveViewRootByViewPath
(
viewPath
,
node
)
},
true
);
var
viewChildren
=
node
.
viewChildren
||
[];
for
(
var
i
=
0
,
len
=
viewChildren
.
length
;
i
<
len
;
i
++
)
{
...
...
@@ -492,7 +508,7 @@ define(function (require) {
clipRect
.
width
,
clipRect
.
height
);
prunning
(
viewChildren
[
i
],
childClipRect
);
prunning
(
viewChildren
[
i
],
childClipRect
,
viewPath
);
}
}
...
...
test/treemap-disk.html
浏览文件 @
abdb25cf
...
...
@@ -55,6 +55,15 @@
<input
type=
"radio"
id=
"colorMapping-1"
name=
"colorMapping"
onclick=
"colorMappingChange('value');"
/>
<label
for=
"colorMapping-1"
>
byValue
</label>
</span>
<span
class=
"item"
>
<span
class=
"item-title"
>
leafDepth:
</span>
<input
type=
"radio"
id=
"leafDepth-0"
name=
"leafDepth"
onclick=
"leafDepthChange(null);"
checked=
"checked"
/>
<label
for=
"leafDepth-0"
>
Not set
</label>
<input
type=
"radio"
id=
"leafDepth-1"
name=
"leafDepth"
onclick=
"leafDepthChange(1);"
/>
<label
for=
"leafDepth-1"
>
Set to 1
</label>
<input
type=
"radio"
id=
"leafDepth-2"
name=
"leafDepth"
onclick=
"leafDepthChange(2);"
/>
<label
for=
"leafDepth-1"
>
Set to 2
</label>
</span>
</div>
<div
id=
"main"
></div>
...
...
@@ -94,6 +103,14 @@
});
}
function
leafDepthChange
(
value
)
{
chart
.
setOption
({
series
:
[{
leafDepth
:
value
}]
});
}
function
getLevelOption
(
colorMapping
)
{
return
[
{
...
...
test/treemap-option.html
0 → 100644
浏览文件 @
abdb25cf
<!DOCTYPE html>
<html>
<head>
<meta
charset=
"utf-8"
>
<title>
Option View
</title>
<script
src=
"esl.js"
></script>
<script
src=
"config.js"
></script>
<style
type=
"text/css"
>
body
{
margin
:
0
;
}
html
,
body
,
#option-view-chart
{
height
:
100%
;
}
</style>
</head>
<body>
<div
id=
"option-view-chart"
></div>
<script
src=
"./lib/jquery.min.js"
></script>
<script>
var
echarts
;
var
formatUtil
;
var
chart
;
require
([
'
echarts
'
,
'
echarts/util/format
'
,
'
echarts/component/tooltip
'
,
'
echarts/component/legend
'
,
'
echarts/chart/treemap
'
],
function
(
ec
,
format
)
{
echarts
=
ec
;
formatUtil
=
format
;
chart
=
echarts
.
init
(
$
(
'
#option-view-chart
'
)[
0
]);
chart
.
showLoading
();
$
.
getJSON
(
'
./data/option-view.json
'
,
initEcharts
);
});
function
convert
(
source
,
target
,
basePath
)
{
for
(
var
key
in
source
)
{
var
path
=
basePath
?
(
basePath
+
'
.
'
+
key
)
:
key
;
if
(
key
.
match
(
/^
\$
/
))
{
}
else
{
target
.
children
=
target
.
children
||
[];
var
child
=
{
name
:
path
};
target
.
children
.
push
(
child
);
convert
(
source
[
key
],
child
,
path
);
}
}
target
.
value
=
source
.
$count
||
1
;
}
function
initEcharts
(
rawData
)
{
chart
.
hideLoading
();
var
data
=
{};
convert
(
rawData
,
data
,
''
);
chart
.
setOption
({
title
:
{
text
:
'
配置项查询分布
'
,
left
:
'
center
'
},
tooltip
:
{},
series
:
[{
name
:
'
option
'
,
type
:
'
treemap
'
,
visibleMin
:
300
,
data
:
data
.
children
,
leafDepth
:
1
,
nodeClick
:
'
link
'
,
itemStyle
:
{
normal
:
{
// gapWidth: 1
// borderWidth: 1
}
},
levels
:
[
{},
{
colorSaturation
:
[
0.2
,
0.7
]
}
]
}]
});
}
$
(
window
).
resize
(
function
()
{
chart
&&
chart
.
resize
();
})
</script>
</body>
</html>
\ No newline at end of file
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录