【问题标题】:Handling Mouse Events in Overlapping SVG Layers在重叠的 SVG 层中处理鼠标事件
【发布时间】:2013-05-23 20:11:39
【问题描述】:

我正在使用 d3.js 构建地图可视化。我正在为美国各州和县绘制填充多边形。县的 SVG 图层位于州图层的下方。状态已填充,但 fill-opacity 设置为 0;需要填充(我认为)才能捕获点击事件。

我想在州级捕获点击事件,但我想在县级捕获鼠标悬停事件。

但是,鼠标悬停事件被州捕获,而不是传递到县。

有没有办法将事件向下传递一层或以其他方式触发县的鼠标悬停事件?

【问题讨论】:

  • 您是否有指向您正在使用的示例的链接?

标签: javascript jquery html svg d3.js


【解决方案1】:

如果您想在单击某个州时执行某些操作,例如更改边框样式或形状的不透明度,您可以利用每个县都属于一个州这一事实,只需将县分组到州中,即可捕获在县的“点击”事件中,选择相应的州元素并更改其视觉属性。该策略的模型:

// 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);
        });

这里有一个工作小提琴:http://jsfiddle.net/pnavarrc/PGTCM/5/。问候,

【讨论】:

    【解决方案2】:

    这是一个 d3 函数,可以满足您的需求。

    它通过暂时禁用顶层的指针事件,并在下一层手动触发鼠标事件,将事件传递给较低的层。

    function passThruEvents(g) {
        g   .on('mousemove.passThru', passThru)
            .on('mousedown.passThru', passThru)
        ;
    
        function passThru(d) {
            var e = d3.event;
    
            var prev = this.style.pointerEvents;
            this.style.pointerEvents = 'none';
    
            var el = document.elementFromPoint(d3.event.x, d3.event.y);
    
            var e2 = document.createEvent('MouseEvent');
            e2.initMouseEvent(e.type,e.bubbles,e.cancelable,e.view, e.detail,e.screenX,e.screenY,e.clientX,e.clientY,e.ctrlKey,e.altKey,e.shiftKey,e.metaKey,e.button,e.relatedTarget);
    
            el.dispatchEvent(e2);
    
            this.style.pointerEvents = prev;
        }
    }
    

    【讨论】:

    • 这个解决方案很棒并且很容易适应其他情况,但是,被最顶层元素“遮蔽”的元素将无法通过:hover 设置样式,我真的很想解决这个问题。
    猜你喜欢
    • 2013-09-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-09-22
    • 2015-06-05
    • 1970-01-01
    • 1970-01-01
    • 2015-02-06
    相关资源
    最近更新 更多