d3-org-chart
Version:
Highly customizable org chart, created with d3
250 lines (219 loc) • 14.9 kB
HTML
<html>
<head>
<meta charset="UTF-8">
<title>OrgChart</title>
<link rel="shortcut icon" type="image/x-icon" href="misc/favicon.ico">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
<!---------------- ORG CHART NON ESSENTIAL CONTENT ------------>
<script src="https://unpkg.com/html2canvas@1.1.4/dist/html2canvas.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/2.3.1/jspdf.umd.min.js"></script>
<link href="https://cdn.jsdelivr.net/npm/simptip@1.0.4/simptip.min.css" rel="stylesheet">
<style>
[data-tooltip]:focus:after {
display: none;
border-bottom-color: none ;
;
}
[data-tooltip]:focus:before {
display: none;
border-bottom-color: none ;
;
}
[data-tooltip]:after {
height: auto ;
padding: 11px 11px 11px 11px ;
content: attr(data-tooltip);
white-space: pre;
line-height: 16px ;
text-align: left ;
}
</style>
<div class="action-buttons" style="margin:0 100px">
<button onclick='chart.setExpanded("O-6164").render()' class="simptip-position-bottom"
data-tooltip='chart.setExpanded("O-6164") 
 .render()'>Expand O-6164</button>
<button onclick='chart.setExpanded("O-6164",false).render()' class="simptip-position-bottom"
data-tooltip='chart.setExpanded("O-6164",false) 
 .render()'>Collapse O-6164</button>
<button onclick='chart.addNode({id:"root child",parentId:"O-6066"})' class="simptip-position-bottom"
data-tooltip='chart.addNode({id:"root child",parentId:"O-6066"})'>Add node as roots' child</button>
<button onclick='chart.addNode({id:"5-th level node",parentId:"O-6164",_centered:true})'
class="simptip-position-bottom"
data-tooltip='chart.addNode({id:"5-th level node",parentId:"O-6164",_centered:true})'>Insert node at 5-th
level</button>
<button onclick='chart.removeNode("O-6067")' class="simptip-position-bottom"
data-tooltip='chart.removeNode("O-6067")'>Remove O-6067</button>
<button onclick='chart.fit()' class="simptip-position-bottom" data-tooltip='chart.fit()'>Fit
</button>
<button onclick='chart.layout(["right","bottom","left","top"][index++%4]).render().fit()'
class="simptip-position-bottom"
data-tooltip='chart.layout(["right","bottom","left","top"][index++%4]) 
 .render() 
 .fit()'>Swap
Layouts
</button>
<button onclick='chart.setCentered("O-6162").render()' class="simptip-position-bottom"
data-tooltip='chart.setCentered("O-6162") 
 .render()'>Center O-6162 </button>
<button onclick='chart.setHighlighted("O-6162").render()' class="simptip-position-bottom"
data-tooltip='chart.setHighlighted("O-6162") 
 .render()'>Highlight O-6162 </button>
<button onclick='chart.setUpToTheRootHighlighted("O-6162").render()' class="simptip-position-bottom"
data-tooltip='chart.setUpToTheRootHighlighted("O-6162") 
 .render()'>Highlight O-6162 to root </button>
<button onclick='chart.clearHighlighting()' class="simptip-position-bottom"
data-tooltip='chart.clearHighlighting() 
 .render()'>Clear highlighting </button>
<button onclick='chart.fullscreen()' class="simptip-position-bottom" data-tooltip='chart.fullscreen()'>Full
Screen </button>
<button onclick='chart.zoomIn()' class="simptip-position-bottom" data-tooltip='chart.zoomIn()'>Zoom In </button>
<button onclick='chart.zoomOut()' class="simptip-position-bottom" data-tooltip='chart.zoomOut()'>Zoom Out
</button>
<button onclick='chart.exportImg()' class="simptip-position-bottom" data-tooltip='chart.exportImg()'>Export
Current Image
</button>
<button onclick='chart.exportImg({full:true})' class="simptip-position-bottom" data-tooltip='chart.exportImg({full:true})'>Export
Export Full Image
</button>
<button onclick='chart.exportSvg()' class="simptip-position-bottom" data-tooltip='chart.exportSvg()'>Export
SVG
</button>
<button onclick='chart.expandAll()' class="simptip-position-bottom" data-tooltip='chart.expandAll()'>Expand All
</button>
<button onclick='chart.collapseAll()' class="simptip-position-bottom" data-tooltip='chart.collapseAll()'>Collapse All
</button>
<button onclick='chart.connections([{from:"O-6067",to:"O-6070",label:"Conflicts of interest"}]).render()' class="simptip-position-bottom"
data-tooltip='chart.connections({from:"",to:""}) 
 .render()'>Multi Node Connections
</button>
<button onclick='downloadPdf()' class="simptip-position-bottom" data-tooltip='downloadPdf()'>Download PDF
</button>
<script>
function downloadPdf() {
chart.exportImg({
save: false,
onLoad: (base64 => {
var pdf = new jspdf.jsPDF();
var img = new Image()
img.src = base64;
img.onload = function () {
pdf.addImage(img, 'JPEG', 5, 5, 595 / 3, img.height / img.width * 595 / 3);
pdf.save('chart.pdf');
}
})
})
}
</script>
</div>
<a href="https://github.com/bumbeishvili/d3-organization-chart">
<img style="position:fixed;top:0;right:0;border:0;z-index:2;" width="149" height="149"
src="https://bumbeishvili.github.io/d3-tooltip/forkme.png" alt="Fork me on GitHub">
</a>
<!---------------- ORG CHART ESSENTIAL CONTENT ---------------->
<script src="https://d3js.org/d3.v7.min.js"></script>
<script src="./build/d3-org-chart.js"></script>
<script src="https://cdn.jsdelivr.net/npm/d3-flextree@2.0.0/build/d3-flextree.js"></script>
<div class="chart-container" style=" padding-top:10px; height:1200px ;background-color:white"> </div>
<script>
var index = 0;
var chart;
d3.csv('misc/data.csv')
.then(dataFlattened => {
chart = new d3.OrgChart()
.container('.chart-container')
.data(dataFlattened)
// .svgHeight(window.innerHeight)
// .nodeWidth((d3Node) => {
// return 200;
// let i = 0;
// if (d3Node.parent) { i = d3Node.parent.children.indexOf(d3Node); }
// if (i && i == d3Node.parent.children.length - 1) { return 600; }
// return (!i || i == d3Node.parent.children.length - 1) ? 300 : 100
// })
// .nodeHeight((d3Node) => {
// return 100;
// let i = 0;
// if (d3Node.parent) { i = d3Node.parent.children.indexOf(d3Node); }
// if (i && i == d3Node.parent.children.length - 1) { return 300; }
// return (!i || i == d3Node.parent.children.length - 1) ? 200 : 100
// })
// .siblingsMargin(d3Node => 0)
// .childrenMargin(d3Node => 50)
// .neightbourMargin((n1, n2) => 50)
// .compactMarginPair(d3Node => 70)
// .compactMarginBetween(d3Node => 30)
// .setActiveNodeCentered(true)
// .layout(new URLSearchParams(new URL(document.location.href).search).get('layout') || "top")
// .onNodeClick(d => console.log(d + ' node clicked'))
// .linkUpdate(function (d3Node, i, arr) {
// const link = this;
// d3.select(link)
// .attr('stroke-dasharray', !i ? '2 2' : 'none')
// .attr('stroke-width', 3)
// })
// .nodeUpdate(function (data, i, arr) {
// d3.select(this).on('click.node', (event, d, i) => {
// console.log(d.nodeId + ' node clicked')
// })
// })
// .connections(
// [
// { id: 1, from: "O-6067", to: "O-6068", label: "Directly Reports To" },
// { id: 2, from: "O-6070", to: "O-6066", label: "Reports To" },
// { id: 3, from: "O-6088", to: "O-6069", label: "They were coworkers once" },
// { id: 3, from: "O-6164", to: "O-6070", label: "Possible conflicts of interest" }
// ],
// )
// .nodeContent(function (d, i, arr, state) {
// return `
// <div style="padding:0px">
// <!--
// ${state.layout == 'top' && state.compact && d.flexCompactDim && (d.flexCompactDim[0] || d.flexCompactDim[0] == 1) ? ` <div style="border:1px solid black;opacity:0.5;margin-left:${-(d.flexCompactDim[0] / 2 - d.width) / 2 + state.compactMarginPair(d) / 4}px;width:${d.flexCompactDim[0]}px;height:${d.flexCompactDim[1]}px;z-index:-1;position:absolute;background-color:red"></div>` : ''}
// ${state.layout == 'bottom' && state.compact && d.flexCompactDim && (d.flexCompactDim[0] || d.flexCompactDim[0] == 1) ? ` <div style="border:1px solid black;opacity:0.5;margin-top:${-d.flexCompactDim[1] + d.height}px;margin-left:${-(d.flexCompactDim[0] / 2 - d.width) / 2 + state.compactMarginPair(d) / 4}px;width:${d.flexCompactDim[0]}px;height:${d.flexCompactDim[1]}px;z-index:-1;position:absolute;background-color:red"></div>` : ''}
// ${state.layout == 'left' && state.compact && d.flexCompactDim && (d.flexCompactDim[0] || d.flexCompactDim[0] == 1) ? ` <div style="border:1px solid black;opacity:0.5;margin-top:${-(d.flexCompactDim[0]/2-d.height)/2+ state.compactMarginPair(d) / 4}px;margin-left:${0}px;width:${d.flexCompactDim[1]}px;height:${d.flexCompactDim[0]}px;z-index:-1;position:absolute;background-color:red"></div>` : ''}
// ${state.layout == 'right' && state.compact && d.flexCompactDim && (d.flexCompactDim[0] || d.flexCompactDim[0] == 1) ? ` <div style="border:1px solid black;opacity:0.5; margin-top:${-(d.flexCompactDim[0]/2-d.height)/2+ state.compactMarginPair(d) / 4}px;margin-left:${d.width-d.flexCompactDim[1]}px;width:${d.flexCompactDim[1]}px;height:${d.flexCompactDim[0]}px;z-index:-1;position:absolute;background-color:red"></div>` : ''}
// -->
// <img src="${d.data.imageUrl}" style="border-radius:100px;width:60px;height:60px;" />
// ID: ${d.data.id} <br>
// Children Direct:${d.data._directSubordinates}<br>
// Children Total:${d.data._totalSubordinates}
// </div>
// `;
// })
.nodeHeight(d => 85)
.nodeWidth(d => {
return 220
})
.childrenMargin(d => 50)
.onNodeClick(d=>alert('ok'))
.compactMarginBetween(d => 35)
.compactMarginPair(d => 30)
.neightbourMargin((a, b) => 20)
.buttonContent(({ node, state }) => {
return `<div style="color:#716E7B;border-radius:5px;padding:3px;font-size:10px;margin:auto auto;background-color:white;border: 1px solid #E4E2E9"> <span style="font-size:9px">${node.children ? `<i class="fas fa-angle-up"></i>` : `<i class="fas fa-angle-down"></i>`}</span> ${node.data._directSubordinates} </div>`
})
.linkUpdate(function (d, i, arr) {
d3.select(this)
.attr("stroke", d => d.data._upToTheRootHighlighted ? '#152785' : '#E4E2E9')
.attr("stroke-width", d => d.data._upToTheRootHighlighted ? 5 : 1)
if (d.data._upToTheRootHighlighted) {
d3.select(this).raise()
}
})
.nodeContent(function (d, i, arr, state) {
const colors = ['#278B8D', '#404040', '#0C5C73', '#33C6CB'];
const color = "#FFFFFF"
return `
<div style="font-family: 'Inter', sans-serif;background-color:${color}; position:absolute;margin-top:-1px; margin-left:-1px;width:${d.width}px;height:${d.height}px;border-radius:10px;border: 1px solid #E4E2E9">
<div style="background-color:${color};position:absolute;margin-top:-25px;margin-left:${15}px;border-radius:100px;width:50px;height:50px;" ></div>
<img src=" ${d.data.imageUrl}" style="position:absolute;margin-top:-20px;margin-left:${20}px;border-radius:100px;width:40px;height:40px;" />
<div style="color:#08011E;position:absolute;right:20px;top:17px;font-size:10px;"><i class="fas fa-ellipsis-h"></i></div>
<div style="font-size:15px;color:#08011E;margin-left:20px;margin-top:32px"> ${d.data.name} </div>
<div style="color:#716E7B;margin-left:20px;margin-top:3px;font-size:10px;"> ${d.data.positionName} </div>
</div>
`;
})
.render()
})
</script>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter&display=swap" rel="stylesheet">
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.4/css/all.min.css" rel="stylesheet">
<style>
</style>
</body>