Skip to content

Instantly share code, notes, and snippets.

@GeraldHost
Created January 12, 2021 21:05
Show Gist options
  • Save GeraldHost/10a094d6757d7acf2cb4ea8925af63bd to your computer and use it in GitHub Desktop.
Save GeraldHost/10a094d6757d7acf2cb4ea8925af63bd to your computer and use it in GitHub Desktop.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>The HTML5 Herald</title>
<meta name="description" content="The HTML5 Herald" />
<meta name="author" content="SitePoint" />
<link rel="stylesheet" href="css/styles.css?v=1.0" />
</head>
<body>
<script src="https://d3js.org/d3.v6.min.js"></script>
<script>
const width = 200;
const height = 200;
const radius = 10;
// https://stackoverflow.com/questions/33330074/d3-js-detect-intersection-area
function intersection(x0, y0, r0, x1, y1, r1) {
var a, dx, dy, d, h, rx, ry;
var x2, y2;
/* dx and dy are the vertical and horizontal distances between
* the circle centers.
*/
dx = x1 - x0;
dy = y1 - y0;
/* Determine the straight-line distance between the centers. */
d = Math.sqrt(dy * dy + dx * dx);
/* Check for solvability. */
if (d > r0 + r1) {
/* no solution. circles do not intersect. */
return false;
}
if (d < Math.abs(r0 - r1)) {
/* no solution. one circle is contained in the other */
return false;
}
/* 'point 2' is the point where the line through the circle
* intersection points crosses the line between the circle
* centers.
*/
/* Determine the distance from point 0 to point 2. */
a = (r0 * r0 - r1 * r1 + d * d) / (2.0 * d);
/* Determine the coordinates of point 2. */
x2 = x0 + (dx * a) / d;
y2 = y0 + (dy * a) / d;
/* Determine the distance from point 2 to either of the
* intersection points.
*/
h = Math.sqrt(r0 * r0 - a * a);
/* Now determine the offsets of the intersection points from
* point 2.
*/
rx = -dy * (h / d);
ry = dx * (h / d);
/* Determine the absolute intersection points. */
var xi = x2 + rx;
var xi_prime = x2 - rx;
var yi = y2 + ry;
var yi_prime = y2 - ry;
return [xi, xi_prime, yi, yi_prime];
}
const svg = d3
.create("svg")
.attr("viewBox", [0, 0, width, height])
.attr("stroke-width", 0.2);
var lineGraph = svg
.append("svg:svg")
.attr("width", width)
.attr("height", height);
// Using for loop to draw multiple horizontal lines
for (var j = 10; j <= width - 10; j = j + 10) {
lineGraph
.append("svg:line")
.attr("x1", 10)
.attr("y1", j)
.attr("x2", width - 10)
.attr("y2", j)
.style("stroke", "rgb(6,120,155)")
.style("stroke-width", 0.1);
}
// Using for loop to draw multiple vertical lines
for (var j = 10; j <= height - 10; j = j + 10) {
lineGraph
.append("svg:line")
.attr("x1", j)
.attr("y1", 10)
.attr("x2", j)
.attr("y2", height - 10)
.style("stroke", "rgb(6,120,155)")
.style("stroke-width", 0.1);
}
const snapTo = (x, y) => {
if (x % 10 > 10 / 2) {
x += 10 - (x % 10);
} else {
x -= x % 10;
}
if (y % 10 > 10 / 2) {
y += 10 - (y % 10);
} else {
y -= y % 10;
}
return { x, y };
};
const circles = d3
.range(10)
.map((i) =>
snapTo(
Math.random() * (width - radius * 2) + radius,
Math.random() * (height - radius * 2) + radius
)
);
const circle = svg
.append("g")
.attr("id", "root")
.selectAll("g")
.data(circles)
.join("g")
.append("g")
.attr("transform", (d) => `translate(${d.x},${d.y})`)
.call((g) =>
g
.append("circle")
.attr("r", radius)
.attr("fill", (d, i) => d3.schemeCategory10[i % 10])
.attr("fill-opacity", 0.2)
)
.call(
d3
.drag()
.on("start", (event, d) => {
circle
.filter((p) => p === d)
.raise()
.attr("stroke", "black");
svg
.select("#root")
.append("g")
.attr("id", "shadow")
.style("stroke-width", 0.2)
.lower()
.append("circle")
.attr("r", radius)
.attr("fill", "grey")
.attr("stroke", "#e4e4e4")
.attr("stroke-dasharray", "2,2")
.attr("fill-opacity", 0.1)
.attr("transform", () => `translate(${d.x},${d.y})`);
})
.on("drag", (event, d) => {
d.x = event.x;
d.y = event.y;
})
.on("end", (event, d) => {
let c = circle.filter((p) => p === d);
c.attr("stroke", null);
console.log("END");
})
.on("end.update", (event, d) => {
console.log("END UPDATE");
let c = circle.filter((p) => p === d);
const { x, y } = snapTo(d.x, d.y);
d.x = x;
d.y = y;
svg.select("#shadow").remove();
let found = false;
circle.each((d2) => {
if (d2 !== d) {
const int = intersection(
d.x,
d.y,
radius,
d2.x,
d2.y,
radius
);
if (int) {
found = d2;
}
}
});
if (found) {
d.x = found.x;
d.y = found.y;
}
c.attr("transform", (d) => `translate(${d.x},${d.y})`);
})
.on("drag.update", update)
);
function update() {
console.log("UPDATE");
circle.attr("transform", (d) => {
return `translate(${d.x},${d.y})`;
});
}
document.body.append(svg.node());
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment