It’s me again with my “Wheel of life” thing. But since last time i’ve got many steps further. I actually arrived at the final step, adding text in sections.
Here is the code I have so far (open in full screen):
d3.select('#step').on('click',function(){ sections = document.getElementById("sections").value; deuxiemeEtape(sections); }); function deuxiemeEtape(sections){ var form=d3.select("#form2") form.append('hr'); form.append('p') .html('Titres des petites sections') .style('text-decoration','underline') for (i=1;i<parseInt(sections)+1;i++){ form.append('label') .html("Nom de la petite section "+i); form.append('input') .attr('type','text') .attr('id','ps'+i); } form.append('hr'); form.append('p') .html('Titres des sections') .style('text-decoration','underline'); for (i=1;i<(parseInt(sections)+2)/2;i++){ form.append('label') .html("Nom de la section "+i); form.append('input') .attr('type','text') .attr('id','gs'+i); } d3.select("#circles").attr('disabled',''); d3.select("#sections").attr('disabled',''); d3.select("#step").attr('disabled',''); form.append('button') .attr("id","create") .html("Créer") .on('click', onClickButton); form.append('button') .attr("id","reset") .html("Reset") .on('click',reloadPage); } function reloadPage(){ window.location.reload(); } const createSvg = (circles, sections) => { const svg = d3.select('#canvas'); const width = parseInt(svg.attr('width')); const height = parseInt(svg.attr('height')); svg.selectAll('g').remove(); const g = svg.append('g') .attr('transform', `translate(${width / 2},${height / 2})`); let i; for (i = parseInt(circles)+1; i >= 0; i--) { if (i==circles){ g.append('circle') .attr('r', 40 + i * 30) .style('fill', 'blue') .style('stroke', 'black'); }else if (i==parseInt(circles)+1){ g.append('circle') .attr('r', 40 + i * 30) .style('fill', 'red') .style('stroke', 'black'); } else { g.append('circle') .attr('r', 40 + i * 30) .style('fill', 'white') .style('stroke', 'black'); } } const angle = Math.PI * 2 / sections; let points = ""; for (i = 0; i <= sections; i++) { if(i%2==0){ //Regular sections radius = (circles) * 30 + 70; } else { //Small sections radius = (circles-1) * 30 + 70; } const x = radius * Math.sin(angle * i); const y = radius * -Math.cos(angle * i); g.append('line') .attr('x1', 0) .attr('y1', 0) .attr('x2', x) .attr('y2', y) .style('stroke', 'black'); points += ` ${x},${y}`; } // Don't mind this, it's WIP function onPolygonClick () { const x = d3.event.layerX - width / 2; const y = d3.event.layerY - height / 2; const radius = Math.hypot(x, y); let clickAngle = Math.atan2(x, -y); if (clickAngle < 0){ clickAngle = Math.PI * 2 + clickAngle; } const circle = Math.abs(Math.ceil((radius - 40) / 30)); const sector = Math.floor(clickAngle / angle) alert("Cliqué sur cercle "+circle+" / secteur "+sector+""); } // Don't mind this, it's WIP g.append('polygon') .attr('points', points) .style('fill', 'white') .style('stroke', 'black') .style('fill-opacity', 0.01) .style('cursor', 'pointer') .style('display','none') .on('click', onPolygonClick); } function onClickButton () { const circles = d3.select('#circles').node().value; const sections = d3.select('#sections').node().value; createSvg(circles, sections); }
body{ margin:0; padding:0; background-color: rgb(78, 98, 112); } #formulaire,#form2{ width:9.3% } input{ border-radius: 3px; margin:1em 0; } svg{ border:3px black solid }
<!DOCTYPE html> <html lang="fr"> <head> <meta charset="utf-8"> <title>SVG</title> <link rel="stylesheet" type="text/css" href="style.css"> </head> <body> <div> <div id="contenu"> <div id="formulaire"> <label>Number of circles</label> <input type="number" min="1" id="circles" /> <br /> <label>Number of sections</label> <input type="number" min="1" id="sections" /> <button id="step">Suivant</button> </div> <div id="form2"> <!-- Insert inputs here --> </div> </div> <div> <svg id="canvas" height="750" width="1700"> </svg> </div> </div> <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script> <script src="script.js"></script> </body> </html>
So as you can see, the inputs to get the text are added below the previous one. I need to add the text of the small sections in the blue circle, and the regular sections in the red circles ! I can’t figure how to do this.
Here is an exemple of how it should look with the text :
Thank you for reading this ! And thank you for answering if you do !
Advertisement
Answer
I could achieve it to append text but not making text center aligned exactly.
d3.select('#step').on('click', function() { sections = document.getElementById("sections").value; deuxiemeEtape(sections); }); function deuxiemeEtape(sections) { var form = d3.select("#form2") form.append('hr'); form.append('p') .html('Titres des petites sections') .style('text-decoration', 'underline') for (i = 1; i < parseInt(sections) + 1; i++) { form.append('label') .html("Nom de la petite section " + i); form.append('input') .attr('class', 'sub-sections') .attr('type', 'text') .attr('id', 'ps' + i); } form.append('hr'); form.append('p') .html('Titres des sections') .style('text-decoration', 'underline'); for (i = 1; i < (parseInt(sections) + 2) / 2; i++) { form.append('label') .html("Nom de la section " + i); form.append('input') .attr('class', 'sections') .attr('type', 'text') .attr('id', 'gs' + i); } d3.select("#circles").attr('disabled', ''); d3.select("#sections").attr('disabled', ''); d3.select("#step").attr('disabled', ''); form.append('button') .attr("id", "create") .html("Créer") .on('click', onClickButton); form.append('button') .attr("id", "reset") .html("Reset") .on('click', reloadPage); } function reloadPage() { window.location.reload(); } const createSvg = (circles, sections) => { const svg = d3.select('#canvas'); const width = parseInt(svg.attr('width')); const height = parseInt(svg.attr('height')); svg.selectAll('g').remove(); const g = svg.append('g') .attr('transform', `translate(${width / 2},${height / 2})`); const archThickness = 30; const fullCircle = 2 * 3.14; //adding inner sections const arcSizeSmallSections = fullCircle / sections; const subSectionInputs = document.querySelectorAll('.sub-sections'); for (let i = 0; i < circles; i++) { for (let j = 0; j < sections; j++) { if (i + 1 === circles) { appendArcs(g, i, j, archThickness, arcSizeSmallSections, 'blue', subSectionInputs[j].value); } else { appendArcs(g, i, j, archThickness, arcSizeSmallSections, 'white', i + 1); } } } // adding outer sections const mergeSplits = Math.ceil(sections / 2); const arcSizeSections = fullCircle / sections; const sectionInputs = document.querySelectorAll('.sections'); const endAngle = 2 * arcSizeSections; for (let j = 0; j < mergeSplits; j++) { g.append("path") .attr("d", d3.arc() .innerRadius(circles * archThickness) .outerRadius((circles + 1) * archThickness) .startAngle(j * endAngle) .endAngle(((j + 1) * endAngle) > fullCircle ? fullCircle : (j + 1) * endAngle) ) .attr("id", () => 'section' + circles + j) .attr('stroke', 'black') .attr('fill', 'red'); g.append("text") .attr("class", "monthText") .attr("dy", 22) .append("textPath") .attr("startOffset", "22%") .style("text-anchor", "middle") .attr("xlink:href", () => "#section" + circles + j) .text(() => sectionInputs[j].value); } } function appendArcs(parent, i, j, archThickness, arcSize, color, text) { parent .append("path") .attr("d", d3.arc() .innerRadius(i * archThickness) .outerRadius((i + 1) * archThickness) .startAngle(j * arcSize) .endAngle((j + 1) * arcSize) ) .attr("id", () => 'section' + i + j) .attr('stroke', 'black') .attr('fill', color); if (text) { parent.append("text") .attr("class", "monthText") .attr("dy", 22) .style("text-anchor", "middle") .append("textPath") .attr("startOffset", "22%") .attr("xlink:href", () => "#section" + i + j) .text(() => text); } } function onClickButton() { const circles = d3.select('#circles').node().value; const sections = d3.select('#sections').node().value; createSvg(parseInt(circles), parseInt(sections)); }
body { margin: 0; padding: 0; background-color: rgb(78, 98, 112); } #formulaire, #form2 { width: 9.3% } input { border-radius: 3px; margin: 1em 0; } svg { border: 3px black solid } .monthText { fill: #161414; font-size: 22px; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script> <div> <div id="contenu"> <div id="formulaire"> <label>Number of circles</label> <input type="number" min="1" id="circles" /> <br /> <label>Number of sections</label> <input type="number" min="1" id="sections" /> <button id="step">Suivant</button> </div> <div id="form2"> <!-- Insert inputs here --> </div> </div> <div> <svg id="canvas" height="750" width="1700"> </svg> </div> </div>
Added support for dynamic sub sections.
d3.select('#step').on('click', function() { sections = document.getElementById("sections").value; deuxiemeEtape(sections); }); function deuxiemeEtape(sections) { var form = d3.select("#form2") form.append('hr'); form.append('p').html('Titres des sections').style('text-decoration', 'underline'); for (i = 1; i <= parseInt(sections); i++) { let ind = 0, row = i; const secGroup = form.append('div').attr('class', 'section'); const sec = secGroup.append('div').attr('class', 'section-info'); sec.append('label').html("Nom de la section " + i); sec.append('input').attr('type', 'text'); sec.append('button').attr('type', 'button').attr('class', 'ms-2').text('Add Sub section') .on('click', () => { const subSecGroup = subSections.append('div').attr('class', 'sub-section'); subSecGroup.append('label').html("Nom de la petite section " + row + ++ind); subSecGroup.append('input').attr('type', 'text'); subSecGroup.append('button').attr('type', 'button').attr('class', 'ms-2') .text('Remove').on('click', () => { subSecGroup.remove(); }) }); const subSections = secGroup.append('div').attr('class', 'ms-5 my-3 sub-sections'); const subSecGroup = subSections.append('div').attr('class', 'sub-section'); subSecGroup.append('label').html("Nom de la petite section " + i + 0); subSecGroup.append('input').attr('type', 'text'); } d3.select("#circles").attr('disabled', ''); d3.select("#sections").attr('disabled', ''); d3.select("#step").attr('disabled', ''); form.append('button') .attr("id", "create") .html("Créer") .on('click', onClickButton); form.append('button') .attr("id", "reset") .html("Reset") .on('click', reloadPage); } function reloadPage() { window.location.reload(); } const createSvg = (circles) => { const svg = d3.select('#canvas'); const width = parseInt(svg.attr('width')); const height = parseInt(svg.attr('height')); svg.selectAll('g').remove(); const g = svg.append('g') .attr('transform', `translate(${width / 2},${height / 2})`); const archThickness = 30; const fullCircle = 2 * 3.14; //adding inner sections const subSectionInputs = document.querySelectorAll('.sub-section input'); const arcSizeSmallSections = fullCircle / subSectionInputs.length; for (let i = 0; i < circles; i++) { for (let j = 0; j < subSectionInputs.length; j++) { if (i + 1 === circles) { appendArcs(g, i, j, archThickness, arcSizeSmallSections, 'blue', subSectionInputs[j].value); } else { appendArcs(g, i, j, archThickness, arcSizeSmallSections, 'white', i + 1); } } } // adding outer sections const sections = document.querySelectorAll('.section'); let prevAngle = 0; for (let j = 0; j < sections.length; j++) { const subSections = sections[j].querySelectorAll('.sub-section input'); const endAngle = prevAngle + (subSections.length * arcSizeSmallSections); const text = sections[j].querySelector('.section-info input').value; g.append("path") .attr("d", d3.arc() .innerRadius(circles * archThickness) .outerRadius((circles + 1) * archThickness) .startAngle(prevAngle) .endAngle(endAngle) ) .attr("id", () => 'section' + circles + j) .attr('stroke', 'black') .attr('fill', 'red'); g.append("text") .attr("class", "monthText") .attr("dy", 22) .append("textPath") .attr("startOffset", "22%") .style("text-anchor", "middle") .attr("xlink:href", () => "#section" + circles + j) .text(() => text); prevAngle = endAngle; } } function appendArcs(parent, i, j, archThickness, arcSize, color, text) { parent .append("path") .attr("d", d3.arc() .innerRadius(i * archThickness) .outerRadius((i + 1) * archThickness) .startAngle(j * arcSize) .endAngle((j + 1) * arcSize) ) .attr("id", () => 'section' + i + j) .attr('stroke', 'black') .attr('fill', color); if (text) { parent.append("text") .attr("class", "monthText") .attr("dy", 22) .style("text-anchor", "middle") .append("textPath") .attr("startOffset", "22%") .attr("xlink:href", () => "#section" + i + j) .text(() => text); } } function onClickButton() { const circles = d3.select('#circles').node().value; const sections = d3.select('#sections').node().value; createSvg(parseInt(circles), parseInt(sections)); }
body { margin: 0; padding: 0; background-color: rgb(78, 98, 112); } input { border-radius: 3px; margin: 1em 0; } svg { border: 3px black solid } .monthText { fill: #161414; font-size: 22px; }
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-eOJMYsd53ii+scO/bJGFsiCZc+5NDVN2yr8+0RDqr0Ql0h+rP48ckxlpbzKgwra6" crossorigin="anonymous"> <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script> <div class="container"> <div id="contenu" class="row"> <div id="formulaire" class="col-6"> <label>Number of circles</label> <input type="number" min="1" id="circles" /> </div> <div class="col-6"> <label>Number of sections</label> <input type="number" min="1" id="sections" /> </div> </div> <div class="row my-2"> <button type="button" class="btn btn-primary col-2 m-auto" id="step">Suivant</button> </div> <div id="form2"> <!-- Insert inputs here --> </div> <div> <svg id="canvas" height="750" width="1700"></svg> </div> </div>