gpt4 book ai didi

javascript - 具有不同环/弧的正值和负值的特殊 donut chart

转载 作者:太空狗 更新时间:2023-10-29 13:51:02 26 4
gpt4 key购买 nike

我正在尝试在 D3 中创建一种特殊的圆环图,它将包含不同的正值和负值圆环。这些值可以大于 100% 或小于 -100%,因此将有一个圆弧表示剩余值。以下是图表的示例图像:enter image description here

第一个正类别(Category_1 - 灰色)值为 80,因此 80% 用灰色填充圆圈,为下一个正类别留下 20%。下一个正类别值(Category_2 - 橙色)是 160。因此它首先使用 Category_1 剩余的 20%(现在剩余 140 个值)。然后它填充下一个圆(向上)100%(现在还剩 40 个值),对于剩余的值 (40),它向上创建部分圆。

现在,我们将 Category_3(深红色)设置为负值 (-120%),因此如果创建一个向内的圆并填充它 100%(现在还剩 20 个值),然后它会创建一个向内的圆弧以剩余值 (20)。我们有另一个负类别(Category_4 - 红色),因此它将从前一个负类别 (Category_3) 结束的位置开始,并从那里填充 20% 的区域。

编辑 3:我创建了一个非常基本的基于圆弧的圆环图,当总值超过 100 时,我可以为剩余值创建外环。以下是 JSFiddle 链接:

http://jsfiddle.net/rishabh1990/zmuqze80/

data = [20, 240];

var startAngle = 0;
var previousData = 0;
var exceedingData;
var cumulativeData = 0;
var remainder = 100;
var innerRadius = 60;
var outerRadius = 40;
var filledFlag;

var arc = d3.svg.arc()
.innerRadius(innerRadius)
.outerRadius(outerRadius)

for (var i = 0; i < data.length; i++) {

filledFlag = 0;
exceedingData = 0;

console.log("---------- Iteration: " + (i + 1) + "---------");

if (data[i] > remainder) {
filledFlag = 1;
exceedingData = data[i] - remainder;
console.log("Exceeding: " + exceedingData);
data[i] = data[i] - exceedingData;
data.splice(i + 1, 0, exceedingData);
}

if( filledFlag === 1) {
cumulativeData = 0;
} else {
cumulativeData += data[i];
}

console.log("Previous: " + previousData);
console.log("Data: " + data, "Current Data: " + data[i]);
var endAngle = (previousData + (data[i] / 50)) * Math.PI;
console.log("Start " + startAngle, "End " + endAngle);
previousData = previousData + data[i] / 50;

//if(i===1) endAngle = 1.4 * Math.PI;
//if(i===2) endAngle = 2 * Math.PI;

var vis = d3.select("#svg_donut");

arc.startAngle(startAngle).endAngle(endAngle);


vis.append("path")
.attr("d", arc)
.attr("transform", "translate(200,200)")
.style("fill", function(d) {
if (i === 0) return "red";
//if (i === 1) return "green";
//if (i === 2) return "blue"
//if (i === 3) return "orange"
//if (i === 4) return "yellow";
});

if (exceedingData > 0) {
console.log("Increasing Radius From " + outerRadius + " To " + (outerRadius + 40));
outerRadius = outerRadius + 22;
innerRadius = innerRadius + 22;
arc.innerRadius(innerRadius).outerRadius(outerRadius);
console.log("Outer: ", outerRadius);
}

if (remainder === 100) {
remainder = 100 - data[i];
} else {
remainder = 100 - cumulativeData;
};

if (filledFlag === 1) {
remainder = 100;
}

console.log("Remainder: " + remainder);

startAngle = endAngle;

}

请分享一些实现的想法。

最佳答案

好的,这需要一些时间,但它似乎有效。首先,让我们确定您所描述的圆环图也可以呈现为一系列条形图——使用完全相同的数据。所以我从那里开始,最终将它制作成圆环图,但也将条形图的实现留在了那里。另一件事是,通用解决方案应该能够以任何值换行段,而不仅仅是 100,因此我包含了一个 slider ,可以让您改变换行值。最后 - 这在条形图而不是 donut 实现中更容易解释 - 而不是总是让条形图像文本一样从左到右换行,可能需要锯齿形,即交替从左到右换行然后从右换行 -向左等等。这样做的效果是,当一个金额在两条单独的线上分成两段时,之字形方法将使这两个段彼此相邻。我添加了一个复选框来打开/关闭此之字形行为。

这是一个 working jsFiddle another iteration

这里是重要的部分:

有一个函数 wrap(data, wrapLength),它接受一组 data 值和一个 wrapLength 来包装这些值。该函数计算出哪些数据值必须被拆分成子段并返回一个新的数组,每个段的对象都有 x1x2 y 值。 x1x2 是每个柱的开始和结束,y 是柱的行。在圆环图中,这些值等效于每个弧的起始 Angular (x1)、结束 Angular (x2) 和半径 (y)。

函数 wrap() 不知道如何计算负值和正值,所以 wrap() 必须调用两次 — 一次包含所有负值然后是所有的优点。从那里开始,一些处理被选择性地仅应用于底片,然后更多的处理被应用于两组的组合。最后两段中描述的整组转换由以下代码片段捕获。我在这里不包括 wrap() 的实现,只是调用它的代码;也不包括渲染代码,一旦 segments 生成,这就非常简单了。

// Turn N data points into N + x segments, as dictated by wrapLength. Do this separately
// for positive and negative values. They'll be merged further down, after we apply
// a specific transformation to just the negatives
var positiveSegments = wrap(data.filter(function(d) { return d.value > 0; }), wrapLength);
var negativeSegments = wrap(data.filter(function(d) { return d.value < 0; }), wrapLength);

// Flip and offset-by-one the y-value of every negative segment. I.e. 0 becomes -1, 1 becomes -2
negativeSegments.forEach(function(segment) { segment.y = -(segment.y + 1); });

// Flip the order of the negative segments, so that their sorted from negative-most y-value and up
negativeSegments.reverse()

// Combine negative and positive segments
segments = negativeSegments.concat(positiveSegments);

if(zigzag) {
segments.forEach(function(segment) {
if(Math.abs(segment.y) % 2 == (segment.y < 0 ? 0 : 1)) { flipSegment(segment, wrapLength); }
});
}

// Offset the y of every segment (negative or positive) so that the minimum y is 0
// and goes up from there
var maxNegativeY = negativeSegments[0].y * -1;
segments.forEach(function(segment) { segment.y += maxNegativeY; });

关于javascript - 具有不同环/弧的正值和负值的特殊 donut chart ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37882720/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com