D3-单选按钮未更新数据可视化

时间:2019-01-28 02:20:02

标签: d3.js

我创建了一个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))
    }

1 个答案:

答案 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);
}