Skip to content

Instantly share code, notes, and snippets.

@akngs
Last active December 11, 2017 13:30
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save akngs/6e01eb6fc6c0c9eb892abb406219fd6f to your computer and use it in GitHub Desktop.
Save akngs/6e01eb6fc6c0c9eb892abb406219fd6f to your computer and use it in GitHub Desktop.
Interactive and visual explanation of SVG path's "arc" command
license: gpl-3.0

Interactive and visual explanation of SVG path's "arc" command.

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Interactive and visual explanation of SVG path's "arc" command.</title>
<style>
html {
font-size: 14px;
font-family: sans-serif;
}
body {
margin: 0;
padding: 1em;
}
svg {
background-color: #EEE;
}
#command {
font-family: monospace;
background-color: #EEE;
padding: 0.1em 0.5em;
}
form .row {
padding: 0.5em 0;
}
form input[type=number] {
width: 3em;
}
form .pair {
margin-right: 0.5em;
}
form .pair::before {
display: inline-block;
content: " ";
width: 1em;
height: 1rem;
}
.arc {
stroke: #FC0;
fill: none;
}
.ellipse {
fill: none;
stroke: #AAA;
}
.dot0 { fill: #1776b6; }
.pair.x0::before, .pair.y0::before { background-color: #1776b6; }
.dot1 { fill: #ff7f00; }
.pair.x1::before, .pair.y1::before { background-color: #ff7f00; }
.x-line { stroke: #24a221; }
.pair.rx::before { background-color: #24a221; }
.y-line { stroke: #d8241f; }
.pair.ry::before { background-color: #d8241f; }
</style>
</head>
<body>
<form>
<div class="row">
<span class="pair x0">
<label for="x0">X<sub>0</sub>:</label>
<input type="number" id="x0" value="100">
</span>
<span class="pair y0">
<label for="y0">Y<sub>0</sub>:</label>
<input type="number" id="y0" value="100">
</span>
<span class="pair x1">
<label for="x1">X<sub>1</sub>:</label>
<input type="number" id="x1" value="150">
</span>
<span class="pair y1">
<label for="y1">Y<sub>1</sub>:</label>
<input type="number" id="y1" value="150">
</span>
<span class="pair rx">
<label for="rx">R<sub>x</sub>:</label>
<input type="number" id="rx" value="70">
</span>
<span class="pair ry">
<label for="ry">R<sub>y</sub>:</label>
<input type="number" id="ry" value="50">
</span>
</div>
<div class="row">
<label for="rotate">Rotation:</label>
<input type="number" id="rotate" value="0"> deg
<br>
<input type="checkbox" id="sweep">
<label for="sweep">Sweep</label>
<br>
<input type="checkbox" id="large">
<label for="large">Large arc</label>
</div>
</form>
<p>Arc command: <span id="command"></span></p>
<script src="//d3js.org/d3.v4.min.js"></script>
<script>
var sin = Math.sin,
cos = Math.cos,
pi = Math.PI,
qs = document.querySelector.bind(document);
var W = 400, H = 300;
var root = d3.select('body').append('svg')
.attr('width', W)
.attr('height', H);
// Create elements
var arc = root.append('path')
.attr('class', 'arc')
.attr('stroke-width', 6);
var ellipse = root.append('path')
.attr('class', 'ellipse');
var xLine = root.append('line')
.attr('class', 'x-line')
.attr('stroke-width', 2);
var yLine = root.append('line')
.attr('class', 'y-line')
.attr('stroke-width', 2);
var dots = root.selectAll('.point').data([0, 0]).enter().append('circle')
.attr('class', function (_, i) { return 'dot dot' + i; })
.attr('r', 5)
.call(d3.drag().on('drag', function (d, i) {
qs('#x' + i).value = d3.event.x;
qs('#y' + i).value = d3.event.y;
update();
}));
d3.selectAll('input').on('change', update);
update();
function update() {
// Update data
var points = [
[+qs('#x0').value, +qs('#y0').value],
[+qs('#x1').value, +qs('#y1').value]
];
var ar = [+qs('#rx').value, +qs('#ry').value];
var rotate = +qs('#rotate').value;
var large = qs('#large').checked ? 1 : 0;
var sweep = qs('#sweep').checked ? 1 : 0;
// Render the arc and guides
var d = ['M' + points[0], 'A' + ar, rotate, large, sweep, points[1]].join(' ');
qs('#command').innerText = '<path d="' + d + '" />';
arc.attr('d', d);
ellipse.attr('d', [
'M' + points[0], 'A' + ar, rotate, large, sweep, points[1],
'A' + ar, rotate, large ? 0 : 1, sweep, points[0]
].join(' '));
var bbox = ellipse.node().getBBox(),
center = [bbox.x + bbox.width * 0.5, bbox.y + bbox.height * 0.5],
rad = rotate / 360 * pi * 2;
xLine
.attr('x1', center[0])
.attr('y1', center[1])
.attr('x2', center[0] + cos(rad) * ar[0])
.attr('y2', center[1] + sin(rad) * ar[0]);
yLine
.attr('x1', center[0])
.attr('y1', center[1])
.attr('x2', center[0] - cos(rad + pi * 0.5) * ar[1])
.attr('y2', center[1] - sin(rad + pi * 0.5) * ar[1]);
dots
.data(points)
.attr('cx', function (d) { return d[0]; })
.attr('cy', function (d) { return d[1]; });
}
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment