I'm trying to re-create the following with HTML, JS & CSS:
My goal is to be able to replace the content in each of the circles with whatever I want, just like a table.
So far I've read the following post - Circular HTML table. This one has an answer but I wasn't able to get it working and it uses some CSS extension
After reading the code I tried to make my own implementation, and was able to get to this point:
with the following code: codepen.io
function createLayer(radius) {
let circleGraph = document.createElement("div");
circleGraph.classList.add("circlegraph");
circleGraph.style.width = `${radius}px`;
circleGraph.style.height = `${radius}px`;
for (let j = 0; j < 12; j++) {
let note = document.createElement("div");
note.classList.add("circle");
note.classList.add("center");
let content = document.createTextNode(`${j}`)
note.appendChild(content);
circleGraph.appendChild(note);
}
let circles = circleGraph.querySelectorAll( '.circle' )
let theta = 0, dtheta = Math.PI * 2 / circles.length
for( let i = 0; i < circles.length; ++i ){
let circle = circles[i]
theta += dtheta
circle.style.transform = `translate(-50%, -50%) rotate(${theta}rad) translate(${radius}px) `;
circle.style.transform += `rotate(${Math.PI/2}rad)`;
}
document.body.appendChild(circleGraph)
}
createLayer(100);
createLayer(150);
createLayer(200);
createLayer(250);
html, body {
margin: 0;
height: 100%;
}
.circlegraph {
margin: auto;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
.circlegraph .circle {
position: absolute;
top: 50%; left: 50%;
width: 50%;
height: 50px;
transform-origin: center;
border: 1px solid red;
/*border-radius: 50%;*/
}
.center{
display: flex;
justify-content: center;
align-items: center;
}
I'm looking to get some help making it match the original image. If you know of a better way of doing this rather than translating each element by hand I would love to see it.
Taking inspiration from @HoratioNullbuilt's comment I was able to make an extensible modification of the example they had linked:
http://blog.fofwebdesign.co.uk/16-circular-segment-pie-chart-menu-experimental
The reason why it needed to be extended was that the many of the values were hardcoded, for example you couldn't have different layers with different numbers of elements in them.
After the modification here is the result:
https://codepen.io/cuppajoeman/pen/oNGwxzQ
radial.js
let data = [
Array.from(Array(15).keys()).map(String),
Array.from(Array(13).keys()).map(String),
Array.from(Array(10).keys()).map(String),
Array.from(Array(7).keys()).map(String),
Array.from(Array(4).keys()).map(String),
]
function getRandomHTMLColor() {
var r = 255*Math.random()|0,
g = 255*Math.random()|0,
b = 255*Math.random()|0;
return 'rgb(' + r + ',' + g + ',' + b + ')';
}
function createPieMenu() {
let pieMenu = document.createElement("div");
pieMenu.id = "pie-menu"
pieMenu.classList.add("pie-outer");
let widthDelta = 100/data.length;
let widthPercentage = 100;
for (let i = 0; i < data.length; i ++) {
let dataItem = data[i];
let numSegments = dataItem.length;
let segmentAngle = (Math.PI * 2)/numSegments;
let skewAngle = (Math.PI/2) - segmentAngle;
let pie = document.createElement("div");
let pieRotateAngle = (Math.PI/2) - segmentAngle/2;
pie.classList.add("pie");
console.log(widthPercentage);
pie.style.width = `${widthPercentage}%`;
pie.style.background = getRandomHTMLColor();
pie.style.transform = `translate(-50%,-50%) rotate(${pieRotateAngle}rad)`;
let pieList = document.createElement("ul");
for (let j = 0; j < dataItem.length; j ++) {
let rotationAngle = segmentAngle * j;
let dataContent = dataItem[j];
let pieListItem = document.createElement('li'); // create a new list item
let pieItemAnchor = document.createElement('a'); // create a new list item
pieListItem.style.transform = `rotate(${rotationAngle}rad) skew(${skewAngle}rad)`;
pieItemAnchor.appendChild(document.createTextNode(dataContent)); // append the text to the li
let anchorRotate = segmentAngle/2 - Math.PI/2;
let anchorSkew = segmentAngle - Math.PI/2;
pieItemAnchor.style.transform = `skew(${anchorSkew}rad) rotate(${anchorRotate}rad)`;
pieListItem.appendChild(pieItemAnchor);
pieList.appendChild(pieListItem)
}
pie.appendChild(pieList);
pieMenu.appendChild(pie);
widthPercentage -= widthDelta;
}
document.body.appendChild(pieMenu);
}
createPieMenu();
radial.css
html, body {
margin:0;
padding:0;
font:1em/1.75 Verdana, Arial, Helvetica, sans-serif;
-ms-text-size-adjust:100%;
-webkit-text-size-adjust:100%
}
.pie-outer *, .pie-outer {
padding:0;
margin:0
}
.pie-outer {
position:relative;
padding-top:100%;
margin:auto
}
.pie {
pointer-events:none;
position:absolute;
top:50%;
left:50%;
overflow:hidden;
border:2px solid #000;
border-radius:50%;
}
.pie ul {
list-style-type:none
}
.pie ul:after {
content:" ";
display:block;
width:100%;
padding-top:100%
}
.pie li {
position:absolute;
top:-50%;
left:-50%;
width:100%;
height:100%;
margin-left:-2px;
margin-top:-2px;
overflow:hidden;
border:1px solid #000;
-webkit-transform-origin:100% 100%;
-ms-transform-origin:100% 100%;
transform-origin:100% 100%
}
.pie a {
pointer-events:auto;
font-size:2.125vw;
/*line-height:170%;*/
display:block;
position:absolute;
top:50%;
left:50%;
width:100%;
height:100%;
text-decoration:none;
text-align:center;
color:#fff;
-webkit-tap-highlight-color:rgba(0,0,0,0);
}
.pie a:hover {
background:rgba(255,255,255,0.25)
}
@media ( min-width:42em ) {
/* #### - > 672px - #### */
.pie-outer {
padding-top:0;
width:40em;
height:40em
}
.pie a {
font-size:1em
}
}
radial.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Circular Menu</title>
<link rel="stylesheet" href="radial.css">
</head>
<body>
<script src="radial.js"></script>
</body>
</html>
Some notes:
The above code doesn't work when there your data list contains a list of size two, but I haven't gone into why that might happen (probably some edge case work for sizes 1 and 2).
The mouse hover effect has a slight bug which is that if you hover on the crack between two adjacent sections, it will highlight the next layer outward (only seems to happen if the next layer outward has a different number of cells).
The location of the text in the cells is not perfect, the problem is something to do with the line-height (which I commented out), modifications to fix the text position are welcome.