我创建了一个D3图表,用户单击一个单选按钮后,我想对其进行更新。按钮的值不是数据的一部分,而是基于新选择的timeRange值(应从“现在”开始36小时)沿X轴更新的时间范围以及应更新的Y轴数据。 。我可以从console.log语句中得知,当用户单击单选按钮时timeRange正在更新,但无法弄清楚更新该图表所需的操作(change()函数是我要使用的功能)做到这一点。
这里是一个小提琴:https://jsfiddle.net/dtepdc/L1qf0bvk/
这是我的代码:
const dataset = [
{
start_date: "2019-01-27T14:30:40",
end_date: "2019-01-27T16:32:25",
elapsed_time: 130,
coNum:"CO19044"
},
{
start_date: "2019-01-27T03:05:40",
end_date: "2019-01-27T03:32:25",
elapsed_date: 189,
coNum:"CO12904"
},
{
start_date: "2019-01-26T22:15:40",
end_date: "2019-01-26T23:32:25",
elapsed_time: 89,
coNum:"CO18345"
},
{
start_date: "2019-01-26T07:00:40",
end_date: "2019-01-26T07:40:25",
elapsed_time: 89,
coNum:"CO12005"
}
];
const coNumW = window.innerWidth,
coNumH = window.innerHeight,
margin = {top: coNumH * 0.15, right: coNumW * 0.05, bottom: coNumH * 0.12, left: coNumW * 0.12},
w = coNumW - margin.left - margin.right,
h = coNumH - margin.top - margin.bottom;
const xSc = d3.scaleTime().range([0, w]),
ySc = d3.scaleBand().range([h, 0]),
xAxis = d3.axisBottom(xSc),
yAxis = d3.axisLeft(ySc),
filtered = [],
dateFormat = d3.timeFormat("%Y-%m-%d %I:%M %p");
const svg = d3.select("body")
.append("svg")
.attr("width", coNumW)
.attr("height", coNumH)
.append("g").classed("no-select", true)
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
let radio = d3.select('input[name="options"]:checked').property("value");
let timeRange = radio;
let start = moment().subtract(timeRange, 'hours').format('LLL');
const end = moment().format('LLL');
timeRange = this.value;
dataset.forEach(function(d, i) {
console.log('forEach timeRange: ', timeRange);
d.start_date = new Date(d.start_date);
d.end_date = new Date(d.end_date);
if (d.start_date >= new Date(start) && d.end_date <= new Date(end)) {
filtered.push(d);
}
});
xSc.domain([new Date(end), new Date(start)])
.range([0, w]);
ySc.domain(filtered.map(d => d.coNum)).padding(0.1);
console.log('xSc & ySc timeRange: ', timeRange)
svg.append("g")
.attr("class", "x Axis")
.attr("transform", "translate(0, " + h + ")")
.call(xAxis)
svg.append("g")
.attr("class", "y Axis")
.call(yAxis);
const tasks = svg.append("g").attr("class", "dataCont")
.selectAll("g")
.data(filtered)
.enter()
.append("g")
.on("mouseenter", showData);
tasks.append("rect")
.attr("x", function(d) {
return xSc(d.start_date) + 2; // + 2 is for padding
})
.attr("y", function(d) {
return ySc(d.coNum);
})
.attr("width", function(d) {
return xSc(d.start_date) - xSc(d.end_date) - 2;
})
.attr("height", function(d) {
return ySc.bandwidth();
})
.attr("fill", "green");
d3.selectAll("input")
.on("change", change);
function change() {
timeRange = this.value;
dataset.forEach(function(d, i) {
console.log('forEach timeRange: ', timeRange);
d.start_date = new Date(d.start_date);
d.end_date = new Date(d.end_date);
if (d.start_date >= new Date(start) && d.end_date <= new Date(end)) {
filtered.push(d);
}
});
xSc.domain([new Date(end), new Date(start)])
.range([0, w]);
ySc.domain(filtered.map(d => d.coNum)).padding(0.1);
console.log('xSc & ySc timeRange: ', timeRange)
svg.append("g")
.attr("class", "x Axis")
.attr("transform", "translate(0, " + h + ")")
.call(xAxis)
svg.append("g")
.attr("class", "y Axis")
.call(yAxis);
const tasks = svg.append("g").attr("class", "dataCont")
.selectAll("g")
.data(filtered)
.enter()
.append("g")
.on("mouseenter", showData);
tasks.append("rect")
.attr("x", function(d) {
return xSc(d.start_date) + 2; // + 2 is for padding
})
.attr("y", function(d) {
return ySc(d.coNum);
})
.attr("width", function(d) {
return xSc(d.start_date) - xSc(d.end_date) - 2;
})
.attr("height", function(d) {
return ySc.bandwidth();
})
.attr("fill", "green");
}
function showData(d) {
const dur = (d.end_date - d.start_date)/3600000;
console.log("-" + d.coNum + "- start_date: " + dateFormat(d.start_date) + " || end_date: " + dateFormat(d.end_date))
}
答案 0 :(得分:0)
我在一个项目中做了类似的事情。我认为您最缺少的是,当您更改数据时,需要删除当前图表并绘制一个新图表。您也许可以让Angular为您做到这一点,但是我不确定如何做到。
就个人而言,我会将逻辑重构为drawChart(filteredData)
和filterData(unfilteredData, HOW TO FILTER)
之类的东西。最初的页面加载量是调用drawChart
并使用您想要的任何数据(它可以通过filterData()
。您的change()
函数将从无线电中获取HOW TO FILTER
按钮,将其传递到filterData()
,然后删除图表,然后使用过滤后的数据调用drawChart
。这种体系结构可以使图表的每次绘制都相同,如果您需要更改绘制图表的方式,可以做到一处。
新的change
函数示例
change(howToFilter){
var filteredData = filterData(dataset, howToFilter);
CODE TO REMOVE THE CHART
drawChart(filteredData);
}