d3.js - D3 - 不更新数据可视化的单选按钮
问题描述
我创建了一个 D3 图表,我想在用户单击其中一个单选按钮后对其进行更新。按钮的值不是数据的一部分,而是沿 X 轴的时间范围的更新,应该更新以及基于新选择的 timeRange 值的 Y 轴数据(起点是从“现在”开始的 36 小时) . 我可以从 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))
}
解决方案
我在一个项目中做过类似的事情。我认为您缺少的主要内容是,当您更改数据时,您需要删除当前图表并绘制一个新图表。你也许可以让 Angular 为你做这件事,但我不知道怎么做。
就个人而言,我会将逻辑重构为类似drawChart(filteredData)
and 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);
}
推荐阅读
- xcode - 使用 Xcode 首选项与 .gitignore 文件
- haskell - Simple examples to clarify on memoisation and strictness
- java - Firebase 数据库无法检索值
- python - 从 Anaconda 64 位安装切换到 32 位安装,但保持安装库
- c# - 为什么对象和集合初始值设定项的组合使用 Add 方法?
- scala - 无法更改 Spark foreach 函数体内的全局变量
- html - 如何缩进列表和子列表菜单?
- json - 当预期的字符串数组返回对象时,Gson 抛出异常
- python - 在python中循环到邻接矩阵
- apache-spark - 如何使用 Spark Scala 加入 3 个 RDD