Delete eng/common/InterdependencyGraph.html which is unused. (#5763)
Co-authored-by: Wes Haggard <weshaggard@users.noreply.github.com>
This commit is contained in:
Родитель
2e4e87f490
Коммит
32250eaf25
|
@ -1,356 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>Interdependency Graph</title>
|
||||
<meta charset="utf-8">
|
||||
<script src="https://cdn.jsdelivr.net/npm/cytoscape@3.11.0/dist/cytoscape.min.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/dagre/0.8.4/dagre.min.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/cytoscape-dagre@2.2.2/cytoscape-dagre.min.js"></script>
|
||||
<script type="application/javascript">
|
||||
const renderGraph = (data) => {
|
||||
const config = {
|
||||
container: document.getElementById('cy'),
|
||||
elements: [],
|
||||
autounselectify: true,
|
||||
|
||||
layout: {
|
||||
name: 'dagre',
|
||||
ranker: 'tight-tree',
|
||||
nodeSep: 10,
|
||||
rankSep: 400,
|
||||
padding: 10
|
||||
},
|
||||
|
||||
style: [
|
||||
{
|
||||
selector: '.hidden',
|
||||
style: {
|
||||
'display': 'none'
|
||||
}
|
||||
},
|
||||
{
|
||||
selector: 'node',
|
||||
style: {
|
||||
'background-color': '#fff',
|
||||
'border-color': '#333',
|
||||
'border-width': '1px',
|
||||
'height': 'label',
|
||||
'label': 'data(label)',
|
||||
'padding': '8px',
|
||||
'shape': 'round-rectangle',
|
||||
'text-halign': 'center',
|
||||
'text-valign': 'center',
|
||||
'text-wrap': 'wrap',
|
||||
'width': 'label'
|
||||
}
|
||||
},
|
||||
{
|
||||
selector: 'node.internal',
|
||||
style: {
|
||||
'background-color': '#7f7'
|
||||
}
|
||||
},
|
||||
{
|
||||
selector: 'node.internalbinary',
|
||||
style: {
|
||||
'background-color': '#fb7'
|
||||
}
|
||||
},
|
||||
{
|
||||
selector: 'node.collapsed',
|
||||
style: {
|
||||
'background-color': '#b7f'
|
||||
}
|
||||
},
|
||||
{
|
||||
selector: 'node.search',
|
||||
style: {
|
||||
'background-color': '#ff7',
|
||||
'border-width': '6px',
|
||||
'display': 'element'
|
||||
}
|
||||
},
|
||||
{
|
||||
selector: 'node.highlight',
|
||||
style: {
|
||||
'background-color': '#fff',
|
||||
'border-width': '6px',
|
||||
'display': 'element'
|
||||
}
|
||||
},
|
||||
{
|
||||
selector: 'node.highlight.in',
|
||||
style: {
|
||||
'border-color': '#7bf'
|
||||
}
|
||||
},
|
||||
{
|
||||
selector: 'node.highlight.out',
|
||||
style: {
|
||||
'border-color': '#f77'
|
||||
}
|
||||
},
|
||||
{
|
||||
selector: 'node.highlight.source',
|
||||
style: {
|
||||
'border-color': '#f77'
|
||||
}
|
||||
},
|
||||
{
|
||||
selector: 'node.highlight.internal',
|
||||
style: {
|
||||
'background-color': '#7f7'
|
||||
}
|
||||
},
|
||||
{
|
||||
selector: 'node.highlight.internalbinary',
|
||||
style: {
|
||||
'background-color': '#fb7'
|
||||
}
|
||||
},
|
||||
{
|
||||
selector: 'node.highlight.collapsed',
|
||||
style: {
|
||||
'background-color': '#b7f'
|
||||
}
|
||||
},
|
||||
{
|
||||
selector: 'node.highlight.search',
|
||||
style: {
|
||||
'background-color': '#ff7'
|
||||
}
|
||||
},
|
||||
{
|
||||
selector: 'edge',
|
||||
style: {
|
||||
'curve-style': 'bezier',
|
||||
'label': 'data(label)',
|
||||
'line-color': '#333',
|
||||
'target-arrow-color': '#333',
|
||||
'target-arrow-shape': 'triangle',
|
||||
'width': '1.5px'
|
||||
}
|
||||
},
|
||||
{
|
||||
selector: 'edge.highlight',
|
||||
style: {
|
||||
'display': 'element',
|
||||
'width': '6px'
|
||||
}
|
||||
},
|
||||
{
|
||||
selector: 'edge.highlight.in',
|
||||
style: {
|
||||
'line-color': '#7bf',
|
||||
'target-arrow-color': '#7bf'
|
||||
}
|
||||
},
|
||||
{
|
||||
selector: 'edge.highlight.out',
|
||||
style: {
|
||||
'line-color': '#f77',
|
||||
'target-arrow-color': '#f77'
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
// Add the nodes
|
||||
for (const pkg of Object.keys(data)) {
|
||||
config.elements.push({
|
||||
data: {
|
||||
id: pkg,
|
||||
label: `${data[pkg].name}\n${data[pkg].version}`
|
||||
},
|
||||
classes: data[pkg].type
|
||||
})
|
||||
}
|
||||
|
||||
// Add the edges
|
||||
for (const pkg of Object.keys(data)) {
|
||||
for (const dep of data[pkg].deps) {
|
||||
const dest = `${dep.name}:${dep.version}`
|
||||
const edge = {
|
||||
data: {
|
||||
id: `${pkg}:${dest}`,
|
||||
source: pkg,
|
||||
target: dest,
|
||||
label: dep.label || ''
|
||||
}
|
||||
}
|
||||
config.elements.push(edge)
|
||||
}
|
||||
}
|
||||
|
||||
const cy = cytoscape(config)
|
||||
|
||||
cy.on('mouseover', 'node', event => {
|
||||
const element = event.target
|
||||
if (element.hasClass('pinned')) { return }
|
||||
|
||||
element.addClass('highlight source')
|
||||
element.outgoers().addClass('highlight out')
|
||||
element.incomers().addClass('highlight in')
|
||||
})
|
||||
|
||||
cy.on('mouseout', 'node', event => {
|
||||
const element = event.target
|
||||
if (element.hasClass('pinned')) { return }
|
||||
|
||||
element.removeClass('source')
|
||||
if (!element.hasClass('in') && !element.hasClass('out')) {
|
||||
element.removeClass('highlight')
|
||||
}
|
||||
|
||||
element.outgoers().forEach(e => {
|
||||
e.removeClass('out')
|
||||
if (!e.hasClass('in') && !e.hasClass('source')) {
|
||||
e.removeClass('highlight')
|
||||
}
|
||||
})
|
||||
|
||||
element.incomers().forEach(e => {
|
||||
e.removeClass('in')
|
||||
if (!e.hasClass('out') && !e.hasClass('source')) {
|
||||
e.removeClass('highlight')
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
cy.on('cxttap', 'node', event => {
|
||||
const element = event.target
|
||||
if (!element.hasClass('pinned')) {
|
||||
element.addClass('pinned')
|
||||
|
||||
} else {
|
||||
element.removeClass('pinned')
|
||||
}
|
||||
})
|
||||
|
||||
document.addEventListener('keydown', event => {
|
||||
if (document.activeElement.id === 'search') { return }
|
||||
|
||||
if (event.key === '-') {
|
||||
cy.nodes('.internal').forEach(node => {
|
||||
if (!node.hasClass('hidden')) {
|
||||
triggerCollapse(cy, node, true)
|
||||
}
|
||||
})
|
||||
} else if (event.key === '=') {
|
||||
cy.nodes('.internal').forEach(node => {
|
||||
triggerCollapse(cy, node, false)
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
let searchTerm = ''
|
||||
document.getElementById('search').addEventListener('input', event => {
|
||||
const newValue = event.target.value
|
||||
if (searchTerm !== newValue) {
|
||||
searchTerm = newValue
|
||||
cy.nodes().removeClass('search')
|
||||
if (searchTerm.length > 0) {
|
||||
const matches = cy.nodes(`[label *= '${searchTerm}']`)
|
||||
matches.addClass('search')
|
||||
document.getElementById('matches').innerText = `Matches: ${matches.length}`
|
||||
} else {
|
||||
document.getElementById('matches').innerText = ''
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
cy.on('tap', 'node', event => {
|
||||
const element = event.target
|
||||
const collapse = !element.hasClass('collapsed')
|
||||
triggerCollapse(cy, element, collapse)
|
||||
element.emit('mouseout')
|
||||
element.emit('mouseover')
|
||||
})
|
||||
}
|
||||
|
||||
const triggerCollapse = (cy, element, collapse) => {
|
||||
if (element.outgoers().length === 0) { return }
|
||||
|
||||
if (collapse) {
|
||||
element.addClass('collapsed')
|
||||
} else {
|
||||
element.removeClass('collapsed')
|
||||
}
|
||||
|
||||
if (collapse) {
|
||||
element.outgoers('edge').addClass('hidden')
|
||||
const orphans = cy.filter(e => {
|
||||
return e.isNode() &&
|
||||
!e.hasClass('internal') &&
|
||||
!e.incomers('edge').some(g => !g.hasClass('hidden'))
|
||||
})
|
||||
orphans.forEach(o => {
|
||||
o.addClass('hidden')
|
||||
o.successors().addClass('hidden') // no-op when only one tier of external nodes are present
|
||||
})
|
||||
} else {
|
||||
element.outgoers().removeClass('hidden')
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
body {
|
||||
margin: 10 auto;
|
||||
color: #333;
|
||||
font-weight: 300;
|
||||
font-family: "Helvetica Neue", Helvetica, Arial, sans-serf;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 3em;
|
||||
font-weight: 300;
|
||||
z-index: -2;
|
||||
}
|
||||
|
||||
#cy {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
z-index: -1;
|
||||
pointer-events: all;
|
||||
}
|
||||
|
||||
.panel {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.panel div {
|
||||
margin: 4px auto;
|
||||
}
|
||||
|
||||
.panel input {
|
||||
pointer-events: all;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="panel">
|
||||
<h1>Dependency Graph</h1>
|
||||
<label for="search">Search:</label>
|
||||
<input id="search" type="search" autocomplete="off" size="64" />
|
||||
<div id="matches"></div>
|
||||
</div>
|
||||
<div id="cy"></div>
|
||||
<script type="application/javascript">
|
||||
const params = new URLSearchParams(window.location.search);
|
||||
const src = params.get("data") || "data.js";
|
||||
const script = document.createElement("script");
|
||||
script.src = src;
|
||||
script.async = false;
|
||||
script.addEventListener("load", () => renderGraph(data));
|
||||
script.addEventListener("error", e => {
|
||||
const dest = document.getElementsByClassName("panel")[0];
|
||||
dest.innerText = `Failed to load ${src}`;
|
||||
});
|
||||
document.head.appendChild(script);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
Загрузка…
Ссылка в новой задаче