【问题标题】:Why is the window resize event appending the g element repeatedly?为什么窗口调整大小事件重复附加 g 元素?
【发布时间】:2019-02-06 06:09:42
【问题描述】:

当我尝试使用 D3 调整事件的大小时,它显示我在图表中附加的元素“g”在调整大小期间重复打印。如何使用this 关键字?或类似的东西? This is the code on js fiddle.

问题:如何使用 d3 中的this 关键字解决?

function redraw(){
    let chartContainer = document.getElementById("bar_Chart");
    let containerWidth = chartContainer.clientWidth;
    let containerHeight = chartContainer.clientHeight;


    let inputData = [
        {name: "JAN", value:  10},
        {name: "FEB", value:  8},
        {name: "MAR", value: 15},
        {name: "APR", value: 16},
        {name: "MAY", value: 23},
        {name: "JUN", value: 30},
        {name: "JUL", value: 12},
        {name: "AUG", value: 41},
        {name: "SEP", value: 52},
        {name: "OCT", value: 23},
        {name: "NOV", value: 32},
        {name: "DEC", value: 42}
    ];

    let margin = {top: 20, right: 30, bottom: 30, left: 40};
    let width = containerWidth - margin.left - margin.right;
    let height = containerHeight - margin.top - margin.bottom;
        let x = d3.scaleBand()
        .rangeRound([0, width])
        .padding(0.1);

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

    let tooltip = d3.select("body").append("div").attr("class", "toolTip");


    let chart = d3.select(".chart-svg")
        .attr("width", width + margin.left + margin.right)
        .attr("height", height + margin.top + margin.bottom)
        .append("g")
        .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

    x.domain(inputData.map(function(d) { return d.name; }));
    y.domain([0, d3.max(inputData, function (d) { return d.value; })]);
    let xAxis = d3.axisBottom(x);

    let yAxis = d3.axisLeft(y);

    chart.append("g")
        .attr("class", "x axis")
        .attr("transform", "translate(0," + height + ")")
        .call(xAxis)



    chart.append("g")
        .attr("class", "y axis")
        .call(yAxis)


    chart.selectAll(".bar")
        .data(inputData)
        .enter().append("rect")
        .attr("class", "bar")
        .attr("x", function(d) { return x(d.name); })
        .attr("y", function(d) { return y(d.value); })
        .attr("height", function(d) { return height - y(d.value); })
        .attr("width", x.bandwidth())
        .on("mouseover", function (d) {
            tooltip.transition()
                .duration(200)
                .style("opacity", 0.85)
                .style("left", d3.event.pageX - 50 + "px")
                .style("top", d3.event.pageY - 70 + "px");
            tooltip
                .style("display", "inline-block")
                .html((d.name) + "£" + (d.value));
            d3.select(this).transition()
            .duration(300)
            .style("fill", "red");
        })
        .on("mouseout", function () {
            tooltip.transition()
                .duration(200)
                .style("opacity", 0);
            tooltip
                .style("display", "none");
            d3.select(this).transition()
                .duration(300)
                .style("fill", "steelblue")
                .style("transition", "scale(1.8)");
        });

    }


    redraw();
    window.addEventListener("resize", redraw);

【问题讨论】:

    标签: javascript jquery d3.js


    【解决方案1】:

    当您第一次绘制图表时,您需要调用 enter 将数据绑定到 DOM 元素并调用 append 来创建 DOM 元素。当您调整窗口大小时,您不想再调用enterappend,因为数据已经绑定到 DOM 元素并且 DOM 元素已经存在。您真正想要做的就是使用attr 调整事物的大小并重新设置您的坐标轴。

    您可以有两个函数drawredraw,这与draw 相同,只是它不调用enterappend。我在这里展示它们:

    let inputData = [
        {name: "JAN", value:  10},
        {name: "FEB", value:  8},
        {name: "MAR", value: 15},
        {name: "APR", value: 16},
        {name: "MAY", value: 23},
        {name: "JUN", value: 30},
        {name: "JUL", value: 12},
        {name: "AUG", value: 41},
        {name: "SEP", value: 52},
        {name: "OCT", value: 23},
        {name: "NOV", value: 32},
        {name: "DEC", value: 42}
    ];
    
    let margin = {top: 20, right: 30, bottom: 30, left: 40};
    
    function draw() {
        let chartContainer = document.getElementById("bar_Chart"); 
        let containerWidth = chartContainer.clientWidth; 
        let containerHeight = chartContainer.clientHeight;
    
        let width = containerWidth - margin.left - margin.right;
        let height = containerHeight - margin.top - margin.bottom;
    
        let x = d3.scaleBand()
            .rangeRound([0, width])
            .padding(0.1);
    
        let y = d3.scaleLinear()
            .range([height, 0]);
    
        let tooltip = d3.select("body").append("div").attr("class", "toolTip");
    
        let chart = d3.select(".chart-svg")
            .attr("width", width + margin.left + margin.right)
            .attr("height", height + margin.top + margin.bottom)
            .append("g")
            .attr("transform", "translate(" + margin.left + "," + margin.top + ")");
    
        x.domain(inputData.map(function(d) { return d.name; }));
        y.domain([0, d3.max(inputData, function (d) { return d.value; })]);
        let xAxis = d3.axisBottom(x);
    
        let yAxis = d3.axisLeft(y);
    
        chart.append("g")
            .attr("class", "x axis")
            .attr("transform", "translate(0," + height + ")")
            .call(xAxis)
    
        chart.append("g")
            .attr("class", "y axis")
            .call(yAxis)
    
        chart.selectAll(".bar")
            .data(inputData)
            .enter().append("rect")
            .attr("class", "bar")
            .attr("x", function(d) { return x(d.name); })
            .attr("y", function(d) { return y(d.value); })
            .attr("height", function(d) { return height - y(d.value); })
            .attr("width", x.bandwidth())
            .on("mouseover", function (d) {
                tooltip.transition()
                    .duration(200)
                    .style("opacity", 0.85)
                    .style("left", d3.event.pageX - 50 + "px")
                    .style("top", d3.event.pageY - 70 + "px");
                tooltip
                    .style("display", "inline-block")
                    .html((d.name) + "£" + (d.value));
                d3.select(this).transition()
                .duration(300)
                .style("fill", "red");
            })
            .on("mouseout", function () {
                tooltip.transition()
                    .duration(200)
                    .style("opacity", 0);
                tooltip
                    .style("display", "none");
                d3.select(this).transition()
                    .duration(300)
                    .style("fill", "steelblue")
                    .style("transition", "scale(1.8)");
            });
    }
    
    function redraw() { 
        let chartContainer = document.getElementById("bar_Chart"); 
        let containerWidth = chartContainer.clientWidth; 
        let containerHeight = chartContainer.clientHeight;
        let width = containerWidth - margin.left - margin.right;
        let height = containerHeight - margin.top - margin.bottom;
    
        let x = d3.scaleBand()
            .rangeRound([0, width])
            .padding(0.1);
    
        let y = d3.scaleLinear()
            .range([height, 0]);
    
        let tooltip = d3.select("body").append("div").attr("class", "toolTip");
    
        let chart = d3.select(".chart-svg")
            .attr("width", width + margin.left + margin.right)
            .attr("height", height + margin.top + margin.bottom)
            .attr("transform", "translate(" + margin.left + "," + margin.top + ")");
    
        x.domain(inputData.map(function(d) { return d.name; }));
        y.domain([0, d3.max(inputData, function (d) { return d.value; })]);
    
        let xAxis = d3.axisBottom(x);
        let yAxis = d3.axisLeft(y);
    
        chart.select(".x.axis")
            .attr("transform", "translate(0," + height + ")")
            .call(xAxis)
    
        chart.select(".y.axis")
            .call(yAxis)
    
        chart.selectAll(".bar")
            .data(inputData)
            .attr("class", "bar")
            .attr("x", function(d) { return x(d.name); })
            .attr("y", function(d) { return y(d.value); })
            .attr("height", function(d) { return height - y(d.value); })
            .attr("width", x.bandwidth())
    }
    
    document.addEventListener('DOMContentLoaded', draw);
    window.addEventListener("resize", redraw);
    

    还是有问题。 X 方向与窗口的宽度很好地缩放,但 Y 方向没有。我相信你不应该在redraw 函数中使用let containerHeight = chartContainer.clientHeight;,因为它没有正确计算容器元素的高度(无论窗口是增大还是缩小都会增加)。我会把这个留给你解决。我改用window.innerHeight 玩了,这似乎效果更好,但它计算的是窗口的高度,而不是容器 div。

    【讨论】:

    • 你能在这编辑一下吗?并给我链接? jsfiddle.net/Towhid/y9s2xuke
    • 你能解决这个问题吗?请帮帮我。这是一个很大的麻烦,我从昨晚开始尝试这个。
    猜你喜欢
    • 2019-09-23
    • 2014-04-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-13
    相关资源
    最近更新 更多