Подтвердить что ты не робот

Градиент по ссылкам на диаграмме D3 Санки

Здесь находится jsfiddle для Sankey diagram:

enter image description here

Я пытаюсь изменить цвета ссылок, чтобы цвет каждой ссылки был фактически градиентом от его исходного цвета node до его целевого цвета node. (предполагается, что непрозрачность останется 0,2 или 0,5 в зависимости от того, наводится ли мышь или нет по ссылке, поэтому ссылки останутся немного "бледнее", чем узлы).

Я взглянул на этот приятный и поучительный пример, который рисует этот цикл заполнения градиентом:

enter image description here

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

Кроме того, обратите внимание, что ссылки в исходной диаграмме Sankey перемещаются, а node перетаскивается, и он должен отображать градиент даже в этих переходных состояниях. Небольшой проблемой является также прозрачность ссылок и узлов, а также порядок рисования. Я был бы признателен за идеи, подсказки.

4b9b3361

Ответ 1

@VividD: Просто увидел ваш комментарий, но я все равно сделал все. Не стесняйтесь игнорировать это, пока не разобрались сами, но я хотел убедиться, что I знал, как это сделать. Плюс, это действительно общий вопрос, так хорошо иметь для справки.

Как получить градиент, расположенный вдоль линии

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

  • В инициализации создайте элемент <defs> (определения) в SVG и сохраните выделение для переменной:

    var defs = svg.append("defs");
    
  • Определите функцию, которая создаст идентификатор уникальный для вашего градиента из объекта данных ссылки. Также неплохо дать название функции для определения цвета node:

    function getGradID(d){return "linkGrad-" + d.source.name + d.target.name;}
    function nodeColor(d) { return d.color = color(d.name.replace(/ .*/, ""));}
    
  • Создайте выделение <linearGradient> объектов в <defs> и присоедините его к вашим данным ссылки, затем установите смещения остановки и координаты линий в соответствии с исходными и целевыми объектами данных.

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

    var grads = defs.selectAll("linearGradient")
                     .data(graph.links, getLinkID);
    
    grads.enter().append("linearGradient")
                 .attr("id", getGradID)
                 .attr("gradientUnits", "objectBoundingBox"); //stretch to fit
    
    grads.html("") //erase any existing <stop> elements on update
         .append("stop")
         .attr("offset", "0%")
         .attr("stop-color", function(d){
               return nodeColor( (d.source.x <= d.target.x)? d.source: d.target) 
              });
    
    grads.append("stop")
         .attr("offset", "100%")
         .attr("stop-color", function(d){
               return nodeColor( (d.source.x > d.target.x)? d.source: d.target) 
              });
    

    К сожалению, когда путь является полностью прямой, его ограничивающий прямоугольник не существует (независимо от ширины штриха) и net result градиент не окрашивается.

    Поэтому мне пришлось переключиться на более общий шаблон, в котором градиент расположен и наклонен вдоль линии между источником и целью:

    grads.enter().append("linearGradient")
        .attr("id", getGradID)
        .attr("gradientUnits", "userSpaceOnUse");
    
    grads.attr("x1", function(d){return d.source.x;})
        .attr("y1", function(d){return d.source.y;})
        .attr("x2", function(d){return d.target.x;})
        .attr("y2", function(d){return d.target.y;});
    
    /* and the stops set as before */
    
  • Конечно, теперь, когда градиент определен на основе системы координат вместо того, чтобы основываться на длине пути, вам нужно обновлять эти координаты всякий раз, когда движется node, поэтому мне пришлось обернуть эти позиционирования операторов в функции, которую я мог бы вызвать в функции dragmove().

  • Наконец, при создании путей ссылок установите их заливку как функцию CSS url(), ссылающуюся на соответствующий уникальный идентификатор градиента, полученный из данных (с использованием предопределенной функции полезности):

    link.style("stroke", function(d){
        return "url(#" + getGradID(d) + ")";
    })
    

И Voila!
Sankey diagram with custom gradients from the data