D3:Noobie,试图建立一个传奇,不确定为什么它不起作用

时间:2018-04-04 21:52:03

标签: javascript d3.js

我正在显示基于年和月的温度图。我想在图表底部显示一个图例,以显示每种颜色对应的温度。有人可以帮我理解如何做到这一点以及我做错了什么?

以下是此特定部分的代码:

svg.selectAll("rect")
      .data(colors)
      .enter()
      .append("rect")
      .attr("x", (d, i) => {
      return 300 + i*legendWidth})
      .attr("y", h - 50)
      .attr("width", legendWidth)
      .attr("height", legendHeight)
      .attr("fill", (d, i) => colors[i])
      .attr("fill-opacity", "0.5");

预期产量: enter image description here

目前获得: enter image description here

这是一个Codepen:https://codepen.io/lieberscott/pen/dmjJWg?editors=0110

Full JS:

document.addEventListener("DOMContentLoaded",function(){
  req=new XMLHttpRequest();
  req.open("GET","https://raw.githubusercontent.com/FreeCodeCamp/ProjectReferenceData/master/global-temperature.json", true);
  req.send();
  req.onload=function(){
    const dataset=JSON.parse(req.responseText);
    const data = dataset.monthlyVariance;
    const w = 1000;
    const h = 600;
    const padding = 92;
    const boxWidth = Math.ceil(w / (data.length / 12)); // width / number of years
    const boxHeight = Math.floor((h - padding - padding) / 12) + 4; // height / 12
    // need +4 above because 1753 months != 2015 months
    const months = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
    const colors = ["#3910ed", "#3479f9", "#2fc0ed", "#36edba", "#e2fff7", "#fff1a5", "#d6bc2c", "#f9a86d", "#c17036", "#f26060", "#561212"];
    const legendWidth = 30;
    const legendHeight = 20;

    const svg = d3.select(".chart")
    .append("svg")
    .attr("width", w)
    .attr("height", h);

    const xScale = d3.scaleLinear()
    .domain([1753, 2015])
    .range([padding, w - padding]);

    const yScale = d3.scaleLinear()
    .domain([1, 12])
    .range([padding, h - padding]);

    let tooltip = d3.select("body")
    .append("div")
    .attr("class", "tooltip");      

    svg.selectAll("rect")
      .data(data)
      .enter()
      .append("rect")
      .attr("x", (d, i) => xScale(d.year))
      .attr("y", (d, i) => yScale(d.month - 1))
      .attr("width", boxWidth)
      .attr("height", boxHeight)
      .attr("fill", (d) => 8.66 + d.variance < 3 ? colors[0] : 8.66 + d.variance < 4 ? colors[1] : 8.66 + d.variance < 5 ? colors[2] : 8.66 + d.variance < 6 ? colors[3] : 8.66 + d.variance < 7 ? colors[4] : 8.66 + d.variance < 8 ? colors[5] : 8.66 + d.variance < 9 ? colors[6] : 8.66 + d.variance < 10 ?  colors[7] : 8.66 + d.variance < 11 ? colors[8] : 8.66 + d.variance < 12 ? colors[9] : colors[10])
      .attr("fill-opacity", "0.5")
      .on("mousemove", (d) => {
        tooltip
          .style("left", d3.event.pageX - 50 +"px")
          .style("top", d3.event.pageY - 70 + "px")
          .style("display", "inline-block")
          .html("<span>" + d.year + " &#8212; " + months[d.month-1] + "<br/>" + Math.round((8.33 + d.variance)*100)/100 + " ℃<br/>" + d.variance + " ℃</span>")
       })
        .on("mouseout", (d) => {
          tooltip
            .style("display", "none");
        });

    svg.selectAll("rect")
      .data(colors)
      .enter()
      .append("rect")
      .attr("x", (d, i) => {
      return 300 + i*legendWidth})
      .attr("y", h - 50)
      .attr("width", legendWidth)
      .attr("height", legendHeight)
      .attr("fill", (d, i) => colors[i])
      .attr("fill-opacity", "0.5");


    svg.selectAll("text")
      .data(months)
      .enter()
      .append("text")
      .text((month) => month)
      .attr("x", padding - 5)
      .attr("y", (month, i) => (padding + (i*boxHeight) - boxHeight / 3)) // divided by 3 instead of 2 b/c y attribute aligns by bottom of text and I want it to be centered
      .style("text-anchor", "end");

    const xAxis = d3.axisBottom(xScale);
    // .tickFormat(d3.timeFormat("%Y")); // so it's 2015, not 2,015

    svg.append("g")
      .attr("transform", "translate(0," + (h - padding) + ")")
      .call(xAxis);

    svg.append("text") // subhead
      .attr("x", w/2)
      .attr("y", 20)
      .attr("font-size", "25px")
      .style("text-anchor", "middle")
      .text("1753 - 2015");

    svg.append("text") // subhead
      .attr("x", w/2)
      .attr("y", 35)
      .attr("font-size", "12px")
      .style("text-anchor", "middle")
      .text("Temperatures are in Celsius and reported as anomalies relative to the Jan 1951-Dec 1980 average.");

    svg.append("text") // subhead
      .attr("x", w/2)
      .attr("y", 50)
      .attr("font-size", "12px")
      .style("text-anchor", "middle")
      .text("Estimated Jan 1951-Dec 1980 absolute temperature ℃: 8.66 +/- 0.07.");
    };
  });

1 个答案:

答案 0 :(得分:2)

出现问题的原因是您创建了图例:

svg.selectAll("rect")
  .data(colors)
  .enter()
  .append("rect")
  ...

第一行选择DOM中已有的矩形,即构成可视化/图表的矩形。

第二行更新此选择的数据。由于选择中的矩形多于数据数组中的颜色,因此无需输入,输入选择为空,因此不会附加任何内容。

由于您没有应用任何更新,并且您只是使用(空)输入选择来追加和设置图例样式,因此可视化中没有任何明显变化。

相反,您可以使用svg.selectAll(null)(或svg.selectAll()),这将创建一个空选择,以便为数据数组中的每个项目输入一个项目。这是一个更新的plunkr