Clock SVG

by sazakharov

HTML

<svg viewbox="-450 -450 900 900">
  <defs>
    <line id="mark--major" y1="28.8"></line>
    <line id="mark--minor" y1="14.4"></line>
    <circle id="cc" r="360"></circle>
  </defs>
  <g id="ticks"></g>
  <g id="hands">
    <g class="hand--h">
      <line y2="-234"></line>
      <line y1="-136.8" y2="-205.2"></line>
    </g>
    <g transform="rotate(25)" class="hand--m">
      <line y2="-298.8"></line>
      <line y1="-201.60000000000002" y2="-270"></line>
    </g>
    <g transform="rotate(60)" class="hand--s">
      <line y1="36" y2="-342"></line>
      <circle r="14.4"></circle>
      <circle r="7.2"></circle>
    </g>
  </g>
  <g id="progress">
    <path id="arc"></path>
    <polygon id="vertex" points="0,-405 -39,-425 -20,-405  -39,-385"></polygon>
  </g>
</svg>

CSS

body {
  margin: 0;
  background: #000;
}

svg {
  display: block;
  margin: calc(50vh - 50vmin) auto;
  min-width: 15em;
  min-height: 15em;
  width: 100vmin;
  height: 100vmin;
  max-width: 100em;
  max-height: 100em;
  font-size: 1em;
}

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

[id*='mark'] {
  stroke: #eee;
}

[id='mark--major'] {
  stroke-width: 7;
}

[id='mark--minor'] {
  stroke-width: 2;
}

[id='ticks'] text {
  dominant-baseline: middle;
  text-anchor: middle;
  font: 20px verdana, sans-serif;
  fill: #aaa;
}
[id='ticks'] .quad {
  font: 700 28px verdana, sans-serif;
  fill: #eee;
}

.hand--h, .hand--m {
  stroke: #eee;
  stroke-linecap: round;
}
.hand--h line:nth-child(2), .hand--m line:nth-child(2) {
  stroke: #4ca454;
  stroke-width: 3;
}
.hand--h {
  stroke-width: 7;
}
.hand--m {
  stroke-width: 5;
}
.hand--s {
  stroke: #be4c39;
}
.hand--s line {
  stroke-width: 2;
}
.hand--s circle {
  fill: #e18728;
}
.hand--s circle:nth-of-type(2) {
  fill: #e0a197;
}

[id='arc'] {
  fill: transparent;
  stroke: #4ca454;
  stroke-width: 4;
  stroke-linecap: round;
}

[id='vertex'] {
  fill: #4ca454;
}

.counterclockwise [id='vertex'] {
  fill: #be4c39;
}
.counterclockwise [id='arc'] {
  stroke: #be4c39;
}

JavaScript

/* because IE */
Math.sign = Math.sign || function(x) {
  x = +x; // convert to a number
  if (x === 0 || isNaN(x)) {
    return x;
  }
  return x > 0 ? 1 : -1;
}

/* because me lazy */
Object.getOwnPropertyNames(Math).map(function(p) {
  window[p] = Math[p];
});

Node.prototype.setAttrs = function(attr_obj) {
  for(var prop in attr_obj) {
    this.setAttribute(prop, attr_obj[prop]);
  }
};

var NS_URI = 'http://www.w3.org/2000/svg', 
    XLink_NS = 'http://www.w3.org/1999/xlink', 
		
		ns = 60, 
		mi = 5, 
		qi = .25*ns, 
		r = ~~document.getElementById('cc').getAttribute('r'),
		svg = document.querySelector('svg'), 
		wrap = document.getElementById('ticks'), 
		h_el = document.querySelector('.hand--h'), 
		m_el = document.querySelector('.hand--m'), 
		s_el = document.querySelector('.hand--s'), 
		h_max = 12, h_rad = 2*PI/h_max, h_deg = 360/h_max, 
		m_max = 60, m_rad = 2*PI/m_max, m_deg = 360/m_max, 
		s_max = 60, s_rad = 2*PI/s_max, s_deg = 360/s_max, 
		ms_max = 1000, ms_rad = s_rad/ms_max, ms_deg = s_deg/ms_max, 
		prev_s, 
		p_el = document.getElementById('progress'), 
		a_el = document.getElementById('arc'), 
		v_el = document.getElementById('vertex'),
		arc_r = -1*v_el.getAttribute('points').split(' ')[0].split(',')[1], 
		clockwise = true;

var init = function () {
	var frag = document.createDocumentFragment(), 
			curr_tick_group, curr_tick, text0, text1, 
			is_major, is_quad, ref, 
			curr_angle, base_angle = 360/ns, bb;
	
	for(var i = 0; i < ns; i++) {
		is_major = (i%mi === 0);
		is_quad = (i%qi === 0);
		
		ref = '#mark--' + (is_major ? 'major' : 'minor');
		curr_angle = i*base_angle
		
		curr_tick_group = document.createElementNS(NS_URI, 'g');
		curr_tick = document.createElementNS(NS_URI, 'use');
		curr_tick.setAttributeNS(XLink_NS, 'xlink:href', ref);
		
		curr_tick.setAttribute(
			'transform', 
			'rotate(' + curr_angle + ')' + 
			'translate(0 -' + r + ')'
		);
		
		if(is_major) {
			curr_tick.setAttribute('class', 'major');
			
			text1 =...