Handling Mouse Events in Overlapping SVG Layers

前端 未结 2 2003
别跟我提以往
别跟我提以往 2021-02-15 01:04

I am building a map visualization with d3.js. I am drawing filled polygons for both the US states and counties. The SVG layer for counties is under the layer for states. The sta

2条回答
  •  梦如初夏
    2021-02-15 01:35

    If you want to do something when you click a state, like changing the border style, or the opacity of the shape, you can use the fact that every county belongs to a state and just group the counties in states, capturing the 'click' event in the county, select the corresponding state element and change its visual attributes. A mockup of this strategy:

    // Setup the visualization, assuming that you have a div with id 'chart'
    var width = 300,
        height = 300,
        div = d3.select('#chart'),
        svg = div.append('svg')
            .attr('width', width)
            .attr('height', height);
    
    // Array of states, each one containing one or more counties. In this example,
    // the states are rectangles, but you get the idea
    var states = [
        {
            width: 300,
            height: 300,
            name: 'Fake State',
            counties: [
                {x:   5, y: 5, width:  95, height: 290, fill: '#b4a0a0'},
                {x: 100, y: 5, width: 150, height: 290, fill: '#b4c0a0'},
                {x: 250, y: 5, width:  45, height: 290, fill: '#a4a0c0'}
            ]
        }];
    
    // Create a group for each state, with class state
    var gstates = svg.selectAll('g.state')
        .data(states)
        .enter()
        .append('g')
        .classed('state', true);
    
    // Add the state background, in this case, a transparent rectangle
    gstates
        .append('rect')
        .classed('state', true)
        .attr('width', function(d) { return d.width; })
        .attr('height', function(d) { return d.height; })
        .attr('fill', '#444')
        .attr('fill-opacity', 0.0);
    
    // For each group, add rectangles for each county, binding them to the
    // county array of each state.
    gstates.selectAll('rect.county')
        .data(function(d) { return d.counties; })
        .enter()
        .append('rect')
        .classed('county', true)
            .attr('x', function(d) { return d.x; })
            .attr('y', function(d) { return d.y; })
            .attr('width', function(d) { return d.width; })
            .attr('height', function(d) { return d.height; })
            .attr('fill', function(d) { return d.fill; })
            .on('mouseover', function() {
                d3.select(this).attr('fill-opacity', 0.5);
            })
            .on('mouseout', function() {
                d3.select(this).attr('fill-opacity', 0.9);
            })
            .on('click', function() {
                // Retrive the parent group of each county, and then select
                // the shape corresponding to the state and alter its properties
                // you can also access the state data
                var parent = d3.select(d3.select(this).node().parentNode),
                    state = parent.select('rect.state');
                    // Output 'Fake State'
                    console.log(parent[0][0].__data__.name);
                    state.attr('fill-opacity', 1.0);
            });
    

    There is a working fiddle here: http://jsfiddle.net/pnavarrc/PGTCM/5/. Regards,

提交回复
热议问题