d3图表重绘不在窗口调整大小

时间:2017-09-29 10:11:40

标签: d3.js

我使用d3显示几个等效折线图,我使用单个chart()功能构建,接受所有图表数据。

chart()函数根据需要调用此draw()函数,该函数遍历页面上的所有占位符图表元素。

我希望在调整视口大小时重绘所有图表。因此,为此,我使用d3.select("svg").remove();删除现有图表,然后再次调用draw()函数。

不幸的是,当重新绘制图表时,并非所有元素都是正确的 - 我的路径不会出现(尽管它出现在标记中),而其他一些圆形对象也没有显示)。我不知道为什么会这样。

请参阅我创建的codepen。另外,这是相关代码:

function debounce(func, wait, immediate) {
    var timeout;
    return function() {
        var context = this, args = arguments;
        var later = function() {
            timeout = null;
            if (!immediate) func.apply(context, args);
        };
        var callNow = immediate && !timeout;
        clearTimeout(timeout);
        timeout = setTimeout(later, wait);
        if (callNow) func.apply(context, args);
    };
}

var data = [], promos = [], stocks = [], start = [], end = [];

data['chart-7114'] = [{"date":"2017-08-14","value":"5.0000"},{"date":"2017-08-16","value":"5.0000"},{"date":"2017-08-17","value":"5.0000"},{"date":"2017-08-24","value":"5.0000"},{"date":"2017-08-31","value":"5.0000"},{"date":"2017-09-13","value":"5.0000"},{"date":"2017-09-14","value":"5.0000"},{"date":"2017-09-25","value":"6.4500"},{"date":"2017-09-26","value":"6.4500"},{"date":"2017-09-27","value":"6.4500"},{"date":"2017-09-28","value":"6.4500"}];
                promos['chart-7114'] = [{"start_date":"2017-08-14","end_date":"2017-08-16"},{"start_date":"2017-08-24","end_date":"2017-08-24"},{"start_date":"2017-09-13","end_date":"2017-09-14"}];
                stocks['chart-7114'] = [{"start_date":"2017-08-16","end_date":"2017-08-16"},{"start_date":"2017-09-14","end_date":"2017-09-14"},{"start_date":"2017-09-26","end_date":"2017-09-26"}];
                start['chart-7114'] = "2017-08-14";
                end['chart-7114'] = "2017-09-28";


$(document).ready(function() {

function chart(selector, data, promos, stocks, start, end) {

    var margin = {top: 20, right: 20, bottom: 30, left: 60},
        width = $(selector).width() - margin.left - margin.right,
        height = $(selector).height() - margin.top - margin.bottom;

    var svg = d3.select(selector).append("svg")
        .attr("width", width + margin.left + margin.right)
        .attr("height", height + margin.top + margin.bottom);

    g = svg.append("g").attr("transform", "translate(" + margin.left + "," + margin.top + ")");

    var parseDate = d3.timeParse("%Y-%m-%d"),
        formatDate = d3.timeFormat("%Y"),
        formatDate2 = d3.timeFormat("%d/%m/%Y");

    var x = d3.scaleTime()
        .domain([parseDate(start), parseDate(end)])
        .range([0, width]);

    var y = d3.scaleLinear()
        .range([height, 0]);

    var xAxis = d3.axisBottom(x);
    var yAxis = d3.axisLeft(y);

    var area = d3.line()
        .curve(d3.curveLinear)
        .y(function(d) { return y(d.value); });

    var areaPath = g.append("path")
        .attr('class', 'line')
        .attr("clip-path", "url(#clip)");

    var yGroup = g.append("g");

    var xGroup = g.append("g")
        .attr("transform", "translate(0," + height + ")");

    var tip = d3.tip()
        .attr('class', 'd3-tip')
        .offset([-10, 0])
        .html(function(d) {
            return "Date: " + formatDate2(d.date) + "<br>Price: &pound;" + d.value;
        });

    g.call(tip);

    var promoHighlights = g.selectAll('.promo')
        .data(promos)
        .enter().append("rect")
            .attr('class', 'promo' )
            .style("pointer-events","all")
            .attr("height", height);


    var stockHighlights = g.selectAll('.nostock')
        .data(stocks)
        .enter().append("rect")
            .attr('class', 'nostock' )
            .style("pointer-events","all")
            .attr("height", height);

    var zoom = d3.zoom()
        .scaleExtent([1 / 4, 8])
        .translateExtent([[-width, -Infinity], [2 * width, Infinity]])
        .on("zoom", zoomed);

    var zoomRect = g.append("rect")
        .attr("width", width + margin.left + margin.right)
        .attr("height", height + margin.top + margin.bottom)
        .attr("fill", "none")
        .attr("pointer-events", "all")
        .call(zoom);

    var toolTips = g.selectAll("circle")
        .data(data).enter()
        .append("circle")
            .attr("r", 4)
            .style("pointer-events","all")
            .on('mouseover', function(d, e) {
                tip.show(d);
                d3.select(this).attr('r', 8);
            })
            .on('mouseout', function(d, e) {
                tip.hide(d);
                d3.select(this).attr('r', 4);
            });

    g.append("clipPath")
        .attr("id", "clip")
        .append("rect")
            .attr("width", width)
            .attr("height", height);

    data.forEach(function(d) {
        d.date = parseDate(d.date);
        d.value = +d.value;
    });

    var xExtent = d3.extent(data, function(d) { return d.date; });
    zoom.translateExtent([[x(xExtent[0]), -Infinity], [x(xExtent[1]), Infinity]]);
    y.domain([0, d3.max(data, function(d) { return d.value; })+1]);
    yGroup.call(yAxis).select(".domain").remove();
    areaPath.datum(data);
    zoomRect.call(zoom.transform, d3.zoomIdentity);
    toolTips.attr("cy", function(d) { return y(d.value); });

    function zoomed() {
        var xz = d3.event.transform.rescaleX(x);
        xGroup.call(xAxis.scale(xz));
        areaPath.attr("d", area.x(function(d) { return xz(d.date); }));
        toolTips.attr("cx", function(d) { return xz(d.date); });
        promoHighlights.attr("x", function(d) { return xz(parseDate(d.start_date)); })
            .attr("width", function(d) {
                if(d.end_date != d.start_date) {
                    //console.log(parseDate(d.end_date));
                    return xz(parseDate(d.end_date))-xz(parseDate(d.start_date));
                }
                else {
                    return xz(d3.timeDay.offset(parseDate(d.end_date)))-xz(parseDate(d.start_date));
                }
            });
        stockHighlights.attr("x", function(d) {
                return xz(parseDate(d.start_date));
            })
            .attr("width", function(d) {
                if(d.end_date != d.start_date) {
                    //console.log(parseDate(d.end_date));
                    return xz(parseDate(d.end_date))-xz(parseDate(d.start_date));
                }
                else {
                    return xz(d3.timeDay.offset(parseDate(d.end_date)))-xz(parseDate(d.start_date));
                }
            });
    }

}

function draw() {
    $('.chart').each(function() {
        chart_id = $(this).attr('id');
        chart('#'+$(this).attr('id'), data[chart_id], promos[chart_id], stocks[chart_id], start[chart_id], end[chart_id]);
    });
}

if($('.chart').length > 0) {
    draw();

    $(window).resize(debounce(function(){
        d3.select("svg").remove();
        draw();
    },100));
}

});

2 个答案:

答案 0 :(得分:0)

您必须查看此示例。 code on jsbin

function render() {
    updateDimensions(window.innerWidth);   
    x.range([0, width]);
    y.range([height, 0]);
    svg
      .attr('width', '100%')
      .attr('height', height + margin.top + margin.bottom);
    fh = svg.style("height").replace("px", "");
    fw = svg.style("width").replace("px", "");
    chartWrapper
      .attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');           
    xAxis.scale(x);
    yAxis.scale(y);
    if(window.innerWidth < wbreakPoint) {
      xAxis.ticks(d3.timeHour.every(12))
    }
    else {
      xAxis.ticks(d3.timeHour.every(5))
    };
    if(window.innerinnerHeight < hbreakPoint) {   
      yAxis.ticks(Math.max(height/50, 2))
    }
    else {
      yAxis.ticks(Math.max(height/50, 2));
    }; 
    svg.select('.x.axis')
        .attr('transform', 'translate(0,' + height + ')')
        .transition()
        .duration(200)
        .call(xAxis)
        .selectAll("text")  
            .style("text-anchor", "end")
            .attr("dx", "-.8em")
            .attr("dy", ".15em")
            .attr("transform", "rotate(-50)" ); 
    svg.select('.y.axis')
        .transition()
        .duration(200)
        .call(yAxis);
    chartWrapper.select("text")
        .attr("x", (fw / 2))             
        .attr("y", 0 - (margin.top / 2))
        .attr("text-anchor", "middle");     
    path
        .transition()
        .duration(1000)
        .attr('d',  d => lineGen(d.Data))
        .attr("stroke-width", 3)
        .attr("fill", "none")
        .attr("stroke", (d, i) => colors(i));
    groups.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
    groups
        .transition()
        .duration(1000);} 
function updateDimensions(winWidth) {
    margin.top = 40;
    margin.right = winWidth < wbreakPoint ? 50 : 80;
    margin.left = winWidth < wbreakPoint ? 30 : 50;
    margin.bottom = 100;
    width = winWidth - margin.left - margin.right;
    height = .1 * width;}
return {render : render}
})(window,d3);
window.addEventListener('resize', Chart.render);

只需删除一些字符串以便更好地理解

var inter = setInterval(function() {
            updateData(jsont1);

或者查看this link with responsive scatterplot

希望有所帮助

答案 1 :(得分:0)

我最终确定了这个问题 - 就是这个循环:

data.forEach(function(d) {
    d.date = parseDate(d.date);
    d.value = +d.value;
});

基本上,这是更新数组中的日期值。因为它是chart()函数的一部分,所以它试图两次处理日期,然后有效地将它们的值更改为null - 并打破数据。