Asynchronous 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创建的变量嵌套:

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建议是一个单独的建议吗?