Asynchronous d3.json异步解决方案
我有一个从d3.json创建的变量嵌套:Asynchronous d3.json异步解决方案,asynchronous,d3.js,Asynchronous,D3.js,我有一个从d3.json创建的变量嵌套: d3.json("api_all.php", function(data) { data.forEach(e => { e.date = parseDate(e.date); e.value = +e.close; e.stockName = e.stock_name; }); var nest = d3.nest() .key(function(d){ return d.stock
d3.json("api_all.php", function(data) {
data.forEach(e => {
e.date = parseDate(e.date);
e.value = +e.close;
e.stockName = e.stock_name;
});
var nest = d3.nest()
.key(function(d){
return d.stockName;
})
.entries(data);
但是,我有另一个函数,用于记录需要使用保存的嵌套数据的代码:
var initialgraph = function(stockName) {
/*Filter the data to include only stock of interest*/
var selectStock = nest.filter(function(d) {
return d.key == stockName;
})
var selectStockGroups = svg.selectAll(".stockGroups")
.data(selectStock, function(d) {
return d ? d.key : this.key;
})
.enter()
.append("g")
.attr("class", "stockGroups")
.each(function(d) {
y.domain([0, d3.max(data, function(d) { return d.value; })])
});
var initialPath = selectStockGroups.selectAll(".rect")
.data(function(d) {return d.value.year})
.enter()
.append("path")
initialPath
.attr("d", function(d) {
return valueLine(d.values)
})
.attr("class", "rect")
/*Add Y Axis*/
var yaxis = svg.append("g")
.attr("class", "y axis")
.call(d3.axisLeft(y))
};
我还没有找到这个问题的解决方案……我在考虑1)将nest变量作为全局变量,或2)将initialgraph函数作为d3.json数据提取的一部分
我还没有找到正确的方法来执行#1和#2似乎会给我的代码带来很多额外的问题。所以我的偏见就是找到一个解决办法。你有什么建议?谢谢。调用
初始图
,将嵌套
结果作为参数。只有在执行回调时,nest变量中才有有效值
var initialgraph = function (stockName, nest) {
// Filter the data to include only stock of interest
var selectStock = nest.filter(function(d) { return d.key == stockName; });
//....
};
d3.json("api_all.php", function(data) {
data.forEach(e => {
e.date = parseDate(e.date);
e.value = +e.close;
e.stockName = e.stock_name;
});
var nest = d3.nest()
.key(function (d) { return d.stockName; })
.entries(data);
var xExtent = d3.extent(data, function(d) { return d.date; });
x.domain(xExtent);
zoom.translateExtent([[x(xExtent[0]), -Infinity], [x(xExtent[1]), Infinity]])
y.domain([0, d3.max(data, function(d) { return d.value; })]);
yGroup.call(yAxis).select(".domain").remove();
areaPath.datum(data);
zoomRect.call(zoom.transform, d3.zoomIdentity);
/*Build Dropdown Menu*/
var stockDropDown = d3.select("#dropdown")
stockDropDown
.append("select")
.selectAll("option")
.data(nest)
.enter()
.append("option")
.attr("value", function(d){
return d.key;
})
.text(function(d){
return d.key;
});
initialgraph("KYOKUYO CO.,LTD.", nest);
});
如果在回调中定义了initialgraph
,则没有问题,因为它是一个闭包
编辑
就像今天关于异步函数的回答一样,当d3.json()
返回时,并不意味着回调被调用/完成。从第134行删除initialgraph()
调用。并在回调结束时调用它
编辑2
需要查找d3v4和json的示例,以查看d3.json()
的接口是什么。根据文件,它正在使用fetch和promises,但显然不是。真正的界面是
d3.json(url, function (error, data) {
// process the data
});
下面是至少显示基于json的初始图形的完整代码。我还没有验证它是否绘制了正确的图形
在each()
调用中调用y.domain()
没有意义。最大值已根据json数据确定。也许可以使用扩展的d.value
:d3.extend(数据,d=>d.value)代码>
updategraph()
现在获得一个有效的nest
值
var svg = d3.select("svg"),
margin = {top: 20, right: 20, bottom: 30, left: 60},
width = +svg.attr("width") - margin.left - margin.right,
height = +svg.attr("height") - margin.top - margin.bottom,
g = svg.append("g").attr("transform", "translate(" + margin.left + "," + margin.top + ")");
/*Define the rect*/
/*Parse dates*/
var parseDate = d3.timeParse("%Y-%m-%d"),
formatDate = d3.timeFormat("%Y");
/*Set the ranges*/
var x = d3.scaleTime()
.domain([new Date(2002, 0, 1), new Date(2003, 0, 1)])
.range([0, width]);
var y = d3.scaleLinear()
.range([height, 0]);
/*Create axes*/
var xAxis = d3.axisBottom(x);
var yAxis = d3.axisLeft(y);
var area = d3.area()
.curve(d3.curveStepAfter)
.y0(y(0))
.y1(function(d) { return y(d.value); });
var areaPath = g.append("path")
.attr("clip-path", "url(#clip)")
.attr("fill", "steelblue");
var yGroup = g.append("g");
var xGroup = g.append("g")
.attr("transform", "translate(0," + height + ")");
var zoom = d3.zoom()
.scaleExtent([1 / 4, 8])
.translateExtent([[-width, -Infinity], [2 * width, Infinity]])
.on("zoom", zoomed);
var zoomRect = svg.append("rect")
.attr("width", width)
.attr("height", height)
.attr("fill", "none")
.attr("pointer-events", "all")
.call(zoom);
g.append("clipPath")
.attr("id", "clip")
.append("rect")
.attr("width", width)
.attr("height", height);
/*Import Data from API*/
d3.json("api_all.php", function(error, data) {
data.forEach(e => {
e.date = parseDate(e.date);
e.value = +e.close;
e.stockName = e.stock_name;
});
var nest = d3.nest()
.key(function(d){
return d.stockName;
})
.entries(data);
/*Scale range of the data*/
var xExtent = d3.extent(data, function(d) { return d.date; });
x.domain(xExtent);
zoom.translateExtent([[x(xExtent[0]), -Infinity], [x(xExtent[1]), Infinity]])
y.domain([0, d3.max(data, function(d) { return d.value; })]);
yGroup.call(yAxis).select(".domain").remove();
areaPath.datum(data);
zoomRect.call(zoom.transform, d3.zoomIdentity);
/*Build Dropdown Menu*/
var stockDropDown = d3.select("#dropdown");
stockDropDown
.append("select")
.selectAll("option")
.data(nest)
.enter()
.append("option")
.attr("value", function(d){
return d.key;
})
.text(function(d){
return d.key;
});
stockDropDown.on("change", function() {
var selectedStock = d3.select(this)
.select("select")
.property("value");
updateGraph(selectedStock, nest);
});
initialgraph("KYOKUYO CO.,LTD.", nest);
});
/*Function to create initial graph*/
var initialgraph = function(stockName, nest) {
/*Filter the data to include only stock of interest*/
var selectStock = nest.filter(function(d) {
return d.key == stockName;
})
var selectStockGroups = svg.selectAll(".stockGroups")
.data(selectStock, function(d) {
return d ? d.key : this.key;
})
.enter()
.append("g")
.attr("class", "stockGroups")
// .each(function(d) {
// y.domain([0, d3.max(data, function(d) { return d.value; })]);
// })
;
var initialPath = selectStockGroups.selectAll(".rect")
.data(function(d) {return d.value.year})
.enter()
.append("path")
initialPath
.attr("d", function(d) {
return valueLine(d.values)
})
.attr("class", "rect")
/*Add Y Axis*/
var yaxis = svg.append("g")
.attr("class", "y axis")
.call(d3.axisLeft(y))
};
/*Create initial graph*/
//initialgraph("KYOKUYO CO.,LTD.");
/*Update the data*/
var updateGraph = function(stockName, nest) {
var selectStock = nest.filter(function(d) {
return d.key == stockName;
})
var selectStockGroups = svg.selectAll(".stockGroups")
.data(selectStock)
.each(function(d) {
y.domain([0, d3.max(data, function(d) { return d.value; })])
});
selectStockGroups.selectAll("path.rect")
.data(function(d) {return d.value.year;}, function(d) {return d.key})
.transition()
.duration(1000)
.attr("d", function(d) {
return valueLine(d.values)
})
}
/*Zoom function*/
function zoomed() {
var xz = d3.event.transform.rescaleX(x);
xGroup.call(xAxis.scale(xz));
areaPath.attr("d", area.x(function(d) { return xz(d.date); }));
}
我添加了回调,但我仍然得到未定义的nest,现在我也有未定义的stockName…@CharlesLee:没有完整的工作示例,我们必须猜测如何将零件连接在一起。我不知道你的代码是什么。@CharlesLee:对于可以存储伪json的数据,编辑了答案。JSFIDLE不服务于api_all.php
@CharlesLee:发现异步加载存在问题,它需要错误
参数。那么y.domain建议是一个单独的建议吗?