У меня есть диаграмма Санки, где я показываю связи между исходным и целевым сайтами. Теперь я хочу добавить функцию перетаскивания на эту диаграмму, но у меня есть трудности, так как я до сих пор использовал transform / translate. Текущая версия Sankey работает с [[x0, y0], [x1, y1]] координатами и x + width / y + height, а не с translate.
Я нашел пример с перетаскиванием с использованием translate/ преобразовать здесь: https://bl.ocks.org/d3noob/013054e8d7807dff76247b81b0e29030
Это мой текущий пример
const {
DOM
} = new observablehq.Library;
var units = "Links";
var margin = {
top: 10,
right: 10,
bottom: 10,
left: 10
},
width = 900 - margin.left - margin.right,
height = 700 - margin.top - margin.bottom;
// the function for moving the nodes
function dragmove(d) {
console.log(d3.event);
/*???
sankey.update(graph);
*/
}
const d3color = d3.scaleOrdinal(d3.schemeCategory10);
const color = function(name) {
return d3color(name.replace(/ .*/, ""));
}
var format = function(d) {
const f = d3.format(",.0f");
return f(d);
}
// append the svg canvas to the page
var svg = d3.select("#chart")
//.attr("viewBox", [0, 0, width, height]);;
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom);
// Set the sankey diagram properties
const sankey = d3.sankey()
.nodeAlign(d3.sankeyJustify)
.nodeWidth(15)
.nodePadding(10)
.extent([
[margin.top, margin.left],
[width - margin.right, height - margin.bottom]
]);
const data = {
links: [{
source: 1,
target: 0,
value: 1
},
{
source: 3,
target: 2,
value: 24
},
{
source: 5,
target: 4,
value: 1
},
{
source: 5,
target: 6,
value: 1
},
{
source: 7,
target: 6,
value: 2
},
{
source: 9,
target: 8,
value: 2
},
{
source: 11,
target: 10,
value: 32
},
{
source: 11,
target: 4,
value: 32
},
{
source: 11,
target: 12,
value: 32
},
{
source: 11,
target: 13,
value: 32
},
{
source: 11,
target: 14,
value: 30
},
{
source: 11,
target: 15,
value: 32
},
{
source: 11,
target: 16,
value: 32
},
{
source: 17,
target: 6,
value: 3
},
{
source: 18,
target: 4,
value: 1
},
{
source: 19,
target: 2,
value: 62
},
{
source: 20,
target: 6,
value: 7
},
{
source: 21,
target: 6,
value: 1
},
{
source: 23,
target: 22,
value: 7
},
{
source: 23,
target: 4,
value: 18
},
{
source: 23,
target: 6,
value: 15
},
{
source: 23,
target: 24,
value: 2
},
{
source: 25,
target: 6,
value: 1
},
{
source: 26,
target: 4,
value: 1
},
{
source: 26,
target: 6,
value: 1
},
{
source: 28,
target: 27,
value: 24
},
{
source: 28,
target: 29,
value: 1
},
{
source: 28,
target: 2,
value: 24
},
{
source: 28,
target: 30,
value: 24
},
{
source: 28,
target: 10,
value: 24
},
{
source: 28,
target: 12,
value: 10
},
{
source: 28,
target: 31,
value: 12
},
{
source: 28,
target: 32,
value: 9
},
{
source: 28,
target: 33,
value: 24
},
{
source: 28,
target: 14,
value: 22
},
{
source: 34,
target: 6,
value: 1
},
{
source: 35,
target: 24,
value: 1
},
{
source: 36,
target: 27,
value: 12
},
{
source: 36,
target: 37,
value: 12
},
{
source: 36,
target: 14,
value: 12
},
{
source: 38,
target: 4,
value: 3
},
{
source: 38,
target: 6,
value: 1
},
{
source: 38,
target: 39,
value: 1
},
{
source: 40,
target: 22,
value: 8
},
{
source: 40,
target: 4,
value: 6
},
{
source: 40,
target: 41,
value: 1
},
{
source: 40,
target: 42,
value: 6
},
{
source: 43,
target: 30,
value: 21
},
{
source: 44,
target: 6,
value: 1
},
{
source: 45,
target: 10,
value: 1
},
{
source: 45,
target: 4,
value: 5
},
{
source: 45,
target: 42,
value: 2
},
{
source: 45,
target: 6,
value: 2
},
{
source: 46,
target: 4,
value: 3
},
{
source: 46,
target: 6,
value: 1
},
{
source: 47,
target: 4,
value: 7
},
{
source: 47,
target: 41,
value: 9
},
{
source: 47,
target: 42,
value: 6
},
{
source: 47,
target: 6,
value: 6
},
{
source: 48,
target: 6,
value: 1
},
{
source: 49,
target: 4,
value: 3
},
{
source: 49,
target: 6,
value: 13
},
{
source: 49,
target: 24,
value: 1
},
{
source: 50,
target: 4,
value: 1
},
{
source: 51,
target: 4,
value: 1
},
{
source: 51,
target: 41,
value: 6
},
{
source: 51,
target: 42,
value: 3
},
{
source: 51,
target: 6,
value: 11
},
{
source: 52,
target: 4,
value: 3
},
{
source: 52,
target: 6,
value: 1
},
{
source: 53,
target: 4,
value: 1
},
{
source: 53,
target: 39,
value: 1
},
{
source: 54,
target: 22,
value: 2
},
{
source: 54,
target: 41,
value: 7
},
{
source: 56,
target: 55,
value: 3
},
{
source: 57,
target: 27,
value: 4
},
{
source: 57,
target: 30,
value: 4
},
{
source: 57,
target: 10,
value: 4
},
{
source: 57,
target: 4,
value: 4
},
{
source: 57,
target: 58,
value: 4
},
{
source: 59,
target: 4,
value: 3
},
{
source: 59,
target: 60,
value: 2
},
{
source: 59,
target: 41,
value: 5
},
{
source: 59,
target: 6,
value: 5
},
{
source: 59,
target: 24,
value: 1
},
{
source: 61,
target: 4,
value: 1
},
{
source: 61,
target: 6,
value: 1
},
{
source: 62,
target: 6,
value: 1
},
{
source: 63,
target: 41,
value: 1
},
{
source: 63,
target: 6,
value: 1
},
{
source: 64,
target: 4,
value: 1
},
{
source: 65,
target: 6,
value: 1
}
],
nodes: [{
value: 1,
name: 'site1'
},
{
value: 1,
name: 'site2'
},
{
value: 110,
name: 'site3'
},
{
value: 24,
name: 'site4'
},
{
value: 95,
name: 'site5'
},
{
value: 2,
name: 'site6'
},
{
value: 78,
name: 'site7'
},
{
value: 2,
name: 'site8'
},
{
value: 2,
name: 'site9'
},
{
value: 2,
name: 'site10'
},
{
value: 61,
name: 'site11'
},
{
value: 222,
name: 'site12'
},
{
value: 42,
name: 'site13'
},
{
value: 32,
name: 'site14'
},
{
value: 64,
name: 'site15'
},
{
value: 32,
name: 'site16'
},
{
value: 32,
name: 'site17'
},
{
value: 3,
name: 'site18'
},
{
value: 1,
name: 'site19'
},
{
value: 62,
name: 'site20'
},
{
value: 7,
name: 'site21'
},
{
value: 1,
name: 'site22'
},
{
value: 17,
name: 'site23'
},
{
value: 42,
name: 'site24'
},
{
value: 5,
name: 'site25'
},
{
value: 1,
name: 'site26'
},
{
value: 2,
name: 'site27'
},
{
value: 40,
name: 'site28'
},
{
value: 174,
name: 'site29'
},
{
value: 1,
name: 'site30'
},
{
value: 49,
name: 'site31'
},
{
value: 12,
name: 'site32'
},
{
value: 9,
name: 'site33'
},
{
value: 24,
name: 'site34'
},
{
value: 1,
name: 'site35'
},
{
value: 1,
name: 'site36'
},
{
value: 36,
name: 'site37'
},
{
value: 12,
name: 'site38'
},
{
value: 5,
name: 'site39'
},
{
value: 2,
name: 'site40'
},
{
value: 21,
name: 'site41'
},
{
value: 29,
name: 'site42'
},
{
value: 17,
name: 'site43'
},
{
value: 21,
name: 'site44'
},
{
value: 1,
name: 'site45'
},
{
value: 10,
name: 'site46'
},
{
value: 4,
name: 'site47'
},
{
value: 28,
name: 'site48'
},
{
value: 1,
name: 'site49'
},
{
value: 17,
name: 'site50'
},
{
value: 1,
name: 'site51'
},
{
value: 21,
name: 'site52'
},
{
value: 4,
name: 'site53'
},
{
value: 2,
name: 'site54'
},
{
value: 9,
name: 'site55'
},
{
value: 3,
name: 'site56'
},
{
value: 3,
name: 'site57'
},
{
value: 20,
name: 'site58'
},
{
value: 4,
name: 'site59'
},
{
value: 16,
name: 'site60'
},
{
value: 2,
name: 'site61'
},
{
value: 2,
name: 'site62'
},
{
value: 1,
name: 'site63'
},
{
value: 2,
name: 'site64'
},
{
value: 1,
name: 'site65'
},
{
value: 1,
name: 'site66'
}
]
};
const graph = sankey(data);
const node = svg.append("g")
.attr("stroke", "#000")
.selectAll("rect")
.data(graph.nodes)
.join("rect")
.attr("class", "node")
.attr("x", d => d.x0)
.attr("y", d => d.y0)
.attr("height", d => d.y1 - d.y0)
.attr("width", d => d.x1 - d.x0)
.attr("fill", d => d.color = color(d.name))
.style("stroke", d => d3.rgb(d.color).darker(2))
.call(d3.drag()
.subject(function(d) { return d; })
.on("start", function() { this.parentNode.appendChild(this); })
.on("drag", dragmove));
node.append("title")
.text(d => d.name + ': ' + format(d.value))
const link = svg.append("g")
.attr("fill", "none")
.selectAll("g")
.data(graph.links)
.join("g")
.style("mix-blend-mode", "multiply")
.attr("class", "link");
const gradient = link.append("linearGradient")
.attr("id", d => (d.uid = DOM.uid("link")).id)
.attr("gradientUnits", "userSpaceOnUse")
.attr("x1", d => d.source.x1)
.attr("x2", d => d.target.x0);
gradient.append("stop")
.attr("offset", "0%")
.attr("stop-color", d => color(d.source.name));
gradient.append("stop")
.attr("offset", "100%")
.attr("stop-color", d => color(d.target.name));
link.append("path")
.attr("d", d3.sankeyLinkHorizontal())
.attr("stroke", d => d.uid)
.attr("stroke-width", d => Math.max(1, d.width));
link.append("title")
.text(d => d.source.name + ' → ' + d.target.name + ': ' + format(d.value));
svg.append("g")
.style("font", "10px sans-serif")
.selectAll("text")
.data(graph.nodes)
.join("text")
.attr("x", d => d.x0 < width / 2 ? d.x1 + 6 : d.x0 - 6)
.attr("y", d => (d.y1 + d.y0) / 2)
.attr("dy", "0.35em")
.attr("text-anchor", d => d.x0 < width / 2 ? "start" : "end")
.text(d => d.name);
/*
// the function for moving the nodes
function dragmove(d) {
d3.select(this).attr("transform",
"translate(" + d.x + "," + (
d.y = Math.max(0, Math.min(height - d.dy, d3.event.y))
) + ")");
sankey.relayout();
link.attr("d", d3.sankeyLinkHorizontal());
}*/
rect.node {
/*cursor: move; */
fill-opacity: .9;
shape-rendering: crispEdges;
}
.node title {
pointer-events: none;
text-shadow: 0 1px 0 #fff;
}
.link {
fill: none;
stroke: #000;
stroke-opacity: .2;
}
.link:hover {
stroke-opacity: .5;
}
<body>
<div>
<svg id='chart'></svg>
</div>
</body>
<script src="https://d3js.org/d3.v5.min.js"></script>
<script src="https://unpkg.com/d3-sankey@0.12.3/dist/d3-sankey.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/@observablehq/stdlib"></script>
Как работает перетаскивание?