有没有办法从 d3.js 偏移圆弧

问题描述 投票:0回答:1

我正在尝试创建一个环,这个环使用 d3.js,但我遇到了一个问题,当环或弧完成完整时,我想偏移一点,以便它看起来像是在自身之上。

这就是我想要实现的目标:

this is what i am trying to achieve

...这就是我得到的:

this is what i got。这是我的代码

this my js code: 

/* Define properties */
const width = 500;
const height = 500;
const margin = 40;
const circleStroke = 50;
const circleSpace = 2;
const radius = (width - margin) / 2;
const fullCircle = Math.PI * 2;

const configurations = [
    {color: 'hotpink',percentage:0.5}, 
    {color: 'limegreen',percentage:0.6}, 
    {color: 'turquoise',percentage:0.9}
                             ];
/* Add SVG inside <div id="activity"></div> */
const canvas = d3.select('#activity')
  .append('svg')
  .attr('width', width)
  .attr('height', height)

/* Chart configuration. */

filter = canvas.append("defs")
                .append("filter")
                .attr("id", "drop-shadow")
                .attr("height", "130%"); // Adjust this value to control the shadow spread

filter.append("feGaussianBlur")
      .attr("in", "SourceAlpha")
      .attr("stdDeviation", 5); // Adjust the stdDeviation value to control the blur intensity

filter.append("feOffset")
      .attr("dx", 0)
      .attr("dy", 5)
      .attr("result", "offsetblur");

var feMerge = filter.append("feMerge");

feMerge.append("feMergeNode");
feMerge.append("feMergeNode")
      .attr("in", "SourceGraphic");


const rings = canvas.append('g')
.attr('transform', `translate(${width / 2}, ${height / 2})`);

/* Chart configuration. */
arcs = [];
configurations.forEach((ring,index) =>{
    var arc = d3.arc()
    .innerRadius(radius - circleStroke * (index + 1) - circleSpace * index)
    .outerRadius(radius - circleStroke * index - circleSpace * index)
    .cornerRadius(50)
    .startAngle(0)
    .endAngle(fullCircle*ring.percentage);

    arcs.push(arc); // Store arc generators in the array

    rings.append("path")
    .attr("fill",ring.color)
    .attr("d",arc);

});

// Dynamically chaninging the the value of the rings

// Array of input elements
const inputElements = [
    document.getElementById("ring1"),
    document.getElementById("ring2"),
    document.getElementById("ring3")
];

inputElements.forEach((inputElement,index)=>{
    inputElement.addEventListener("input",()=>{
        var ringPercentage = +(inputElement.value/100);
        arcs[index].endAngle(fullCircle * ringPercentage); // Update the end angle of the first arc
        console.log(ringPercentage);
        rings.select(`path:nth-child(${index + 1})`)
        .attr("fill",configurations[index].color)
        .style("filter", "url(#drop-shadow)")
        .attr("d", arcs[index]);


      

        // console.log(arcs[index].endAngle());
        if(ringPercentage==1){
            // create and append a new path to the ring
            rings.append("path");
        }

        if(ringPercentage>1){
            // create a new arc 
            var arc_new = d3.arc()
                    .innerRadius(radius - circleStroke * (index + 1) - circleSpace * index)
                    .outerRadius(radius - circleStroke * index - circleSpace * index)
                    .cornerRadius(50)
                    .startAngle(0)
                    .endAngle(fullCircle*(ringPercentage-1));

                    // get only needed path by 1 ring => 4, 2 ring=> 5,3 ring 6

            switch (inputElement.id) {
                case "ring1":
                    rings.select(`path:nth-child(4)`)
                         .attr("fill",configurations[index].color)
                         .attr("d", arc_new)
                         .style("filter", "url(#drop-shadow)");
                    break;
            
                case "ring2":
                    rings.select(`path:nth-child(5)`)
                    .attr("fill",configurations[index].color)
                    .attr("d", arc_new)
                    .style("filter", "url(#drop-shadow)");
                    break;

                case "ring3":
                    rings.select(`path:nth-child(6)`)
                    .attr("fill",configurations[index].color)
                    .attr("d", arc_new)
                    .style("filter", "url(#drop-shadow)");

                     break;
            }
            
            
        }
    
    })
})


// Define the shadow filter
// Define the filter for the shadow effect

and the my html code:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Ring v2</title>
    <script src="https://d3js.org/d3.v7.min.js"></script>
</head>
<body>
    <div>
        <label for="ring1">Ring 1:</label>
        <input type="range" id="ring1" class="ring-range" min="0" max="150" step="1" value="70" />
    </div>
    <div>
        <label for="ring2">Ring 2:</label>
        <input type="range" id="ring2" class="ring-range" min="0" max="100" step="1" value="90" />
    </div>
    <div>
        <label for="ring3">Ring 3:</label>
        <input type="range" id="ring3" class="ring-range" min="0" max="150" step="1" value="40" />
    </div>
    <div id="activity"></div>
    <script src="test.js"></script>
</html>  

我的想法是创建一个单独的弧线,它将超越旧的弧线,但遵循相同的路径,但我的新弧线的开始并未与前一个弧线合并

javascript html d3.js
1个回答
0
投票

这是一个尝试:

const drawCircle = (container, fullAngle, radius, width, startRGB, endRGB) => {
 const delta = 0.01;
 const steps = fullAngle / delta;
 
 for (let step = 0; step <= steps; step++) {
    const angle = step * delta;
    const x = radius * Math.sin(angle);
    const y = radius * -Math.cos(angle);
  const r = Math.floor((endRGB[0] - startRGB[0]) / steps * step) + startRGB[0];
  const g = Math.floor((endRGB[1] - startRGB[1]) / steps * step) + startRGB[1];
  const b = Math.floor((endRGB[2] - startRGB[2]) / steps * step) + startRGB[2];
  const color = `rgb(${r},${g},${b})`;
  container.append('circle')
    .attr('cx', x)
    .attr('cy', y)
    .attr('r', width / 2)
    .attr('stroke', 'none')
    .attr('fill', color);
 }
}

drawCircle(d3.select('#first'), Math.PI * 2 / 3, 80, 30, [0, 64, 192], [255, 64, 64]);
  
drawCircle(d3.select('#second'), Math.PI * 4 / 3, 80, 30, [255, 32, 32], [32, 192, 255]);

drawCircle(d3.select('#third'), Math.PI * 2, 80, 30, [32, 192, 32], [32, 32, 255]);

 
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<svg width='600' height='200'>
  <g id='first' transform='translate(100,100)'>
  </g>
  <g id='second' transform='translate(300,100)'>
  </g>
  <g id='third' transform='translate(500,100)'>
  </g>
</svg>

© www.soinside.com 2019 - 2024. All rights reserved.