Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
PaddlePaddle
VisualDL
提交
dd4dd938
V
VisualDL
项目概览
PaddlePaddle
/
VisualDL
大约 1 年 前同步成功
通知
88
Star
4655
Fork
642
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
10
列表
看板
标记
里程碑
合并请求
2
Wiki
5
Wiki
分析
仓库
DevOps
项目成员
Pages
V
VisualDL
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
10
Issue
10
列表
看板
标记
里程碑
合并请求
2
合并请求
2
Pages
分析
分析
仓库分析
DevOps
Wiki
5
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
未验证
提交
dd4dd938
编写于
6月 29, 2022
作者:
R
RotPublic
提交者:
GitHub
6月 29, 2022
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Optimize visual effects
Co-authored-by:
N
wuzewu
<
wuzewu@baidu.com
>
上级
6fdfcdea
变更
2
隐藏空白更改
内联
并排
Showing
2 changed file
with
650 addition
and
18 deletion
+650
-18
frontend/packages/netron/src/style.scss
frontend/packages/netron/src/style.scss
+304
-2
frontend/packages/netron/src/view-grapher.js
frontend/packages/netron/src/view-grapher.js
+346
-16
未找到文件。
frontend/packages/netron/src/style.scss
浏览文件 @
dd4dd938
html
{
text-size-adjust
:
100%
;
text-rendering
:
optimizeLegibility
;
}
body
{
overflow
:
hidden
;
margin
:
0
;
width
:
100vw
;
height
:
100vh
;
font-family
:
-
apple-system
,
BlinkMacSystemFont
,
'Segoe WPC'
,
'Segoe UI'
,
'Ubuntu'
,
'Droid Sans'
,
sans-serif
,
'PingFang SC'
;
font-size
:
12px
;
text-rendering
:
geometricPrecision
;
background-color
:
#fff
;
&
.dark
{
background-color
:
#1d1d1f
;
}
}
.graph
{
overflow
:
auto
;
width
:
100%
;
height
:
100%
;
}
.canvas
{
display
:
block
;
// position: absolute;
text-rendering
:
geometricPrecision
;
user-select
:
none
;
cursor
:
grab
;
}
path
{
stroke
:
#666
;
stroke-width
:
1px
;
fill
:
none
;
}
line
{
stroke
:
#666
;
stroke-width
:
1px
;
fill
:
#666
;
}
text
{
font-family
:
-
apple-system
,
BlinkMacSystemFont
,
'Segoe WPC'
,
'Segoe UI'
,
'Ubuntu'
,
'Droid Sans'
,
sans-serif
,
'PingFang SC'
;
font-size
:
11px
;
text-rendering
:
geometricPrecision
;
fill
:
#000
;
.dark
&
{
fill
:
#cfcfd1
;
}
}
.node-item
{
path
{
fill
:
#fff
;
fill-opacity
:
1
;
stroke
:
none
;
transition
:
fill
0
.075s
ease-in
,
fill-opacity
0
.075s
ease-in
;
}
text
{
transition
:
fill
0
.075s
ease-in
;
}
&
:hover
{
path
{
fill
:
#2932e1
;
fill-opacity
:
1
;
}
text
{
fill
:
#fff
;
}
}
}
.node-item-function
path
{
fill
:
#9bb9e8
;
fill-opacity
:
0
.7
;
}
.node-item-type
{
cursor
:
pointer
;
path
{
fill
:
#8bb8ff
;
fill-opacity
:
0
.9
;
}
}
.node-item-type-constant
path
{
fill
:
#b4ccb7
;
}
.node-item-type-control
path
{
fill
:
#a8e9b8
;
}
.node-item-type-layer
path
{
fill
:
#db989a
;
fill-opacity
:
0
.7
;
}
.node-item-type-container
path
{
fill
:
#db989a
;
fill-opacity
:
0
.7
;
}
.node-item-type-wrapper
path
{
fill
:
#6dcde4
;
fill-opacity
:
0
.7
;
}
.node-item-type-conv
path
{
fill
:
#6dcde4
;
fill-opacity
:
0
.7
;
}
.node-item-type-activation
path
{
fill
:
#93c2ca
;
fill-opacity
:
0
.7
;
}
.node-item-type-pool
path
{
fill
:
#de7cce
;
fill-opacity
:
0
.7
;
}
.node-item-type-normalization
path
{
fill
:
#da96bc
;
fill-opacity
:
0
.7
;
}
.node-item-type-dropout
path
{
fill
:
#309e51
;
fill-opacity
:
0
.7
;
}
.node-item-type-pad
path
{
fill
:
#309e51
;
fill-opacity
:
0
.7
;
}
.node-item-type-shape
path
{
fill
:
#d6c482
;
fill-opacity
:
0
.7
;
}
.node-item-type-tensor
path
{
fill
:
#6d7ce4
;
fill-opacity
:
0
.7
;
}
.node-item-type-transform
path
{
fill
:
#cdcb74
;
}
.node-item-type-sequence
path
{
fill
:
#cdcb74
;
}
.node-item-type-data
path
{
fill
:
#2576ad
;
fill-opacity
:
0
.7
;
}
.node-item-type-custom
path
{
fill
:
#e46d6d
;
fill-opacity
:
0
.7
;
}
.node-item-input
{
cursor
:
pointer
;
path
{
fill
:
#fff
;
}
}
.node-item-constant
{
cursor
:
pointer
;
path
{
fill
:
#eee
;
}
}
.node-item-undefined
{
cursor
:
pointer
;
path
{
fill
:
#ca5353
;
fill-opacity
:
0
.7
;
}
}
.node-attribute
{
cursor
:
pointer
;
text
{
font-size
:
9px
;
font-weight
:
normal
;
}
}
.node-attribute
path
{
fill
:
#fff
;
stroke-width
:
0
;
.dark
&
{
fill
:
#262629
;
}
}
.graph-item-input
{
cursor
:
pointer
;
path
{
fill
:
#e49d6d
;
fill-opacity
:
0
.7
;
}
}
.graph-item-output
{
cursor
:
pointer
;
path
{
fill
:
#e4e06d
;
fill-opacity
:
0
.9
;
}
}
.edge-label
text
{
font-size
:
10px
;
}
.edge-path
{
stroke
:
#666
;
stroke-width
:
1px
;
fill
:
none
;
}
#arrowhead-vee
path
{
fill
:
#666
;
}
.edge-path-control-dependency
{
stroke-dasharray
:
3
,
2
;
}
.cluster
.clusterGroup
{
fill
:
#dce9ff
;
stroke
:
#666
;
stroke-width
:
1px
;
}
.node-item-function
path
{
fill
:
#9bb9e8
;
fill-opacity
:
0
.7
;
}
.cluster
.clusterGroup-constant
{
fill
:
#e8efe9
;
}
.cluster
.clusterGroup-control
{
fill
:
#e4f8e9
;
}
.cluster
.clusterGroup-layer
{
fill
:
#f4e0e0
;
}
.cluster
.clusterGroup-conv
{
fill
:
#d3f0f6
;
}
.cluster
.clusterGroup-container
{
fill
:
#f4e0e0
;
}
.cluster
.clusterGroup-wrapper
{
fill
:
#d3f0f6
;
}
.cluster
.clusterGroup-activation
{
fill
:
#deecef
;
}
.cluster
.clusterGroup-pool
{
fill
:
#f5d7f0
;
}
.cluster
.clusterGroup-normalization
{
fill
:
#f3dfea
;
}
.cluster
.clusterGroup-dropout
{
fill
:
#c0e1ca
;
}
.cluster
.clusterGroup-pad
{
fill
:
#c0e1ca
;
}
.cluster
.clusterGroup-shape
{
fill
:
#f2edd9
;
}
.cluster
.clusterGroup-tensor
{
fill
:
#d3d7f6
;
}
.cluster
.clusterGroup-transform
{
fill
:
#f0efd5
;
}
.cluster
.clusterGroup-sequence
{
fill
:
#f0efd5
;
}
.cluster
.clusterGroup-data
{
fill
:
#bdd5e6
;
}
.cluster
.clusterGroup-custom
{
fill
:
#f6d3d3
;
}
.cluster
.clusterButton
{
fill-opacity
:
0
.3
;
fill-opacity
:
0
;
fill
:
#db989a
;
stroke
:
#999
;
cursor
:
pointer
;
}
.cluster
.button-text
{
fill
:
#999
;
}
.cluster.border
{
display
:
none
;
}
.select
{
&
.edge-path
{
stroke
:
#1527c2
;
stroke-width
:
2px
;
stroke-dasharray
:
6px
3px
;
stroke-dashoffset
:
0
;
animation
:
pulse
4s
infinite
linear
;
}
.node.border
{
stroke
:
#1527c2
;
stroke-width
:
2px
;
stroke-dasharray
:
6px
3px
;
stroke-dashoffset
:
0
;
animation
:
pulse
4s
infinite
linear
;
}
.cluster.border
{
display
:
block
;
stroke
:
#1527c2
;
stroke-width
:
2px
;
stroke-dasharray
:
6px
3px
;
stroke-dashoffset
:
0
;
animation
:
pulse
4s
infinite
linear
;
}
}
@keyframes
pulse
{
from
{
stroke-dashoffset
:
100px
;
}
to
{
stroke-dashoffset
:
0
;
}
}
}
\ No newline at end of file
frontend/packages/netron/src/view-grapher.js
浏览文件 @
dd4dd938
...
...
@@ -5,7 +5,7 @@
* 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
* 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,
...
...
@@ -15,50 +15,71 @@
*/
var
grapher
=
grapher
||
{};
var
dagre
=
dagre
||
require
(
'
dagre
'
);
grapher
.
Renderer
=
class
{
constructor
(
host
,
svgElement
,
view
)
{
this
.
_document
=
host
.
document
;
this
.
_svgElement
=
svgElement
;
this
.
_host
=
host
;
this
.
_view
=
view
;
}
render
(
graph
)
{
let
svgClusterGroup
=
null
;
let
svgEdgePathGroup
=
null
;
let
svgEdgeLabelGroup
=
null
;
let
svgNodeGroup
=
null
;
svgClusterGroup
=
this
.
createElement
(
'
g
'
);
svgClusterGroup
.
setAttribute
(
'
id
'
,
'
clusters
'
);
svgClusterGroup
.
setAttribute
(
'
class
'
,
'
clusters
'
);
this
.
_svgElement
.
appendChild
(
svgClusterGroup
);
svgEdgePathGroup
=
this
.
createElement
(
'
g
'
);
svgEdgePathGroup
.
setAttribute
(
'
id
'
,
'
edge-paths
'
);
svgEdgePathGroup
.
setAttribute
(
'
class
'
,
'
edge-paths
'
);
this
.
_svgElement
.
appendChild
(
svgEdgePathGroup
);
svgEdgeLabelGroup
=
this
.
createElement
(
'
g
'
);
svgEdgeLabelGroup
.
setAttribute
(
'
id
'
,
'
edge-labels
'
);
svgEdgeLabelGroup
.
setAttribute
(
'
class
'
,
'
edge-labels
'
);
this
.
_svgElement
.
appendChild
(
svgEdgeLabelGroup
);
svgNodeGroup
=
this
.
createElement
(
'
g
'
);
svgNodeGroup
.
setAttribute
(
'
id
'
,
'
nodes
'
);
svgNodeGroup
.
setAttribute
(
'
class
'
,
'
nodes
'
);
this
.
_svgElement
.
appendChild
(
svgNodeGroup
);
// } else {
//
svgClusterGroup = this._document.getElementById('clusters')
//
svgEdgePathGroup = this._document.getElementById('edge-paths')
//
svgEdgeLabelGroup = this._document.getElementById('edge-labels')
//
svgNodeGroup = this._document.getElementById('nodes')
// svgClusterGroup = this._document.getElementById('clusters')
// svgEdgePathGroup = this._document.getElementById('edge-paths')
// svgEdgeLabelGroup = this._document.getElementById('edge-labels')
// svgNodeGroup = this._document.getElementById('nodes')
// }
for
(
const
nodeId
of
graph
.
nodes
())
{
if
(
graph
.
children
(
nodeId
).
length
==
0
)
{
const
node
=
graph
.
node
(
nodeId
);
// 在这里进行缓存的判断
// console.log('this._document', this._document);
// const nodeDom = this._document.getElementById(node.id);
...
...
@@ -67,11 +88,15 @@ grapher.Renderer = class {
// 这个节点存在过
svgNodeGroup
.
appendChild
(
this
.
_view
.
_nodes
[
node
.
id
]);
const
nodeBox
=
this
.
_view
.
_nodes
[
node
.
id
].
getBBox
();
node
.
width
=
nodeBox
.
width
;
node
.
height
=
nodeBox
.
height
;
node
.
element
=
this
.
_view
.
_nodes
[
node
.
id
];
}
else
{
const
element
=
this
.
createElement
(
'
g
'
);
if
(
node
.
id
)
{
element
.
setAttribute
(
'
id
'
,
node
.
id
);
}
...
...
@@ -80,17 +105,25 @@ grapher.Renderer = class {
Object
.
prototype
.
hasOwnProperty
.
call
(
node
,
'
class
'
)
?
'
node
'
+
node
.
class
:
'
node
'
);
element
.
style
.
opacity
=
0
;
const
container
=
this
.
createElement
(
'
g
'
);
container
.
appendChild
(
node
.
label
);
// node.label 就是fromat 之后的节点
element
.
appendChild
(
container
);
svgNodeGroup
.
appendChild
(
element
);
const
nodeBox
=
node
.
label
.
getBBox
();
const
nodeX
=
-
nodeBox
.
width
/
2
;
const
nodeY
=
-
nodeBox
.
height
/
2
;
container
.
setAttribute
(
'
transform
'
,
'
translate(
'
+
nodeX
+
'
,
'
+
nodeY
+
'
)
'
);
node
.
width
=
nodeBox
.
width
;
node
.
height
=
nodeBox
.
height
;
node
.
element
=
element
;
}
}
...
...
@@ -98,27 +131,43 @@ grapher.Renderer = class {
for
(
const
edgeId
of
graph
.
edges
())
{
const
edge
=
graph
.
edge
(
edgeId
);
if
(
edge
.
label
)
{
const
tspan
=
this
.
createElement
(
'
tspan
'
);
tspan
.
setAttribute
(
'
xml:space
'
,
'
preserve
'
);
tspan
.
setAttribute
(
'
dy
'
,
'
1em
'
);
tspan
.
setAttribute
(
'
x
'
,
'
1
'
);
tspan
.
appendChild
(
this
.
_document
.
createTextNode
(
edge
.
label
));
const
text
=
this
.
createElement
(
'
text
'
);
text
.
appendChild
(
tspan
);
const
textContainer
=
this
.
createElement
(
'
g
'
);
textContainer
.
appendChild
(
text
);
const
labelElement
=
this
.
createElement
(
'
g
'
);
labelElement
.
style
.
opacity
=
0
;
labelElement
.
setAttribute
(
'
class
'
,
'
edge-label
'
);
labelElement
.
appendChild
(
textContainer
);
svgEdgeLabelGroup
.
appendChild
(
labelElement
);
const
edgeBox
=
textContainer
.
getBBox
();
const
edgeX
=
-
edgeBox
.
width
/
2
;
const
edgeY
=
-
edgeBox
.
height
/
2
;
textContainer
.
setAttribute
(
'
transform
'
,
'
translate(
'
+
edgeX
+
'
,
'
+
edgeY
+
'
)
'
);
edge
.
width
=
edgeBox
.
width
;
edge
.
height
=
edgeBox
.
height
;
edge
.
labelElement
=
labelElement
;
}
}
...
...
@@ -128,49 +177,74 @@ grapher.Renderer = class {
for
(
const
nodeId
of
graph
.
nodes
())
{
if
(
graph
.
children
(
nodeId
).
length
==
0
)
{
const
node
=
graph
.
node
(
nodeId
);
node
.
element
.
setAttribute
(
'
transform
'
,
'
translate(
'
+
node
.
x
+
'
,
'
+
node
.
y
+
'
)
'
);
node
.
element
.
style
.
opacity
=
1
;
delete
node
.
element
;
}
}
for
(
const
edgeId
of
graph
.
edges
())
{
const
edge
=
graph
.
edge
(
edgeId
);
if
(
edge
.
labelElement
)
{
edge
.
labelElement
.
setAttribute
(
'
transform
'
,
'
translate(
'
+
edge
.
x
+
'
,
'
+
edge
.
y
+
'
)
'
);
edge
.
labelElement
.
style
.
opacity
=
1
;
delete
edge
.
labelElement
;
}
}
const
edgePathGroupDefs
=
this
.
createElement
(
'
defs
'
);
svgEdgePathGroup
.
appendChild
(
edgePathGroupDefs
);
const
marker
=
this
.
createElement
(
'
marker
'
);
marker
.
setAttribute
(
'
id
'
,
'
arrowhead-vee
'
);
marker
.
setAttribute
(
'
viewBox
'
,
'
0 0 10 10
'
);
marker
.
setAttribute
(
'
refX
'
,
9
);
marker
.
setAttribute
(
'
refY
'
,
5
);
marker
.
setAttribute
(
'
markerUnits
'
,
'
strokeWidth
'
);
marker
.
setAttribute
(
'
markerWidth
'
,
8
);
marker
.
setAttribute
(
'
markerHeight
'
,
6
);
marker
.
setAttribute
(
'
orient
'
,
'
auto
'
);
edgePathGroupDefs
.
appendChild
(
marker
);
const
markerPath
=
this
.
createElement
(
'
path
'
);
markerPath
.
setAttribute
(
'
d
'
,
'
M 0 0 L 10 5 L 0 10 L 4 5 z
'
);
markerPath
.
style
.
setProperty
(
'
stroke-width
'
,
1
);
markerPath
.
style
.
setProperty
(
'
stroke-dasharray
'
,
'
1,0
'
);
marker
.
appendChild
(
markerPath
);
for
(
const
edgeId
of
graph
.
edges
())
{
const
edge
=
graph
.
edge
(
edgeId
);
const
edgePath
=
grapher
.
Renderer
.
_computeCurvePath
(
edge
,
graph
.
node
(
edgeId
.
v
),
graph
.
node
(
edgeId
.
w
));
const
edgeElement
=
this
.
createElement
(
'
path
'
);
edgeElement
.
setAttribute
(
'
class
'
,
Object
.
prototype
.
hasOwnProperty
.
call
(
edge
,
'
class
'
)
?
'
edge-path
'
+
edge
.
class
:
'
edge-path
'
);
edgeElement
.
setAttribute
(
'
d
'
,
edgePath
);
edgeElement
.
setAttribute
(
'
marker-end
'
,
'
url(#arrowhead-vee)
'
);
if
(
edge
.
id
)
{
edgeElement
.
setAttribute
(
'
id
'
,
edge
.
id
);
}
...
...
@@ -183,6 +257,7 @@ grapher.Renderer = class {
svgEdgePathGroup
.
appendChild
(
edgeElement
);
}
const
groupArray
=
[];
for
(
const
nodeId
of
graph
.
nodes
())
{
if
(
!
Number
(
nodeId
)
&&
Number
(
nodeId
)
!==
0
)
{
groupArray
.
push
(
nodeId
);
...
...
@@ -190,52 +265,76 @@ grapher.Renderer = class {
}
const
newGroupArray
=
groupArray
.
sort
((
a
,
b
)
=>
{
let
level1
=
a
.
split
(
'
/
'
).
length
;
let
level2
=
b
.
split
(
'
/
'
).
length
;
return
level1
-
level2
;
});
for
(
const
nodeId
of
newGroupArray
)
{
if
(
graph
.
children
(
nodeId
).
length
>
0
)
{
const
node
=
graph
.
node
(
nodeId
);
// const nodeDom = this._document.getElementById(`node-${nodeId}`)
// if (this._view._nodes.hasOwnProperty(node.id)) {
// // 这个节点存在过
// svgNodeGroup.appendChild(this._view._nodes[node.id]);
// const nodeBox = this._view._nodes[node.id].getBBox();
// node.width = nodeBox.width;
// node.height = nodeBox.height;
// node.element = this._view._nodes[node.id]
if
(
this
.
_view
.
_clusters
.
hasOwnProperty
(
node
.
id
))
{
const
nodeDom
=
this
.
_view
.
_clusters
.
hasOwnProperty
(
node
.
id
);
nodeDom
.
setAttribute
(
'
transform
'
,
'
translate(
'
+
node
.
x
+
'
,
'
+
node
.
y
+
'
)
'
);
nodeDom
.
firstChild
.
setAttribute
(
'
x
'
,
-
node
.
width
/
2
);
nodeDom
.
firstChild
.
setAttribute
(
'
y
'
,
-
node
.
height
/
2
);
nodeDom
.
firstChild
.
setAttribute
(
'
width
'
,
node
.
width
+
10
);
nodeDom
.
firstChild
.
setAttribute
(
'
height
'
,
node
.
height
+
10
);
}
else
{
const
nodeElement
=
this
.
createElement
(
'
g
'
);
nodeElement
.
setAttribute
(
'
class
'
,
'
cluster
'
);
nodeElement
.
setAttribute
(
'
id
'
,
`node-
${
nodeId
}
`
);
nodeElement
.
setAttribute
(
'
transform
'
,
'
translate(
'
+
node
.
x
+
'
,
'
+
node
.
y
+
'
)
'
);
const
rect
=
this
.
createElement
(
'
rect
'
);
const
tspan
=
this
.
createElement
(
'
tspan
'
);
const
button
=
this
.
createElement
(
'
circle
'
);
const
buttonSign
=
this
.
createElement
(
'
tspan
'
);
button
.
setAttribute
(
'
r
'
,
'
6.5
'
);
button
.
setAttribute
(
'
cx
'
,
node
.
width
/
2
-
20
+
7.5
+
10
);
button
.
setAttribute
(
'
cy
'
,
-
(
node
.
height
/
2
)
+
5
+
7.5
);
buttonSign
.
setAttribute
(
'
x
'
,
node
.
width
/
2
-
15
+
9
);
buttonSign
.
setAttribute
(
'
y
'
,
-
(
node
.
height
/
2
)
+
1.3
);
buttonSign
.
setAttribute
(
'
xml:space
'
,
'
preserve
'
);
buttonSign
.
setAttribute
(
'
dy
'
,
'
1em
'
);
buttonSign
.
setAttribute
(
'
font-size
'
,
'
16px
'
);
buttonSign
.
setAttribute
(
'
class
'
,
'
button-text
'
);
button
.
setAttribute
(
'
class
'
,
'
clusterButton
'
);
tspan
.
setAttribute
(
'
xml:space
'
,
'
preserve
'
);
tspan
.
setAttribute
(
'
dy
'
,
'
1em
'
);
tspan
.
setAttribute
(
'
x
'
,
0
);
tspan
.
setAttribute
(
'
y
'
,
-
(
node
.
height
/
2
)
+
5
);
tspan
.
setAttribute
(
'
text-anchor
'
,
'
middle
'
);
let
name
=
''
;
for
(
const
nodes
of
this
.
_host
.
_view
.
_allGraph
.
nodes
)
{
if
(
nodes
.
name
===
node
.
nodeId
)
{
name
=
nodes
.
show_name
.
split
(
'
/
'
)[
nodes
.
show_name
.
split
(
'
/
'
).
length
-
1
];
...
...
@@ -244,23 +343,36 @@ grapher.Renderer = class {
tspan
.
appendChild
(
this
.
_document
.
createTextNode
(
name
));
buttonSign
.
appendChild
(
this
.
_document
.
createTextNode
(
'
-
'
));
const
text
=
this
.
createElement
(
'
text
'
);
text
.
appendChild
(
tspan
);
const
text2
=
this
.
createElement
(
'
text
'
);
text2
.
appendChild
(
buttonSign
);
rect
.
setAttribute
(
'
class
'
,
node
.
classList
.
join
(
'
'
));
rect
.
setAttribute
(
'
x
'
,
-
node
.
width
/
2
);
rect
.
setAttribute
(
'
y
'
,
-
node
.
height
/
2
);
rect
.
setAttribute
(
'
width
'
,
node
.
width
+
10
);
rect
.
setAttribute
(
'
height
'
,
node
.
height
+
10
);
const
borderElement
=
this
.
createElement
(
'
path
'
);
borderElement
.
setAttribute
(
'
class
'
,
[
'
cluster
'
,
'
border
'
].
join
(
'
'
));
borderElement
.
setAttribute
(
'
d
'
,
grapher
.
NodeElement
.
roundedRect
(
grapher
.
NodeElement
.
roundedRect
2
(
-
node
.
width
/
2
,
-
node
.
height
/
2
,
node
.
width
+
10
,
node
.
height
+
10
,
true
,
true
,
true
,
...
...
@@ -270,19 +382,25 @@ grapher.Renderer = class {
nodeElement
.
addEventListener
(
'
click
'
,
()
=>
{
this
.
_view
.
select
({
id
:
`node-
${
nodeId
}
`
,
name
:
nodeId
,
type
:
'
node
'
});
});
text2
.
addEventListener
(
'
click
'
,
()
=>
{
this
.
_host
.
selectNodeId
({
nodeId
:
node
.
nodeId
,
expand
:
node
.
expand
,
isKeepData
:
node
.
isKeepData
});
this
.
_host
.
selectItems
({
id
:
`node-
${
node
.
nodeId
}
`
,
name
:
node
.
nodeId
,
type
:
'
node
'
});
});
...
...
@@ -340,17 +458,23 @@ grapher.Renderer = class {
static
_computeCurvePath
(
edge
,
tail
,
head
)
{
const
points
=
edge
.
points
.
slice
(
1
,
edge
.
points
.
length
-
1
);
points
.
unshift
(
grapher
.
Renderer
.
intersectRect
(
tail
,
points
[
0
]));
points
.
push
(
grapher
.
Renderer
.
intersectRect
(
head
,
points
[
points
.
length
-
1
]));
const
path
=
new
Path
();
const
curve
=
new
Curve
(
path
);
for
(
let
i
=
0
;
i
<
points
.
length
;
i
++
)
{
const
point
=
points
[
i
];
if
(
i
==
0
)
{
curve
.
lineStart
();
}
curve
.
point
(
point
.
x
,
point
.
y
);
if
(
i
==
points
.
length
-
1
)
{
curve
.
lineEnd
();
}
...
...
@@ -361,24 +485,34 @@ grapher.Renderer = class {
static
intersectRect
(
node
,
point
)
{
const
x
=
node
.
x
;
const
y
=
node
.
y
;
const
dx
=
point
.
x
-
x
;
const
dy
=
point
.
y
-
y
;
let
w
=
node
.
width
/
2
;
let
h
=
node
.
height
/
2
;
let
sx
;
let
sy
;
if
(
Math
.
abs
(
dy
)
*
w
>
Math
.
abs
(
dx
)
*
h
)
{
if
(
dy
<
0
)
{
h
=
-
h
;
}
sx
=
dy
===
0
?
0
:
(
h
*
dx
)
/
dy
;
sy
=
h
;
}
else
{
if
(
dx
<
0
)
{
w
=
-
w
;
}
sx
=
w
;
sy
=
dx
===
0
?
0
:
(
w
*
dy
)
/
dx
;
}
return
{
x
:
x
+
sx
,
y
:
y
+
sy
};
...
...
@@ -388,17 +522,21 @@ grapher.Renderer = class {
grapher
.
NodeElement
=
class
{
constructor
(
document
)
{
this
.
_document
=
document
;
this
.
_blocks
=
[];
}
block
(
type
)
{
this
.
_block
=
null
;
switch
(
type
)
{
case
'
header
'
:
this
.
_block
=
new
grapher
.
NodeElement
.
Header
(
this
.
_document
);
break
;
case
'
list
'
:
this
.
_block
=
new
grapher
.
NodeElement
.
List
(
this
.
_document
);
break
;
}
this
.
_blocks
.
push
(
this
.
_block
);
...
...
@@ -407,9 +545,12 @@ grapher.NodeElement = class {
format
(
contextElement
)
{
const
rootElement
=
this
.
createElement
(
'
g
'
);
contextElement
.
appendChild
(
rootElement
);
let
width
=
0
;
let
height
=
0
;
const
tops
=
[];
for
(
const
block
of
this
.
_blocks
)
{
...
...
@@ -424,22 +565,91 @@ grapher.NodeElement = class {
for
(
let
i
=
0
;
i
<
this
.
_blocks
.
length
;
i
++
)
{
// push 进来的header 或者 list
const
top
=
tops
.
shift
();
this
.
_blocks
[
i
].
update
(
rootElement
,
top
,
width
,
i
==
0
,
i
==
this
.
_blocks
.
length
-
1
);
}
const
borderElement
=
this
.
createElement
(
'
path
'
);
borderElement
.
setAttribute
(
'
class
'
,
[
'
node
'
,
'
border
'
].
join
(
'
'
));
borderElement
.
setAttribute
(
'
d
'
,
grapher
.
NodeElement
.
roundedRect
(
0
,
0
,
width
,
height
,
true
,
true
,
true
,
true
));
rootElement
.
appendChild
(
borderElement
);
contextElement
.
innerHTML
=
''
;
return
rootElement
;
}
static
roundedRect
(
x
,
y
,
width
,
height
,
r1
,
r2
,
r3
,
r4
)
{
const
radius
=
5
;
r1
=
r1
?
radius
:
0
;
r2
=
r2
?
radius
:
0
;
r3
=
r3
?
radius
:
0
;
r4
=
r4
?
radius
:
0
;
return
(
'
M
'
+
(
x
+
r1
)
+
'
,
'
+
y
+
'
h
'
+
(
width
-
r1
-
r2
)
+
'
a
'
+
r2
+
'
,
'
+
r2
+
'
0 0 1
'
+
r2
+
'
,
'
+
r2
+
'
v
'
+
(
height
-
r2
-
r3
)
+
'
a
'
+
r3
+
'
,
'
+
r3
+
'
0 0 1
'
+
-
r3
+
'
,
'
+
r3
+
'
h
'
+
(
r3
+
r4
-
width
)
+
'
a
'
+
r4
+
'
,
'
+
r4
+
'
0 0 1
'
+
-
r4
+
'
,
'
+
-
r4
+
'
v
'
+
(
-
height
+
r4
+
r1
)
+
'
a
'
+
r1
+
'
,
'
+
r1
+
'
0 0 1
'
+
r1
+
'
,
'
+
-
r1
+
'
z
'
);
}
static
roundedRect2
(
x
,
y
,
width
,
height
,
r1
,
r2
,
r3
,
r4
)
{
const
radius
=
10
;
r1
=
r1
?
radius
:
0
;
r2
=
r2
?
radius
:
0
;
r3
=
r3
?
radius
:
0
;
r4
=
r4
?
radius
:
0
;
return
(
'
M
'
+
(
x
+
r1
)
+
...
...
@@ -497,39 +707,56 @@ grapher.NodeElement = class {
grapher
.
NodeElement
.
Header
=
class
{
constructor
(
document
)
{
this
.
_document
=
document
;
this
.
_items
=
[];
}
add
(
id
,
classList
,
content
,
tooltip
,
handler
)
{
this
.
_items
.
push
({
id
:
id
,
classList
:
classList
,
content
:
content
,
tooltip
:
tooltip
,
handler
:
handler
});
}
layout
(
parentElement
)
{
this
.
_width
=
0
;
this
.
_height
=
0
;
this
.
_elements
=
[];
let
x
=
0
;
const
y
=
0
;
for
(
const
item
of
this
.
_items
)
{
const
yPadding
=
4
;
const
xPadding
=
7
;
const
element
=
this
.
createElement
(
'
g
'
);
let
classList
=
[
'
node-item
'
];
parentElement
.
appendChild
(
element
);
const
pathElement
=
this
.
createElement
(
'
path
'
);
const
textElement
=
this
.
createElement
(
'
text
'
);
element
.
appendChild
(
pathElement
);
element
.
appendChild
(
textElement
);
if
(
item
.
classList
)
{
classList
=
classList
.
concat
(
item
.
classList
);
}
element
.
setAttribute
(
'
class
'
,
classList
.
join
(
'
'
));
if
(
item
.
id
)
{
element
.
setAttribute
(
'
id
'
,
item
.
id
);
}
...
...
@@ -538,27 +765,41 @@ grapher.NodeElement.Header = class {
}
if
(
item
.
tooltip
)
{
const
titleElement
=
this
.
createElement
(
'
title
'
);
titleElement
.
textContent
=
item
.
tooltip
;
element
.
appendChild
(
titleElement
);
}
if
(
item
.
content
)
{
textElement
.
textContent
=
item
.
content
;
}
const
boundingBox
=
textElement
.
getBBox
();
const
width
=
boundingBox
.
width
+
xPadding
+
xPadding
;
const
height
=
boundingBox
.
height
+
yPadding
+
yPadding
;
this
.
_elements
.
push
({
group
:
element
,
text
:
textElement
,
path
:
pathElement
,
x
:
x
,
y
:
y
,
width
:
width
,
height
:
height
,
tx
:
xPadding
,
ty
:
yPadding
-
boundingBox
.
y
});
x
+=
width
;
if
(
this
.
_height
<
height
)
{
this
.
_height
=
height
;
}
...
...
@@ -578,15 +819,19 @@ grapher.NodeElement.Header = class {
update
(
parentElement
,
top
,
width
,
first
,
last
)
{
const
dx
=
width
-
this
.
_width
;
let
i
;
let
element
;
for
(
i
=
0
;
i
<
this
.
_elements
.
length
;
i
++
)
{
element
=
this
.
_elements
[
i
];
if
(
i
==
0
)
{
element
.
width
=
element
.
width
+
dx
;
}
else
{
element
.
x
=
element
.
x
+
dx
;
element
.
tx
=
element
.
tx
+
dx
;
}
element
.
y
=
element
.
y
+
top
;
...
...
@@ -594,40 +839,61 @@ grapher.NodeElement.Header = class {
for
(
i
=
0
;
i
<
this
.
_elements
.
length
;
i
++
)
{
element
=
this
.
_elements
[
i
];
element
.
group
.
setAttribute
(
'
transform
'
,
'
translate(
'
+
element
.
x
+
'
,
'
+
element
.
y
+
'
)
'
);
const
r1
=
i
==
0
&&
first
;
const
r2
=
i
==
this
.
_elements
.
length
-
1
&&
first
;
const
r3
=
i
==
this
.
_elements
.
length
-
1
&&
last
;
const
r4
=
i
==
0
&&
last
;
element
.
path
.
setAttribute
(
'
d
'
,
grapher
.
NodeElement
.
roundedRect
(
0
,
0
,
element
.
width
,
element
.
height
,
r1
,
r2
,
r3
,
r4
)
);
element
.
text
.
setAttribute
(
'
x
'
,
6
);
element
.
text
.
setAttribute
(
'
y
'
,
element
.
ty
);
element
.
text
.
setAttribute
(
'
x
'
,
7
);
element
.
text
.
setAttribute
(
'
y
'
,
element
.
ty
-
1
);
}
let
lineElement
;
for
(
i
=
0
;
i
<
this
.
_elements
.
length
;
i
++
)
{
element
=
this
.
_elements
[
i
];
if
(
i
!=
0
)
{
lineElement
=
this
.
createElement
(
'
line
'
);
lineElement
.
setAttribute
(
'
class
'
,
'
node
'
);
lineElement
.
setAttribute
(
'
x1
'
,
element
.
x
);
lineElement
.
setAttribute
(
'
x2
'
,
element
.
x
);
lineElement
.
setAttribute
(
'
y1
'
,
top
);
lineElement
.
setAttribute
(
'
y2
'
,
top
+
this
.
_height
);
parentElement
.
appendChild
(
lineElement
);
}
}
if
(
!
first
)
{
lineElement
=
this
.
createElement
(
'
line
'
);
lineElement
.
setAttribute
(
'
class
'
,
'
node
'
);
lineElement
.
setAttribute
(
'
x1
'
,
0
);
lineElement
.
setAttribute
(
'
x2
'
,
width
);
lineElement
.
setAttribute
(
'
y1
'
,
top
);
lineElement
.
setAttribute
(
'
y2
'
,
top
);
parentElement
.
appendChild
(
lineElement
);
}
}
...
...
@@ -640,6 +906,7 @@ grapher.NodeElement.Header = class {
grapher
.
NodeElement
.
List
=
class
{
constructor
(
document
)
{
this
.
_document
=
document
;
this
.
_items
=
[];
}
...
...
@@ -657,49 +924,72 @@ grapher.NodeElement.List = class {
layout
(
parentElement
)
{
this
.
_width
=
0
;
this
.
_height
=
0
;
const
x
=
0
;
const
y
=
0
;
this
.
_element
=
this
.
createElement
(
'
g
'
);
this
.
_element
.
setAttribute
(
'
class
'
,
'
node-attribute
'
);
parentElement
.
appendChild
(
this
.
_element
);
if
(
this
.
_handler
)
{
this
.
_element
.
addEventListener
(
'
click
'
,
this
.
_handler
);
}
this
.
_backgroundElement
=
this
.
createElement
(
'
path
'
);
this
.
_element
.
appendChild
(
this
.
_backgroundElement
);
this
.
_element
.
setAttribute
(
'
transform
'
,
'
translate(
'
+
x
+
'
,
'
+
y
+
'
)
'
);
this
.
_height
+=
3
;
for
(
const
item
of
this
.
_items
)
{
const
yPadding
=
1
;
const
xPadding
=
6
;
const
textElement
=
this
.
createElement
(
'
text
'
);
if
(
item
.
id
)
{
textElement
.
setAttribute
(
'
id
'
,
item
.
id
);
}
textElement
.
setAttribute
(
'
xml:space
'
,
'
preserve
'
);
this
.
_element
.
appendChild
(
textElement
);
if
(
item
.
tooltip
)
{
const
titleElement
=
this
.
createElement
(
'
title
'
);
titleElement
.
textContent
=
item
.
tooltip
;
textElement
.
appendChild
(
titleElement
);
}
const
textNameElement
=
this
.
createElement
(
'
tspan
'
);
textNameElement
.
textContent
=
item
.
name
;
if
(
item
.
separator
.
trim
()
!=
'
=
'
)
{
textNameElement
.
style
.
fontWeight
=
'
bold
'
;
}
textElement
.
appendChild
(
textNameElement
);
const
textValueElement
=
this
.
createElement
(
'
tspan
'
);
textValueElement
.
textContent
=
item
.
separator
+
item
.
value
;
textElement
.
appendChild
(
textValueElement
);
const
size
=
textElement
.
getBBox
();
const
width
=
xPadding
+
size
.
width
+
xPadding
;
if
(
this
.
_width
<
width
)
{
this
.
_width
=
width
;
}
textElement
.
setAttribute
(
'
x
'
,
x
+
xPadding
);
textElement
.
setAttribute
(
'
y
'
,
this
.
_height
+
yPadding
-
size
.
y
);
this
.
_height
+=
yPadding
+
size
.
height
+
yPadding
;
}
this
.
_height
+=
3
;
...
...
@@ -721,9 +1011,13 @@ grapher.NodeElement.List = class {
this
.
_element
.
setAttribute
(
'
transform
'
,
'
translate(0,
'
+
top
+
'
)
'
);
const
r1
=
first
;
const
r2
=
first
;
const
r3
=
last
;
const
r4
=
last
;
this
.
_backgroundElement
.
setAttribute
(
'
d
'
,
grapher
.
NodeElement
.
roundedRect
(
0
,
0
,
width
,
this
.
_height
,
r1
,
r2
,
r3
,
r4
)
...
...
@@ -731,11 +1025,17 @@ grapher.NodeElement.List = class {
if
(
!
first
)
{
const
lineElement
=
this
.
createElement
(
'
line
'
);
lineElement
.
setAttribute
(
'
class
'
,
'
node
'
);
lineElement
.
setAttribute
(
'
x1
'
,
0
);
lineElement
.
setAttribute
(
'
x2
'
,
width
);
lineElement
.
setAttribute
(
'
y1
'
,
0
);
lineElement
.
setAttribute
(
'
y2
'
,
0
);
this
.
_element
.
appendChild
(
lineElement
);
}
}
...
...
@@ -748,9 +1048,13 @@ grapher.NodeElement.List = class {
class
Path
{
constructor
()
{
this
.
_x0
=
null
;
this
.
_y0
=
null
;
this
.
_x1
=
null
;
this
.
_y1
=
null
;
this
.
_data
=
''
;
}
...
...
@@ -769,7 +1073,9 @@ class Path {
closePath
()
{
if
(
this
.
_x1
!==
null
)
{
this
.
_x1
=
this
.
_x0
;
this
.
_y1
=
this
.
_y0
;
this
.
_data
+=
'
Z
'
;
}
}
...
...
@@ -786,9 +1092,13 @@ class Curve {
lineStart
()
{
this
.
_x0
=
NaN
;
this
.
_x1
=
NaN
;
this
.
_y0
=
NaN
;
this
.
_y1
=
NaN
;
this
.
_point
=
0
;
}
...
...
@@ -796,10 +1106,13 @@ class Curve {
switch
(
this
.
_point
)
{
case
3
:
this
.
curve
(
this
.
_x1
,
this
.
_y1
);
this
.
_context
.
lineTo
(
this
.
_x1
,
this
.
_y1
);
break
;
case
2
:
this
.
_context
.
lineTo
(
this
.
_x1
,
this
.
_y1
);
break
;
}
if
(
this
.
_line
||
(
this
.
_line
!==
0
&&
this
.
_point
===
1
))
{
...
...
@@ -810,10 +1123,13 @@ class Curve {
point
(
x
,
y
)
{
x
=
+
x
;
y
=
+
y
;
switch
(
this
.
_point
)
{
case
0
:
this
.
_point
=
1
;
if
(
this
.
_line
)
{
this
.
_context
.
lineTo
(
x
,
y
);
}
else
{
...
...
@@ -822,29 +1138,42 @@ class Curve {
break
;
case
1
:
this
.
_point
=
2
;
break
;
case
2
:
this
.
_point
=
3
;
this
.
_context
.
lineTo
((
5
*
this
.
_x0
+
this
.
_x1
)
/
6
,
(
5
*
this
.
_y0
+
this
.
_y1
)
/
6
);
this
.
curve
(
x
,
y
);
break
;
default
:
this
.
curve
(
x
,
y
);
break
;
}
this
.
_x0
=
this
.
_x1
;
this
.
_x1
=
x
;
this
.
_y0
=
this
.
_y1
;
this
.
_y1
=
y
;
}
curve
(
x
,
y
)
{
this
.
_context
.
bezierCurveTo
(
(
2
*
this
.
_x0
+
this
.
_x1
)
/
3
,
(
2
*
this
.
_y0
+
this
.
_y1
)
/
3
,
(
this
.
_x0
+
2
*
this
.
_x1
)
/
3
,
(
this
.
_y0
+
2
*
this
.
_y1
)
/
3
,
(
this
.
_x0
+
4
*
this
.
_x1
+
x
)
/
6
,
(
this
.
_y0
+
4
*
this
.
_y1
+
y
)
/
6
);
}
...
...
@@ -852,5 +1181,6 @@ class Curve {
if
(
typeof
module
!==
'
undefined
'
&&
typeof
module
.
exports
===
'
object
'
)
{
module
.
exports
.
Renderer
=
grapher
.
Renderer
;
module
.
exports
.
NodeElement
=
grapher
.
NodeElement
;
}
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录