I want to create an interactive scatter plot graph with the x-axis ranging from 24 to 48 and the y-axis ranging from 10,000 to 100,000. The points should be able to be moved by the user by dragging them, following the cursor.
Currently, when I try to drag a point, it snaps to the bottom of the graph and can only move on the x-axis. I have tried searching for solutions and using chatgpt but they did not work.
This is my code:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Interactive D3 Chart</title>
<script src="https://d3js.org/d3.v6.min.js"></script>
<style>
.axis path,
.axis line {
fill: none;
shape-rendering: crispEdges;
}
.axis text {
font-size: 12px;
}
.dot {
fill: steelblue;
stroke: #000;
stroke-width: 1.5px;
}
.dragging {
fill: orange;
}
</style>
</head>
<body>
<script>
// Set dimensions and margins of the graph
const margin = { top: 20, right: 30, bottom: 40, left: 50 },
width = 800 - margin.left - margin.right,
height = 600 - margin.top - margin.bottom;
// Append the svg object to the body of the page
const svg = d3.select("body").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", `translate(${margin.left},${margin.top})`);
// X scale and axis
const x = d3.scaleLinear()
.domain([24, 48])
.range([0, width]);
svg.append("g")
.attr("transform", `translate(0,${height})`)
.call(d3.axisBottom(x));
// Y scale and axis
const y = d3.scaleLinear()
.domain([10000, 100000])
.range([height, 0]);
svg.append("g")
.call(d3.axisLeft(y));
// Initial data points
const data = [
{x: 30, y: 20000},
{x: 35, y: 50000},
{x: 40, y: 75000},
];
// Create and place the "dots"
const dots = svg.selectAll(".dot")
.data(data)
.enter().append("circle")
.attr("class", "dot")
.attr("cx", d => x(d.x))
.attr("cy", d => y(d.y))
.attr("r", 5)
.call(d3.drag()
.on("start", dragstarted)
.on("drag", dragged)
.on("end", dragended)
);
function dragstarted(event, d) {
d3.select(this).raise().classed("dragging", true);
}
function dragged(event, d) {
const newX = x.invert(event.x);
const newY = y.invert(event.y);
d.x = Math.max(24, Math.min(48, newX));
d.y = Math.max(10000, Math.min(100000, newY));
d3.select(this)
.attr("cx", x(d.x))
.attr("cy", y(d.y));
}
function dragended(event, d) {
d3.select(this).classed("dragging", false);
}
</script>
</body>
</html>