Как перевести линейный градиент для пути

Как перейти линейный градиент для пути

Я работаю над диаграммой sankey, которая обновляется всякий раз, когда я меняю фильтр (radiobuttons), используя d3.js и плагин sankey. Теперь я пытаюсь добавить функцию, которая, когда бы я ни наводил курсор на один из путей, добавлял линейный градиент к пути, идущему от цвета исходного узла к цвету целевого узла. Если я не использую фильтр, все работает нормально, однако градиентная окраска не работает, если я применяю фильтр (цвета установлены неправильно), потому что ссылки переходят. Я думаю, что мне нужно как-то перевести линейный градиент, но я не понимаю, как мне это сделать.

Я написал небольшой скрипт, который показывает проблему, до нажатия кнопки правильные цвета и после того, как она испортилась.

 {amp}lt;!DOCTYPE html{amp}gt; {amp}lt;html lang="en"{amp}gt; {amp}lt;head{amp}gt; {amp}lt;meta charset="UTF-8"{amp}gt; {amp}lt;title{amp}gt;Title{amp}lt;/title{amp}gt; {amp}lt;script src="https://d3js.org/d3.v4.min.js"{amp}gt;{amp}lt;/script{amp}gt; {amp}lt;script src="https://unpkg.com/d3-sankey@0.6"{amp}gt;{amp}lt;/script{amp}gt; {amp}lt;/head{amp}gt; {amp}lt;body{amp}gt; {amp}lt;svg id="diagram" height="150" width="600"{amp}gt;{amp}lt;/svg{amp}gt; {amp}lt;button onclick="updateSankey()"{amp}gt;Click Me!{amp}lt;/button{amp}gt; {amp}lt;style{amp}gt; #diagram{ border: 1px solid black; } {amp}lt;/style{amp}gt; {amp}lt;script{amp}gt; var target = 0; var sankeyLinks; var sankeyData = {nodes:[], links:[]}; calculateLinks(); initSankey(); updateSankey(); function initSankey() { /*simple initialisation of the sankey, should explain itself*/ svg = d3.select("svg"), width =  svg.attr("width"), height =  svg.attr("height"); formatNumber = d3.format(",.0f"), format = function (d) { return formatNumber(d)   " %"; }, color = d3.scaleOrdinal(d3.schemeCategory10); sankey = d3.sankey() .nodeWidth(15) .nodePadding(10) .extent([[1, 1], [width - 1, height - 6]]) .iterations(0); t = d3.transition() .duration(1500) .ease(d3.easeLinear); //set attributes for all links titleGroup = svg.append("g") .attr("class", "titles") .attr("font-family", "sans-serif") .attr("font-size", "150%"); diagram= svg.append("g") .attr("class", "sankey") // .attr("transform", "translate("   marginleft   ","   margintop   ")"); linkGroup = diagram.append("g") .attr("class", "links") .attr("fill", "none"); //.attr("stroke", "#000") //.attr("stroke-opacity", 0.2); //set attributes for all nodes nodeGroup = diagram.append("g") .attr("class", "nodes") .attr("font-family", "sans-serif") .attr("font-size", 10); } function calculateLinks() { if(target == 0) { target = 1; sankeyLinks = [{source:0, target:1, value:5},{source:0, target:2, value:10},{source:0, target:3, value:15}]; } else { target = 0; sankeyLinks = [{source:0, target:2, value:15},{source:0, target:1, value:20},{source:0, target:3, value:10}]; } } function updateSankey() { calculateLinks(); sankeyData.links = sankeyLinks; sankeyData.nodes = [{name: "first"}, {name:"second"}, {name:"third"}, {name: "fourth"}]; sankey(sankeyData); var links = linkGroup.selectAll('path') .data(sankeyData.links); //Set attributes for each link separately links.enter().append("g") .attr("id",function (d,i) {return "path" i;}) .append("path") .attr("stroke", "#000") .attr("stroke-opacity", 0.15) .attr("d", d3.sankeyLinkHorizontal()) .attr("stroke-width", function (d) {return Math.max(1, d.width); }) .on("mouseover",function (d,id) { var pathGroup = svg.select('#path'   id); var path = pathGroup.select("path"); path.attr("stroke","url(#grad" id ")") .attr("stroke-opacity","0.95"); }) .on("mouseout",function (d, id) { pathGroup = svg.select('#path'   id); var path = pathGroup.select("path"); path.attr("stroke","#000") .attr("stroke-opacity","0.15"); }) .append("title") .text(function (d) { //tooltip info for the links return d.source.name   " → "   d.target.name   "n"   format(d.value); }); var pathGradient = svg.select(".links") .selectAll("g") .append("defs") .append("linearGradient") .attr("id",function (d, id) { return "grad"   id; }) //.attr("from", function () {return this.parentElement.parentElement.childNodes[0].getAttribute("from");}) //.attr("to", function () {return this.parentElement.parentElement.childNodes[0].getAttribute("to");}) .attr("gradientUnit","userSpaceOnUse") .attr("style","mix-blend-mode: multiply;") .attr("x1","0%") .attr("x2","100%") .attr("y1","0%") .attr("y2","0%"); pathGradient.append("stop") .attr("class","from") .attr("offset","0%") .attr("style", function (d) { var color = setColor(d.source); return "stop-color:"   color   ";stop-opacity:1"; }); pathGradient.append("stop") .attr("class","to") .attr("offset","100%") .attr("style",function (d) { var color = setColor(d.target); return "stop-color:"   color   ";stop-opacity:1"; }); links.transition(t) .attr("d", d3.sankeyLinkHorizontal()) .attr("stroke-width", function (d) { return Math.max(1, d.width); }) .select('title') .text(function (d) { //same argumentation as above, we need the method again for the transition return d.source.name   " → "   d.target.name   "n"   format(d.value); }); links.exit().remove(); var nodes = nodeGroup.selectAll('.node') .data(sankeyData.nodes); var nodesEnter = nodes.enter() .append("g") .attr('class', 'node'); //set attributes for each node separately nodesEnter.append("rect") .attr("x", function (d) { return d.x0; }) .attr("y", function (d) { return d.y0; }) .attr("height", function (d) { return d.y1 - d.y0; }) .attr("width", function (d) { var width = d.x1 - d.x0; return width; }) .attr("fill", setColor) .attr("stroke", "#000") .attr("fill-opacity", 0.5) //specify Pop-Up when hovering over node nodesEnter.append("title") .text(function (d) { return d.name   "n"   format(d.value); }); //Update selection var nodesUpdate = nodes.transition(t); //same as the links we have to state the methods again in the update nodesUpdate.select("rect") .attr("y", function (d) { return d.y0; }) .attr("x", function (d) { return d.x0; }) .attr("height", function (d) { return d.y1 - d.y0; }); nodesUpdate.select("title") .text(function (d) { return d.name   "n"   format(d.value); }); //Exit selection nodes.exit().remove(); } function setColor(d) { switch (d.name) { case "first": return "#f00"; case "second": return "#ff0"; case "third": return "#f0f"; case "fourth": return "#0ff"; default: return "#0f0"; } } {amp}lt;/script{amp}gt; {amp}lt;/body{amp}gt; {amp}lt;/html{amp}gt; 

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

Я уже понял, что мог бы написать, например, .iterations(15) вместо .iterations(0) в initSankey() чтобы это исправить. В реальном проекте я не могу этого сделать, так как мне нужно установить порядок узлов.

Я надеюсь, что я достаточно ясен в своем объяснении, если нет, не стесняйтесь спрашивать

Я был бы чрезвычайно рад, если бы кто-то мог сказать мне, как решить эту проблему.

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

Понравилась статья? Поделиться с друзьями:
JavaScript & TypeScript
Adblock
detector