d3.js - D3 在 v6 中拖放并单击分组对象
问题描述
根据Mike 的示例,我试图弄清楚如何将概念转移到分组元素。我可以单独创建启动拖动和单击,但在一起我似乎无法单击工作。下面是一个片段——这只是我使用过的许多方法中的一种。
const width = 400;
const height = 300;
const radius = 5;
const svg = d3.select("#chart").append('svg')
.attr('width', '400')
.attr('height', '400')
.style('border', 'solid 1px');
const circles = d3.range(20).map(i => ({
x: Math.random() * (width - radius * 2) + radius,
y: Math.random() * (height - radius * 2) + radius,
index: i
}));
const group = svg.selectAll("g").data(circles).enter()
.append("g")
.attr("cx", d => d.x)
.attr("cy", d => d.y)
.call(d3.drag()
.on("start", dragstarted)
.on("drag", dragged)
.on("end", dragended))
group.append("circle")
.attr("cx", d => d.x)
.attr("cy", d => d.y)
.attr("r", radius)
.attr("fill", d => d3.schemeCategory10[d.index % 10])
.on("click", clicked);
group.append("text")
.attr("x", d => d.x)
.attr("y", d => d.y)
.style("fill", 'white')
.text('a')
function clicked(event, d) {
if (event.defaultPrevented) return; // dragged
d3.select(this).transition()
.attr("fill", "black")
.attr("r", radius * 2)
.transition()
.attr("r", radius)
.attr("fill", d3.schemeCategory10[d.index % 10]);
}
function dragstarted() {
d3.select(this).attr("stroke", "black");
}
function dragged(event, d) {
d3.select(this).raise().attr("cx", d.x = event.x).attr("cy", d.y = event.y);
}
function dragended() {
d3.select(this).attr("stroke", null);
}
<script src="https://d3js.org/d3.v6.js"></script>
<div id="chart"></div>
解决方案
关键问题是您g
使用cx
,属性定位每个cy
属性,并在拖动时更新这些属性。g
元素不能通过cx
or定位cy
,因此最初设置这些元素并在拖动时更新它们不会导致任何变化。
您需要g
使用翻译定位元素:
.attr("transform", d=> "translate("+[d.x,d.y]+")" )
此外,您现在不需要定位圆圈和文本 - 或者每个 x 和 y 坐标将应用两次 - 一次应用于g
子元素,一次应用于子元素。
现在您只需要在每次拖动时更新翻译,例如:
function drag(event,d) {
d.x = event.x;
d.y = event.y;
d3.select(this).raise().attr("transform", d=> "translate("+[d.x,d.y]+")" )
}
这应该给你类似的东西:
const width = 400;
const height = 300;
const radius = 5;
const svg = d3.select("#chart").append('svg')
.attr('width', '400')
.attr('height', '400')
.style('border', 'solid 1px');
const circles = d3.range(20).map(i => ({
x: Math.random() * (width - radius * 2) + radius,
y: Math.random() * (height - radius * 2) + radius,
index: i
}));
const group = svg.selectAll("g").data(circles).enter()
.append("g")
.attr("transform", d=> "translate("+[d.x,d.y]+")" )
.call(d3.drag()
.on("start", dragstarted)
.on("drag", dragged)
.on("end", dragended))
group.append("circle")
.attr("r", radius)
.attr("fill", d => d3.schemeCategory10[d.index % 10])
.on("click", clicked);
group.append("text")
.style("fill", 'white')
.text('a')
function clicked(event, d) {
if (event.defaultPrevented) return; // dragged
d3.select(this).transition()
.attr("fill", "black")
.attr("r", radius * 2)
.transition()
.attr("r", radius)
.attr("fill", d3.schemeCategory10[d.index % 10]);
}
function dragstarted() {
d3.select(this).attr("stroke", "black");
}
function dragged(event, d) {
d.x = event.x;
d.y = event.y;
d3.select(this).raise().attr("transform", d=> "translate("+[d.x,d.y]+")" )
}
function dragended() {
d3.select(this).attr("stroke", null);
}
<script src="https://d3js.org/d3.v6.js"></script>
<div id="chart"></div>
推荐阅读
- javascript - Angular Universal ReferenceError - KeyboardEvent 未定义
- javascript - 如何在只占用空间但不显示文本时显示我的 html 内部文本?
- python - 如何使用 Scrapy 在 MYSQL 上创建表
- html - 将 HTML 表格(用户输入)传输到 Google 表格
- opencv - 首先lazyimported cv2时导入torch失败
- performance - C/C++ 最相关的性能指标
- django - 如何在 Django 中提供包含静态 html 文件的“Docs”文件夹?
- wpf - WPF如何编写触发器来调用命令操作或根据条件设置属性
- swift - 试图找到一种更简单的方法来自动反转 .on 和 off。迅速状态
- ruby - ActiveRecord::ValueTooLong 与 Ruby Gem Mail