更新D3图表导致重复的图表(Updating D3 chart resulting in duplicate charts)

系统教程 行业动态 更新时间:2024-06-14 17:01:34
更新D3图表导致重复的图表(Updating D3 chart resulting in duplicate charts)

我有一段时间试图在点击按钮后将JSON数据更新为D3直方图。

当我解决按钮点击更新问题时,D3 javascript现在每个按钮点击附加一个图表,导致重复的图表而不是简单地更新数据。

我知道每次触发时,click事件都会在D3代码中调用append() ,但是我如何解决这个问题呢?因此每个点击只有一个图表包含更新的数据?

console.log('chart.js loaded'); $(document).ready(function() { var vimeoVideoId = $('p#vimeoVideoId').text(); var api = 'http://localhost:3001/videos/' + vimeoVideoId + '/json'; function initData() { $('#all-notes').click(function() { getData(); }); } function getData() { $.getJSON(api, draw); } function draw(json) { data = json; var duration = data.duration; var timeToSec = function(data) { notes = []; // convert min:sec to seconds for(i=0; i < data.notes.length; i++) { var min_sec = data.notes[i].timecode; var tt = min_sec.split(':'); var seconds = tt[0]*60+tt[1]*1; notes.push(seconds); } return notes; }; noteTimes = timeToSec(data); console.log(noteTimes); // Formatters for counts and times (converting numbers to Dates). var formatCount = d3.format(",.0f"), formatTime = d3.time.format("%H:%M"), formatMinutes = function(d) { return formatTime(new Date(2012, 0, 1, 0, d)); }; var margin = {top: 10, right: 20, bottom: 30, left: 20}, width = 550; height = 285; var x = d3.scale.linear() .domain([0, duration]) // .domain([0, d3.max(noteTimes)]) .range([0, width]); // Generate a histogram using twenty uniformly-spaced bins. var data = d3.layout.histogram() .bins(x.ticks(50)) (noteTimes); var y = d3.scale.linear() .domain([0, d3.max(data, function(d) { return d.y; })]) .range([height, 0]); var xAxis = d3.svg.axis() .scale(x) .orient("bottom") .tickFormat(formatMinutes); var svg = d3.select("#chartSet").append("svg") .attr("width", width + margin.left + margin.right) .attr("height", height + margin.top + margin.bottom) .append("g") .attr("transform", "translate(" + margin.left + "," + margin.top + ")"); var bar = svg.selectAll(".bar") .data(data) .enter().append("g") .attr("class", "bar") .attr("transform", function(d) { return "translate(" + x(d.x) + "," + y(d.y) + ")"; }); bar.append("rect") .attr("x", 1) .attr("width", x(data[0].dx) - 1) .attr("height", function(d) { return height - y(d.y); }); bar.append("text") .attr("dy", ".75em") .attr("y", 6) .attr("x", x(data[0].dx) / 2) .attr("text-anchor", "middle") .text(function(d) { return formatCount(d.y); }); svg.append("g") .attr("class", "x axis") .attr("transform", "translate(0," + height + ")") .call(xAxis); } initData(); });

I am having a hell of a time trying to update JSON data going to a D3 histogram after a button click.

While I solved the button click to update issue, the D3 javascript is now appending one chart per button click, resulting in duplicate charts instead of simply updating the data.

I understand that the click event is calling append() in the D3 code every time it is triggered, but how can I get around this so there's only one chart with updated data per click?

console.log('chart.js loaded'); $(document).ready(function() { var vimeoVideoId = $('p#vimeoVideoId').text(); var api = 'http://localhost:3001/videos/' + vimeoVideoId + '/json'; function initData() { $('#all-notes').click(function() { getData(); }); } function getData() { $.getJSON(api, draw); } function draw(json) { data = json; var duration = data.duration; var timeToSec = function(data) { notes = []; // convert min:sec to seconds for(i=0; i < data.notes.length; i++) { var min_sec = data.notes[i].timecode; var tt = min_sec.split(':'); var seconds = tt[0]*60+tt[1]*1; notes.push(seconds); } return notes; }; noteTimes = timeToSec(data); console.log(noteTimes); // Formatters for counts and times (converting numbers to Dates). var formatCount = d3.format(",.0f"), formatTime = d3.time.format("%H:%M"), formatMinutes = function(d) { return formatTime(new Date(2012, 0, 1, 0, d)); }; var margin = {top: 10, right: 20, bottom: 30, left: 20}, width = 550; height = 285; var x = d3.scale.linear() .domain([0, duration]) // .domain([0, d3.max(noteTimes)]) .range([0, width]); // Generate a histogram using twenty uniformly-spaced bins. var data = d3.layout.histogram() .bins(x.ticks(50)) (noteTimes); var y = d3.scale.linear() .domain([0, d3.max(data, function(d) { return d.y; })]) .range([height, 0]); var xAxis = d3.svg.axis() .scale(x) .orient("bottom") .tickFormat(formatMinutes); var svg = d3.select("#chartSet").append("svg") .attr("width", width + margin.left + margin.right) .attr("height", height + margin.top + margin.bottom) .append("g") .attr("transform", "translate(" + margin.left + "," + margin.top + ")"); var bar = svg.selectAll(".bar") .data(data) .enter().append("g") .attr("class", "bar") .attr("transform", function(d) { return "translate(" + x(d.x) + "," + y(d.y) + ")"; }); bar.append("rect") .attr("x", 1) .attr("width", x(data[0].dx) - 1) .attr("height", function(d) { return height - y(d.y); }); bar.append("text") .attr("dy", ".75em") .attr("y", 6) .attr("x", x(data[0].dx) / 2) .attr("text-anchor", "middle") .text(function(d) { return formatCount(d.y); }); svg.append("g") .attr("class", "x axis") .attr("transform", "translate(0," + height + ")") .call(xAxis); } initData(); });

最满意答案

要处理创建和更新,您必须重新组织draw函数的编写方式。

function draw(json) {

   // Initialization (few wasted CPU cycles)
   // ...

   // Update hook
   var svg = d3.select("#chartSet").data([data]);

   // Enter hook
   var svgEnter = svg.enter();

   // Enter cycle
   svgEnter.append("svg")
      .append("g")
      .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

    // Update cycle
    svg
        .attr("width", width + margin.left + margin.right)
        .attr("height", height + margin.top + margin.bottom);

    // Exit cycle (not really needed here)
    svg.exit().remove();

    // Update hook
    var bar = svg.selectAll(".bar")
        .data(data)

    // Enter hook
    var barEnter = bar.enter();

    // Enter cycle
    var barG_Enter = barEnter
                        .append("g")
                        .attr("class", "bar")
    barG_Enter
        .append("rect")
        .attr("x", 1);

    barG_Enter
        .append("text")
        .attr("dy", ".75em")
        .attr("y", 6)
        .attr("text-anchor", "middle");

    // Update cycle
    bar.attr("transform", function(d) { 
        return "translate(" + x(d.x) + "," + y(d.y) + ")"; });

    bar.select("rect")
        .attr("width", x(data[0].dx) - 1)
        .attr("height", function(d) { return height - y(d.y); });

    bar.select("text")
        .attr("x", x(data[0].dx) / 2)
        .text(function(d) { return formatCount(d.y); });

    // Exit cycle
    bar.exit().remove();

    // Enter cycle
    svgEnter.append("g")
        .attr("class", "x axis")
        .attr("transform", "translate(0," + height + ")")
        .call(xAxis);

    // Update cycle
    svg.select('g.x.axis')
        .call(xAxis);
}
 

这篇经典的enter-update-exit模式在本文中就可重复使用的图形进行了改进 。 这个答案很大程度上依赖于这种模式

使用闭包的稍微好一点的实现,您将能够节省每次初始化时浪费的几个CPU周期。

To handle creation and updates, you will have to reorganize how the draw function is written.

function draw(json) {

   // Initialization (few wasted CPU cycles)
   // ...

   // Update hook
   var svg = d3.select("#chartSet").data([data]);

   // Enter hook
   var svgEnter = svg.enter();

   // Enter cycle
   svgEnter.append("svg")
      .append("g")
      .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

    // Update cycle
    svg
        .attr("width", width + margin.left + margin.right)
        .attr("height", height + margin.top + margin.bottom);

    // Exit cycle (not really needed here)
    svg.exit().remove();

    // Update hook
    var bar = svg.selectAll(".bar")
        .data(data)

    // Enter hook
    var barEnter = bar.enter();

    // Enter cycle
    var barG_Enter = barEnter
                        .append("g")
                        .attr("class", "bar")
    barG_Enter
        .append("rect")
        .attr("x", 1);

    barG_Enter
        .append("text")
        .attr("dy", ".75em")
        .attr("y", 6)
        .attr("text-anchor", "middle");

    // Update cycle
    bar.attr("transform", function(d) { 
        return "translate(" + x(d.x) + "," + y(d.y) + ")"; });

    bar.select("rect")
        .attr("width", x(data[0].dx) - 1)
        .attr("height", function(d) { return height - y(d.y); });

    bar.select("text")
        .attr("x", x(data[0].dx) / 2)
        .text(function(d) { return formatCount(d.y); });

    // Exit cycle
    bar.exit().remove();

    // Enter cycle
    svgEnter.append("g")
        .attr("class", "x axis")
        .attr("transform", "translate(0," + height + ")")
        .call(xAxis);

    // Update cycle
    svg.select('g.x.axis')
        .call(xAxis);
}
 

This classical enter-update-exit pattern is improved upon in this article on making reusable graphs. This answer draws heavily on that pattern.

With a slightly better implementation which uses closures, you will be able to save the few CPU cycles wasted on initialization each time.

更多推荐

data,var,function,click,电脑培训,计算机培训,IT培训"/> <meta name="descr

本文发布于:2023-04-20 18:35:00,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/dzcp/b5244b3b6fa651b2bf12f2772fc6e585.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:图表   Updating   chart   charts   duplicate

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!