简体   繁体   English

在D3图表中DOM元素更新后如何执行追加?

[英]How do I perform append after DOM elements updatein a D3 chart?

I have a Gantt chart that I built with D3 that has an associated filter where a user can select the shortest time, longest time, etc. So when the filter changes the xAxis modifies and some of the elements shift with time. 我有一个用D3构建的甘特图,该图具有关联的过滤器,用户可以在其中选择最短时间,最长时间等。因此,当过滤器更改时,xAxis会修改,并且某些元素会随时间移动。

A have also drawn some lines connecting the elements selected by the filter. A还绘制了一些连接过滤器所选元素的线。

When a selection is made in the filter, I remove the lines (via remove), change the color of the rectangles, and change the axis to the new timescale. 当在过滤器中进行选择时,我删除了这些线(通过删除),更改了矩形的颜色,并将轴更改为新的时间刻度。 However when i go to draw new lines, the references are being pulled from the old rectangles, prior to updating. 但是,当我去画新线时,在更新之前,参考是从旧矩形中拉出来的。

Here is the JSFiddle showing the issue: https://jsfiddle.net/3afumu4d/12/ 这是显示问题的JSFiddle: https ://jsfiddle.net/3afumu4d/12/

To see issue: click the filter icon, then select "Shortest Time", the arrows will redraw but in the wrong location. 要查看问题,请执行以下操作单击过滤器图标,然后选择“最短时间”,箭头将重绘,但位置错误。 It is drawing them in the location of rectangles prior to transition. 它在过渡之前将它们绘制在矩形的位置。

Here is my update method. 这是我的更新方法。

function updateData(){

//remove the lines  
    d3.select("#barsGroup").selectAll('line').remove();
    //remove the arrows
    d3.select("#barsGroup").selectAll('polyline').remove();

//based on selection, calculate start and end times
    var checked = $('input[type=radio][name=timeline]:checked').attr('id');
    taskArray.forEach(function(entry){

        //if it is selected calculate its new start time.
        if(illuminate(entry,checked)){
            var newVal = root.startYear + getDelay(entry, checked);
            entry.startTime = newVal.toString();
            entry.endTime = (newVal + entry.time).toString();
        }


    });


    var minX = d3.min(taskArray, function(d) {return dateFormat.parse(d.startTime);});
    var maxX = d3.max(taskArray, function(d) {return dateFormat.parse(d.endTime);});

    timeScale = d3.time.scale().domain([minX,maxX]).range([0,w-150]);

    //update the boxes
    var chart = d3.select("#innercontainer").transition();

    //get all the rectangles, update all the rectangles
    var updateBoxes = d3.select("#barsGroup").selectAll('rect')
        .data(taskArray)
        .transition()
        .attr("x", function(d){return timeScale(dateFormat.parse(d.startTime)) + sidePadding;})
        .attr("y", function(d, i){return i*gap + topPadding;})
        .attr("width", function(d){return (timeScale(dateFormat.parse(d.endTime))-timeScale(dateFormat.parse(d.startTime)))})
        .attr("fill", function(d){
          for (var i = 0; i < categories.length; i++){
              if (d.component == categories[i]){
                //if true matches selection in filter
                var checked = $('input[type=radio][name=timeline]:checked').attr('id');
                if(illuminate(d,checked)){
                    return d3.rgb(colorScale(i));
                }else{
                    return d3.rgb(colorScale(i)).darker(5);
                }


                //else show darker
              }
          }

         })
        .attr("opacity", function(d){
            for (var i = 0; i < categories.length; i++){
              if (d.component == categories[i]){
                //if true matches selection in filter
                var checked = $('input[type=radio][name=timeline]:checked').attr('id');
                if(illuminate(d,checked)){
                    return 1.0;
                }else{
                    return 0.4;
                }


                //else show darker
              }
          }
        });

    //Update the text boxes
    var textlist = d3.select("#barsGroup").selectAll('text')
    .data(taskArray)
    .transition()
    .attr("x", function(d){
         return (timeScale(dateFormat.parse(d.endTime))-timeScale(dateFormat.parse(d.startTime)))/2 + timeScale(dateFormat.parse(d.startTime)) + sidePadding;
     })
    .attr("y", function(d, i){
         return i*gap + 8+ topPadding;
     })
    .attr("fill", function(d){
                for (var i = 0; i < categories.length; i++){
                    if (d.component == categories[i]){
                        //if true matches selection in filter
                        var checked = $('input[type=radio][name=timeline]:checked').attr('id');
                        if(illuminate(d,checked)){
                            return "#fff";
                        }else{
                            return "#3f3f3f";
                        }
                    }
            }
        }
    );



    //update grid lines

    //scale the axis
    xAxis = d3.svg.axis()
        .scale(timeScale)
        .orient('bottom')
        .ticks(d3.time.year, 5) //TODO: change to years (skip every ten?)
        .tickSize(-h+topPadding+20, 0, 0)
        .tickFormat(d3.time.format('%Y'))

    d3.select(".grid")
    .transition()
    .duration(750)
    .call(xAxis)
    .selectAll("text")  
        .style("text-anchor", "middle")
        .attr("fill", "#fff")
        .attr("stroke", "none")
        .attr("font-size", 10)
        .attr("dy", "1em")
        .each("end",drawArrows(taskArray,checked));;

}

The drawArrows method is what adds arrows to the newly highlighted path through the Gantt Chart. drawArrows方法是通过甘特图向新突出显示的路径添加箭头的方法。 But its not getting new values. 但是它并没有获得新的价值。

Is there any way I can fire the drawArrows method after the DOM elements have updated? 在DOM元素更新后,有什么方法可以触发drawArrows方法?

I found the answer in another Stack Overflow question. 我在另一个堆栈溢出问题中找到了答案。

Essentially I needed to wait for all "rect" transitions to complete, so the rect x,y, width values were updated. 本质上,我需要等待所有“矩形”转换完成,因此更新了矩形x,y,width值。

I used the endAll method approach found here: d3.js transition end event 我使用了在这里找到的endAll方法: d3.js过渡结束事件

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM