Новое для d3. У меня небольшие проблемы с обработчиками событий mouseover и mouseout.
Я хотел разделить круги дальше друг от друга, когда круг выбирается с помощью функции forceCollide. Это работает один раз, а затем круги будут либо поддерживать значение mouseout или mouseover forceCollide, а не возвращаться в исходное состояние.
Любое направление на то, что я делаю неправильно, оценивается.
В то время как я нахожусь в этом, я также не могу получить функции mouseover, чтобы работать, если я пишу их в синтаксисе ES6, любая помощь с этим тоже будет большой, но это может быть по другому вопросу.
Я вставил свой код ниже.
d3.csv('../csv/homeless_population.csv')
.row((data) => {
return {
State: data.State,
PercentHomeless: Number(data.Homeless) / Number(data.Population)
};
})
.get((error, data) => {
let width = 650;
let height = 600;
let maxRadius = d3.max(data, (data) => { return data.PercentHomeless; })
let minRadius = d3.min(data, (data) => { return data.PercentHomeless; })
let svg = d3.selectAll('section')
.append('svg')
.attr('height', height)
.attr('width', width)
.append('g')
.attr('transform', 'translate(0, 0)')
let colors = d3.scaleOrdinal(d3.schemePaired);
let simulation = d3.forceSimulation()
.force('x', d3.forceX(width/2).strength(0.5))
.force('y', d3.forceY(height/2).strength(0.5))
.force('collide', d3.forceCollide((data) => { return r(data.PercentHomeless) + 3; }))
let r = d3.scaleSqrt()
.domain([minRadius, maxRadius])
.range([15,75])
let circles = svg.selectAll('circles')
.data(data)
.enter()
.append('circle')
.attr('stroke', 'black')
.attr('fill', (data) => { return colors(data.State); })
.attr('r', (data) => { return r(data.PercentHomeless); })
.on('mouseover', mouseOn)
.on('mouseout', mouseOff)
function mouseOn(data) {
circles
.attr('opacity', 0.5)
d3.select(this)
.attr('r', r(data.PercentHomeless) * 1.5)
.style('opacity', 1)
simulation
.force('collide', d3.forceCollide((data) => { return r(data.PercentHomeless * 1.5) + 3; }))
}
function mouseOff(data) {
d3.select(this)
.attr('r', r(data.PercentHomeless))
circles
.attr('opacity', 1)
simulation
.force('collide', d3.forceCollide((data) => { return r(data.PercentHomeless) + 3; }))
}
let texts = svg.selectAll(null)
.data(data)
.enter()
.append('text')
.text((data) => { return data.State; } )
.attr('color', 'black')
.attr('font-size', 10)
let ticked = () => {
circles
.attr('cx', (data) => { return data.x; })
.attr('cy', (data) => { return data.y; })
texts
.attr('x', (data) => { return data.x; })
.attr('y', (data) => { return data.y; })
};
simulation.nodes(data)
.on('tick', ticked)
});
На самом деле события мыши работают каждый раз. С другой стороны, симуляция остыла после первого события мыши и почему вы не видите никаких изменений в позициях кругов.
Поэтому вам нужно повторно mouseOn
симуляцию в ваших mouseOn
и mouseOff
. Например:
simulation.alpha(0.8).restart();
Вот демонстрация с использованием упрощенного кода (поскольку у меня нет доступа к вашим данным). Наведите указатель мыши на круги:
var svg = d3.select("svg");
var colour = d3.scaleOrdinal(d3.schemeCategory10);
var data = d3.range(30).map(d => ({
r: 6
}));
var simulation = d3.forceSimulation(data)
.force("x", d3.forceX(150).strength(0.05))
.force("y", d3.forceY(75).strength(0.05))
.force("collide", d3.forceCollide(function(d) {
return d.r + 1;
}));
var circles = svg.selectAll(".circles")
.data(data)
.enter()
.append("circle")
.attr("r", d => d.r)
.attr("fill", (d, i) => colour(i));
circles.on('mouseover', mouseOn)
.on('mouseout', mouseOff)
simulation.nodes(data)
.on("tick", d => {
circles.attr("cx", d => d.x).attr("cy", d => d.y);
});
function mouseOn() {
circles.attr('opacity', 0.5)
d3.select(this)
.attr('r', d => d.r * 1.5);
simulation.force("collide", d3.forceCollide(function(d) {
return d.r * 1.5 + 1;
}));
simulation.alpha(0.8).restart();
}
function mouseOff() {
d3.select(this)
.attr('r', d => d.r);
circles.attr('opacity', 1);
simulation.force("collide", d3.forceCollide(function(d) {
return d.r + 1;
}));
simulation.alpha(0.8).restart();
}
<script src="https://d3js.org/d3.v4.min.js"></script>
<svg></svg>
PS: Вам не нужно передавать data
в функции mouseOn
и mouseOff
.
this
в обработчиках событий? Вот почему функция стрелка не будет работать здесь.