Мне трудно проверить это без примера проекта, но я думаю, что вот что произошло:
К моменту запуска links.forEach(function (link) {
значение links
все еще имеет значение []
,потому что function
в $.getJSON('/visualizer', function(data) {
выполняется асинхронно и, скорее всего, произойдет после выполнения остальной части вашего кода.
Попробуйте модульный код инициализации и вызов его после асинхронного кода.Примерно так:
<script>
let numRequests = 0
let links = []
let nodes = {}
let link
let node
let testData = [{
"source": "Analytics",
"target": "Science"
}, {
"source": "Analytics",
"target": "Software"
}, {
"source": "Analytics",
"target": "Story"
}, {
"source": "Science",
"target": "Math"
}, {
"source": "Science",
"target": "Statistics"
}, {
"source": "Software",
"target": "R"
}, {
"source": "Software",
"target": "SAS"
}, {
"source": "Software",
"target": "Other"
}, {
"source": "Story",
"target": "Business Communication"
}, {
"source": "Story",
"target": "Visualization"
}]
const addIfUnique = (list, item) => list.indexOf(item) === -1 ? list.concat(item) : list
const byName = (links, {source, target}) => addIfUnique(addIfUnique(links, source), target)
const toNode = (name, i) => ({name, index: i})
function addLinks(data) {
let names = data.reduce(byName, [])
const toLink = ({source, target}) => ({
source: names.indexOf(source),
target: names.indexOf(target)
})
nodes = names.map(toNode)
links = data.map(toLink)
}
function tick() {
link.attr("x1", d => d.source.x)
.attr("y1", d => d.source.y)
.attr("x2", d => d.target.x)
.attr("y2", d => d.target.y)
node.attr("transform", d => `translate(${d.x},${d.y})`)
}
function mouseover() {
d3.select(this).select("circle").transition()
.duration(750)
.attr("r", 16)
}
function mouseout() {
d3.select(this).select("circle").transition()
.duration(750)
.attr("r", 12)
}
function click() {
d3.select(this).select("text").transition()
.duration(750)
.attr("x", 22)
.style("stroke-width", ".5px")
.style("opacity", 1)
.style("fill", "#E34A33")
.style("font", "17.5px serif")
d3.select(this).select("circle").transition()
.duration(750)
.style("fill", "#E34A33")
.attr("r", 16)
}
function dblclick() {
d3.select(this).select("circle").transition()
.duration(750)
.attr("r", 12)
.style("fill", "#E34A33")
d3.select(this).select("text").transition()
.duration(750)
.attr("x", 14)
.style("stroke", "none")
.style("fill", "#E34A33")
.style("stroke", "none")
.style("opacity", 0.6)
.style("font", "14px serif")
}
function drawGraph() {
const width = 900
const height = 300
const force = d3.layout.force()
.nodes(d3.values(nodes))
.links(links)
.size([width, height])
.linkDistance(50)
.charge(-200)
.on("tick", tick)
.start()
const svg = d3.select("#trythis").append("svg")
.attr("width", width)
.attr("height", height)
link = svg.selectAll(".link")
.data(force.links())
.enter().append("line")
.attr("class", "link")
node = svg.selectAll(".node")
.data(force.nodes())
.enter().append("g")
.attr("class", "node")
.on("mouseover", mouseover)
.on("mouseout", mouseout)
.on("click", click)
.on("dblclick", dblclick)
.call(force.drag)
node.append("circle")
.attr("r", 12)
.style("fill", "#C71585")
node.append("text")
.attr("x", 14)
.attr("dy", ".35em")
.style("fill", "#333")
.text(d => d.name)
}
function verifyItem1IsCorrect() {
const item1 = JSON.stringify(links[0])
console.log(`${item1} is links 0`)
}
function setUpGraph(data) {
addLinks(data)
drawGraph()
verifyItem1IsCorrect()
}
// $.getJSON('/visualizer', setUpGraph)
setUpGraph(testData)
</script>
РЕДАКТИРОВАТЬ : API D3.js v3 имеет очень специфическую разметку, необходимую для ссылок и узлов .
Массив узлов содержит объекты с простым целочисленным индексом и именем строки, а массив ссылок содержит объекты с атрибутами источника и назначения, но источник и цели должны быть либо:
- целые числа, относящиеся к индексам узлов;или
- ссылки на объекты на фактические узлы в массиве узлов.