JSFiddle - React, Tailwind, and code Playground
by fxi
HTML
<script src="https://d3js.org/d3.v4.min.js"></script>
<script src="https://cdn.rawgit.com/edeno/d3-save-svg/gh-pages/assets/d3-save-svg.min.js"></script>
<h1>Mapx roles</h1>
<div id="rolesRadial"></div>
<button id="export">export svg</button>
CSS
/**
https://evenbettermotherfucking.website/
**/
body {
margin: 5% auto;
background: #f2f2f2;
color: #444444;
font-family: -apple-system, BlinkMacSystemFont, “Segoe UI”, Roboto, Helvetica, Arial, sans-serif;
font-size: 16px;
line-height: 1.8;
text-shadow: 0 1px 0 #ffffff;
max-width: 73%;
}
code {
background: white;
}
a {
border-bottom: 1px solid #444444;
color: #444444;
text-decoration: none;
}
a:hover {
border-bottom: 0;
}
#rolesRadial {
outline: 1px solid #444444;
}
.node circle {
fill: #999;
}
.node text {
font: 9px sans-serif;
}
.node--internal circle {
fill: #555;
}
.node--internal text {
text-shadow: 0 1px 0 #fff, 0 -1px 0 #fff, 1px 0 0 #fff, -1px 0 0 #fff;
}
.link {
fill: none;
stroke: #555;
stroke-opacity: 0.2;
stroke-width: 1px;
}
.svg-container {
display: inline-block;
position: relative;
width: 100%;
padding-bottom: 100%;
/* aspect ratio */
vertical-align: top;
overflow: hidden;
}
.svg-content-responsive {
display: inline-block;
position: absolute;
top: 0;
left: 0;
}
JavaScript
/*
* Build mapx roles hierarchy
*/
var target = [
"superuser",
"admin",
"dev",
"publisher",
"user",
"public",
"self",
"none"
];
var roles = {
superuser: {
read: [0, 1, 2, 3, 4, 5, 6],
edit: [0, 1, 2, 3, 4, 5, 6],
publish: [0, 1, 2, 3, 4, 5, 6]
},
admin: {
read: [1, 2, 3, 4, 5, 6],
edit: [1, 2, 3, 4, 5, 6],
publish: [1, 2, 3, 4, 5, 6]
},
dev: {
read: [2, 3, 4, 5, 6],
edit: [2, 3, 4, 5, 6],
publish: [2, 3, 4, 5, 6]
},
publisher: {
read: [3, 4, 5, 6],
edit: [3, 4, 5, 6],
publish: [3, 4, 5, 6]
},
user: {
read: [4, 5, 6],
edit: [6],
publish: [3, 6]
},
public: {
read: [5],
edit: [7],
publish: [7]
}
};
var elContainer = d3.select("div#rolesRadial");
var width = 500;
var height = 500;
elContainer
.append("div")
.classed("svg-container", true)
.append("svg")
.attr("preserveAspectRatio", "xMinYMin meet")
.attr("viewBox", "0 0 " + width + " " + height)
.classed("svg-content-responsive", true);
var elSvg = d3.select("svg");
var g = elSvg
.append("g")
.attr(
"transform",
"translate(" +
(width / 2) + "," +
(height / 2) + ")"
);
var tree = d3.tree()
.size([2 * Math.PI, Math.min(width, height) / 2.7])
.separation(function(a, b) {
return (a.parent == b.parent ? 2 : 6) / a.depth;
});
var data = toHierarchy();
var root = tree(data);
var link = g.selectAll(".link")
.data(root.links())
.enter().append("path")
.attr("class", "link")
.attr("d", d3.linkRadial()
.angle(function(d) {
return d.x ;
})
.radius(function(d) {
return d.y ;
}));
var node = g.selectAll(".node")
.data(root.descendants())
.enter().append("g")
.attr("class", function(d) {
return "node" + (d.children ? " node--internal" : " node--leaf");
})
.attr("transform", function(d) {
return "translate(" + radialPoint(d.x, d.y) + ")";
});
node.append("circle")
.attr("r", 1.5);
node.append("text")
...