Как изменить непрозрачность узла? - PullRequest
1 голос
/ 02 декабря 2019

Сценарий:

При наведении курсора мыши на конкретном узле я пытаюсь выделить этот узел и все его взаимосвязанные узлы, изменив непрозрачность, и все остальные узлы должны быть размыты.

Ожидание: при наведении курсора мыши на узел непрозрачность этого узла и всех его взаимосвязанных узлов должна быть равна 1, тогда как другие узлы должны быть размыты с использованием меньшей непрозрачности.

Существующая функциональность: она не работает, как ожидается, при наведении курсорана любом узле в первый раз. Но со второго раза он работает правильно.

Пожалуйста, обратитесь к jsfiddle: jsfiddle

var nodeElements =  g.append("g")
  .attr("class", "nodes")
  .selectAll("circle")
  .data(graph.nodes)
  .enter().append("circle")
  .attr("r", 60)

  .attr("stroke", "#fff")
  .attr('stroke-width', 21)
  .attr("id", function(d) { return d.id })
   //.attr("fill", function(d) {return color(d.id)}) 
     .attr('fill', function(d, i) { return 'url(#grad' + i + ')'; })
     .on('contextmenu', function(d){ 
        d3.event.preventDefault();
        menu(d3.mouse(svg.node())[0], d3.mouse(svg.node())[1]);
    })
      .on('mouseover', selectNode)
      .on('mouseout', releaseNode)
  .call(d3.drag()
    .on("start", dragstarted)
    .on("drag", dragged)
    .on("end", dragended));


function selectNode(selectedNode) {
  var neighbors = getNeighbors(selectedNode)
        nodeElements.transition().duration(500)
        .attr('opacity', function(node) {
        return setOpacity(node,neighbors, selectedNode);
   })
   .attr('r', function(node) {
        return getNodeRadius(node,neighbors);
   });
   nodeElements.attr('fill', function(node) {
        // send selectedNode to your getNodeColor
        return getNodeColor(node,neighbors,selectedNode);
    })
   textElements.style('font-size', function(node) {
    return getTextColor(node, neighbors)
  })
  textElements.attr('opacity', function(node) {
        return setOpacity(node,neighbors, selectedNode);
   })

  linkElements.style('stroke', function(link) {
    return getLinkColor(selectedNode, link)
  })
}

function releaseNode() {
nodeElements
.attr('r', 60)
.attr('fill', function(d, i) { return 'url(#grad' + i + ')'; })
 .attr('opacity', 1);

linkElements.style('stroke', 'grey');
textElements.attr('opacity','1');
}



 function setOpacity(node, neighbors, selectedNode) {
        if (Array.isArray(neighbors) && neighbors.indexOf(node.id) > -1) {
            return 1;
        } else {
            return 0.3;
        }
    }

1 Ответ

2 голосов
/ 02 декабря 2019

Решение довольно простое: не используйте attr для установки непрозрачности, используйте style вместо:

nodeElements.transition()
    .duration(500)
    .style('opacity', function(node) {
        return setOpacity(node,neighbors, selectedNode);
    })

Вот код только с этим изменением: https://jsfiddle.net/uye24zjn/

Объяснение

Объяснение немного сложнее. Во-первых, имейте в виду, что вы никогда не устанавливали предыдущую непрозрачность, будь то с помощью attr или style.

При переходе непрозрачность D3 использует геттер для получения исходного значения, применяя соответствующий метод (attr или style). И здесь возникает проблема: поскольку вы никогда не устанавливали непрозрачность с помощью метода attr, предыдущее значение, использующее attr в качестве получателя, равно null. Однако, используя style, значение равно 1:

const circle = d3.select("g")
  .append("circle")
  .attr("r", 50);

console.log("The opacity value using 'attr' as a getter is: " + circle.attr("opacity"))
console.log("The opacity value using 'style' as a getter is: " + circle.style("opacity"))
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<svg>
  <g transform="translate(150,75)"></g>
</svg>
<script src="https://d3js.org/d3.v4.min.js"></script>

В результате D3 попытается перейти с null (ноль) на 1, и вы увидите круги, исчезающие в началеперехода. В качестве демонстрации наведите курсор на круг:

const circle = d3.select("g")
  .append("circle")
  .attr("r", 50);

circle.on("mouseover", function() {
  d3.select(this).transition()
    .duration(1000)
    .attr("opacity", function() {
      return 1
    });
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<svg>
  <g transform="translate(150,75)"></g>
</svg>
<script src="https://d3js.org/d3.v4.min.js"></script>

Проблема возникает только при первом наведении курсора мыши (точно так же, как ваш код), потому что после наведения на кружок непрозрачность устанавливается в качестве атрибута, и там будетне более null, когда attr используется в качестве получателя.

Как правило, используйте attr, чтобы установить атрибуты , и style, чтобы установить стили . Другими словами: используйте style, чтобы установить все, что вы будете делать с помощью файла CSS.

...