D3-单选按钮未更新数据可视化 [英] D3 - Radio Buttons not Updating Data Visualization

查看:70
本文介绍了D3-单选按钮未更新数据可视化的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我创建了一个D3图表,在用户单击其中一个单选按钮后,我想对其进行更新.按钮的值不是数据的一部分,而是基于新选择的timeRange值(应从现在"开始36小时)沿X轴更新的时间范围以及应更新的Y轴数据. .我可以从console.log语句中得知,当用户单击单选按钮时timeRange正在更新,但无法弄清楚更新该图表所需的操作(change()函数是我要使用的功能)做到这一点.

I have created a D3 chart which I would like to update after the user clicks on one of the radio buttons. The value of the button isn't part of the data but an update of the time range along the X axis which should update as well as Y axis data based on the newly selected timeRange value (starting point is 36 hours from "now"). I can tell from console.log statements that the timeRange is updating when the user clicks on a radio button but can't figure out what I need to do to get that chart updated (the change() function is what I am trying to use to make this happen.

这是一个小提琴: 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为您做到这一点,但我不确定如何做到.

I've done something similar in a project. I think the main thing you are missing is that when you change the data you need to remove the current chart and draw a new one. You may be able to make Angular do this for you, but I'm not sure how.

就个人而言,我会将逻辑重构为drawChart(filteredData)filterData(unfilteredData, HOW TO FILTER)之类的东西.最初的页面加载绘图是使用所需的任何数据调用drawChart(它可以通过filterData().您的change()函数将从单选按钮中获取HOW TO FILTER,并将其传递给filterData() ,然后删除图表,然后使用过滤后的数据调用drawChart.此体系结构使图表的每次绘制都相同,如果您需要更改绘制图表的方式,则可以在一个地方完成.

Personally, I would refactor the logic into something like drawChart(filteredData) and filterData(unfilteredData, HOW TO FILTER). The initial draw on page load would be a call to drawChart with whatever data you want (it could go through filterData(). Your change() function would take the HOW TO FILTER from the radio button, pass it to filterData(), then remove the chart, then call drawChart with the filtered data. This architecture makes every draw of the chart the same and if you need changes to how the chart it drawn you can do it one place.

新的change函数示例

change(howToFilter){
  var filteredData = filterData(dataset, howToFilter);
  CODE TO REMOVE THE CHART
  drawChart(filteredData);
}

这篇关于D3-单选按钮未更新数据可视化的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆