简体   繁体   中英

d3js: click event in reusable chart

I have a reusable chart that works fine. I added the following simple code to the reusable chart expecting that it would add click listener to all the charts created by it.

d3.cloudshapes.barChart = function module() {
    var margin = {top: 10, right: 10, bottom: 20, left: 20},
        width = 500,
        height = 500,
        gap = 0,
        ease = "bounce";
    var svg;


    // Define the 'inner' function: which, through the surreal nature of JavaScript scoping, can access
    // the above variables. 
    function exports(_selection) {
        _selection.each(function(_data) {
            var chartW = 60,
                chartH = 60;

        var test_data = _data.value;

            var x1 = d3.scale.ordinal()
                    .domain(test_data.map(function(d) { return d.x; }))
                    .rangeRoundBands([0, chartW], 0.1);

            var y1 = d3.scale.linear()
                    .domain([0, 36])
                    .range([chartH, 0]);

        var color = d3.scale.category10();

        // If no SVG exists, create one - and add key groups:
            if (!svg) {
                svg = d3.select(this)
                     .append("svg")
             .attr("width", width)
             .attr("height", height)
                     .classed("chart", true);
                var container = svg.append("g").classed("container-group", true);
                container.append("g").classed("chart-group", true);
        container.attr({transform: "translate(" + 60*_data.row + "," + 60*_data.col + ")"});
        container.on("click", click);

            }

        // Transition the width and height of the main SVG and the key 'g' group: 
            svg.classed("chart", true).transition().attr({width: width, height: height});
           var container = svg.append("g").classed("container-group", true);
        container.append("g").classed("chart-group", true);
        container.attr({transform: "translate(" + 60*_data.row + "," + 60*_data.col + ")"});

        container.on("click", click);

            function click()  {
                console.log("I got clicked");
            }

        // Define gap between bars: 
            var gapSize = x1.rangeBand() / 100 * gap;

        // Define width of each bar: 
            var barW = x1.rangeBand() - gapSize;

            // Select all bars and bind data:  
            var bars = svg.selectAll(".chart-group")
                        .selectAll(".bar")
                        .data(test_data);

        bars.enter().append("rect")
            .classed("bar", "true")
            .attr({
                width: barW,
                x: function (d) {                   
                    return x1(d.x) + gapSize / 2; },
                y: function(d) { return y1(d.y); },
                height: function(d) { return chartH - y1(d.y); }
        })
            .attr("fill", function(d) { return color(d.x); });



        });
    }

But the click function works just for the last instance of graph rendered by the reusable chart. How can a click listener added to each graph rendered by the reusable chart ??

A simpler version is here fiddle . I want to add a zoomed popover bar chart svg on clicking on little bar charts. I think the problem is with dynamically created div because when I tried creating charts in predefined div than the click function works fine.

Any help would be much appreciated !

The scope of the svg variable is causing the problem. In your code, the svg variable value is shared throug all the instances of your reusable function. You probably want to use enter() to create the SVG element and the inner components, and add the click listener to the component. The svg variable should be defined inside the exports function.

// rest of the code...
function exports(selection) {
    selection.each(function(data) {

        // Select the SVG element
        var svg = d3.select(this).selectAll('svg').data([data]);

        // Create the SVG element on enter, set it's size
        svg.enter().append('svg')
            .attr('width', width)
            .attr('height', height);

        var component = svg.selectAll('g.component').data([data]);

        // Create the component group on enter and set its attributes
        component.enter().append('g');

        // Add other elements...

        // click listener
        component.on('click', function(d) {
            // click callback.
        });


    });
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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