7-segment SVG

by PhilQ

HTML

<svg id="lcd"
	xmlns="http://www.w3.org/2000/svg"
	xmlns:xlink="http://www.w3.org/1999/xlink"
>
	<defs>

		<filter
			id="dropshadow"
			filterUnits="userSpaceOnUse"
			primitiveUnits="userSpaceOnUse"
			x="-100%" y="-100%"
			width="300%" height="300%"
		>
			<feDropShadow dx="1" dy="2" stdDeviation="1" flood-color="black" flood-opacity="0.35"/>
		</filter>

		<filter
			id="dropshadowSymbols"
			filterUnits="userSpaceOnUse"
			primitiveUnits="userSpaceOnUse"
			x="-100%" y="-100%"
			width="300%" height="300%"
		>
			<feDropShadow dx="4" dy="8" stdDeviation="4" flood-color="black" flood-opacity="0.35"/>
		</filter>

		<filter id="dropshadow2" x="-100%" y="-100%" width="300%" height="300%">
			<feOffset result="offOut" in="SourceAlpha" dx="5" dy="8" />
			<feGaussianBlur result="blurOut" in="offOut" stdDeviation="1" />
			<feComponentTransfer result="coloredOut" in="blurOut">
				<feFuncA type="linear" slope="0.3"/>
				<!--
				<feFuncR type="table" tableValues="1 0"/>
				<feFuncG type="linear" slope="0.0"/>
				<feFuncB type="linear" slope="0.0"/>
				-->
			</feComponentTransfer>
			<!--
			<feComposite in="BackgroundImage" in2="coloredOut" operator="over" result="compOut"/>
			<feBlend in="SourceGraphic" in2="coloredOut" mode="darken" />
			-->
			<feMerge> 
				<feMergeNode/>
				<feMergeNode in="SourceGraphic"/>
			</feMerge>
		</filter>

	</defs>
</svg>
<button id="mute">Mute</button>
<button id="start">Start</button>
<button id="reset">Reset</button>
<input type="checkbox" id="repeat" value="true">

SCSS

body {
	margin: 50px;
	background: #acbba8;
}

svg {
	position: fixed;
	top: 50%;
	left: 50%;
	transform: translate(-50%, -50%);
	width: 400px;
	height: 400px;
	border: 1px solid red;
	overflow: visible;
}

#clock {
	//transform: translate(-50%, -50%);
}

symbol, use {
	overflow: visible;
}

path.segment, circle {
	fill: #a2b19e;
	fill: rgba(0, 0, 0, 0.05);

	&.on {
		fill: #171b1e;
		filter: url(#dropshadowSymbols);
	}
}

path.circle-part {
	stroke: #a2b19e;
	stroke-width: 10;
	fill: none;
	stroke-linecap: butt;

	&.on {
		stroke: #171b1e;
		filter: url(#dropshadow);
	}
}

#mute {
	position: fixed;
	top: 50px;
	right: 50px;
	font-size: 20px;
}

#start {
	position: fixed;
	top: 50px;
	left: 50px;
	font-size: 20px;
}

#reset {
	position: fixed;
	top: 100px;
	left: 50px;
	font-size: 20px;
}

#repeat {
	position: fixed;
	top: 150px;
	left: 50px;
	width: 26px;
	height: 26px;
}

JavaScript

function deg2rad(deg) {
 	return deg * (Math.PI/180);
}
function rad2deg(rad) {
	return rad * (180/Math.PI);
}

var beep = (function() {
	return function(duration, frequency, gain, finishedCallback) {

		duration = +duration;

		if (typeof finishedCallback != "function") {
			finishedCallback = function () {};
		}

		var oscillatorNode = audioCtx.createOscillator();
		oscillatorNode.type = "triangle"; // "sine", "triangle", "sawtooth", "square", "custom"
		oscillatorNode.frequency.setValueAtTime(frequency, audioCtx.currentTime); // value in hertz
		if (!gain) {
			gain = 0.1;
		}
		
		var gainNode = audioCtx.createGain();
		gainNode.gain.value = gain;

		oscillatorNode.connect(gainNode);
		if (!isMuted) {
			gainNode.connect(audioCtx.destination);
		}

		if (oscillatorNode.noteOn) oscillatorNode.noteOn(0);
		if (oscillatorNode.start) oscillatorNode.start();

		setTimeout(function () {
			if (oscillatorNode.noteOff) oscillatorNode.noteOff(0);
			if (oscillatorNode.stop) oscillatorNode.stop();
			finishedCallback();
		}, duration);

	};
})();


// Helper variables
var segs = [];
var pX = [];
var pY = [];

// Using arcs & set radius
function getRoundedCorner(prevP, curP, nextP, cc) {
	var counterclockwise = cc || false;
	
	if (counterclockwise) {
		var tmp = prevP;
		prevP = nextP;
		nextP = tmp;
	}
	var aF = rad2deg(Math.atan2(pY[curP] - pY[prevP], pX[curP] - pX[prevP]));
	var aT = rad2deg(Math.atan2(pY[nextP] - pY[curP], pX[nextP] - pX[curP]));

	// Tangents of circle part
	var rcF = aF - 90;
	var rcT = aT - 90;
	rcF += (rcF > 180? -360: (rcF < -180? 360: 0));
	rcT += (rcT > 180? -360: (rcT < -180? 360: 0));

	// Mid angle of tangent lines
	var midA = (rcF + rcT) / 2;

	// If straight line, don't use circle part
	if (midA % 180 == 0 || r_inner == 0) {
		return ['L', pX[curP], pY[curP]].join(' ');
	}

	// Half of angle difference
	var halfDA = midA - rcF;
	while (halfDA < 0) {
		halfDA += 360;
	}

	// Relative position of corner to circle center
	var distToCorner =...