Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
PaddlePaddle
VisualDL
提交
5b9dacfc
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看板
未验证
提交
5b9dacfc
编写于
6月 23, 2022
作者:
R
RotPublic
提交者:
GitHub
6月 23, 2022
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Add dynamic graph frontend
上级
96fb036b
变更
23
展开全部
隐藏空白更改
内联
并排
Showing
23 changed file
with
6417 addition
and
265 deletion
+6417
-265
frontend/.eslintrc.js
frontend/.eslintrc.js
+3
-3
frontend/packages/core/package.json
frontend/packages/core/package.json
+2
-0
frontend/packages/core/public/locales/en/common.json
frontend/packages/core/public/locales/en/common.json
+2
-0
frontend/packages/core/public/locales/en/graph.json
frontend/packages/core/public/locales/en/graph.json
+4
-1
frontend/packages/core/public/locales/zh/common.json
frontend/packages/core/public/locales/zh/common.json
+2
-0
frontend/packages/core/public/locales/zh/graph.json
frontend/packages/core/public/locales/zh/graph.json
+4
-1
frontend/packages/core/src/components/Check.tsx
frontend/packages/core/src/components/Check.tsx
+122
-0
frontend/packages/core/src/components/GraphPage/Argument.tsx
frontend/packages/core/src/components/GraphPage/Argument.tsx
+2
-2
frontend/packages/core/src/components/GraphPage/GraphDynamic.tsx
...d/packages/core/src/components/GraphPage/GraphDynamic.tsx
+509
-0
frontend/packages/core/src/components/GraphPage/GraphStatic.tsx
...nd/packages/core/src/components/GraphPage/GraphStatic.tsx
+0
-0
frontend/packages/core/src/pages/graphDynamic.tsx
frontend/packages/core/src/pages/graphDynamic.tsx
+383
-0
frontend/packages/core/src/pages/graphStatic.tsx
frontend/packages/core/src/pages/graphStatic.tsx
+4
-2
frontend/packages/core/src/routes/index.ts
frontend/packages/core/src/routes/index.ts
+12
-2
frontend/packages/icons/icons/shrink.svg
frontend/packages/icons/icons/shrink.svg
+18
-0
frontend/packages/mock/data/graph_runs.js
frontend/packages/mock/data/graph_runs.js
+17
-0
frontend/packages/netron/src/index.js
frontend/packages/netron/src/index.js
+38
-4
frontend/packages/netron/src/paddle-metadata.js
frontend/packages/netron/src/paddle-metadata.js
+2266
-0
frontend/packages/netron/src/sidebar.js
frontend/packages/netron/src/sidebar.js
+136
-19
frontend/packages/netron/src/style.scss
frontend/packages/netron/src/style.scss
+138
-32
frontend/packages/netron/src/view-grapher.js
frontend/packages/netron/src/view-grapher.js
+856
-0
frontend/packages/netron/src/view.js
frontend/packages/netron/src/view.js
+515
-199
frontend/packages/netron/src/view2.js
frontend/packages/netron/src/view2.js
+1379
-0
frontend/yarn.lock
frontend/yarn.lock
+5
-0
未找到文件。
frontend/.eslintrc.js
浏览文件 @
5b9dacfc
...
...
@@ -27,9 +27,9 @@ module.exports = {
},
plugins
:
[
'
license-header
'
],
rules
:
{
'
no-console
'
:
'
warn
'
,
'
sort-imports
'
:
'
error
'
,
'
license-header/header
'
:
[
'
error
'
,
'
./license-header.js
'
]
'
sort-imports
'
:
'
warn
'
,
'
no-console
'
:
'
warn
'
//
'license-header/header': ['error', './license-header.js']
},
overrides
:
[
{
...
...
frontend/packages/core/package.json
浏览文件 @
5b9dacfc
...
...
@@ -26,6 +26,7 @@
"dev"
:
"snowpack dev"
,
"dev:reload"
:
"yarn dev --reload"
,
"build"
:
"snowpack build && node builder/post-build.js"
,
"lint"
:
"eslint --ext .tsx,.jsx.ts,.js,.mjs"
,
"snowpack"
:
"snowpack"
,
"test"
:
"web-test-runner
\"
test/**/*.tsx
\"
"
},
...
...
@@ -48,6 +49,7 @@
"d3-format"
:
"3.0.1"
,
"echarts"
:
"4.9.0"
,
"echarts-gl"
:
"1.1.2"
,
"eslint-plugin-simple-import-sort"
:
"^7.0.0"
,
"eventemitter3"
:
"4.0.7"
,
"file-saver"
:
"2.0.5"
,
"i18next"
:
"20.6.0"
,
...
...
frontend/packages/core/public/locales/en/common.json
浏览文件 @
5b9dacfc
...
...
@@ -10,6 +10,8 @@
"empty"
:
"Nothing to display"
,
"error"
:
"Error occurred"
,
"graph"
:
"Graphs"
,
"graphDynamic"
:
"dynamic"
,
"graphStatic"
:
"static"
,
"high-dimensional"
:
"High Dimensional"
,
"histogram"
:
"Histogram"
,
"hyper-parameter"
:
"Hyper Parameters"
,
...
...
frontend/packages/core/public/locales/en/graph.json
浏览文件 @
5b9dacfc
...
...
@@ -43,12 +43,15 @@
"type"
:
"Type"
,
"version"
:
"Version"
},
"restore-size"
:
"Restore Size"
,
"restore-size"
:
"Fully Shrinked data model"
,
"expend-size"
:
"Fully expanded Data Model"
,
"show-attributes"
:
"Show Attributes"
,
"show-initializers"
:
"Show Initializers"
,
"show-node-names"
:
"Show Node Names"
,
"keep-expanded"
:
"keep expanded"
,
"subgraph"
:
"Select Subgraph"
,
"supported-model"
:
"Supported models: "
,
"Choose-model"
:
"Choose a model"
,
"supported-model-list"
:
"PaddlePaddle, ONNX, Keras, Core ML, Caffe, Caffe2, Darknet, MXNet, ncnn, TensorFlow Lite"
,
"upload-model"
:
"Upload Model"
,
"upload-tip"
:
"Click or Drop file here to view neural network models"
,
...
...
frontend/packages/core/public/locales/zh/common.json
浏览文件 @
5b9dacfc
...
...
@@ -10,6 +10,8 @@
"empty"
:
"暂无数据"
,
"error"
:
"发生错误"
,
"graph"
:
"网络结构"
,
"graphDynamic"
:
"动态"
,
"graphStatic"
:
"静态"
,
"high-dimensional"
:
"数据降维"
,
"histogram"
:
"直方图"
,
"hyper-parameter"
:
"超参可视化"
,
...
...
frontend/packages/core/public/locales/zh/graph.json
浏览文件 @
5b9dacfc
...
...
@@ -43,16 +43,19 @@
"type"
:
"类型"
,
"version"
:
"版本"
},
"restore-size"
:
"重置大小"
,
"restore-size"
:
"全收缩数据模型"
,
"expend-size"
:
"全展开数据模型"
,
"show-attributes"
:
"显示参数"
,
"show-initializers"
:
"显示初始化参数"
,
"show-node-names"
:
"显示节点名称"
,
"subgraph"
:
"选择子图"
,
"keep-expanded"
:
"保持展开"
,
"supported-model"
:
"VisualDL支持:"
,
"supported-model-list"
:
"PaddlePaddle、ONNX、Keras、Core ML、Caffe、Caffe2、Darknet、MXNet、ncnn、TensorFlow Lite"
,
"upload-model"
:
"上传模型"
,
"upload-tip"
:
"点击或拖拽文件到页面上传模型,进行结构展示"
,
"vertical"
:
"垂直"
,
"Choose-model"
:
"选择模型"
,
"zoom-in"
:
"放大"
,
"zoom-out"
:
"缩小"
}
frontend/packages/core/src/components/Check.tsx
0 → 100644
浏览文件 @
5b9dacfc
/**
* Copyright 2020 Baidu Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* 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
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import
React
,
{
FunctionComponent
,
useCallback
}
from
'
react
'
;
import
{
ellipsis
,
em
,
half
,
math
,
position
,
sameBorder
,
size
,
transitionProps
}
from
'
~/utils/style
'
;
import
styled
from
'
styled-components
'
;
const
height
=
em
(
20
);
const
checkSize
=
em
(
16
);
const
checkMark
=
// eslint-disable-next-line
'
data:image/svg+xml;base64,PHN2ZyBoZWlnaHQ9IjgiIHZpZXdCb3g9IjAgMCAxMSA4IiB3aWR0aD0iMTEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PHBhdGggZD0ibTkuNDc5NDI3MDggMTAuMTg3NWgtNS4yNXYtMS4zMTI1aDMuOTM3bC4wMDA1LTcuODc1aDEuMzEyNXoiIGZpbGw9IiNmNWY1ZjUiIGZpbGwtcnVsZT0iZXZlbm9kZCIgdHJhbnNmb3JtPSJtYXRyaXgoLjcwNzEwNjc4IC43MDcxMDY3OCAtLjcwNzEwNjc4IC43MDcxMDY3OCA0Ljk2Mjk5NCAtNi4yMDg0NCkiLz48L3N2Zz4=
'
;
const
Wrapper
=
styled
.
label
<
{
disabled
?:
boolean
}
>
`
position: relative;
display: inline-flex;
align-items: flex-start;
cursor:
${
props
=>
(
props
.
disabled
?
'
not-allowed
'
:
'
pointer
'
)}
;
`
;
const
Input
=
styled
.
input
.
attrs
<
{
disabled
?:
boolean
}
>
(
props
=>
({
type
:
'
checkbox
'
,
disabled
:
!!
props
.
disabled
}))
`
${
size
(
0
)}
${
position
(
'
absolute
'
,
0
,
null
,
null
,
0
)}
opacity: 0;
pointer-events: none;
`
;
const
Inner
=
styled
.
div
<
{
checked
?:
boolean
;
size
?:
string
;
disabled
?:
boolean
}
>
`
color:
${
props
=>
(
props
.
checked
?
'
var(--text-invert-color)
'
:
'
transparent
'
)}
;
flex-shrink: 0;
${
props
=>
size
(
math
(
`
${
checkSize
}
*
${
props
.
size
===
'
small
'
?
0.875
:
1
}
`
))}
margin:
${
half
(
`
${
height
}
-
${
checkSize
}
`
)}
0;
margin-right:
${
em
(
10
)}
;
${
props
=>
sameBorder
({
color
:
props
.
disabled
||
!
props
.
checked
?
'
var(--text-lighter-color)
'
:
'
var(--primary-color)
'
})}
;
background-color:
${
props
=>
props
.
disabled
?
props
.
checked
?
'
var(--text-lighter-color)
'
:
'
transparent
'
:
props
.
checked
?
'
var(--primary-color)
'
:
'
var(--background-color)
'
}
;
background-image:
${
props
=>
(
props
.
checked
?
`url("
${
checkMark
}
")`
:
'
none
'
)}
;
background-repeat: no-repeat;
background-position: center center;
background-size:
${
em
(
10
)}
${
em
(
8
)}
;
position: relative;
${
transitionProps
([
'
border-color
'
,
'
background-color
'
,
'
color
'
])}
${
Wrapper
}
:hover > & {
border-color:
${
props
=>
props
.
disabled
?
'
var(--text-lighter-color)
'
:
props
.
checked
?
'
var(--primary-color)
'
:
'
var(--text-lighter-color)
'
}
;
}
`
;
const
Content
=
styled
.
div
<
{
disabled
?:
boolean
}
>
`
line-height:
${
height
}
;
flex-grow: 1;
${
props
=>
(
props
.
disabled
?
'
color: var(--text-lighter-color);
'
:
''
)}
${
transitionProps
(
'
color
'
)}
${
ellipsis
()}
`
;
type
CheckboxProps
=
{
value
:
string
;
checked
?:
boolean
;
className
?:
string
;
onChange
?:
(
checked
:
string
)
=>
unknown
;
size
?:
'
small
'
;
title
?:
string
;
disabled
?:
boolean
;
};
const
Checkbox
:
FunctionComponent
<
CheckboxProps
>
=
({
value
,
checked
,
children
,
size
,
disabled
,
className
,
title
,
onChange
})
=>
{
const
onChangeInput
=
useCallback
(()
=>
{
if
(
disabled
)
{
return
;
}
if
(
onChange
)
{
onChange
(
value
);
}
},
[
disabled
,
onChange
]);
return
(
<
Wrapper
disabled
=
{
disabled
}
className
=
{
className
}
title
=
{
title
}
>
<
Input
onChange
=
{
onChangeInput
}
checked
=
{
checked
}
disabled
=
{
disabled
}
/>
<
Inner
checked
=
{
checked
}
size
=
{
size
}
disabled
=
{
disabled
}
/>
<
Content
disabled
=
{
disabled
}
>
{
children
}
</
Content
>
</
Wrapper
>
);
};
export
default
Checkbox
;
frontend/packages/core/src/components/GraphPage/Argument.tsx
浏览文件 @
5b9dacfc
...
...
@@ -61,7 +61,7 @@ const Wrapper = styled.div`
${
transitionProps
(
'
color
'
)}
&:hover,
&:active {
&:active {
color: var(--text-light-color);
}
}
...
...
@@ -96,7 +96,7 @@ const Argument: FunctionComponent<ArgumentProps> = ({value, expand, showNodeDocu
{
value
.
name
}
:
<
b
>
{
value
.
value
}
</
b
>
</>
)
:
(
value
.
value
.
split
(
'
\n
'
).
map
((
line
,
index
)
=>
(
new
String
(
value
.
value
)
.
split
(
'
\n
'
).
map
((
line
,
index
)
=>
(
<
React
.
Fragment
key
=
{
index
}
>
{
index
!==
0
&&
<
br
/>
}
{
line
}
...
...
frontend/packages/core/src/components/GraphPage/GraphDynamic.tsx
0 → 100644
浏览文件 @
5b9dacfc
/**
* Copyright 2020 Baidu Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* 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
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import
type
{
Documentation
,
OpenedResult
,
Properties
,
SearchItem
,
SearchResult
}
from
'
~/resource/graph/types
'
;
import
React
,
{
useCallback
,
useEffect
,
useImperativeHandle
,
useMemo
,
useRef
,
useState
}
from
'
react
'
;
import
{
contentHeight
,
position
,
primaryColor
,
rem
,
size
,
transitionProps
}
from
'
~/utils/style
'
;
import
ChartToolbox
from
'
~/components/ChartToolbox
'
;
import
HashLoader
from
'
react-spinners/HashLoader
'
;
import
logo
from
'
~/assets/images/netron.png
'
;
import
netron
from
'
@visualdl/netron
'
;
import
styled
from
'
styled-components
'
;
import
{
toast
}
from
'
react-toastify
'
;
import
{
fetcher
}
from
'
~/utils/fetch
'
;
import
useTheme
from
'
~/hooks/useTheme
'
;
import
{
useTranslation
}
from
'
react-i18next
'
;
const
PUBLIC_PATH
:
string
=
import
.
meta
.
env
.
SNOWPACK_PUBLIC_PATH
;
let
IFRAME_HOST
=
`
${
window
.
location
.
protocol
}
//
${
window
.
location
.
host
}
`
;
if
(
PUBLIC_PATH
.
startsWith
(
'
http
'
))
{
const
url
=
new
URL
(
PUBLIC_PATH
);
IFRAME_HOST
=
`
${
url
.
protocol
}
//
${
url
.
host
}
`
;
}
const
toolboxHeight
=
rem
(
40
);
const
Wrapper
=
styled
.
div
`
position: relative;
height:
${
contentHeight
}
;
background-color: var(--background-color);
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
${
transitionProps
(
'
background-color
'
)}
`
;
const
RenderContent
=
styled
.
div
<
{
show
:
boolean
}
>
`
position: absolute;
top: 0;
left: 0;
${
size
(
'
100%
'
,
'
100%
'
)}
opacity:
${
props
=>
(
props
.
show
?
1
:
0
)}
;
z-index:
${
props
=>
(
props
.
show
?
0
:
-
1
)}
;
pointer-events:
${
props
=>
(
props
.
show
?
'
auto
'
:
'
none
'
)}
;
`
;
const
Toolbox
=
styled
(
ChartToolbox
)
`
height:
${
toolboxHeight
}
;
border-bottom: 1px solid var(--border-color);
padding: 0
${
rem
(
20
)}
;
${
transitionProps
(
'
border-color
'
)}
`
;
const
Content
=
styled
.
div
`
position: relative;
height: calc(100% -
${
toolboxHeight
}
);
> iframe {
${
size
(
'
100%
'
,
'
100%
'
)}
border: none;
}
> .powered-by {
display: block;
${
position
(
'
absolute
'
,
null
,
null
,
rem
(
20
),
rem
(
30
))}
color: var(--graph-copyright-color);
font-size:
${
rem
(
14
)}
;
user-select: none;
img {
height: 1em;
filter: var(--graph-copyright-logo-filter);
vertical-align: middle;
}
}
`
;
const
Loading
=
styled
.
div
`
${
size
(
'
100%
'
,
'
100%
'
)}
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
overscroll-behavior: none;
cursor: progress;
font-size:
${
rem
(
16
)}
;
line-height:
${
rem
(
60
)}
;
`
;
export
type
GraphRef
=
{
export
(
type
:
'
svg
'
|
'
png
'
):
void
;
changeGraph
(
name
:
string
):
void
;
search
(
value
:
string
):
void
;
select
(
item
:
SearchItem
):
void
;
setSelectItems
(
data
:
Theobj
):
void
;
setLoadings
(
data
:
boolean
):
void
;
showModelProperties
():
void
;
showNodeDocumentation
(
data
:
Theobj
):
void
;
};
interface
Theobj
{
[
propname
:
string
]:
unknown
;
}
type
GraphProps
=
{
files
:
FileList
|
File
[]
|
null
;
uploader
:
JSX
.
Element
;
showAttributes
:
boolean
;
showInitializers
:
boolean
;
showNames
:
boolean
;
horizontal
:
boolean
;
isKeepData
:
boolean
;
runs
:
string
[]
|
undefined
;
selectedRuns
:
string
;
onRendered
?:
()
=>
unknown
;
onOpened
?:
(
data
:
OpenedResult
)
=>
unknown
;
onSearch
?:
(
data
:
SearchResult
)
=>
unknown
;
onShowModelProperties
?:
(
data
:
Properties
)
=>
unknown
;
onShowNodeProperties
?:
(
data
:
Properties
)
=>
unknown
;
onShowNodeDocumentation
?:
(
data
:
Documentation
)
=>
unknown
;
};
const
Graph
=
React
.
forwardRef
<
GraphRef
,
GraphProps
>
(
(
{
uploader
,
showAttributes
,
runs
,
selectedRuns
,
isKeepData
,
showInitializers
,
showNames
,
horizontal
,
onRendered
,
onOpened
,
onSearch
,
onShowModelProperties
,
onShowNodeProperties
,
onShowNodeDocumentation
},
ref
)
=>
{
const
{
t
,
i18n
}
=
useTranslation
(
'
graph
'
);
const
language
:
string
=
i18n
.
language
;
const
theme
=
useTheme
();
const
[
ready
,
setReady
]
=
useState
(
false
);
const
[
rendered
,
setRendered
]
=
useState
(
false
);
const
[
loading
,
setLoading
]
=
useState
(
true
);
const
[
item
,
setSelectItem
]
=
useState
<
Theobj
|
null
>
();
const
[
isExpend
,
setIsExpend
]
=
useState
(
0
);
const
[
isRetract
,
setIsretract
]
=
useState
(
0
);
const
[
modelDatas
,
setModelDatas
]
=
useState
<
Theobj
>
();
const
[
allModelDatas
,
setAllModelDatas
]
=
useState
<
Theobj
>
();
const
[
selectNodeId
,
setSelectNodeId
]
=
useState
();
const
[
searchNodeId
,
setSearchNodeId
]
=
useState
<
Theobj
>
();
const
iframe
=
useRef
<
HTMLIFrameElement
>
(
null
);
const
handler
=
useCallback
(
(
event
:
MessageEvent
)
=>
{
if
(
event
.
data
)
{
const
{
type
,
data
}
=
event
.
data
;
switch
(
type
)
{
case
'
status
'
:
switch
(
data
)
{
case
'
ready
'
:
return
setReady
(
true
);
case
'
loading
'
:
// return setLoading(true);
return
1
;
case
'
rendered
'
:
setLoading
(
false
);
setRendered
(
true
);
// changeSvg()
onRendered
?.();
return
;
}
return
;
case
'
opened
'
:
return
onOpened
?.(
data
);
case
'
search
'
:
return
onSearch
?.(
data
);
case
'
cancel
'
:
return
setLoading
(
false
);
case
'
error
'
:
toast
.
error
(
data
);
setLoading
(
false
);
return
;
case
'
show-model-properties
'
:
return
onShowModelProperties
?.(
data
);
case
'
show-node-properties
'
:
return
onShowNodeProperties
?.(
data
);
case
'
show-node-documentation
'
:
return
onShowNodeDocumentation
?.(
data
);
case
'
nodeId
'
:
return
setSelectNodeId
?.(
data
);
case
'
selectItem
'
:
return
setSelectItem
?.(
data
);
}
}
},
[
onRendered
,
onOpened
,
onSearch
,
onShowModelProperties
,
onShowNodeProperties
,
onShowNodeDocumentation
]
);
const
dispatch
=
useCallback
((
type
:
string
,
data
?:
unknown
)
=>
{
iframe
.
current
?.
contentWindow
?.
postMessage
(
{
type
,
data
},
IFRAME_HOST
);
},
[]);
useEffect
(()
=>
{
keydown
();
},
[]);
useEffect
(()
=>
{
window
.
addEventListener
(
'
message
'
,
handler
);
dispatch
(
'
ready
'
);
return
()
=>
{
window
.
removeEventListener
(
'
message
'
,
handler
);
};
},
[
handler
,
dispatch
]);
useEffect
(()
=>
{
if
(
selectedRuns
)
{
setLoading
(
true
);
getGraph
();
// getAllGraph()
}
},
[
selectedRuns
]);
useEffect
(()
=>
{
if
(
isExpend
)
{
// debugger
setLoading
(
true
);
const
refresh
=
false
;
const
expand_all
=
true
;
fetcher
(
'
/graph/graph
'
+
`?run=
${
selectedRuns
}
`
+
`&refresh=
${
refresh
}
`
+
`&expand_all=
${
expand_all
}
`
).
then
((
res
:
Theobj
)
=>
{
setSelectItem
(
null
);
setModelDatas
(
res
);
});
}
},
[
isExpend
]);
useEffect
(()
=>
{
if
(
isRetract
)
{
// debugger
setLoading
(
true
);
const
refresh
=
true
;
const
expand_all
=
false
;
fetcher
(
'
/graph/graph
'
+
`?run=
${
selectedRuns
}
`
+
`&refresh=
${
refresh
}
`
+
`&expand_all=
${
expand_all
}
`
).
then
((
res
:
Theobj
)
=>
{
setSelectItem
(
null
);
setModelDatas
(
res
);
});
}
},
[
isRetract
]);
useEffect
(()
=>
{
if
(
ready
)
{
dispatch
(
'
change-select
'
,
item
);
}
},
[
dispatch
,
item
,
ready
]);
useEffect
(()
=>
{
if
(
!
allModelDatas
)
{
return
;
}
if
(
ready
)
{
dispatch
(
'
change-allGraph
'
,
allModelDatas
);
}
},
[
dispatch
,
allModelDatas
,
ready
]);
useEffect
(()
=>
{
if
(
!
modelDatas
)
{
return
;
}
if
(
ready
)
{
dispatch
(
'
change-graph
'
,
modelDatas
);
}
},
[
dispatch
,
modelDatas
,
ready
]);
useEffect
(()
=>
{
if
(
!
selectNodeId
)
{
return
;
}
// debugger;
setLoading
(
true
);
const
selectNodeIds
:
Theobj
=
selectNodeId
;
fetcher
(
'
/graph/manipulate
'
+
`?run=
${
selectedRuns
}
`
+
`&nodeid=
${
selectNodeIds
.
nodeId
}
`
+
`&expand=
${
selectNodeIds
.
expand
}
`
+
`&keep_state=
${
isKeepData
}
`
).
then
((
res
:
Theobj
)
=>
{
setModelDatas
(
res
);
});
},
[
selectNodeId
]);
useEffect
(()
=>
{
if
(
!
searchNodeId
)
{
return
;
}
// debugger
setLoading
(
true
);
const
searchNodeIds
:
Theobj
=
searchNodeId
;
const
is_node
=
searchNodeIds
.
type
===
'
node
'
?
true
:
false
;
fetcher
(
'
/graph/search
'
+
`?run=
${
selectedRuns
}
`
+
`&nodeid=
${
searchNodeIds
.
name
}
`
+
`&keep_state=
${
isKeepData
}
`
+
`&is_node=
${
is_node
}
`
).
then
((
res
:
Theobj
)
=>
{
setModelDatas
(
res
);
});
},
[
searchNodeId
]);
useEffect
(
()
=>
(
ready
&&
dispatch
(
'
toggle-attributes
'
,
showAttributes
))
||
undefined
,
[
dispatch
,
showAttributes
,
ready
]
);
useEffect
(
()
=>
(
ready
&&
dispatch
(
'
toggle-initializers
'
,
showInitializers
))
||
undefined
,
[
dispatch
,
showInitializers
,
ready
]
);
useEffect
(()
=>
(
ready
&&
dispatch
(
'
toggle-names
'
,
showNames
))
||
undefined
,
[
dispatch
,
showNames
,
ready
]);
useEffect
(
()
=>
(
ready
&&
dispatch
(
'
toggle-direction
'
,
horizontal
))
||
undefined
,
[
dispatch
,
horizontal
,
ready
]
);
useEffect
(()
=>
(
ready
&&
dispatch
(
'
toggle-theme
'
,
theme
))
||
undefined
,
[
dispatch
,
theme
,
ready
]);
useEffect
(()
=>
(
ready
&&
dispatch
(
'
toggle-Language
'
,
language
))
||
undefined
,
[
dispatch
,
language
,
ready
]);
useImperativeHandle
(
ref
,
()
=>
({
export
(
type
)
{
dispatch
(
'
export
'
,
type
);
},
changeGraph
(
name
)
{
dispatch
(
'
change-graph
'
,
name
);
},
search
(
value
)
{
dispatch
(
'
search
'
,
value
);
},
setSelectItems
(
data
:
Theobj
)
{
setSelectItem
(
data
);
},
setLoadings
(
data
:
boolean
)
{
setLoading
(
data
);
},
select
(
item
)
{
const
a
=
document
.
querySelector
(
'
iframe
'
)
as
HTMLIFrameElement
;
const
documents
=
a
.
contentWindow
?.
document
as
Document
;
if
(
item
.
type
===
'
node
'
)
{
for
(
const
node
of
documents
.
getElementsByClassName
(
'
cluster
'
))
{
if
(
node
.
getAttribute
(
'
id
'
)
===
`node-
${
item
.
name
}
`
)
{
dispatch
(
'
select
'
,
item
);
return
;
}
}
for
(
const
node
of
documents
.
getElementsByClassName
(
'
node
'
))
{
if
(
node
.
getAttribute
(
'
id
'
)
===
`node-
${
item
.
name
}
`
)
{
dispatch
(
'
select
'
,
item
);
return
;
}
}
}
else
if
(
item
.
type
===
'
input
'
)
{
for
(
const
node
of
documents
.
getElementsByClassName
(
'
edge-path
'
))
{
if
(
node
.
getAttribute
(
'
id
'
)
===
`edge-
${
item
.
name
}
`
)
{
dispatch
(
'
select
'
,
item
);
return
;
}
}
}
setSelectItem
(
item
);
setSearchNodeId
(
item
);
},
showModelProperties
()
{
dispatch
(
'
show-model-properties
'
);
},
showNodeDocumentation
(
data
)
{
dispatch
(
'
show-node-documentation
'
,
data
);
}
}));
const
keydown
=
()
=>
{
document
.
addEventListener
(
'
keydown
'
,
e
=>
{
if
(
e
.
code
===
'
MetaLeft
'
||
e
.
code
===
'
MetaRight
'
||
e
.
code
===
'
ControlLeft
'
||
e
.
code
===
'
AltLeft
'
||
e
.
code
===
'
AltRight
'
)
{
dispatch
(
'
isAlt
'
,
true
);
}
});
document
.
addEventListener
(
'
keyup
'
,
e
=>
{
if
(
e
.
code
===
'
MetaLeft
'
||
e
.
code
===
'
MetaRight
'
||
e
.
code
===
'
ControlLeft
'
||
e
.
code
===
'
AltLeft
'
||
e
.
code
===
'
AltRight
'
)
{
dispatch
(
'
isAlt
'
,
false
);
}
});
};
const
getGraph
=
async
()
=>
{
const
refresh
=
true
;
const
expand_all
=
false
;
const
result
=
await
fetcher
(
'
/graph/graph
'
+
`?run=
${
selectedRuns
}
`
+
`&refresh=
${
refresh
}
`
+
`&expand_all=
${
expand_all
}
`
);
const
allResult
=
await
fetcher
(
'
/graph/get_all_nodes
'
+
`?run=
${
selectedRuns
}
`
);
// const allResult = await fetcher('/graph/graph' + `?run=${selectedRuns}`);
setSelectItem
(
null
);
if
(
result
)
setModelDatas
(
result
);
if
(
allResult
)
setAllModelDatas
(
allResult
);
};
const
content
=
useMemo
(()
=>
{
if
(
loading
)
{
return
(
<
Loading
>
<
HashLoader
size
=
"60px"
color
=
{
primaryColor
}
/>
</
Loading
>
);
}
return
null
;
},
[
loading
]);
const
uploaderContent
=
useMemo
(()
=>
{
if
(
!
runs
&&
!
loading
)
{
return
uploader
;
}
},
[
runs
,
loading
,
uploader
]);
const
svgContent
=
useMemo
(()
=>
{
return
(
<
Content
>
<
iframe
ref
=
{
iframe
}
src
=
{
PUBLIC_PATH
+
netron
}
frameBorder
=
{
0
}
scrolling
=
"yes"
marginWidth
=
{
0
}
marginHeight
=
{
0
}
></
iframe
>
<
a
className
=
"powered-by"
href
=
"https://github.com/lutzroeder/netron"
target
=
"_blank"
rel
=
"noreferrer"
>
Powered by
<
img
src
=
{
PUBLIC_PATH
+
logo
}
alt
=
"netron"
/>
</
a
>
</
Content
>
);
},
[
rendered
]);
return
(
<
Wrapper
>
{
content
}
{
uploaderContent
}
<
RenderContent
show
=
{
!
loading
&&
rendered
}
>
<
Toolbox
items
=
{
[
{
icon
:
'
zoom-in
'
,
tooltip
:
t
(
'
graph:zoom-in
'
),
onClick
:
()
=>
dispatch
(
'
zoom-in
'
)
},
{
icon
:
'
zoom-out
'
,
tooltip
:
t
(
'
graph:zoom-out
'
),
onClick
:
()
=>
dispatch
(
'
zoom-out
'
)
},
{
icon
:
'
restore-size
'
,
tooltip
:
t
(
'
expend-size
'
),
onClick
:
()
=>
{
const
id
=
isExpend
+
1
;
setIsExpend
(
id
);
}
},
{
icon
:
'
shrink
'
,
tooltip
:
t
(
'
restore-size
'
),
onClick
:
()
=>
{
const
id
=
isRetract
+
1
;
setIsretract
(
id
);
}
}
]
}
reversed
tooltipPlacement
=
"bottom"
/>
{
svgContent
}
</
RenderContent
>
</
Wrapper
>
);
}
);
Graph
.
displayName
=
'
Graph
'
;
export
default
Graph
;
frontend/packages/core/src/components/GraphPage/Graph.tsx
→
frontend/packages/core/src/components/GraphPage/Graph
Static
.tsx
浏览文件 @
5b9dacfc
文件已移动
frontend/packages/core/src/pages/graphDynamic.tsx
0 → 100644
浏览文件 @
5b9dacfc
/**
* Copyright 2020 Baidu Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* 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
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import
Aside
,
{
AsideSection
}
from
'
~/components/Aside
'
;
import
type
{
Documentation
,
OpenedResult
,
Properties
,
SearchItem
,
SearchResult
}
from
'
~/resource/graph/types
'
;
import
GraphComponent
,
{
GraphRef
}
from
'
~/components/GraphPage/GraphDynamic
'
;
import
React
,
{
FunctionComponent
,
useCallback
,
useEffect
,
useMemo
,
useRef
,
useState
}
from
'
react
'
;
import
Select
,
{
SelectProps
}
from
'
~/components/Select
'
;
import
{
actions
,
selectors
}
from
'
~/store
'
;
import
{
primaryColor
,
rem
,
size
}
from
'
~/utils/style
'
;
import
{
useDispatch
,
useSelector
}
from
'
react-redux
'
;
import
Check
from
'
~/components/Check
'
;
import
Button
from
'
~/components/Button
'
;
import
Checkbox
from
'
~/components/Checkbox
'
;
import
Content
from
'
~/components/Content
'
;
import
Field
from
'
~/components/Field
'
;
import
ModelPropertiesDialog
from
'
~/components/GraphPage/ModelPropertiesDialog
'
;
import
NodeDocumentationSidebar
from
'
~/components/GraphPage/NodeDocumentationSidebar
'
;
import
NodePropertiesSidebar
from
'
~/components/GraphPage/NodePropertiesSidebar
'
;
import
RadioButton
from
'
~/components/RadioButton
'
;
import
RadioGroup
from
'
~/components/RadioGroup
'
;
import
Search
from
'
~/components/GraphPage/Search
'
;
import
Title
from
'
~/components/Title
'
;
import
Uploader
from
'
~/components/GraphPage/Uploader
'
;
import
styled
from
'
styled-components
'
;
import
{
fetcher
}
from
'
~/utils/fetch
'
;
import
{
useTranslation
}
from
'
react-i18next
'
;
const
FullWidthButton
=
styled
(
Button
)
`
width: 100%;
`
;
const
FullWidthSelect
=
styled
<
React
.
FunctionComponent
<
SelectProps
<
NonNullable
<
OpenedResult
[
'
selected
'
]
>>>>
(
Select
)
`
width: 100%;
`
;
const
ExportButtonWrapper
=
styled
.
div
`
display: flex;
justify-content: space-between;
> * {
flex: 1 1 auto;
&:not(:last-child) {
margin-right:
${
rem
(
20
)}
;
}
}
`
;
// TODO: better way to auto fit height
const
SearchSection
=
styled
(
AsideSection
)
`
max-height: calc(100% -
${
rem
(
40
)}
);
display: flex;
flex-direction: column;
&:not(:last-child) {
padding-bottom: 0;
}
`
;
const
Graph
:
FunctionComponent
=
()
=>
{
const
{
t
}
=
useTranslation
([
'
graph
'
,
'
common
'
]);
const
storeDispatch
=
useDispatch
();
const
storeModel
=
useSelector
(
selectors
.
graph
.
model
);
const
graph
=
useRef
<
GraphRef
>
(
null
);
const
file
=
useRef
<
HTMLInputElement
>
(
null
);
const
[
files
,
setFiles
]
=
useState
<
FileList
|
File
[]
|
null
>
(
storeModel
);
const
[
filesId
,
setFilesId
]
=
useState
(
0
);
const
[
runs
,
setRuns
]
=
useState
<
string
[]
>
();
const
[
selectedRuns
,
setSelectedRuns
]
=
useState
<
string
>
(
''
);
const
[
isKeepData
,
setIsKeepData
]
=
useState
(
false
);
const
setModelFile
=
useCallback
(
(
f
:
FileList
|
File
[])
=>
{
storeDispatch
(
actions
.
graph
.
setModel
(
f
));
setFiles
(
f
);
},
[
storeDispatch
]
);
const
onClickFile
=
useCallback
(()
=>
{
if
(
file
.
current
)
{
file
.
current
.
value
=
''
;
file
.
current
.
click
();
}
},
[]);
const
onChangeFile
=
(
e
:
React
.
ChangeEvent
<
HTMLInputElement
>
)
=>
{
const
target
=
e
.
target
as
EventTarget
&
HTMLInputElement
;
const
file
:
FileList
|
null
=
target
.
files
as
FileList
;
if
(
file
[
0
].
name
.
split
(
'
.
'
)[
1
]
!==
'
pdmodel
'
)
{
alert
(
'
该页面只能解析paddle的模型,如需解析请跳转网络结构静态图页面
'
);
return
;
}
if
(
target
&&
target
.
files
&&
target
.
files
.
length
)
{
fileUploader
(
target
.
files
);
}
};
const
fileUploader
=
(
files
:
FileList
)
=>
{
const
formData
=
new
FormData
();
// 将文件转二进制
formData
.
append
(
'
file
'
,
files
[
0
]);
formData
.
append
(
'
filename
'
,
files
[
0
].
name
);
fetcher
(
'
/graph/upload
'
,
{
method
:
'
POST
'
,
body
:
formData
}).
then
(
res
=>
{
// debugger
const
newFilesId
=
filesId
+
1
;
setFilesId
(
newFilesId
);
},
res
=>
{
// debugger
const
newFilesId
=
filesId
+
1
;
setFilesId
(
newFilesId
);
}
);
};
const
[
modelGraphs
,
setModelGraphs
]
=
useState
<
OpenedResult
[
'
graphs
'
]
>
([]);
const
[
selectedGraph
,
setSelectedGraph
]
=
useState
<
NonNullable
<
OpenedResult
[
'
selected
'
]
>>
(
''
);
const
setOpenedModel
=
useCallback
((
data
:
OpenedResult
)
=>
{
setModelGraphs
(
data
.
graphs
);
setSelectedGraph
(
data
.
selected
||
''
);
},
[]);
const
changeGraph
=
useCallback
((
name
:
string
)
=>
{
setSelectedGraph
(
name
);
graph
.
current
?.
changeGraph
(
name
);
},
[]);
const
[
search
,
setSearch
]
=
useState
(
''
);
const
[
searching
,
setSearching
]
=
useState
(
false
);
const
[
searchResult
,
setSearchResult
]
=
useState
<
SearchResult
>
({
text
:
''
,
result
:
[]});
const
onSearch
=
useCallback
((
value
:
string
)
=>
{
setSearch
(
value
);
graph
.
current
?.
search
(
value
);
},
[]);
const
onSelect
=
useCallback
((
item
:
SearchItem
)
=>
{
setSearch
(
item
.
name
);
graph
.
current
?.
select
(
item
);
},
[]);
const
[
showAttributes
,
setShowAttributes
]
=
useState
(
false
);
const
[
showInitializers
,
setShowInitializers
]
=
useState
(
true
);
const
[
showNames
,
setShowNames
]
=
useState
(
false
);
const
[
horizontal
,
setHorizontal
]
=
useState
(
false
);
const
[
modelData
,
setModelData
]
=
useState
<
Properties
|
null
>
(
null
);
const
[
nodeData
,
setNodeData
]
=
useState
<
Properties
|
null
>
(
null
);
const
[
nodeDocumentation
,
setNodeDocumentation
]
=
useState
<
Documentation
|
null
>
(
null
);
useEffect
(()
=>
{
// debugger
fetcher
(
'
/graph_runs
'
).
then
((
res
:
unknown
)
=>
{
const
result
=
res
as
string
[];
setRuns
(
result
);
setSelectedRuns
(
result
[
0
]);
});
},
[
filesId
]);
useEffect
(()
=>
{
setSearch
(
''
);
setSearchResult
({
text
:
''
,
result
:
[]});
},
[
files
,
showAttributes
,
showInitializers
,
showNames
]);
const
bottom
=
useMemo
(
()
=>
searching
?
null
:
(
<
FullWidthButton
type
=
"primary"
rounded
onClick
=
{
onClickFile
}
>
{
t
(
'
graph:change-model
'
)
}
</
FullWidthButton
>
),
[
t
,
onClickFile
,
searching
]
);
const
[
rendered
,
setRendered
]
=
useState
(
false
);
const
content
=
(
runs
:
string
)
=>
{
return
<
div
>
{
runs
}
</
div
>;
// return (<p>Content</p>)
};
const
aside
=
useMemo
(()
=>
{
if
(
!
rendered
)
{
return
null
;
}
if
(
nodeDocumentation
)
{
return
(
<
Aside
width
=
{
rem
(
360
)
}
>
<
NodeDocumentationSidebar
data
=
{
nodeDocumentation
}
onClose
=
{
()
=>
setNodeDocumentation
(
null
)
}
/>
</
Aside
>
);
}
if
(
nodeData
)
{
return
(
<
Aside
width
=
{
rem
(
360
)
}
>
<
NodePropertiesSidebar
data
=
{
nodeData
}
onClose
=
{
()
=>
setNodeData
(
null
)
}
showNodeDocumentation
=
{
()
=>
graph
.
current
?.
showNodeDocumentation
(
nodeData
)
}
/>
</
Aside
>
);
}
return
(
<
Aside
bottom
=
{
bottom
}
>
<
SearchSection
>
<
Search
text
=
{
search
}
data
=
{
searchResult
}
onChange
=
{
onSearch
}
onSelect
=
{
onSelect
}
onActive
=
{
()
=>
setSearching
(
true
)
}
onDeactive
=
{
()
=>
setSearching
(
false
)
}
/>
</
SearchSection
>
{
!
searching
&&
(
<>
<
AsideSection
>
<
FullWidthButton
onClick
=
{
()
=>
graph
.
current
?.
showModelProperties
()
}
>
{
t
(
'
graph:model-properties
'
)
}
</
FullWidthButton
>
</
AsideSection
>
{
modelGraphs
.
length
>
1
&&
(
<
AsideSection
>
<
Field
label
=
{
t
(
'
graph:subgraph
'
)
}
>
<
FullWidthSelect
list
=
{
modelGraphs
}
value
=
{
selectedGraph
}
onChange
=
{
changeGraph
}
/>
</
Field
>
</
AsideSection
>
)
}
<
AsideSection
>
<
Field
label
=
{
t
(
'
graph:display-data
'
)
}
>
<
div
>
<
Checkbox
checked
=
{
showAttributes
}
onChange
=
{
setShowAttributes
}
>
{
t
(
'
graph:show-attributes
'
)
}
</
Checkbox
>
</
div
>
<
div
>
<
Checkbox
checked
=
{
showInitializers
}
onChange
=
{
setShowInitializers
}
>
{
t
(
'
graph:show-initializers
'
)
}
</
Checkbox
>
</
div
>
<
div
>
<
Checkbox
checked
=
{
showNames
}
onChange
=
{
setShowNames
}
>
{
t
(
'
graph:show-node-names
'
)
}
</
Checkbox
>
</
div
>
<
div
>
<
Checkbox
checked
=
{
isKeepData
}
onChange
=
{
setIsKeepData
}
>
{
/* {'保持展开状态'} */
}
{
t
(
'
graph:keep-expanded
'
)
}
</
Checkbox
>
</
div
>
</
Field
>
</
AsideSection
>
<
AsideSection
>
<
Field
label
=
{
t
(
'
graph:direction
'
)
}
>
<
RadioGroup
value
=
{
horizontal
}
onChange
=
{
setHorizontal
}
>
<
RadioButton
value
=
{
false
}
>
{
t
(
'
graph:vertical
'
)
}
</
RadioButton
>
<
RadioButton
value
=
{
true
}
>
{
t
(
'
graph:horizontal
'
)
}
</
RadioButton
>
</
RadioGroup
>
</
Field
>
</
AsideSection
>
<
AsideSection
>
<
Field
label
=
{
t
(
'
graph:export-file
'
)
}
>
<
ExportButtonWrapper
>
<
Button
onClick
=
{
()
=>
graph
.
current
?.
export
(
'
png
'
)
}
>
{
t
(
'
graph:export-png
'
)
}
</
Button
>
<
Button
onClick
=
{
()
=>
graph
.
current
?.
export
(
'
svg
'
)
}
>
{
t
(
'
graph:export-svg
'
)
}
</
Button
>
</
ExportButtonWrapper
>
</
Field
>
</
AsideSection
>
<
AsideSection
>
<
Field
label
=
{
t
(
'
graph:Choose-model
'
)
}
>
<
div
className
=
"run-list"
>
{
runs
&&
runs
.
map
((
run
:
string
,
index
:
number
)
=>
(
<
div
key
=
{
index
}
>
<
Check
checked
=
{
selectedRuns
===
run
?
true
:
false
}
value
=
{
run
}
title
=
{
run
}
onChange
=
{
(
value
:
string
)
=>
{
setSelectedRuns
(
run
);
}
}
>
{
/* <Popover content={content(run)}> */
}
<
span
className
=
"run-item"
>
{
/* <i style={{backgroundColor: run.colors[0]}}></i> */
}
{
run
.
split
(
'
/
'
)[
run
.
split
(
'
/
'
).
length
-
1
]
}
</
span
>
{
/* </Popover> */
}
</
Check
>
</
div
>
))
}
</
div
>
</
Field
>
</
AsideSection
>
</>
)
}
</
Aside
>
);
},
[
t
,
bottom
,
search
,
searching
,
searchResult
,
selectedRuns
,
modelGraphs
,
selectedGraph
,
changeGraph
,
onSearch
,
onSelect
,
showAttributes
,
showInitializers
,
showNames
,
horizontal
,
rendered
,
nodeData
,
nodeDocumentation
]);
const
uploader
=
useMemo
(
()
=>
<
Uploader
onClickUpload
=
{
onClickFile
}
onDropFiles
=
{
setModelFile
}
/>,
[
onClickFile
,
setModelFile
]
);
return
(
<>
<
Title
>
{
t
(
'
common:graph
'
)
}
</
Title
>
<
ModelPropertiesDialog
data
=
{
modelData
}
onClose
=
{
()
=>
setModelData
(
null
)
}
/>
<
Content
aside
=
{
aside
}
>
<
GraphComponent
ref
=
{
graph
}
files
=
{
files
}
uploader
=
{
uploader
}
showAttributes
=
{
showAttributes
}
showInitializers
=
{
showInitializers
}
showNames
=
{
showNames
}
isKeepData
=
{
isKeepData
}
horizontal
=
{
horizontal
}
selectedRuns
=
{
selectedRuns
}
onRendered
=
{
()
=>
setRendered
(
true
)
}
onOpened
=
{
setOpenedModel
}
onSearch
=
{
data
=>
setSearchResult
(
data
)
}
onShowModelProperties
=
{
data
=>
setModelData
(
data
)
}
runs
=
{
runs
}
onShowNodeProperties
=
{
data
=>
{
setNodeData
(
data
);
setNodeDocumentation
(
null
);
}
}
onShowNodeDocumentation
=
{
data
=>
setNodeDocumentation
(
data
)
}
/>
<
input
ref
=
{
file
}
type
=
"file"
multiple
=
{
false
}
onChange
=
{
onChangeFile
}
style
=
{
{
display
:
'
none
'
}
}
/>
</
Content
>
</>
);
};
export
default
Graph
;
frontend/packages/core/src/pages/graph.tsx
→
frontend/packages/core/src/pages/graph
Static
.tsx
浏览文件 @
5b9dacfc
...
...
@@ -16,7 +16,7 @@
import
Aside
,
{
AsideSection
}
from
'
~/components/Aside
'
;
import
type
{
Documentation
,
OpenedResult
,
Properties
,
SearchItem
,
SearchResult
}
from
'
~/resource/graph/types
'
;
import
GraphComponent
,
{
GraphRef
}
from
'
~/components/GraphPage/Graph
'
;
import
GraphComponent
,
{
GraphRef
}
from
'
~/components/GraphPage/Graph
Static
'
;
import
React
,
{
FunctionComponent
,
useCallback
,
useEffect
,
useMemo
,
useRef
,
useState
}
from
'
react
'
;
import
Select
,
{
SelectProps
}
from
'
~/components/Select
'
;
import
{
actions
,
selectors
}
from
'
~/store
'
;
...
...
@@ -311,7 +311,9 @@ const Graph: FunctionComponent = () => {
horizontal
=
{
horizontal
}
onRendered
=
{
()
=>
setRendered
(
true
)
}
onOpened
=
{
setOpenedModel
}
onSearch
=
{
data
=>
setSearchResult
(
data
)
}
onSearch
=
{
data
=>
{
setSearchResult
(
data
);
}
}
onShowModelProperties
=
{
data
=>
setModelData
(
data
)
}
onShowNodeProperties
=
{
data
=>
{
setNodeData
(
data
);
...
...
frontend/packages/core/src/routes/index.ts
浏览文件 @
5b9dacfc
...
...
@@ -75,8 +75,18 @@ const routes: Route[] = [
},
{
id
:
Pages
.
Graph
,
path
:
'
/graph
'
,
component
:
React
.
lazy
(()
=>
import
(
'
~/pages/graph
'
))
children
:
[
{
id
:
'
graphDynamic
'
,
path
:
'
/graphDynamic
'
,
component
:
React
.
lazy
(()
=>
import
(
'
~/pages/graphDynamic
'
))
},
{
id
:
'
graphStatic
'
,
path
:
'
/graphStatic
'
,
component
:
React
.
lazy
(()
=>
import
(
'
~/pages/graphStatic
'
))
}
]
},
{
id
:
Pages
.
Histogram
,
...
...
frontend/packages/icons/icons/shrink.svg
0 → 100644
浏览文件 @
5b9dacfc
<?xml version="1.0" encoding="UTF-8"?>
<svg
width=
"16px"
height=
"16px"
viewBox=
"0 0 16 16"
version=
"1.1"
xmlns=
"http://www.w3.org/2000/svg"
xmlns:xlink=
"http://www.w3.org/1999/xlink"
>
<title>
收起全部
</title>
<defs>
<rect
id=
"path-1"
x=
"0"
y=
"0"
width=
"16"
height=
"16"
></rect>
</defs>
<g
id=
"页面-1"
stroke=
"none"
stroke-width=
"1"
fill=
"none"
fill-rule=
"evenodd"
>
<g
id=
"1.2网格展开,右下角出现缩略地图"
transform=
"translate(-698.000000, -91.000000)"
>
<g
id=
"形状结合"
transform=
"translate(698.000000, 91.000000)"
>
<mask
id=
"mask-2"
fill=
"white"
>
<use
xlink:href=
"#path-1"
></use>
</mask>
<use
id=
"蒙版"
fill=
"#D8D8D8"
opacity=
"0"
xlink:href=
"#path-1"
></use>
<path
d=
"M7.56666006,9.03333994 C7.80600238,8.79399762 8.20070348,8.80070348 8.44831908,9.04831908 L8.44831908,9.04831908 L13.2085352,13.8085352 C13.4561508,14.0561508 13.4628566,14.4508519 13.2235143,14.6901942 C12.984172,14.9295365 12.5894709,14.9228306 12.3418553,14.6752151 L12.3418553,14.6752151 L8.02995827,10.363318 L3.67312385,14.7201525 C3.43385086,14.9594254 3.03908042,14.9527889 2.79146483,14.7051733 C2.54384923,14.4575577 2.53721271,14.0627873 2.77648569,13.8235143 L2.77648569,13.8235143 Z M2.79146483,1.20853517 C3.03908042,0.96091958 3.433753,0.954185191 3.67306012,1.19349231 L3.67306012,1.19349231 L8.03008573,5.55051792 L12.3419827,1.2386209 C12.5895983,0.991005306 12.9842709,0.984270917 13.223578,1.22357804 C13.4628852,1.46288515 13.4561508,1.85755773 13.2085352,2.10517333 L13.2085352,2.10517333 L8.44831908,6.86538942 C8.20070348,7.11300501 7.8060309,7.1197394 7.56672379,6.88043229 L7.56672379,6.88043229 L2.77642196,2.09013046 C2.53711485,1.85082334 2.54384923,1.45615077 2.79146483,1.20853517 Z"
fill=
"#999999"
mask=
"url(#mask-2)"
></path>
</g>
</g>
</g>
</svg>
\ No newline at end of file
frontend/packages/mock/data/graph_runs.js
0 → 100644
浏览文件 @
5b9dacfc
/**
* Copyright 2020 Baidu Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* 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
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
export
default
{
status
:
0
,
msg
:
''
,
data
:
[
'
test_add_graph/
'
,
'
test_add_graph/test1
'
]};
frontend/packages/netron/src/index.js
浏览文件 @
5b9dacfc
...
...
@@ -17,9 +17,8 @@
// cSpell:words actived nextcode
const
view
=
require
(
'
./view
'
);
const
view2
=
require
(
'
./view2
'
);
const
host
=
{};
host
.
BrowserHost
=
class
{
constructor
()
{
window
.
eval
=
()
=>
{
...
...
@@ -54,7 +53,6 @@ host.BrowserHost = class {
this
.
_view
=
view
;
return
Promise
.
resolve
();
}
start
()
{
window
.
addEventListener
(
'
message
'
,
...
...
@@ -64,12 +62,19 @@ host.BrowserHost = class {
const
type
=
originalData
.
type
;
const
data
=
originalData
.
data
;
switch
(
type
)
{
// 在此书添加一个this._view的事件传递Graph页面过来的数据
case
'
change-files
'
:
return
this
.
_changeFiles
(
data
);
case
'
zoom-in
'
:
return
this
.
_view
.
zoomIn
();
case
'
zoom-out
'
:
return
this
.
_view
.
zoomOut
();
case
'
select-item
'
:
return
this
.
_view
.
selectItem
(
data
);
case
'
toggle-Language
'
:
return
this
.
_view
.
toggleLanguage
(
data
);
case
'
isAlt
'
:
return
this
.
_view
.
changeAlt
(
data
);
case
'
zoom-reset
'
:
return
this
.
_view
.
resetZoom
();
case
'
toggle-attributes
'
:
...
...
@@ -78,6 +83,8 @@ host.BrowserHost = class {
return
this
.
_view
.
toggleInitializers
(
data
);
case
'
toggle-names
'
:
return
this
.
_view
.
toggleNames
(
data
);
case
'
toggle-KeepData
'
:
return
this
.
_view
.
toggleKeepData
(
data
);
case
'
toggle-direction
'
:
return
this
.
_view
.
toggleDirection
(
data
);
case
'
toggle-theme
'
:
...
...
@@ -86,6 +93,10 @@ host.BrowserHost = class {
return
this
.
_view
.
export
(
`
${
document
.
title
}
.
${
data
}
`
);
case
'
change-graph
'
:
return
this
.
_view
.
changeGraph
(
data
);
case
'
change-allGraph
'
:
return
this
.
_view
.
changeAllGrap
(
data
);
case
'
change-select
'
:
return
this
.
_view
.
changeSelect
(
data
);
case
'
search
'
:
return
this
.
_view
.
find
(
data
);
case
'
select
'
:
...
...
@@ -116,8 +127,19 @@ host.BrowserHost = class {
}
status
(
status
)
{
// 反传回去
this
.
message
(
'
status
'
,
status
);
}
selectNodeId
(
nodeInfo
)
{
// 反传回去
console
.
log
(
'
节点点击事件触发了
'
,
nodeInfo
);
this
.
message
(
'
nodeId
'
,
nodeInfo
);
}
selectItems
(
item
)
{
// 反传回去
console
.
log
(
'
节点点击事件触发了
'
,
item
);
this
.
message
(
'
selectItem
'
,
item
);
}
error
(
message
,
detail
)
{
this
.
message
(
'
error
'
,
(
message
===
'
Error
'
?
''
:
message
+
'
'
)
+
detail
);
...
...
@@ -176,6 +198,7 @@ host.BrowserHost = class {
}
_changeFiles
(
files
)
{
console
.
log
(
'
files
'
,
files
);
if
(
files
&&
files
.
length
)
{
files
=
Array
.
from
(
files
);
const
file
=
files
.
find
(
file
=>
this
.
_view
.
accept
(
file
.
name
));
...
...
@@ -498,4 +521,15 @@ class BrowserFileContext {
}
}
window
.
__view__
=
new
view
.
View
(
new
host
.
BrowserHost
());
function
getCaption
(
obj
)
{
let
index
=
obj
.
lastIndexOf
(
'
/
'
);
//获取-后边的字符串
let
newObj
=
obj
.
substring
(
index
+
1
,
obj
.
length
);
return
newObj
;
}
const
hash
=
getCaption
(
document
.
referrer
);
console
.
log
(
'
hash
'
,
hash
);
if
(
hash
===
'
graphStatic
'
)
{
window
.
__view__
=
new
view2
.
View
(
new
host
.
BrowserHost
());
}
else
{
window
.
__view__
=
new
view
.
View
(
new
host
.
BrowserHost
());
}
frontend/packages/netron/src/paddle-metadata.js
0 → 100644
浏览文件 @
5b9dacfc
此差异已折叠。
点击以展开。
frontend/packages/netron/src/sidebar.js
浏览文件 @
5b9dacfc
...
...
@@ -547,7 +547,7 @@ sidebar.ModelSidebar = class {
}
}
if
(
this
.
_model
.
_graphs
.
length
>
1
)
{
if
(
this
.
_model
)
{
// let graphSelector = new sidebar.SelectView(
// this._host,
// this._model.graphs.map(g => g.name),
...
...
@@ -683,23 +683,98 @@ sidebar.FindSidebar = class {
const
id
=
item
.
id
;
const
nodesElement
=
graphElement
.
getElementById
(
'
nodes
'
);
let
nodeElement
=
nodesElement
.
firstChild
;
while
(
nodeElement
)
{
if
(
nodeElement
.
id
==
id
)
{
selection
.
push
(
nodeElement
);
if
(
nodesElement
)
{
let
nodeElement
=
nodesElement
.
firstChild
;
while
(
nodeElement
)
{
if
(
nodeElement
.
id
==
id
)
{
selection
.
push
(
nodeElement
);
}
nodeElement
=
nodeElement
.
nextSibling
;
}
}
const
clustersElement
=
graphElement
.
getElementById
(
'
clusters
'
);
if
(
clustersElement
)
{
let
clusterElement
=
clustersElement
.
firstChild
;
while
(
clusterElement
)
{
if
(
clusterElement
.
id
==
id
)
{
selection
.
push
(
clusterElement
);
}
clusterElement
=
clusterElement
.
nextSibling
;
}
nodeElement
=
nodeElement
.
nextSibling
;
}
const
edgePathsElement
=
graphElement
.
getElementById
(
'
edge-paths
'
);
let
edgePathElement
=
edgePathsElement
.
firstChild
;
while
(
edgePathElement
)
{
if
(
edgePathElement
.
id
==
id
)
{
selection
.
push
(
edgePathElement
);
if
(
edgePathsElement
)
{
let
edgePathElement
=
edgePathsElement
.
firstChild
;
while
(
edgePathElement
)
{
if
(
edgePathElement
.
id
===
id
)
{
// console.log('edgePathElement',edgePathElement.getAttribute("fromnode"),item);
// if (item.fromnode && edgePathElement.getAttribute("fromnode") === item.fromnode) {
// selection.push(edgePathElement);
// }
// if (item.tonode && edgePathElement.getAttribute("tonode") === item.tonode) {
// selection.push(edgePathElement);
// }
selection
.
push
(
edgePathElement
);
}
edgePathElement
=
edgePathElement
.
nextSibling
;
}
edgePathElement
=
edgePathElement
.
nextSibling
;
}
let
initializerElement
=
graphElement
.
getElementById
(
id
);
if
(
initializerElement
)
{
while
(
initializerElement
.
parentElement
)
{
initializerElement
=
initializerElement
.
parentElement
;
if
(
initializerElement
.
id
&&
initializerElement
.
id
.
startsWith
(
'
node-
'
))
{
selection
.
push
(
initializerElement
);
break
;
}
}
}
if
(
selection
.
length
>
0
)
{
return
selection
;
}
return
null
;
}
static
selection2
(
item
,
graphElement
)
{
const
selection
=
[];
const
id
=
item
.
id
;
const
nodesElement
=
graphElement
.
getElementById
(
'
nodes
'
);
if
(
nodesElement
)
{
let
nodeElement
=
nodesElement
.
firstChild
;
while
(
nodeElement
)
{
if
(
nodeElement
.
id
==
id
)
{
selection
.
push
(
nodeElement
);
}
nodeElement
=
nodeElement
.
nextSibling
;
}
}
const
clustersElement
=
graphElement
.
getElementById
(
'
clusters
'
);
if
(
clustersElement
)
{
let
clusterElement
=
clustersElement
.
firstChild
;
while
(
clusterElement
)
{
if
(
clusterElement
.
id
==
id
)
{
selection
.
push
(
clusterElement
);
}
clusterElement
=
clusterElement
.
nextSibling
;
}
}
const
edgePathsElement
=
graphElement
.
getElementById
(
'
edge-paths
'
);
if
(
edgePathsElement
)
{
let
edgePathElement
=
edgePathsElement
.
firstChild
;
while
(
edgePathElement
)
{
if
(
edgePathElement
.
id
===
id
)
{
if
(
item
.
fromnode
&&
edgePathElement
.
getAttribute
(
'
fromnode
'
)
===
item
.
fromnode
)
{
selection
.
push
(
edgePathElement
);
}
if
(
item
.
tonode
&&
edgePathElement
.
getAttribute
(
'
tonode
'
)
===
item
.
tonode
)
{
selection
.
push
(
edgePathElement
);
}
}
edgePathElement
=
edgePathElement
.
nextSibling
;
}
}
let
initializerElement
=
graphElement
.
getElementById
(
id
);
if
(
initializerElement
)
{
while
(
initializerElement
.
parentElement
)
{
...
...
@@ -725,7 +800,6 @@ sidebar.FindSidebar = class {
const
edgeMatches
=
new
Set
();
const
result
=
[];
for
(
const
node
of
this
.
_graph
.
nodes
)
{
const
initializers
=
[];
...
...
@@ -744,13 +818,14 @@ sidebar.FindSidebar = class {
});
edgeMatches
.
add
(
argument
.
name
);
}
else
{
initializers
.
push
(
argument
.
initializer
);
//
initializers.push(argument.initializer);
}
}
}
}
const
name
=
node
.
name
;
console
.
log
(
'
name
'
,
node
);
const
operator
=
node
.
type
;
if
(
!
nodeMatches
.
has
(
name
)
&&
...
...
@@ -759,12 +834,55 @@ sidebar.FindSidebar = class {
)
{
result
.
push
({
type
:
'
node
'
,
name
:
n
ode
.
n
ame
,
id
:
'
node-
'
+
n
ode
.
n
ame
name
:
name
,
id
:
'
node-
'
+
name
});
nodeMatches
.
add
(
n
ode
.
n
ame
);
nodeMatches
.
add
(
name
);
}
// let path = node.name.split('/');
// path.pop();
// let groupName = path.join('/');
// console.log('groupName', groupName);
// const clusterNode = name => {
// if (
// !nodeMatches.has(name) &&
// name &&
// (name.toLowerCase().indexOf(text) != -1 || (operator && operator.toLowerCase().indexOf(text) != -1))
// ) {
// result.push({
// type: 'node',
// name: name,
// id: 'node-' + name
// });
// nodeMatches.add(name);
// let path = name.split('/');
// while (path.length > 0) {
// const name = path.join('/');
// path.pop();
// if (name) {
// clusterNode(name);
// }
// }
// }
// };
// if (groupName) {
// clusterNode(groupName);
// // g.setParent(nodeId, groupName);
// }
// clusterNode(node.show_name);
// if (
// !nodeMatches.has(name) &&
// name &&
// (name.toLowerCase().indexOf(text) != -1 || (operator && operator.toLowerCase().indexOf(text) != -1))
// ) {
// result.push({
// type: 'node',
// name: node.name,
// id: 'node-' + node.name
// });
// //
// nodeMatches.add(node.name);
// }
for
(
const
initializer
of
initializers
)
{
result
.
push
({
type
:
'
initializer
'
,
...
...
@@ -792,7 +910,6 @@ sidebar.FindSidebar = class {
}
}
}
return
{
text
:
searchText
,
result
:
result
...
...
frontend/packages/netron/src/style.scss
浏览文件 @
5b9dacfc
...
...
@@ -8,8 +8,8 @@ body {
margin
:
0
;
width
:
100vw
;
height
:
100vh
;
font-family
:
-
apple-system
,
BlinkMacSystemFont
,
'Segoe WPC'
,
'Segoe UI'
,
'Ubuntu'
,
'Droid Sans'
,
sans-serif
,
'PingFang SC'
;
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
;
...
...
@@ -27,7 +27,7 @@ body {
.canvas
{
display
:
block
;
position
:
absolute
;
//
position: absolute;
text-rendering
:
geometricPrecision
;
user-select
:
none
;
cursor
:
grab
;
...
...
@@ -46,13 +46,14 @@ line {
}
text
{
font-family
:
-
apple-system
,
BlinkMacSystemFont
,
"Segoe WPC"
,
"Segoe UI"
,
"Ubuntu"
,
"Droid Sans"
,
sans-serif
,
"PingFang SC"
;
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
:
#
CFCFD
1
;
fill
:
#
cfcfd
1
;
}
}
...
...
@@ -70,7 +71,7 @@ text {
&
:hover
{
path
{
fill
:
#2932
E
1
;
fill
:
#2932
e
1
;
fill-opacity
:
1
;
}
...
...
@@ -81,7 +82,7 @@ text {
}
.node-item-function
path
{
fill
:
#9
BB9E
8
;
fill
:
#9
bb9e
8
;
fill-opacity
:
0
.7
;
}
...
...
@@ -89,70 +90,88 @@ text {
cursor
:
pointer
;
path
{
fill
:
#8
BB8FF
;
fill
:
#8
bb8ff
;
fill-opacity
:
0
.9
;
}
}
.node-item-type-constant
path
{
fill
:
#
B4CCB
7
;
fill
:
#
b4ccb
7
;
}
.node-item-type-control
path
{
fill
:
#
A8E9B
8
;
fill
:
#
a8e9b
8
;
}
.node-item-type-layer
path
{
fill
:
#DB989A
;
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
:
#6dcde4
;
fill-opacity
:
0
.7
;
}
.node-item-type-conv
path
{
fill
:
#6dcde4
;
fill-opacity
:
0
.7
;
}
.node-item-type-activation
path
{
fill
:
#93
C2CA
;
fill
:
#93
c2ca
;
fill-opacity
:
0
.7
;
}
.node-item-type-pool
path
{
fill
:
#
DE7CCE
;
fill
:
#
de7cce
;
fill-opacity
:
0
.7
;
}
.node-item-type-normalization
path
{
fill
:
#
DA96BC
;
fill
:
#
da96bc
;
fill-opacity
:
0
.7
;
}
.node-item-type-dropout
path
{
fill
:
#309E51
;
fill
:
#309e51
;
fill-opacity
:
0
.7
;
}
.node-item-type-pad
path
{
fill
:
#309e51
;
fill-opacity
:
0
.7
;
}
.node-item-type-shape
path
{
fill
:
#
D6C
482
;
fill
:
#
d6c
482
;
fill-opacity
:
0
.7
;
}
.node-item-type-tensor
path
{
fill
:
#6
D7CE
4
;
fill
:
#6
d7ce
4
;
fill-opacity
:
0
.7
;
}
.node-item-type-transform
path
{
fill
:
#CDCB74
;
fill
:
#cdcb74
;
}
.node-item-type-sequence
path
{
fill
:
#cdcb74
;
}
.node-item-type-data
path
{
fill
:
#2576
AD
;
fill
:
#2576
ad
;
fill-opacity
:
0
.7
;
}
.node-item-type-custom
path
{
fill
:
#
E46D6D
;
fill
:
#
e46d6d
;
fill-opacity
:
0
.7
;
}
...
...
@@ -176,7 +195,7 @@ text {
cursor
:
pointer
;
path
{
fill
:
#
CA
5353
;
fill
:
#
ca
5353
;
fill-opacity
:
0
.7
;
}
}
...
...
@@ -203,7 +222,7 @@ text {
cursor
:
pointer
;
path
{
fill
:
#
E49D6D
;
fill
:
#
e49d6d
;
fill-opacity
:
0
.7
;
}
}
...
...
@@ -212,7 +231,7 @@ text {
cursor
:
pointer
;
path
{
fill
:
#
E4E06D
;
fill
:
#
e4e06d
;
fill-opacity
:
0
.9
;
}
}
...
...
@@ -235,18 +254,97 @@ text {
stroke-dasharray
:
3
,
2
;
}
.cluster
rect
{
stroke
:
#000
;
fill
:
#000
;
fill-opacity
:
0
.02
;
stroke-opacity
:
0
.06
;
.cluster
.clusterGroup
{
fill
:
#dce9ff
;
stroke
:
#666
;
stroke-width
:
1px
;
}
.node-item-function
path
{
fill
:
#9bb9e8
;
fill-opacity
:
0
.7
;
}
.cluster
.clusterGroup-constant
{
fill
:
#e8efe9
;
}
.select
{
.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
:
#db989a
;
stroke
:
#999
;
cursor
:
pointer
;
}
.cluster
.button-text
{
fill
:
#999
;
}
.cluster.border
{
display
:
none
;
}
.select
{
&
.edge-path
{
stroke
:
#1527
C
2
;
stroke
:
#1527
c
2
;
stroke-width
:
2px
;
stroke-dasharray
:
6px
3px
;
stroke-dashoffset
:
0
;
...
...
@@ -254,7 +352,15 @@ text {
}
.node.border
{
stroke
:
#1527C2
;
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
;
...
...
frontend/packages/netron/src/view-grapher.js
0 → 100644
浏览文件 @
5b9dacfc
此差异已折叠。
点击以展开。
frontend/packages/netron/src/view.js
浏览文件 @
5b9dacfc
此差异已折叠。
点击以展开。
frontend/packages/netron/src/view2.js
0 → 100644
浏览文件 @
5b9dacfc
此差异已折叠。
点击以展开。
frontend/yarn.lock
浏览文件 @
5b9dacfc
...
...
@@ -6146,6 +6146,11 @@ eslint-plugin-react@7.25.1:
resolve "^2.0.0-next.3"
string.prototype.matchall "^4.0.5"
eslint-plugin-simple-import-sort@^7.0.0:
version "7.0.0"
resolved "https://registry.npmmirror.com/eslint-plugin-simple-import-sort/-/eslint-plugin-simple-import-sort-7.0.0.tgz#a1dad262f46d2184a90095a60c66fef74727f0f8"
integrity sha512-U3vEDB5zhYPNfxT5TYR7u01dboFZp+HNpnGhkDB2g/2E4wZ/g1Q9Ton8UwCLfRV9yAKyYqDh62oHOamvkFxsvw==
eslint-scope@5.1.1, eslint-scope@^5.1.1:
version "5.1.1"
resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c"
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录