#javascript #html #css #d3.js #display
Вопрос:
Я пытаюсь добавить два визуальных элемента d3 в свой index.html страница, но одновременно отображается только один из визуальных элементов. Два визуальных элемента используют один и тот же код, и единственное различие заключается в используемых данных. Они хорошо работают по отдельности, но я не могу заставить их появляться на одной странице вместе.
var margins = {
top: 20,
bottom: 300,
left: 30,
right: 100
};
var height = 800;
var width = 500;
var totalWidth = width margins.left margins.right;
var totalHeight = height margins.top margins.bottom;
var svg = d3.select('body')
.append('svg')
.attr('width', totalWidth)
.attr('height', totalHeight);
var graphGroup = svg.append('g')
.attr('transform', "translate(" margins.left "," margins.top ")");
var levels = [
[
{id: 'Gaia'},
{id:'Ouranos', parents:['Gaia']}
],
[
{id:'Aphrodite', parents:['Ouranos']},
{id: 'Themis', parents: ['Gaia', 'Ouranos']},
{id: 'Mnemosyne', parents: ['Gaia', 'Ouranos']},
{id: 'Hyperion', parents: ['Gaia', 'Ouranos']},
{id: 'Thea', parents: ['Gaia', 'Ouranos']},
{id: 'Crius', parents: ['Gaia', 'Ouranos']},
{id: 'Oceanus', parents: ['Gaia', 'Ouranos']},
{id: 'Tethys', parents: ['Gaia', 'Ouranos']},
{id: 'Iapetus', parents: ['Gaia', 'Ouranos']},
{id: 'Coeus', parents: ['Gaia', 'Ouranos']},
{id: 'Phoebe', parents: ['Gaia','Ouranos']},
{id: 'Kronos', parents: ['Gaia', 'Ouranos']},
{id: 'Rhea', parents: ['Gaia', 'Ouranos']},
],
[
{id: 'Pleione', parents:['Oceanus','Tethys']},
{id:'Atlas',parents:['Iapetus']},
{id:'Semele'},
{id:'Maia', parents:['Pleione','Atlas']},
{id:'Leto',parents:['Coeus','Phoebe']},
{id:'Zeus',parents:['Kronos','Rhea']},
{id:'Hera',parents:['Kronos','Rhea']},
{id:'Poseidon',parents:['Kronos','Rhea']},
{id:'Amphitrite'},
{id:'Hestia',parents:['Kronos','Rhea']},
{id:'Hades',parents:['Kronos','Rhea']},
{id:'Demeter',parents:['Kronos','Rhea']},
],
[
{id:'Dionysus',parents:['Semele','Zeus']},
{id:'Hermes',parents:['Maia','Zeus']},
{id:'Apollo',parents:['Leto','Zeus']},
{id:'Artemis',parents:['Leto','Zeus']},
{id:'Athena',parents:['Zeus']},
{id:'Ares',parents:['Zeus','Hera']},
{id:'Hephaistos',parents:['Zeus','Hera']},
{id:'Hebe',parents:['Zeus','Hera']},
{id:'Triton',parents:['Poseidon','Amphitrite']},
{id:'Benthesikyme',parents:['Poseidon','Amphitrite']},
{id:'Rhodos',parents:['Poseidon','Amphitrite']},
{id:'Persephone',parents:['Zeus','Demeter']},
{id:'Zagreus', parents:['Hades','Persephone']},
{id:'Macaria', parents:['Hades','Persephone']}
]
]
// precompute level depth
levels.forEach((l, i) => l.forEach(n => n.level = i));
var nodes = levels.reduce(((a, x) => a.concat(x)), []);
var nodes_index = {};
nodes.forEach(d => nodes_index[d.id] = d);
// objectification
nodes.forEach(d => {
d.parents = (d.parents === undefined ? [] : d.parents).map(p => nodes_index[p])
})
// precompute bundles
levels.forEach((l, i) => {
var index = {}
l.forEach(n => {
if (n.parents.length == 0) {
return
}
var id = n.parents.map(d => d.id).sort().join('--')
if (id in index) {
index[id].parents = index[id].parents.concat(n.parents)
} else {
index[id] = {
id: id,
parents: n.parents.slice(),
level: i
}
}
n.bundle = index[id]
})
l.bundles = Object.keys(index).map(k => index[k])
l.bundles.forEach((b, i) => b.i = i)
})
var links = []
nodes.forEach(d => {
d.parents.forEach(p => links.push({
source: d,
bundle: d.bundle,
target: p
}))
})
var bundles = levels.reduce(((a, x) => a.concat(x.bundles)), [])
// reverse pointer from parent to bundles
bundles.forEach(b => b.parents.forEach(p => {
if (p.bundles_index === undefined) {
p.bundles_index = {}
}
if (!(b.id in p.bundles_index)) {
p.bundles_index[b.id] = []
}
p.bundles_index[b.id].push(b)
}))
nodes.forEach(n => {
if (n.bundles_index !== undefined) {
n.bundles = Object.keys(n.bundles_index).map(k => n.bundles_index[k])
} else {
n.bundles_index = {}
n.bundles = []
}
n.bundles.forEach((b, i) => b.i = i)
})
links.forEach(l => {
if (l.bundle.links === undefined) {
l.bundle.links = []
}
l.bundle.links.push(l)
})
// layout
const padding = 20
const node_height = 22
const node_width = 70
const bundle_width = 14
const level_y_padding = 16
const metro_d = 4
const c = 16
const min_family_height = 16
nodes.forEach(n => n.height = (Math.max(1, n.bundles.length) - 1) * metro_d)
var x_offset = padding
var y_offset = padding
levels.forEach(l => {
x_offset = l.bundles.length * bundle_width
y_offset = level_y_padding
l.forEach((n, i) => {
n.x = n.level * node_width x_offset
n.y = node_height y_offset n.height / 2
y_offset = node_height n.height
})
})
var i = 0
levels.forEach(l => {
l.bundles.forEach(b => {
b.x = b.parents[0].x node_width (l.bundles.length - 1 - b.i) * bundle_width
b.y = i * node_height
})
i = l.length
})
links.forEach(l => {
l.xt = l.target.x
l.yt = l.target.y l.target.bundles_index[l.bundle.id].i * metro_d - l.target.bundles.length * metro_d / 2 metro_d / 2
l.xb = l.bundle.x
l.xs = l.source.x
l.ys = l.source.y
})
// compress vertical space
var y_negative_offset = 0
levels.forEach(l => {
y_negative_offset = -min_family_height d3.min(l.bundles, b => d3.min(b.links, link => (link.ys - c) - (link.yt c))) || 0
l.forEach(n => n.y -= y_negative_offset)
})
// very ugly, I know
links.forEach(l => {
l.yt = l.target.y l.target.bundles_index[l.bundle.id].i * metro_d - l.target.bundles.length * metro_d / 2 metro_d / 2
l.ys = l.source.y
l.c1 = l.source.level - l.target.level > 1 ? node_width c : c
l.c2 = c
})
const cluster = d3.cluster()
.size([width, height]);
const root = d3.hierarchy(links);
cluster(root);
let oValues = Object.values(root)[0];
let linkks = oValues.map(x => x.bundle.links);
linkks.forEach((linkk) => {
//nodeG1 are nodes that have children
let nodeG1 = svg.append("g")
.selectAll("circle")
.data(linkk)
.join("circle")
.attr("cx", d => d.target.x)
.attr("cy", d => d.target.y)
.attr("fill", "lightblue")
.attr("stroke", (d) => {
return '#' Math.floor(16777215 * Math.sin(3 * Math.PI / (5 * (parseInt(d.target.level) 1)))).toString(16);
})
.attr("r", 6);
//nodeG11 are nodes that have parents
let nodeG11 = svg.append("g")
.selectAll("circle")
.data(linkk)
.join("circle")
.attr("cx", d => d.source.x)
.attr("cy", d => d.source.y)
.attr("fill", "gray")
.attr("stroke", (d) => {
return '#' Math.floor(16777215 * Math.sin(3 * Math.PI / (5 * (parseInt(d.source.level) 1)))).toString(16);
})
.attr("r", 6);
let nodeG2 = svg.append("g")
.attr("font-family", "papyrus")
.attr("font-size", 16)
.selectAll("text")
.data(linkk)
.join("text")
.attr("class", "text")
.attr("x", d => d.target.x padding)
.attr("y", d => d.target.y)
.text(d => d.target.id )
.attr("fill", (d) => {
return '#' 0;
});
let nodeG22 = svg.append("g")
.attr("font-family", "papyrus")
.attr("font-size", 16)
.selectAll("text")
.data(linkk)
.join("text")
.attr("class", "text")
.attr("x", d => d.source.x padding)
.attr("y", d => d.source.y)
.text(d => d.source.id )
.attr("fill", (d) => {
return '#' 0;
});
let nodeG = svg.append('g')
.attr('class', 'node')
.selectAll("path")
.data(linkk)
.join('path')
.attr("class", "link")
.attr("d", d3.linkHorizontal()
.source(d => [d.xs, d.ys])
.target(d => [d.xt, d.yt]))
.attr("fill", "none")
.attr("stroke-opacity", 10)
.attr("stroke-width", .75)
.attr("stroke", (d) => {
return '#' Math.floor(16776960 * Math.sin(3 * Math.PI / (4 * parseInt(d.source.level)))).toString(16);
});
});
path {
display: block;
z-index: 0;
}
text,
circle {
display: block;
z-index: 1000;
}
<!DOCTYPE html>
<link rel="stylesheet" type="text/css" href="greek.css"/>
<link rel="stylesheet" type="text/css" href="main.css"/>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Here</title>
</head>
<body style="background-color: antiquewhite;">
<center>
<h style="font-size:50px">Greek and Norse Gods: </h>
</center>
<script src="https://d3js.org/d3.v5.min.js"></script>
<script src="greek.js"></script>
<script src="norse.js"></script>
</body>
</html>
Есть ли способ заставить два визуальных элемента появляться бок о бок?
Ответ №1:
Похоже, есть только один элемент svg. Я думаю, что вы добавляете обе древовидные структуры в один и тот же svg и элемент и перезаписываете первую со второй. Попробуйте создать два элемента svg и отдельно добавить греческий и норвежский узлы. У меня не было возможности проверить это, однако, может быть, это поможет.