【问题标题】:Appending a Line between a start and end date在开始日期和结束日期之间添加一条线
【发布时间】:2019-08-01 19:36:40
【问题描述】:

基本上,我使用 D3 创建基于甘特图的图表。我有一个 .json 文件,其中包含我的数据,并且能够创建我的 x-y 比例尺以显示适当的信息。我遇到的这个问题是,我希望这些行在数组中 15 个项目的每个项目的开始日期和结束日期之间延伸,所有这些项目都包含名称、开始日期和结束日期。当我启动图表时,信息会显示,但它只显示一条从 y 轴开始的实线,并一直延伸到个人开始日期。

在尝试纠正这种情况时,我意识到通过将今天的日期作为新项目添加到 startDate 下的数组中,任何日期为今天的项目都完全按照我的意愿行事,而其他项目则不然。我不确定是什么原因造成的,但推测它可能与日期的解析方式有关?完全不知所措,因为我还是 d3 的新手。

// employment.json 
[
    {
      "name": "Placeholder 1",
      "position": "Occupation 1",
      "startDate": "2013-09-05",
      "endDate": "2019-08-01"
    },
    {
      "name": "Placeholder 2",
      "position": "Occupation 1",
      "startDate": "2013-09-05",
      "endDate": "2018-10-31"
    },
    {
      "name": "Placeholder 3",
      "position": "Occupation 1",
      "startDate": "2013-11-05",
      "endDate": "2014-03-03"
    },
    {
      "name": "Placeholder 4",
      "position": "Occupation 1",
      "startDate": "2014-05-09",
      "endDate": "2015-04-06"
    },
    {
      "name": "Placeholder 5",
      "position": "Occupation 1",
      "startDate": "2014-12-01",
      "endDate": "2019-08-01"
    },
    {
      "name": "Placeholder 6",
      "position": "Occupation 1",
      "startDate": "2015-04-20",
      "endDate": "2016-10-18"
    },
    {
      "name": "Placeholder 7",
      "position": "Occupation 1",
      "startDate": "2016-05-05",
      "endDate": "2019-07-31"
    },
    {
      "name": "Placeholder 8",
      "position": "Occupation 1",
      "startDate": "2016-11-07",
      "endDate": "2017-05-12"
    },
    {
      "name": "Placeholder 9",
      "position": "Occupation 1",
      "startDate": "2017-09-18",
      "endDate": "2019-08-01"
    },
    {
      "name": "Placeholder 10",
      "position": "Occupation 1",
      "startDate": "2018-01-11",
      "endDate": "2018-09-20"
    },
    {
      "name": "Placeholder 11",
      "position": "Occupation 1",
      "startDate": "2018-04-17",
      "endDate": "2018-07-24"
    },
    {
      "name": "Placeholder 12",
      "position": "Occupation 1",
      "startDate": "2018-07-04",
      "endDate": "2018-08-30"
    },
    {
      "name": "Placeholder 13",
      "position": "Occupation 1",
      "startDate": "2018-07-09",
      "endDate": "2019-08-01"
    },
    {
      "name": "Placeholder 14",
      "position": "Occupation 1",
      "startDate": "2019-01-16",
      "endDate": "2019-08-01"
    },
    {
      "name": "Placeholder 15",
      "position": "Occupation 1",
      "startDate": "2019-04-01",
      "endDate": "2019-08-01"
    },
    {
      "name": "Total Time",
      "position": "Occupation 1",
      "startDate": "2013-09-05",
      "endDate": "2019-08-01"
     }
  ]

// app.js

var margin = {top: 10, right: 30, bottom: 80, left: 100},
    width = 960 - margin.left - margin.right,
    height = 560 - margin.top - margin.bottom;

var svg = d3.select("#employment_history")
  .append("svg")
    .attr("width", width + margin.left + margin.right)
    .attr("height", height + margin.top + margin.bottom)
  .append("g")
    .attr("transform",
          "translate(" + margin.left + "," + margin.top + ")");

d3.json('json/employment.json', function(error, data) {
    if (error) {
      return console.warn(error);
    } else {
      console.log(data);
    }

    var x = d3.scaleBand()
        .range([0, width ])
        .domain(data.map(function(d) { return d.startDate }, 
data.map(function(d) { return d.endDate })))
        .padding(0.2);
    svg.append('g')
        .attr("transform", "translate(0," + height + ")")
        .call(d3.axisBottom(x))
        .selectAll("text")
        .attr("transform", "translate(-10,0)rotate(-45)")
        .style("text-anchor", "end");

    var y = d3.scaleBand()
        .range([ 0, height ])
        .domain(data.map(function(d) { return d.name; }))
        .padding(2);
      svg.append("g")
        .call(d3.axisLeft(y))

  // Lines
  svg.selectAll("myLine")
    .data(data)
    .enter()
    .append("line")
      .attr("x1", function(d) { return x(d.startDate); })
      .attr("x2", function(d) { return x(d.endDate); })
      .attr("y1", function(d) { return y(d.name); })
      .attr("y2", function(d) { return y(d.name); })
      .attr("stroke", "orange")
      .attr("stroke-width", "2px")
  })  

控制台中没有显示错误,它提供了一个从 Y 轴开始并延伸到开始日期的图表,而不是从开始日期开始并连接到结束日期。

我正在努力完成的一个示例以及我为创建它所遵循的示例如下:https://www.d3-graph-gallery.com/graph/lollipop_cleveland.html

【问题讨论】:

    标签: javascript d3.js charts gantt-chart


    【解决方案1】:

    你有错误的规模

    这里的主要问题是 x 轴,它应该使用 时间尺度,而不是波段尺度。那么,让我们看看必要的更改:

    首先,解析数据数组中的日期:

    const parse = d3.timeParse("%Y-%m-%d");
    
    data.forEach(function(d) {
      d.startDate = parse(d.startDate);
      d.endDate = parse(d.endDate);
    });
    

    然后,设置时间尺度,根据日期计算域:

    var x = d3.scaleTime()
      .range([0, width])
      .domain([d3.min(data, function(d) {
        return d.startDate
      }), d3.max(data, function(d) {
        return d.endDate
      })]);
    

    最后,你的 y 刻度应该是刻度,而不是带刻度:

    var y = d3.scalePoint()
      .range([0, height])
      .domain(data.map(function(d) {
        return d.name;
      }))
      .padding(0.5);
    

    这是工作代码(在较小的 SVG 中):

    const data = [{
        "name": "Placeholder 1",
        "position": "Occupation 1",
        "startDate": "2013-09-05",
        "endDate": "2019-08-01"
      },
      {
        "name": "Placeholder 2",
        "position": "Occupation 1",
        "startDate": "2013-09-05",
        "endDate": "2018-10-31"
      },
      {
        "name": "Placeholder 3",
        "position": "Occupation 1",
        "startDate": "2013-11-05",
        "endDate": "2014-03-03"
      },
      {
        "name": "Placeholder 4",
        "position": "Occupation 1",
        "startDate": "2014-05-09",
        "endDate": "2015-04-06"
      },
      {
        "name": "Placeholder 5",
        "position": "Occupation 1",
        "startDate": "2014-12-01",
        "endDate": "2019-08-01"
      },
      {
        "name": "Placeholder 6",
        "position": "Occupation 1",
        "startDate": "2015-04-20",
        "endDate": "2016-10-18"
      },
      {
        "name": "Placeholder 7",
        "position": "Occupation 1",
        "startDate": "2016-05-05",
        "endDate": "2019-07-31"
      },
      {
        "name": "Placeholder 8",
        "position": "Occupation 1",
        "startDate": "2016-11-07",
        "endDate": "2017-05-12"
      },
      {
        "name": "Placeholder 9",
        "position": "Occupation 1",
        "startDate": "2017-09-18",
        "endDate": "2019-08-01"
      },
      {
        "name": "Placeholder 10",
        "position": "Occupation 1",
        "startDate": "2018-01-11",
        "endDate": "2018-09-20"
      },
      {
        "name": "Placeholder 11",
        "position": "Occupation 1",
        "startDate": "2018-04-17",
        "endDate": "2018-07-24"
      },
      {
        "name": "Placeholder 12",
        "position": "Occupation 1",
        "startDate": "2018-07-04",
        "endDate": "2018-08-30"
      },
      {
        "name": "Placeholder 13",
        "position": "Occupation 1",
        "startDate": "2018-07-09",
        "endDate": "2019-08-01"
      },
      {
        "name": "Placeholder 14",
        "position": "Occupation 1",
        "startDate": "2019-01-16",
        "endDate": "2019-08-01"
      },
      {
        "name": "Placeholder 15",
        "position": "Occupation 1",
        "startDate": "2019-04-01",
        "endDate": "2019-08-01"
      },
      {
        "name": "Total Time",
        "position": "Occupation 1",
        "startDate": "2013-09-05",
        "endDate": "2019-08-01"
      }
    ];
    
    var margin = {
        top: 10,
        right: 30,
        bottom: 80,
        left: 100
      },
      width = 600 - margin.left - margin.right,
      height = 400 - margin.top - margin.bottom;
    
    var svg = d3.select("body")
      .append("svg")
      .attr("width", width + margin.left + margin.right)
      .attr("height", height + margin.top + margin.bottom)
      .append("g")
      .attr("transform",
        "translate(" + margin.left + "," + margin.top + ")");
    
    const parse = d3.timeParse("%Y-%m-%d");
    
    data.forEach(function(d) {
      d.startDate = parse(d.startDate);
      d.endDate = parse(d.endDate);
    });
    
    var x = d3.scaleTime()
      .range([0, width])
      .domain([d3.min(data, function(d) {
        return d.startDate
      }), d3.max(data, function(d) {
        return d.endDate
      })]);
    
    svg.append('g')
      .attr("transform", "translate(0," + height + ")")
      .call(d3.axisBottom(x))
      .selectAll("text")
      .attr("transform", "translate(-10,0)rotate(-45)")
      .style("text-anchor", "end");
    
    var y = d3.scalePoint()
      .range([0, height])
      .domain(data.map(function(d) {
        return d.name;
      }))
      .padding(0.5);
    
    svg.append("g")
      .call(d3.axisLeft(y))
    
    // Lines
    svg.selectAll("myLine")
      .data(data)
      .enter()
      .append("line")
      .attr("x1", function(d) {
        return x(d.startDate);
      })
      .attr("x2", function(d) {
        return x(d.endDate);
      })
      .attr("y1", function(d) {
        return y(d.name);
      })
      .attr("y2", function(d) {
        return y(d.name);
      })
      .attr("stroke", "orange")
      .attr("stroke-width", "2px")
    <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>

    【讨论】:

    • 您太棒了,非常感谢您提供如此深思熟虑的答案-我知道我的解释令人困惑,所以也感谢您解决这个问题!
    猜你喜欢
    • 1970-01-01
    • 2020-10-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多