在 d3.js v6+ 中将元素标记为已单击
Mark element as clicked in d3.js v6+
我的问题: 我有一些数据点绑定到圆形元素。现在,每次用户点击一个圆圈时,我都想将其颜色更改为红色。为此,我想使用一个更新函数,每次用户点击一个圆圈时都会调用该函数。由于我不仅要更改单击的圆圈,还要更改基于单击哪个圆圈的其他元素,因此我需要以某种方式记住单击的是哪个圆圈。我在 d3.js v3 中看到这是通过简单地将数据保存到事件侦听器中的变量 (clickedCircle
) 并在稍后调用它来完成的。但是,这似乎不再适用于 d3.js v6+。在 v6+ 中执行此操作的最佳方法是什么?
快速 d3.js v3 示例(改编自 this chart 的基本思想):
var data = [
{x: 10, y: 20},
{x: 30, y: 10},
{x: 20, y: 55},
];
svg = d3.select(#div1)
.append("svg")
.attr("width", 100)
.attr("height", 100)
;
var circles;
var clickedCircle;
function update() {
circles = svg.selectAll("circle")
.data(data)
.enter()
.append("circle")
.attr("cx", function(d) { return d.position.x } )
.attr("cy", function(d) { return d.position.y } )
.attr("r", 10)
.on("click", function(e, d) { clickedCircle = d; update(); } )
;
circles
.style("fill", function(d) {
if (d === clickedCircle) {
return "red"
} else {
return "black"
}
})
;
}
这是 D3 v7 的示例。如果您单击一个圆圈,该圆圈将变为红色并且其数据显示在文本标签中。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<script src="https://d3js.org/d3.v7.js"></script>
</head>
<body>
<div id="chart"></div>
<script>
// margin convention set up
const margin = { top: 10, bottom: 10, left: 10, right: 10 };
const width = 110 - margin.left - margin.right;
const height = 110 - margin.top - margin.bottom;
const svg = d3.select('#chart')
.append('svg')
.attr('width', width + margin.left + margin.right)
.attr('height', height + margin.top + margin.bottom);
const g = svg.append('g')
.attr('transform', `translate(${margin.left},${margin.top})`);
// data
const data = [
{ x: 10, y: 20 },
{ x: 30, y: 10 },
{ x: 20, y: 55 },
];
// draw cirlces
const circles = g.selectAll('circle')
.data(data)
.join('circle')
.attr('cx', d => d.x)
.attr('cy', d => d.y)
.attr('r', 10)
.attr('fill', 'black')
.on('click', update);
// text label
const label = g.append('text')
.attr('y', height);
// update when circle is clicked
function update(event, d) {
// reset all circles to black
circles.attr('fill', 'black');
// color the clicked circle red
d3.select(this).attr('fill', 'red');
// update the label
label.text(`x: ${d.x}, y: ${d.y}`);
}
</script>
</body>
</html>
我的问题: 我有一些数据点绑定到圆形元素。现在,每次用户点击一个圆圈时,我都想将其颜色更改为红色。为此,我想使用一个更新函数,每次用户点击一个圆圈时都会调用该函数。由于我不仅要更改单击的圆圈,还要更改基于单击哪个圆圈的其他元素,因此我需要以某种方式记住单击的是哪个圆圈。我在 d3.js v3 中看到这是通过简单地将数据保存到事件侦听器中的变量 (clickedCircle
) 并在稍后调用它来完成的。但是,这似乎不再适用于 d3.js v6+。在 v6+ 中执行此操作的最佳方法是什么?
快速 d3.js v3 示例(改编自 this chart 的基本思想):
var data = [
{x: 10, y: 20},
{x: 30, y: 10},
{x: 20, y: 55},
];
svg = d3.select(#div1)
.append("svg")
.attr("width", 100)
.attr("height", 100)
;
var circles;
var clickedCircle;
function update() {
circles = svg.selectAll("circle")
.data(data)
.enter()
.append("circle")
.attr("cx", function(d) { return d.position.x } )
.attr("cy", function(d) { return d.position.y } )
.attr("r", 10)
.on("click", function(e, d) { clickedCircle = d; update(); } )
;
circles
.style("fill", function(d) {
if (d === clickedCircle) {
return "red"
} else {
return "black"
}
})
;
}
这是 D3 v7 的示例。如果您单击一个圆圈,该圆圈将变为红色并且其数据显示在文本标签中。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<script src="https://d3js.org/d3.v7.js"></script>
</head>
<body>
<div id="chart"></div>
<script>
// margin convention set up
const margin = { top: 10, bottom: 10, left: 10, right: 10 };
const width = 110 - margin.left - margin.right;
const height = 110 - margin.top - margin.bottom;
const svg = d3.select('#chart')
.append('svg')
.attr('width', width + margin.left + margin.right)
.attr('height', height + margin.top + margin.bottom);
const g = svg.append('g')
.attr('transform', `translate(${margin.left},${margin.top})`);
// data
const data = [
{ x: 10, y: 20 },
{ x: 30, y: 10 },
{ x: 20, y: 55 },
];
// draw cirlces
const circles = g.selectAll('circle')
.data(data)
.join('circle')
.attr('cx', d => d.x)
.attr('cy', d => d.y)
.attr('r', 10)
.attr('fill', 'black')
.on('click', update);
// text label
const label = g.append('text')
.attr('y', height);
// update when circle is clicked
function update(event, d) {
// reset all circles to black
circles.attr('fill', 'black');
// color the clicked circle red
d3.select(this).attr('fill', 'red');
// update the label
label.text(`x: ${d.x}, y: ${d.y}`);
}
</script>
</body>
</html>