gpt4 book ai didi

javascript - 从 JSON 返回值,而不是子项计数

转载 作者:行者123 更新时间:2023-11-29 18:56:17 26 4
gpt4 key购买 nike

我不想打印 flare.json 中特定节点的子节点数,而是打印 flare.json 中子节点的实际值。将鼠标悬停在父节点(带有子节点)上时,我想要打印所有子节点(和子子节点,...)值的总和。

有类似的问题(不是特定的d3)建议递归函数。但是到目前为止,所有代码片段都没有帮助我。 d3 是否附带了一些功能来实现这种行为?

var width = 300,
height = 300,
radius = Math.min(width, height) / 2,
color = d3.scale.category20c();

var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + width / 2 + "," + height * .50 + ")");

var partition = d3.layout.partition()
.sort(null)
.size([2 * Math.PI, radius * radius])
.value(function(d) { return 1; });

var arc = d3.svg.arc()
.startAngle(function(d) { return d.x; })
.endAngle(function(d) { return d.x + d.dx; })
.innerRadius(function(d) { return Math.sqrt(d.y); })
.outerRadius(function(d) { return Math.sqrt(d.y + d.dy); });


d3.json("https://raw.githubusercontent.com/d3/d3-hierarchy/master/test/data/flare.json", function(error, root) {

if (error) throw error;

var data = root;

var path = svg.datum(root).selectAll("path")
.data(partition.nodes)
.enter()
.append("path")
.attr("display", function(d) { return d.depth ? null : "none"; }) // hide inner ring
.attr("d", arc)
.style("stroke", "#fff")
.style("fill-rule", "evenodd")
.style("fill", howToFill)
.each(stash)
.on("mouseover", onMouseOver)
.on("mouseout", onMouseOut);


var value = function(d) { return d.value; };
});

function stash(d) {
d.x0 = d.x;
d.dx0 = d.dx;
}

function arcTween(a) {
var i = d3.interpolate({x: a.x0, dx: a.dx0}, a);
return function(t) {
var b = i(t);
a.x0 = b.x;
a.dx0 = b.dx;
return arc(b);
};
}

function howToFill(d) {
if ( d.name == "-" ) {
return "#fff";
} else {
return color((d.children ? d : d.parent).name);
}
}

// Mouseover

function onMouseOver(d) {
d3.select(this)
svg.append("text")
.style("text-anchor", "middle")
.text(function() { return d.name + " - " + d.value; });
}

function onMouseOut(d) {
d3.select(this)
svg
.select("text")
.remove();
}

d3.select(self.frameElement).style("height", height + "px");
<!DOCTYPE html>
<meta charset="utf-8">
<head>
<link rel="stylesheet" type="text/css" href="main.css">
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.17/d3.min.js"></script>
</head>
<body>
<script type="text/javascript" src="chart.js"></script>
</body>

最佳答案

这是显示实际计数的代码版本:

var width = 300,
height = 300,
radius = Math.min(width, height) / 2,
color = d3.scale.category20c();

var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + width / 2 + "," + height * .50 + ")");

var partition = d3.layout.partition()
.sort(null)
.size([2 * Math.PI, radius * radius])
.value(function(d) { return 1; });

var arc = d3.svg.arc()
.startAngle(function(d) { return d.x; })
.endAngle(function(d) { return d.x + d.dx; })
.innerRadius(function(d) { return Math.sqrt(d.y); })
.outerRadius(function(d) { return Math.sqrt(d.y + d.dy); });

d3.json("https://raw.githubusercontent.com/d3/d3-hierarchy/master/test/data/flare.json", function(error, root) {

if (error) throw error;

// Deep copy of the root object (for use by the mouseover function)
// since the d3 partitioning will modify root and only keep
// partitioning details:
var initialData = JSON.parse(JSON.stringify(root));

var data = root;

var path = svg.datum(root).selectAll("path")
.data(partition.nodes)
.enter()
.append("path")
.attr("display", function(d) { return d.depth ? null : "none"; }) // hide inner ring
.attr("d", arc)
.style("stroke", "#fff")
.style("fill-rule", "evenodd")
.style("fill", howToFill)
.each(stash)
.on("mouseover", onMouseOver)
.on("mouseout", onMouseOut);


var value = function(d) { return d.value; };

// Let's move the onMouseOver function inside the json extractor in order
// to easily work with "initialData":
function onMouseOver(d) {
d3.select(this)
svg.append("text")
.style("text-anchor", "middle")
//.text(function() { return d.name + " - " + d.value; });
.text(function() {
return d.name + " - " + sumValue(findElem(initialData, d.name, d.depth, 0));
});
}
});

function stash(d) {
d.x0 = d.x;
d.dx0 = d.dx;
}

function arcTween(a) {
var i = d3.interpolate({x: a.x0, dx: a.dx0}, a);
return function(t) {
var b = i(t);
a.x0 = b.x;
a.dx0 = b.dx;
return arc(b);
};
}

function howToFill(d) {
if ( d.name == "-" ) {
return "#fff";
} else {
return color((d.children ? d : d.parent).name);
}
}

function onMouseOut(d) {
d3.select(this)
svg
.select("text")
.remove();
}

d3.select(self.frameElement).style("height", height + "px");

function findElem(elmt, name, searchedDepth, currDepth) {
if (currDepth > searchedDepth)
return undefined
else if (elmt.name == name && searchedDepth == currDepth) {
return elmt;
}
else if (elmt.children) {
var result = elmt.children.map(c => findElem(c, name, searchedDepth, currDepth + 1)).filter(x => x);
return result.length == 1 ? result[0] : undefined;
}
else
return undefined;
}

function sumValue(elmt) {
try {
if (elmt.children)
return elmt.children.map(c => sumValue(c)).reduce((a, b) => a + b, 0);
else
return elmt.value;
} catch(err) {
// The try catch is there to hide the exception due to the "data"
// value which is not supported. Not sure how to cleanly fix this
// corner case:
return "error";
}
}
<meta charset="utf-8">
<head>
<link rel="stylesheet" type="text/css" href="main.css">
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.17/d3.min.js"></script>
</head>
<body>
<script type="text/javascript" src="chart.js"></script>
</body>


在鼠标悬停期间,让我们首先找回悬停的实际数据元素。问题是,d3 布局分区从模型中删除了数据信息......所以这就是为什么我们需要返回原始数据以找到有问题的节点:

function findElem(elmt, name, searchedDepth, currDepth) {
if (currDepth > searchedDepth)
return undefined
else if (elmt.name == name && searchedDepth == currDepth) {
return elmt;
}
else if (elmt.children) {
var result = elmt.children.map(c => findElem(c, name, searchedDepth, currDepth + 1)).filter(x => x);
return result.length == 1 ? result[0] : undefined;
}
else
return undefined;
}

以这种方式从鼠标悬停函数调用:

.text( function() {
return d.name + " - " + sumValue(findElem(initialData, d.name, d.depth, 0));
});

其中 initialDatajson 的深拷贝(否则,由于提取的 json root 被分区修改,我们将丢失原始数据信息)。

注意 depth 的用法,以处理不同节点可以具有相同标签的事实(例如,有多个节点位于不同的深度,名为“data”)。


一旦我们有了相关节点,我们就可以通过这种方式递归地对所有子值求和:

function sumValue(elmt) {
if (elmt.children)
return elmt.children.map(c => sumValue(c)).reduce((a, b) => a + b, 0);
else
return elmt.value;
}

关于javascript - 从 JSON 返回值,而不是子项计数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49304491/

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