d3js 坐标轴和抛物线(可以拖拽改变形状,复制 删除)
时间: 2024-12-07 17:13:17
(部分内容来自网络,其真实性存疑,为了避免对您造成误导,请谨慎甄别。)
要使用 D3.js 实现带有坐标轴的抛物线,并且可以通过拖拽改变抛物线的形状、复制和删除它,下面是一个完整的示例。
示例代码
以下代码创建了一个 SVG 画布,添加坐标轴,并在上面绘制可拖拽的抛物线。用户可以通过按钮复制、删除抛物线以及拖拽来改变它的形状。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="https://d3js.org/d3.v7.min.js"></script>
<title>D3.js 坐标轴与可拖拽抛物线示例</title>
<style>
svg {
border: 1px solid #ccc;
}
.curve {
fill: none;
stroke: orange;
stroke-width: 2;
cursor: pointer;
}
.control-point {
fill: red;
cursor: pointer;
}
</style>
</head>
<body>
<button id="addParabola">添加抛物线</button>
<button id="deleteParabola">删除抛物线</button>
<button id="cloneParabola">复制抛物线</button>
<svg width="800" height="400"></svg>
<script>
const svg = d3.select("svg");
const width = +svg.attr("width");
const height = +svg.attr("height");
// 添加坐标轴
const xScale = d3.scaleLinear().domain([0, 800]).range([0, width]);
const yScale = d3.scaleLinear().domain([400, 0]).range([0, height]);
// 绘制 X 轴
svg.append("g")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(xScale));
// 绘制 Y 轴
svg.append("g")
.call(d3.axisLeft(yScale));
let parabolas = []; // 存储抛物线的控制点
let selectedParabola = null;
// 添加抛物线
d3.select("#addParabola").on("click", function() {
const points = [
{ x: 100, y: 300 }, // 顶点
{ x: 400, y: 100 }, // 控制点
{ x: 700, y: 300 } // 终点
];
parabolas.push(points);
renderParabola(points);
});
// 渲染抛物线
function renderParabola(points) {
const lineGenerator = d3.line()
.curve(d3.curveBasisX)
.x(d => xScale(d.x))
.y(d => yScale(d.y));
// 绘制抛物线路径
const path = svg.append("path")
.attr("class", "curve")
.attr("d", lineGenerator(points))
.on("click", function() {
if (selectedParabola) {
selectedParabola.classed("selected", false);
}
selectedParabola = d3.select(this);
selectedParabola.classed("selected", true);
})
.call(d3.drag()
.on("start", dragstarted)
.on("drag", dragged)
.on("end", dragended));
// 绘制控制点
const controlPoints = svg.selectAll(".control-point")
.data(points)
.enter().append("circle")
.attr("class", "control-point")
.attr("r", 5)
.attr("cx", d => xScale(d.x))
.attr("cy", d => yScale(d.y))
.call(d3.drag()
.on("start", dragControlPointStarted)
.on("drag", dragControlPointDragged)
.on("end", dragControlPointEnded));
// 更新路径
function updatePath() {
path.attr("d", lineGenerator(points));
controlPoints
.attr("cx", d => xScale(d.x))
.attr("cy", d => yScale(d.y));
}
function dragstarted(event) {
d3.select(this).raise();
}
function dragged(event) {
const dx = event.dx * (width / xScale.domain()[1]);
const dy = -event.dy * (height / yScale.domain()[1]);
points.forEach(p => {
p.x += dx;
p.y += dy;
});
updatePath();
}
// 控制点拖拽
function dragControlPointStarted(event) {
d3.select(this).raise().classed("active", true);
}
function dragControlPointDragged(event, d) {
const newX = xScale.invert(d3.pointer(event)[0]);
const newY = yScale.invert(d3.pointer(event)[1]);
d.x = newX;
d.y = newY;
updatePath();
}
function dragControlPointEnded(event) {
d3.select(this).classed("active", false);
}
}
// 删除选中的抛物线
d3.select("#deleteParabola").on("click", function() {
if (selectedParabola) {
selectedParabola.remove();
selectedParabola = null;
svg.selectAll(".control-point").remove(); // 移除控制点
parabolas.pop(); // 从数组中移除抛物线
}
});
// 复制选中的抛物线
d3.select("#cloneParabola").on("click", function() {
if (selectedParabola) {
const selectedPoints = parabolas.find(points => {
const path = svg.selectAll(".curve").nodes().indexOf(selectedParabola.node());
return points === path;
});
if (selectedPoints) {
const newPoints = selectedPoints.map(p => ({ x: p.x + 20, y: p.y + 10 })); // 复制偏移
parabolas.push(newPoints);
renderParabola(newPoints);
}
}
});
</script>
</body>
</html>代码解释
SVG 和坐标轴:
创建一个 800x400 大小的 SVG,并在其上面添加 X 轴和 Y 轴。
存储抛物线:
用一个数组 parabolas 存储所有的抛物线的控制点,selectedParabola 用于存储当前选中的抛物线。
添加抛物线:
点击“添加抛物线”按钮时,初始化一条抛物线并在 SVG 上渲染。
渲染抛物线:
使用 D3 的 line 生成器和 curveBasisX 来创建一条平滑的抛物线,并根据控制点绘制。
拖拽功能:
通过拖拽事件,用户可以整体改变抛物线的位置,或移动控制点以改变其形状。
删除和复制抛物线:
可以通过按钮删除当前选中的抛物线,或复制当前选中的抛物线。
使用说明
添加抛物线: 点击 "添加抛物线" 按钮将创建一条新的抛物线。
拖动抛物线: 点击并拖动已绘制的抛物线来移动它。
拖动控制点: 可以拖动红色的控制点来修改抛物线的形状。
删除和复制: 点击 "删除抛物线" 按钮删除选中的抛物线;点击 "复制抛物线" 按钮将复制选中的抛物线,并略微偏移位置。
将上述代码粘贴到一个 HTML 文件中并在浏览器中打开,就可以体验整个功能。如果你有其他需求或者想了解更多细节,欢迎随时告诉我!