这将是一个艰难的...
我正在努力与d3.js合作,为从事任务的人制作某种图表。
这将是示例数据。
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之前做一些逻辑?比较开始/结束日期?任何帮助都非常高兴!
答案 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; });