Playing with paths to create bracket and elbow connectors (1 + 2) for annotations.
TODO: Rewrite to use SVG path strings and add labels with line lengths.
license: mit |
<!DOCTYPE html> | |
<head> | |
<meta charset="utf-8"> | |
<script src="https://d3js.org/d3.v4.min.js"></script> | |
<style> | |
body { margin:0;position:fixed;top:0;right:0;bottom:0;left:0; } | |
.connector-b { | |
stroke: red; | |
stroke-width: 1px; | |
stroke-dasharray: 5,5; | |
} | |
.connector-a { | |
stroke: blue; | |
stroke-width: 1px; | |
stroke-dasharray: 5,5; | |
} | |
.connector-45 { | |
stroke: black; | |
stroke-width: 2px; | |
} | |
.connector-90 { | |
stroke: black; | |
stroke-width: 2px; | |
} | |
.connector-line { | |
opacity: 1; | |
stroke: #bbb; | |
stroke-width: 1px; | |
stroke-dasharray: 5,5; | |
} | |
circle { | |
fill: white; | |
} | |
</style> | |
</head> | |
<body> | |
<script> | |
var width = 960, | |
height = 500; | |
var svg = d3.select("body").append("svg") | |
.attr("width", width) | |
.attr("height", height) | |
var config = { | |
radius: 10 | |
}; | |
var data = [{x: 300, y: 200, colour: "cyan"}, {x: 500, y: 300, colour: "magenta"}]; | |
var dragbehaviour = d3.drag() | |
.on("drag", dragged); | |
var points = svg.selectAll("circle") | |
.data(data) | |
.enter().append("circle") | |
.attr("cx", d => d.x) | |
.attr("cy", d => d.y) | |
.attr("r", config.radius) | |
.style("fill", d => d.colour) | |
.call(dragbehaviour); | |
var connector = svg.append("line") | |
.attr("class", "connector-line") | |
.attr("x1", data[0].x) | |
.attr("y1", data[0].y) | |
.attr("x2", data[1].x) | |
.attr("y2", data[1].y); | |
var connectorB = svg.append("line") | |
.attr("class", "connector-b") | |
.attr("x1", data[0].x) | |
.attr("y1", data[0].y) | |
.attr("x2", data[0].x) | |
.attr("y2", data[0].y + calculateLine1().b); | |
var connectorA = svg.append("line") | |
.attr("class", "connector-a") | |
.attr("x1", data[0].x) | |
.attr("y1", data[0].y + calculateLine1().b) | |
.attr("x2", data[0].x + calculateLine1().c) | |
.attr("y2", data[0].y + calculateLine1().b); | |
var connector45 = svg.append("line") | |
.attr("class", "connector-45") | |
.attr("x1", data[0].x) | |
.attr("y1", data[0].y) | |
.attr("x2", data[0].x + calculateLine1().a) | |
.attr("y2", data[0].y + calculateLine1().b); | |
var connector90 = svg.append("line") | |
.attr("class", "connector-90") | |
.attr("x1", data[0].x + calculateLine1().a) | |
.attr("y1", data[0].y + calculateLine1().b) | |
.attr("x2", data[1].x) | |
.attr("y2", data[1].y); | |
points.raise(); | |
function dragged(d) { | |
d3.select(this) | |
.attr("cx", d.x = Math.max(0, Math.min(width, d3.event.x))) | |
.attr("cy", d.y = Math.max(0, Math.min(height, d3.event.y))); | |
connector | |
.attr("x1", data[0].x) | |
.attr("y1", data[0].y) | |
.attr("x2", data[1].x) | |
.attr("y2", data[1].y); | |
connectorB | |
.attr("x1", data[0].x) | |
.attr("y1", data[0].y) | |
.attr("x2", data[0].x) | |
.attr("y2", data[0].y + calculateLine1().b); | |
connectorA | |
.attr("x1", data[0].x) | |
.attr("y1", data[0].y + calculateLine1().b) | |
.attr("x2", data[0].x + calculateLine1().c) | |
.attr("y2", data[0].y + calculateLine1().b); | |
connector45 | |
.attr("x1", data[0].x) | |
.attr("y1", data[0].y) | |
.attr("x2", data[0].x + calculateLine1().a) | |
.attr("y2", data[0].y + calculateLine1().b); | |
connector90 | |
.attr("x1", data[0].x + calculateLine1().a) | |
.attr("y1", data[0].y + calculateLine1().b) | |
.attr("x2", data[1].x) | |
.attr("y2", data[1].y); | |
} | |
// Rewrite to use | |
function calculateLine1() { | |
var b = data[1].y - data[0].y; | |
var a = Math.abs(Math.tan(Math.PI / 4) * b); | |
var c = data[1].x - data[0].x; | |
var h = Math.sqrt(Math.pow(b, 2) + Math.pow(c, 2)); | |
var ab = Math.sqrt(Math.pow(a, 2) + Math.pow(b, 2)); | |
/* | |
Check if the line between the two points is less than | |
the hypotenuse between a and b | |
*/ | |
if (h < ab) { | |
a = data[1].x - data[0].x; | |
b = Math.abs(Math.tan(Math.PI / 4) * a); | |
if ((data[1].y - data[0].y) < 0) { | |
b = -b;; | |
} | |
} else { | |
if ((data[1].x - data[0].x) < 0) { | |
a = -a; | |
} | |
} | |
return {a: a, b: b, c: c}; | |
} | |
</script> | |
</body> |