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")
 ...