gpt4 book ai didi

javascript - d3 v4 向力导向图添加箭头

转载 作者:行者123 更新时间:2023-12-03 01:14:40 26 4
gpt4 key购买 nike

我正在尝试在 d3.js 中创建一个力导向图,其中箭头指向大小不均匀的节点。我遇到了这个例子here但在我的一生中,我无法调整我的代码来添加箭头。我不确定是否需要在刻度函数中添加额外的内容,或者我是否错误地引用了某些内容。谁能帮帮我吗?

Codepen - https://codepen.io/quirkules/pen/dqXRwj

var links_data = [{"source":"ABS","target":"ABS","count":8},{"source":"ABS","target":"ATS","count":1},{"source":"ABS","target":"CR","count":8},{"source":"ABS","target":"ENV","count":1},{"source":"ABS","target":"INT","count":16},{"source":"ABS","target":"ITS","count":9},{"source":"ABS","target":"PDG","count":1},{"source":"ABS","target":"PER","count":4},{"source":"ABS","target":"PRAC","count":3},{"source":"AC","target":"AC","count":1},{"source":"AC","target":"INT","count":9},{"source":"AC","target":"ITS","count":1},{"source":"ACDC","target":"ACDC","count":1},{"source":"ACDC","target":"CR","count":2},{"source":"ACDC","target":"ITS","count":13},{"source":"ACDC","target":"PER","count":4},{"source":"APL","target":"APL","count":8},{"source":"APL","target":"CR","count":3},{"source":"APL","target":"ENV","count":1},{"source":"APL","target":"INT","count":1},{"source":"APL","target":"ITS","count":29},{"source":"APL","target":"LA","count":1},{"source":"APL","target":"PEG","count":1},{"source":"APL","target":"PER","count":3},{"source":"AST","target":"AST","count":17},{"source":"AST","target":"COP","count":1},{"source":"AST","target":"DBT","count":2},{"source":"AST","target":"DEVOPS","count":1},{"source":"AST","target":"IGN","count":1},{"source":"AST","target":"INT","count":2},{"source":"AST","target":"ITS","count":32},{"source":"AST","target":"PDG","count":2},{"source":"AST","target":"PER","count":8},{"source":"ATS","target":"ABS","count":1},{"source":"ATS","target":"ATS","count":21},{"source":"ATS","target":"DBT","count":1},{"source":"ATS","target":"INT","count":3},{"source":"ATS","target":"PDG","count":1},{"source":"ATS","target":"PEG","count":1},{"source":"CAR","target":"APL","count":1},{"source":"CAR","target":"CAR","count":9},{"source":"CAR","target":"COP","count":1},{"source":"CAR","target":"INT","count":9},{"source":"CAR","target":"ITS","count":8},{"source":"IGN","target":"CR","count":4},{"source":"IGN","target":"IGN","count":13},{"source":"IGN","target":"INT","count":5},{"source":"IGN","target":"ITS","count":13},{"source":"IGN","target":"PER","count":4},{"source":"IGN","target":"PRAC","count":1},{"source":"LA","target":"AC","count":1},{"source":"LA","target":"INT","count":1},{"source":"LA","target":"ITS","count":37},{"source":"LA","target":"LA","count":18},{"source":"LA","target":"PER","count":2},{"source":"LOT","target":"LOT","count":18},{"source":"PDG","target":"ABS","count":1},{"source":"PDG","target":"AST","count":4},{"source":"PDG","target":"ATS","count":1},{"source":"PDG","target":"CAR","count":1},{"source":"PDG","target":"CR","count":8},{"source":"PDG","target":"ICS","count":1},{"source":"PDG","target":"IGN","count":3},{"source":"PDG","target":"INT","count":18},{"source":"PDG","target":"ITS","count":6},{"source":"PDG","target":"NRB","count":4},{"source":"PDG","target":"ONT","count":1},{"source":"PDG","target":"PDG","count":24},{"source":"PDG","target":"PER","count":1},{"source":"PEG","target":"CAR","count":1},{"source":"PEG","target":"ENV","count":1},{"source":"PEG","target":"INFRA","count":1},{"source":"PEG","target":"ITS","count":22},{"source":"PEG","target":"LA","count":1},{"source":"PEG","target":"PEG","count":51},{"source":"PEG","target":"PER","count":6},{"source":"RPT","target":"ABS","count":1},{"source":"RPT","target":"APL","count":1},{"source":"RPT","target":"IGN","count":1},{"source":"RPT","target":"INT","count":9},{"source":"RPT","target":"ITS","count":2},{"source":"RPT","target":"RPT","count":11},{"source":"RPT","target":"RTR","count":1},{"source":"RWWA","target":"INT","count":1},{"source":"RWWA","target":"ITS","count":1},{"source":"RWWA","target":"PER","count":1},{"source":"RWWA","target":"RWWA","count":1},{"source":"SCOR","target":"SCOR","count":5},{"source":"SPK","target":"INT","count":4},{"source":"SPK","target":"ITS","count":4},{"source":"SPK","target":"SPK","count":21},{"source":"TS","target":"CS","count":1},{"source":"TS","target":"TS","count":10}];

var nodes_data = [{"name":"ABS","total":11},{"name":"ATS","total":23},{"name":"CR","total":25},{"name":"ENV","total":3},{"name":"INT","total":78},{"name":"ITS","total":177},{"name":"PDG","total":28},{"name":"PER","total":33},{"name":"PRAC","total":4},{"name":"AC","total":2},{"name":"ACDC","total":1},{"name":"APL","total":10},{"name":"LA","total":20},{"name":"PEG","total":53},{"name":"AST","total":21},{"name":"COP","total":2},{"name":"DBT","total":3},{"name":"DEVOPS","total":1},{"name":"IGN","total":18},{"name":"CAR","total":11},{"name":"LOT","total":18},{"name":"ICS","total":1},{"name":"NRB","total":4},{"name":"ONT","total":1},{"name":"INFRA","total":1},{"name":"RPT","total":11},{"name":"RTR","total":1},{"name":"RWWA","total":1},{"name":"SCOR","total":5},{"name":"SPK","total":21},{"name":"CS","total":1},{"name":"TS","total":10}];

//create node size scale
var nodeSizeScale = d3.scaleLinear()
.domain(d3.extent(nodes_data, d => d.total))
.range([30, 70]);

//create node size scale
var linkSizeScale = d3.scaleLinear()
.domain(d3.extent(links_data, d => d.count))
.range([5, 30]);

//create node size scale
var linkColourScale = d3.scaleLinear()
.domain(d3.extent(links_data, d => d.count))
.range(['blue', 'red']);

//document.getElementsByTagName('body')[0].innerHTML = '<div>' + JSON.stringify(nodes_data) + '</div>';

//create somewhere to put the force directed graph
var height = 650,
width = 950;

var svg = d3.select("body").append("svg")
.attr('width',width)
.attr('height',height);

var radius = 15;


//set up the simulation and add forces
var simulation = d3.forceSimulation()
.nodes(nodes_data);

var link_force = d3.forceLink(links_data)
.id(function(d) { return d.name; })
;

var charge_force = d3.forceManyBody()
.strength(-1000);

var center_force = d3.forceCenter(width / 2, height / 2);

simulation
.force("charge_force", charge_force)
.force("center_force", center_force)
.force("link",link_force)
;

//add tick instructions:
simulation.on("tick", tickActions );

// THIS CODE SECTION ISN'T RENDERING
// Per-type markers, as they don't inherit styles.
svg.append("defs").selectAll("marker")
.data(["dominating"])
.enter().append("marker")
.attr("id", function (d) {
return d;
})
.attr("viewBox", "0 -5 10 10")
.attr("refX", 15)
.attr("refY", -1.5)
.attr("markerWidth", 12)
.attr("markerHeight", 12)
.attr("orient", "auto")
.append("path")
.attr("d", "M0,-5L10,0L0,5");

//add encompassing group for the zoom
var g = svg.append("g")
.attr("class", "everything");

// add the curved links to our graphic
var link = g.selectAll(".link")
.data(links_data)
.enter()
.append("path")
.attr("class", "link")
.style('stroke', d => {return linkColourScale(d.count);})
.attr('stroke-opacity', 0.5)
.attr('stroke-width', d => {return linkSizeScale(d.count);});

//draw circles for the nodes
var node = g.append("g")
.attr("class", "nodes")
.selectAll("circle")
.data(nodes_data)
.enter()
.append("circle")
.attr("r", d => {return nodeSizeScale(d.total);})
.attr("fill", "#333")
.on("mouseover", mouseOver(.1))
.on("mouseout", mouseOut);

//add text labels
var text = g.append("g")
.attr("class", "labels")
.selectAll("text")
.data(nodes_data)
.enter().append("text")
.style("text-anchor","middle")
.style("font-weight", "bold")
.style("pointer-events", "none")
.attr("dy", ".35em")
.text(function(d) { return d.name });

//add drag capabilities
var drag_handler = d3.drag()
.on("start", drag_start)
.on("drag", drag_drag)
.on("end", drag_end);

drag_handler(node);


//add zoom capabilities
var zoom_handler = d3.zoom()
.on("zoom", zoom_actions);

zoom_handler(svg);

/** Functions **/

//Drag functions
//d is the node
function drag_start(d) {
if (!d3.event.active) simulation.alphaTarget(0.3).restart();
d.fx = d.x;
d.fy = d.y;
}

//make sure you can't drag the circle outside the box
function drag_drag(d) {
d.fx = d3.event.x;
d.fy = d3.event.y;
}

function drag_end(d) {
if (!d3.event.active) simulation.alphaTarget(0);
d.fx = null;
d.fy = null;
}

//Zoom functions
function zoom_actions(){
g.attr("transform", d3.event.transform)
}

function tickActions() {
//update circle positions each tick of the simulation
node
.attr("cx", function(d) { return d.x; })
.attr("cy", function(d) { return d.y; });

//update link positions
link.attr("d", positionLink);

text.attr("x", function(d) { return d.x; })
.attr("y", function(d) { return d.y; });
}

// links are drawn as curved paths between nodes,
// through the intermediate nodes
function positionLink(d) {
var offset = 30;

var midpoint_x = (d.source.x + d.target.x) / 2;
var midpoint_y = (d.source.y + d.target.y) / 2;

var dx = (d.target.x - d.source.x);
var dy = (d.target.y - d.source.y);

var normalise = Math.sqrt((dx * dx) + (dy * dy));

var offSetX = midpoint_x + offset * (dy / normalise);
var offSetY = midpoint_y - offset * (dx / normalise);

return "M" + d.source.x + "," + d.source.y +
"S" + offSetX + "," + offSetY +
" " + d.target.x + "," + d.target.y;
}

// build a dictionary of nodes that are linked
var linkedByIndex = {};
links_data.forEach(function(d) {
linkedByIndex[d.source.index + "," + d.target.index] = 1;
});

// check the dictionary to see if nodes are linked
function isConnected(a, b) {
return linkedByIndex[a.index + "," + b.index] || linkedByIndex[b.index + "," + a.index] || a.index == b.index;
}

// fade nodes on hover
function mouseOver(opacity) {
return function(d) {
// check all other nodes to see if they're connected
// to this one. if so, keep the opacity at 1, otherwise
// fade
node.style("stroke-opacity", function(o) {
thisOpacity = isConnected(d, o) ? 1 : opacity;
return thisOpacity;
});
node.style("fill-opacity", function(o) {
thisOpacity = isConnected(d, o) ? 1 : opacity;
return thisOpacity;
});
text.style("fill-opacity", function(o) {
thisOpacity = isConnected(d, o) ? 1 : opacity;
return thisOpacity;
});
// also style link accordingly
link.style("stroke-opacity", function(o) {
return o.source === d || o.target === d ? 1 : opacity;
});
link.style("stroke", function(o) {
return o.source === d || o.target === d ? linkColourScale(o.count) : "#333";
});
};
}

function mouseOut() {
node.style("stroke-opacity", 1);
node.style("fill-opacity", 1);
text.style("fill-opacity", 1);
link.style("stroke-opacity", 0.5);
link.style("stroke", d => {return linkColourScale(d.count);});
}

最佳答案

我已将您提到的示例中的相同代码更改应用于您的代码,并且它似乎工作正常。

唯一需要的额外更新是,由于您有连接到自身的节点,因此我必须仅将标记结束属性和路径长度更新应用于过滤后的链接集。

var links_data = [{"source":"ABS","target":"ABS","count":8},{"source":"ABS","target":"ATS","count":1},{"source":"ABS","target":"CR","count":8},{"source":"ABS","target":"ENV","count":1},{"source":"ABS","target":"INT","count":16},{"source":"ABS","target":"ITS","count":9},{"source":"ABS","target":"PDG","count":1},{"source":"ABS","target":"PER","count":4},{"source":"ABS","target":"PRAC","count":3},{"source":"AC","target":"AC","count":1},{"source":"AC","target":"INT","count":9},{"source":"AC","target":"ITS","count":1},{"source":"ACDC","target":"ACDC","count":1},{"source":"ACDC","target":"CR","count":2},{"source":"ACDC","target":"ITS","count":13},{"source":"ACDC","target":"PER","count":4},{"source":"APL","target":"APL","count":8},{"source":"APL","target":"CR","count":3},{"source":"APL","target":"ENV","count":1},{"source":"APL","target":"INT","count":1},{"source":"APL","target":"ITS","count":29},{"source":"APL","target":"LA","count":1},{"source":"APL","target":"PEG","count":1},{"source":"APL","target":"PER","count":3},{"source":"AST","target":"AST","count":17},{"source":"AST","target":"COP","count":1},{"source":"AST","target":"DBT","count":2},{"source":"AST","target":"DEVOPS","count":1},{"source":"AST","target":"IGN","count":1},{"source":"AST","target":"INT","count":2},{"source":"AST","target":"ITS","count":32},{"source":"AST","target":"PDG","count":2},{"source":"AST","target":"PER","count":8},{"source":"ATS","target":"ABS","count":1},{"source":"ATS","target":"ATS","count":21},{"source":"ATS","target":"DBT","count":1},{"source":"ATS","target":"INT","count":3},{"source":"ATS","target":"PDG","count":1},{"source":"ATS","target":"PEG","count":1},{"source":"CAR","target":"APL","count":1},{"source":"CAR","target":"CAR","count":9},{"source":"CAR","target":"COP","count":1},{"source":"CAR","target":"INT","count":9},{"source":"CAR","target":"ITS","count":8},{"source":"IGN","target":"CR","count":4},{"source":"IGN","target":"IGN","count":13},{"source":"IGN","target":"INT","count":5},{"source":"IGN","target":"ITS","count":13},{"source":"IGN","target":"PER","count":4},{"source":"IGN","target":"PRAC","count":1},{"source":"LA","target":"AC","count":1},{"source":"LA","target":"INT","count":1},{"source":"LA","target":"ITS","count":37},{"source":"LA","target":"LA","count":18},{"source":"LA","target":"PER","count":2},{"source":"LOT","target":"LOT","count":18},{"source":"PDG","target":"ABS","count":1},{"source":"PDG","target":"AST","count":4},{"source":"PDG","target":"ATS","count":1},{"source":"PDG","target":"CAR","count":1},{"source":"PDG","target":"CR","count":8},{"source":"PDG","target":"ICS","count":1},{"source":"PDG","target":"IGN","count":3},{"source":"PDG","target":"INT","count":18},{"source":"PDG","target":"ITS","count":6},{"source":"PDG","target":"NRB","count":4},{"source":"PDG","target":"ONT","count":1},{"source":"PDG","target":"PDG","count":24},{"source":"PDG","target":"PER","count":1},{"source":"PEG","target":"CAR","count":1},{"source":"PEG","target":"ENV","count":1},{"source":"PEG","target":"INFRA","count":1},{"source":"PEG","target":"ITS","count":22},{"source":"PEG","target":"LA","count":1},{"source":"PEG","target":"PEG","count":51},{"source":"PEG","target":"PER","count":6},{"source":"RPT","target":"ABS","count":1},{"source":"RPT","target":"APL","count":1},{"source":"RPT","target":"IGN","count":1},{"source":"RPT","target":"INT","count":9},{"source":"RPT","target":"ITS","count":2},{"source":"RPT","target":"RPT","count":11},{"source":"RPT","target":"RTR","count":1},{"source":"RWWA","target":"INT","count":1},{"source":"RWWA","target":"ITS","count":1},{"source":"RWWA","target":"PER","count":1},{"source":"RWWA","target":"RWWA","count":1},{"source":"SCOR","target":"SCOR","count":5},{"source":"SPK","target":"INT","count":4},{"source":"SPK","target":"ITS","count":4},{"source":"SPK","target":"SPK","count":21},{"source":"TS","target":"CS","count":1},{"source":"TS","target":"TS","count":10}];

var nodes_data = [{"name":"ABS","total":11},{"name":"ATS","total":23},{"name":"CR","total":25},{"name":"ENV","total":3},{"name":"INT","total":78},{"name":"ITS","total":177},{"name":"PDG","total":28},{"name":"PER","total":33},{"name":"PRAC","total":4},{"name":"AC","total":2},{"name":"ACDC","total":1},{"name":"APL","total":10},{"name":"LA","total":20},{"name":"PEG","total":53},{"name":"AST","total":21},{"name":"COP","total":2},{"name":"DBT","total":3},{"name":"DEVOPS","total":1},{"name":"IGN","total":18},{"name":"CAR","total":11},{"name":"LOT","total":18},{"name":"ICS","total":1},{"name":"NRB","total":4},{"name":"ONT","total":1},{"name":"INFRA","total":1},{"name":"RPT","total":11},{"name":"RTR","total":1},{"name":"RWWA","total":1},{"name":"SCOR","total":5},{"name":"SPK","total":21},{"name":"CS","total":1},{"name":"TS","total":10}];

//create node size scale
var nodeSizeScale = d3.scaleLinear()
.domain(d3.extent(nodes_data, d => d.total))
.range([30, 70]);

//create node size scale
var linkSizeScale = d3.scaleLinear()
.domain(d3.extent(links_data, d => d.count))
.range([5, 30]);

//create node size scale
var linkColourScale = d3.scaleLinear()
.domain(d3.extent(links_data, d => d.count))
.range(['blue', 'red']);

//document.getElementsByTagName('body')[0].innerHTML = '<div>' + JSON.stringify(nodes_data) + '</div>';

//create somewhere to put the force directed graph
var height = 650,
width = 950;

var svg = d3.select("body").append("svg")
.attr('width',width)
.attr('height',height);

var radius = 15;


//set up the simulation and add forces
var simulation = d3.forceSimulation()
.nodes(nodes_data);

var link_force = d3.forceLink(links_data)
.id(function(d) { return d.name; })
;

var charge_force = d3.forceManyBody()
.strength(-1000);

var center_force = d3.forceCenter(width / 2, height / 2);

simulation
.force("charge_force", charge_force)
.force("center_force", center_force)
.force("link",link_force)
;

//add tick instructions:
simulation.on("tick", tickActions );

// THIS CODE SECTION ISN'T RENDERING
// Per-type markers, as they don't inherit styles.
svg.append("defs").selectAll("marker")
.data(["dominating"])
.enter().append("marker")
.attr('markerUnits', 'userSpaceOnUse')
.attr("id", function (d) {
return d;
})
.attr("viewBox", "0 -5 10 10")
.attr("refX", 0)
.attr("refY", 0)
.attr("markerWidth", 12)
.attr("markerHeight", 12)
.attr("orient", "auto-start-reverse")
.append("path")
.attr("d", "M0,-5L10,0L0,5")
.attr("fill", "red");

//add encompassing group for the zoom
var g = svg.append("g")
.attr("class", "everything");

// add the curved links to our graphic
var link = g.selectAll(".link")
.data(links_data)
.enter()
.append("path")
.attr("class", "link")
.style('stroke', d => {return linkColourScale(d.count);})
.attr('stroke-opacity', 0.5)
.attr('stroke-width', d => {return linkSizeScale(d.count);})
.attr("marker-end", function(d) {
if(JSON.stringify(d.target) !== JSON.stringify(d.source))
return "url(#dominating)";
});

//draw circles for the nodes
var node = g.append("g")
.attr("class", "nodes")
.selectAll("circle")
.data(nodes_data)
.enter()
.append("circle")
.attr("r", d => {return nodeSizeScale(d.total);})
.attr("fill", "#333")
.on("mouseover", mouseOver(.1))
.on("mouseout", mouseOut);

//add text labels
var text = g.append("g")
.attr("class", "labels")
.selectAll("text")
.data(nodes_data)
.enter().append("text")
.style("text-anchor","middle")
.style("font-weight", "bold")
.style("pointer-events", "none")
.attr("dy", ".35em")
.text(function(d) { return d.name });

//add drag capabilities
var drag_handler = d3.drag()
.on("start", drag_start)
.on("drag", drag_drag)
.on("end", drag_end);

drag_handler(node);


//add zoom capabilities
var zoom_handler = d3.zoom()
.on("zoom", zoom_actions);

zoom_handler(svg);

/** Functions **/

//Drag functions
//d is the node
function drag_start(d) {
if (!d3.event.active) simulation.alphaTarget(0.3).restart();
d.fx = d.x;
d.fy = d.y;
}

//make sure you can't drag the circle outside the box
function drag_drag(d) {
d.fx = d3.event.x;
d.fy = d3.event.y;
}

function drag_end(d) {
if (!d3.event.active) simulation.alphaTarget(0);
d.fx = null;
d.fy = null;
}

//Zoom functions
function zoom_actions(){
g.attr("transform", d3.event.transform)
}

function tickActions() {
//update circle positions each tick of the simulation
node
.attr("cx", function(d) { return d.x; })
.attr("cy", function(d) { return d.y; });

//update link positions
link.attr("d", positionLink1);
link.filter(function(d){ return JSON.stringify(d.target) !== JSON.stringify(d.source); })
.attr("d",positionLink2);

text.attr("x", function(d) { return d.x; })
.attr("y", function(d) { return d.y; });
}


function positionLink1(d) {
var dx = d.target.x - d.source.x,
dy = d.target.y - d.source.y,
dr = Math.sqrt(dx * dx + dy * dy);
return "M" + d.source.x + "," + d.source.y + "A" + dr + "," + dr + " 0 0,1 " + d.target.x + "," + d.target.y;
}

// recalculate and back off the distance
function positionLink2(d) {
// length of current path
var pl = this.getTotalLength(),
// radius of circle plus marker head
r = nodeSizeScale(d.target.total)+ 12, //12 is the "size" of the marker Math.sqrt(12**2 + 12 **2)
// position close to where path intercepts circle
m = this.getPointAtLength(pl - r);

var dx = m.x - d.source.x,
dy = m.y - d.source.y,
dr = Math.sqrt(dx * dx + dy * dy);

return "M" + d.source.x + "," + d.source.y + "A" + dr + "," + dr + " 0 0,1 " + m.x + "," + m.y;
}

// build a dictionary of nodes that are linked
var linkedByIndex = {};
links_data.forEach(function(d) {
linkedByIndex[d.source.index + "," + d.target.index] = 1;
});

// check the dictionary to see if nodes are linked
function isConnected(a, b) {
return linkedByIndex[a.index + "," + b.index] || linkedByIndex[b.index + "," + a.index] || a.index == b.index;
}

// fade nodes on hover
function mouseOver(opacity) {
return function(d) {
// check all other nodes to see if they're connected
// to this one. if so, keep the opacity at 1, otherwise
// fade
node.style("stroke-opacity", function(o) {
thisOpacity = isConnected(d, o) ? 1 : opacity;
return thisOpacity;
});
node.style("fill-opacity", function(o) {
thisOpacity = isConnected(d, o) ? 1 : opacity;
return thisOpacity;
});
text.style("fill-opacity", function(o) {
thisOpacity = isConnected(d, o) ? 1 : opacity;
return thisOpacity;
});
// also style link accordingly
link.style("stroke-opacity", function(o) {
return o.source === d || o.target === d ? 1 : opacity;
});
link.style("stroke", function(o) {
return o.source === d || o.target === d ? linkColourScale(o.count) : "#333";
});
};
}

function mouseOut() {
node.style("stroke-opacity", 1);
node.style("fill-opacity", 1);
text.style("fill-opacity", 1);
link.style("stroke-opacity", 0.5);
link.style("stroke", d => {return linkColourScale(d.count);});
}
body {
width:99%;
height:100%;
background: #111111;
}

.svg {
width:1000;
height:1000;
}

.link {
fill: none;
}

.labels {
font-family: Arial;
fill: white;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>

关于javascript - d3 v4 向力导向图添加箭头,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52075326/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com