Как заставить только некоторые ребра реагировать на `mouseover` в графике сил D3 v4

Я работаю над этим графом силы в D3 v4.

Когда пользователь щелкает узлы, становятся видимыми только узлы, связанные с ним. Кроме того, края, соединяющие эти узлы, становятся более толстыми, и пользователи могут зависать, чтобы видеть больше информации (всплывающая подсказка справа).

Вот как я выделяю подключенные узлы после щелчка

//Highlight on click
function highlighting () {
//Toggle stores whether the highlighting is on
var node = d3.selectAll('circle');
var link = d3.selectAll('line');
var toggle = 0;
//Create an array logging what is connected to what
var linkedByIndex = {};
for (i = 0; i < dataset.nodes.length; i++) {
    linkedByIndex[i + "," + i] = 1;
};
d3.selectAll('line').each(function (d) {
    linkedByIndex[d.source.index + "," + d.target.index] = 1;
});
//This function looks up whether a pair are neighbours
function neighboring(a, b) {
    return linkedByIndex[a.index + "," + b.index];
}
function connectedNodes() {
    if (toggle == 0) {
        //Reduce the opacity of all but the neighbouring nodes
        d = d3.select(this).node().__data__;
        node.style("opacity", function (o) {
            return neighboring(d, o) | neighboring(o, d) ? 1 : 0.0;
        });
        link.style("opacity", function (o) {
            return d.index==o.source.index | d.index==o.target.index ? 1 : 0.0;
        });
        link.attr('stroke-width' , 4);
        toggle = 1;
        interactivityHighlight();

        //Change navigation div
        d3.select('#click01').classed('hidden', true);
        d3.select('#click02').classed('hidden', false);

    } else {
        //Put them back to starting opacity
        node.style("opacity", 1);
        link.style("opacity", function (d) {return edgeOpacityScale(d.collaborations);});
        link.attr('stroke-width', 1);
        link.attr('class', null);
        toggle = 0;
        //Change navigation
        d3.select('#click01').classed('hidden', false);
        d3.select('#click02').classed('hidden', true);
    }
}
node.on('click', connectedNodes);
}

И это функция, которую я вызываю после нажатия

function interactivityHighlight () {
graph.selectAll('line').on('mouseover', function (d) {
    if (d3.select(this).style('opacity') == 1) {
        d3.select(this)
        .attr('stroke', 'red')
        .attr('stroke-width', 6);

        d3.select('#tooltip')
        .classed('hidden', false);

        d3.select('#tooltip')
        .append('p')
        .attr('id', 'org_names')
        .text('Collaborations between ' + d.source.name + ' and ' + d.target.name);

        d3.select('#tooltip')
        .append('p')
        .attr('id', 'collaborations')
        .text('Worked together on ' + d.collaborations + ' projects');

        d3.select('#tooltip')
        .append('p')
        .attr('id', 'collBudget')
        .text('Total budget: '+ commafy(d.collBudget));
}})

graph.selectAll('line').on('mouseout', function (d) {
    if (d3.select(this).style('opacity') == 1) {
        d3.select(this)
        .attr('stroke', 'black')
        .attr('stroke-width', 4);

        d3.select('#tooltip')
        .selectAll('p')
        .remove();

        d3.select('#tooltip')
        .classed('hidden', true);
}})
}

В основном все несвязанные узлы получают opacity=0 и таким образом стать невидимым. Однако они все еще присутствуют на графике: зависание над линией может не сработать interactivityHighlight() потому что мышь на самом деле зависает над невидимым краем.

Есть ли способ, которым я могу сделать так, чтобы невидимые края действительно исчезли, или сделать так, чтобы видимые грани "встали на вершину" всех остальных?

2 ответа

Решение

Используйте то же правило, которое вы использовали для определения "непрозрачности" для определения "событий указателя":

link.attr("pointer-events", function (o) {
        return d.index==o.source.index | d.index==o.target.index ? "all" : "none";
    });

Добавьте класс css, который включает это правило указателей-событий, например:

.hidden {
  pointer-events: none;
}

А затем установить этот класс по ссылкам

.classed("hidden", function(d) {
    /* return true/false, decide using the same logic you use for opacity */ 
});

Ссылки со скрытым классом позволят событиям указателя проходить к чему-либо ниже

Другие вопросы по тегам