radians explained (SVG + JS, no library)

In this example below you will see how to do a radians explained (SVG + JS, no library) with some HTML / CSS and Javascript

Given a circle of radius r (r can be any value), 1 radian is the measure of an arc whose length is equal to that of our circle's radius r. In half a circle we can fit 3.14 or π radians. A full circle has 2*π radians.

Thumbnail
This awesome code was written by thebabydino, you can see more from this user in the personal repository.
You can find the original code on Codepen.io
Copyright thebabydino ©
  • HTML
  • CSS
  • JavaScript
<!DOCTYPE html>
<html lang="en" >

<head>
  <meta charset="UTF-8">
  <title>radians explained (SVG + JS, no library)</title>
  
  
  
      <style>
      /* NOTE: The styles were added inline because Prefixfree needs access to your styles and they must be inlined if they are on local disk! */
      * {
  transition: opacity .3s;
}

body {
  display: flex;
  overflow: hidden;
  margin: 0;
  height: 100vh;
}

svg {
  flex: 1;
}

line, circle, path {
  fill: currentColor;
  stroke: currentColor;
}

line {
  vector-effect: non-scaling-stroke;
}

text {
  fill: currentColor;
  text-anchor: middle;
  font: 700 8em courier, monospace;
}

tspan {
  font: 700 italic 1em serif;
}

.vlni {
  fill: none;
  stroke-width: 1.5em;
}

[id='axes'] {
  opacity: .5;
}
[id='axes'] use {
  marker-end: url(#arrow);
}
[id='axes'] text {
  dominant-baseline: middle;
}

[id='base'] {
  color: #dea200;
}

[id='over'] {
  color: #a048b9;
}
[id='over'] circle {
  fill-opacity: .5;
  stroke-width: 4px;
  vector-effect: non-scaling-stroke;
}

[id='rlines'] {
  color: #a048b9;
}
[id='rlines'] use:first-of-type, [id='rlines'] use:last-of-type {
  stroke-width: 3px;
}
[id='rlines'] > text {
  dominant-baseline: middle;
}
[id='rlines'] > text:first-of-type, [id='rlines'] > text:last-of-type {
  dominant-baseline: hanging;
}

[id='anim'] {
  color: #d14730;
}
[id='anim'] path {
  stroke-width: 2em;
}
[id='anim'] use {
  stroke-width: 1em;
}

    </style>

    <script src="https://cdnjs.cloudflare.com/ajax/libs/prefixfree/1.0.7/prefixfree.min.js"></script>

</head>

<body>

  
<svg viewBox="-2000 -2000 4000 4000" aria-labelledby="title descr" role="img">
  <title id="title">animation explaining radians</title>
  <descr id="descr">A radian is the measure of a circular arc equal in length to the radius of the same circle. This demo draws a circle of radius r, moves and bends this radius segment over the circle, then multiplies it to reveal that exactly π such arc lengths can be fit in half the circle's circumference</descr>
  <defs>
    <marker id="arrow" viewBox="-50 -70 250 140" markerUnits="strokeWidth" markerWidth="180" markerHeight="120" orient="auto" refX="100">
      <polygon points="50,0 0,-50 150,0 0,50"></polygon>
    </marker>
    <clipPath id="slicer">
      <path></path>
    </clipPath>
    <clipPath id="cutter">
      <path></path>
    </clipPath>
    <line id="axis" x1="-1800" x2="1800"></line>
    <circle class="vlni" id="circle" r="1500"></circle>
    <circle id="point" r="20"></circle>
    <g id="rline">
      <line x2="1500"></line>
      <use xlink:href="#point" x="1500"></use>
    </g>
  </defs>
  <g id="axes">
    <use xlink:href="#axis"></use>
    <text x="1880">
      <tspan>x</tspan>
    </text>
    <use xlink:href="#axis" transform="rotate(90)"></use>
    <text y="1880">
      <tspan>y</tspan>
    </text>
  </g>
  <use id="base" xlink:href="#circle"></use>
  <g id="over" clip-path="url(#slicer)">
    <use xlink:href="#circle"></use>
    <circle r="150"></circle>
  </g>
  <g id="rlines">
    <use xlink:href="#rline"></use>
    <text transform="rotate(0.000)translate(1650)rotate(-0.000)translate(0 20)">0</text>
    <use xlink:href="#rline" transform="rotate(57.296)"></use>
    <text transform="rotate(57.296)translate(1612.5)rotate(-57.296)translate(0 10)">1</text>
    <use xlink:href="#rline" transform="rotate(114.592)"></use>
    <text transform="rotate(114.592)translate(1612.5)rotate(-114.592)translate(0 10)">2</text>
    <use xlink:href="#rline" transform="rotate(171.887)"></use>
    <text transform="rotate(171.887)translate(1612.5)rotate(-171.887)translate(0 10)">3</text>
    <use class="rot" xlink:href="#rline" transform="rotate(57.296)"></use>
    <text transform="rotate(180.000)translate(1725)rotate(-180.000)translate(0 40)">3.14</text>
    <g id="pie">
      <text id="full" transform="translate(1650 -40)">2<tspan>π</tspan></text>
      <text id="half" transform="translate(-1687.5 -40)"><tspan>π</tspan></text>
    </g>
  </g>
  <use id="origin" xlink:href="#point"></use>
  <g id="anim">
    <path class="vlni" id="morphr" d="M0,0C0,0 0,0 0,0"></path>
    <use id="s" xlink:href="#point"></use>
    <use id="e" xlink:href="#point"></use>
  </g>
</svg>
  <script src='https://codepen.io/thebabydino/pen/wWMWqW.js'></script>

  

    <script  src="js/index.js"></script>




</body>

</html>

/*Downloaded from https://www.codeseek.co/thebabydino/radians-explained-svg-js-no-library-qaEmxk */
* {
  transition: opacity .3s;
}

body {
  display: flex;
  overflow: hidden;
  margin: 0;
  height: 100vh;
}

svg {
  flex: 1;
}

line, circle, path {
  fill: currentColor;
  stroke: currentColor;
}

line {
  vector-effect: non-scaling-stroke;
}

text {
  fill: currentColor;
  text-anchor: middle;
  font: 700 8em courier, monospace;
}

tspan {
  font: 700 italic 1em serif;
}

.vlni {
  fill: none;
  stroke-width: 1.5em;
}

[id='axes'] {
  opacity: .5;
}
[id='axes'] use {
  marker-end: url(#arrow);
}
[id='axes'] text {
  dominant-baseline: middle;
}

[id='base'] {
  color: #dea200;
}

[id='over'] {
  color: #a048b9;
}
[id='over'] circle {
  fill-opacity: .5;
  stroke-width: 4px;
  vector-effect: non-scaling-stroke;
}

[id='rlines'] {
  color: #a048b9;
}
[id='rlines'] use:first-of-type, [id='rlines'] use:last-of-type {
  stroke-width: 3px;
}
[id='rlines'] > text {
  dominant-baseline: middle;
}
[id='rlines'] > text:first-of-type, [id='rlines'] > text:last-of-type {
  dominant-baseline: hanging;
}

[id='anim'] {
  color: #d14730;
}
[id='anim'] path {
  stroke-width: 2em;
}
[id='anim'] use {
  stroke-width: 1em;
}


/*Downloaded from https://www.codeseek.co/thebabydino/radians-explained-svg-js-no-library-qaEmxk */
var D = {} /* demo components */
,
    C = {} /* list of constants */;

var Point = function Point(id, x, y) {
	this.x = x || 0;
	this.y = y || 0;
	if (id) this.el = $$('#' + id);

	this.move = function (c) {
		for (var p in c) {
			this[p] = c[p];
			if (this.el) this.el.setAttribute(p, c[p]);
		}
	};
};

var ease = function ease(t, typ) {
	switch (typ) {
		case 'eInOutSin':
			return .5 * (1 + sin(PI * (t - .5)));
	}

	return t;
};

var ani = function ani(data) {
	if (data.t <= data.n) {
		var k = ease(data.t / data.n, 'eInOutSin');

		D[data.ani](k);

		++data.t;
		requestAnimationFrame(ani.bind(this, data));
	} else {
		var m = void 0;

		data.ani = D.next();
		m = data.ani === 'exp' ? 4 : 1;
		data.t = 0;
		data.n = D.dur();
		setTimeout(function () {
			ani(data);
		}, m * C.BT);
	}
};

(function init() {
	(function genConstVals() {
		C.BA = 1; /* base angle */
		C.CA = .5 * PI - C.BA; /* complem of base */
		C.RA = PI - 3 * C.BA; /* remainder angle */
		C.CV = 180 / PI; /* converstion to degrees */
		C.DG = C.BA * C.CV; /* in degrees */
		C.F = .345; /* curve factor */
		C.NF = 40; /* basic uni no of frames */
		C.BT = 500; /* ms break time after ani */
		C.FF = 2 * C.NF; /* for full circ */
		C.R = ~~$$('#circle')._attr('r'); /* rad */
		C.S = C.F * C.R; /* scaled radius */
		C.C = 1.5 * C.R; /* clipping radius */
		C.L = round(2 * PI * C.R); /* circle len */
		C.PF = ['M', 'C']; /* path dir prefs */
	})();

	(function genDemoComps() {
		var act = ['exp', 'drw', 'vrt', 'arc', 'rot'],
		    na = act.length,
		    sel = '#rlines',
		    nr = void 0,
		    nt = void 0,
		    cb = 'M0,0H' + C.C + 'A' + [C.C, C.C] + ' 0 0 1 ';

		D.rotID = 0;
		D.curr = 0;

		D.morphr = {
			'rt': $$('#anim'),
			'el': $$('#morphr'),
			'pts': [],
			'csets': {
				'ini': [],
				'exp': [],
				'vrt': [],
				'arc': []
			},
			'init': function init() {
				var ids = ['s', null, null, 'e'],
				    x = C.R * cos(C.BA),
				    y = C.R * sin(C.BA);

				for (var i = 0; i < 4; i++) {
					var j = ~~(.5 * i),
					    k = 1 - j;

					this.pts.push(new Point(ids[i]));
					this.csets.ini.push([0, 0]);
					this.csets.exp.push([j * C.R, 0]);
					this.csets.vrt.push([C.R, k * C.R]);
					this.csets.arc.push([j * C.R + k * x, k * y]);
				}

				x += C.S * cos(C.CA);
				y -= C.S * sin(C.CA);
				this.csets.arc[2][1] = C.S;
				this.csets.arc[1][0] = x;
				this.csets.arc[1][1] = y;
			}
		};

		D.slicer = $$('#slicer path');
		D.cutter = $$('#cutter path');

		D.base = {
			'el': $$('#base'),
			'init': function init() {
				this.el._attr({
					'stroke-dasharray': C.L,
					'stroke-dashoffset': C.L
				});
			}
		};

		D.rlines = $$(sel + ' use');
		nr = D.rlines.length;
		D.labels = $$(sel + ' text');
		nt = D.labels.length;

		D.over = $$('#over');

		/* extend point to radius */
		D[act[0]] = function (k) {
			var p = this.morphr.pts,
			    s = this.morphr.csets,
			    d = 'M0,0C0,0',
			    a = s.ini,
			    b = s.exp,
			    j = 1 - k,
			    x = j * a[2][0] + k * b[2][0];

			if (k === 0) {
				var u = C.C * cos(C.BA),
				    v = C.C * sin(C.BA),
				    _d = cb + [u, v];

				this.slicer._attr({ 'd': _d });

				p[0].move({ 'x': 0, 'y': 0 });
				p[1].move({ 'x': 0, 'y': 0 });
				this.morphr.rt.style.opacity = .99;
				this.morphr.rt._attr({
					'transform': 'rotate(0)'
				});
				this.morphr.pts[0].el._attr({
					'transform': 'rotate(0)'
				});
				this.base.el._attr({
					'stroke-dashoffset': C.L
				});
				this.over.style.opacity = .001;

				for (var i = 0; i < nt; i++) {
					if (i < nr) this.rlines[i].style.opacity = .001;
					this.labels[i].style.opacity = .001;
				}
				this.rlines[4]._attr({
					'transform': 'rotate(' + C.DG.toFixed(3) + ')'
				});
			}

			for (var _i = 2; _i < 4; _i++) {
				p[_i].move({ 'x': x });
				d += ' ' + x + ',0';
			}

			this.morphr.el._attr({
				'd': d, 'clip-path': 'none'
			});
		};

		/* rotate radius to draw circle */
		D[act[1]] = function (k) {
			D.morphr.rt._attr({
				'transform': 'rotate(' + k * 360 + ')'
			});
			D.base.el._attr({
				'stroke-dashoffset': (1 - k) * C.L
			});
		};

		/* rotate radius to vertical */
		D[act[2]] = function (k) {
			this.morphr.rt._attr({
				'transform': 'rotate(' + k * -90 + ' ' + C.R + ' 0)'
			});
		};

		/* bend radius to arc */
		D[act[3]] = function (k) {
			var p = this.morphr.pts,
			    s = this.morphr.csets,
			    d = '',
			    a = s.vrt,
			    b = s.arc,
			    j = 1 - k;

			if (k === 0) {
				this.morphr.rt._attr({
					'transform': 'rotate(0)'
				});
			}

			if (k === 1) {
				this.rlines[0].style.opacity = this.rlines[1].style.opacity = this.rlines[4].style.opacity = this.labels[0].style.opacity = this.labels[1].style.opacity = this.over.style.opacity = '.999';
			}

			for (var i = 0; i < 3; i++) {
				var x = j * a[i][0] + k * b[i][0],
				    y = j * a[i][1] + k * b[i][1];

				p[i].move({ 'x': x, 'y': y });
				d += (C.PF[i] || ' ') + [x, y];
			}

			d += ' ' + [C.R, 0];
			this.morphr.el._attr({ 'd': d });
		};

		/* rotate radius-len arc by 1 more BA */
		D[act[4]] = function (k) {
			var a = (D.rotID + k) * C.DG,
			    b = 180 - C.DG;

			this.morphr.rt._attr({
				'transform': 'rotate(' + a.toFixed(3) + ')'
			});

			this.rlines[4]._attr({
				'transform': 'rotate(' + min(180, a + C.DG).toFixed(3) + ')'
			});

			if (a > b) {
				var t = C.BA + (b - a) / C.CV,
				    x = round(C.C * cos(t)),
				    y = round(C.C * sin(t)),
				    d = cb + [x, y];

				this.slicer._attr({ 'd': cb + [-C.C, 0] });
				this.cutter._attr({ 'd': d });
				this.morphr.el._attr({
					'clip-path': 'url(#cutter)'
				});

				this.morphr.pts[0].el._attr({
					'transform': 'rotate(' + (b - a) + ')'
				});
			} else {
				var _t = a / C.CV + C.BA,
				    _x = C.C * cos(_t),
				    _y = C.C * sin(_t),
				    _d2 = cb + [_x, _y];

				this.slicer._attr({ 'd': _d2 });
				this.rlines[4]._attr({
					'transform': 'rotate(' + (a + C.DG).toFixed(3) + ')'
				});
			}

			if (k === 1) {
				if (D.rotID < 2) {
					var idx = D.rotID + 2;
					this.rlines[idx].style.opacity = this.labels[idx].style.opacity = .999;
				} else {
					this.labels[4].style.opacity = this.labels[5].style.opacity = this.labels[6].style.opacity = .999;
					this.morphr.rt.style.opacity = .001;
				}
			}
		};

		/* return next action */
		D.next = function () {
			if (D.curr === act.indexOf('rot') && D.rotID < 2) {
				++D.rotID;
			} else {
				D.rotID = 0;
				D.curr = (D.curr + 1) % na;
			}

			return act[D.curr];
		};

		/* return duration for next action */
		D.dur = function () {
			if (D.curr === act.indexOf('drw')) return C.FF;
			return C.NF;
		};
	})();

	(function iniDemoComps() {
		D.morphr.init();
		D.base.init();
	})();

	ani({ 't': 0, 'n': D.dur(), 'ani': 'exp' });
})();

Comments