D3.js只有日期

时间:2016-10-18 09:08:21

标签: d3.js

这将是一个艰难的...

我正在努力与d3.js合作,为从事任务的人制作某种图表。

图表最终应该看起来像这样: enter image description here

这将是示例数据。

var data = [
    {
        'user':'John',
        'tasks': [
            {
                name: 'Task 1',
                start: '2016-10-01',
                end: '2016-10-04'  
            },
            {
                name: 'Task 5',
                start: '2016-10-13',
                end: '2016-10-14'  
            }

        ]
    },
    {
        'user':'Mikael',
        'tasks': [
            {
                name: 'Task 2',
                start: '2016-10-04',
                end: '2016-10-07'  
            }

        ]
    },
    {
        'user':'Oliver',
        'tasks': [
            {
                name: 'Task 4',
                start: '2016-10-10',
                end: '2016-10-12'  
            }

        ]
    },
    {
        'user':'Artur',
        'tasks': [
            {
                name: 'Task 3',
                start: '2016-10-09',
                end: '2016-10-15'  
            }

        ]
    }
];

有人可以给我一些关于如何获得类似东西的提示吗? D3.js是这个图表的正确库吗?数据格式正确还是应该在传递给D3之前做一些逻辑?比较开始/结束日期?任何帮助都非常高兴!

2 个答案:

答案 0 :(得分:1)

在D3中相当直接,您的数据看起来不错。

看看d3.dateScale(),你需要类似的东西(制定你的域名):

var dateScale = d3.scaleTime().domain([new Date("2016-10-01"), new Date("2016-10-31")]).range([0,600]);

您可以使用它来生成刻度线并定位任务<rect>,每个任务一个。

首先,创建一个svg:

var svg = d3.select("body").append("svg").attr("width",600).attr("height",400);

为每个人创建<g>,然后将其翻译到位。

var g = svg.selectAll("g").data(data).enter().append("g").attr("transform", function(_,i) {  return "translate(0," + (i * 20) + ")"; } );

创建一个rect然后使用比例计算其位置(参见“x”属性)。在这里,我们从主数据传递任务数据。

g.selectAll("rect").data( function(d) { return d.tasks; } ).enter().append("rect").attr("width", function() { return 100; } ).attr("height",10).attr("x", function(d) { return dateScale(new Date(d.start));} ).attr("fill","red");

这应该让你开始。查看Example running code

答案 1 :(得分:1)

我同意@Matthew,并用一个完整的例子FIDDLE和一点点演练来扩展他的答案。

首先:我首先将原始数据集展平,只是为了简化示例代码,如下所示:

var dataset = [
    {
        user:'John',
        task: 'Task 1',
        start: '2016-10-01',
        end: '2016-10-04'
    },.....

我们开始为x轴定义时间刻度,为y轴上的用户定义带刻度
在这里,我们使用Ordinal标度将离散域映射到连续范围(波段)。我们使用带范围,因为我们的用户域是离散的。

var xSc = d3.scaleTime().range([0, w]),
    ySc = d3.scaleBand().range([h, 0])
    xAxis = d3.axisTop(xSc),
    yAxis = d3.axisLeft(ySc),
    yScDomArr = []; //This is the array for y scale domain

然后我们为比例准备数据:在这里我们将用户收集到yScDomArr,然后我们将“日期字符串”转换为每个 start 结束条目......

dataset.forEach(function(d, i) {
    yScDomArr.push(d.user);
    d.start = new Date(d.start);
    d.end = new Date(d.end);
});

现在我们可以为x和y标度定义域

xSc.domain([
    d3.min(dataset, function(d, i) { return d.start;}),
    d3.max(dataset, function(d, i) { return d.end;})
]);
ySc.domain(yScDomArr); //yScDomArr define our y domain values as users

...最后我们可以为每个数据条目设置<rect><text>(此处我将g元素中的每个矩形和文本对分组,这会使您的代码变得干净,如果你需要show tooltip的事件监听器,那么它很有用:

var tasks = chartSvg.append("g").attr("class", "dataCont")
        .selectAll("g")
        .data(dataset)
        .enter()
        .append("g");

tasks.append("rect")
        .attr("x", function(d) { return xSc(d.start); })
        .attr("y", function(d) { return ySc(d.user); })
        .attr("width", function(d) { return xSc(d.end) - xSc(d.start); })
        .attr("height", function(d) { return ySc.bandwidth(); });

tasks.append("text")
    .attr("x", function(d) { return xSc(d.start) + ((xSc(d.end) - xSc(d.start)) / 2); })
    .attr("y", function(d) { return ySc(d.user) + ySc.bandwidth() / 2 + 4; })  //+4 is for padding top, just a magic number...
    .text(function(d) { return d.task; });