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> |