javascript - 使用 Javascript 将圆形文本插入 SVG 中的部分
问题描述
又是我的“生命之轮”。但自上次以来,我已经走了很多步。我实际上到达了最后一步,在部分中添加文本。
这是我到目前为止的代码(全屏打开):
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>
如您所见,获取文本的输入添加到前一个下方。我需要在蓝色圆圈中添加小部分的文本,在红色圆圈中添加常规部分!我不知道该怎么做。
谢谢您阅读此篇 !如果你这样做,谢谢你的回答!
解决方案
我可以实现它来附加文本,但不能使文本中心完全对齐。
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>
添加了对动态子部分的支持。
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>
推荐阅读
- sql - 如何将数据从一个表复制到不同数据库中的空表?
- shell - Shell 脚本要求用户从终端输入公司名称、雇员姓名、员工 ID 和员工能力,并显示输出
- vim - vimscript - 使用自动命令捕捉击键
- c++ - 如何重载运算符>>以输入类的向量值?
- assembly - ARm prfm 和 prfum 指令
- c# - 使用依赖注入 C# 在派生类和基类之间分离日志记录
- elasticsearch - Elasticsearch 字段折叠每个字段值返回 >1 个结果
- spring - 如何访问控制器中的 oauth2 不透明令牌
- java - 将Java时间戳转换为字符串?
- mysql - 选择列包含带有括号和引号的子字符串的位置