Binary Watch Face Idea

by Katarn

HTML

<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta.2/css/bootstrap.min.css">
<div
  id="app"
  class="container pt-3"
>
  <svg
    id="watch-face"
    xmlns="http://www.w3.org/2000/svg"
    viewBox="0 0 320 320"
  >
    <path
      v-for="(path, index) in hoursPaths"
      class="hour"
      :class="{
        active: hours & Math.pow(2, index),
      }"
      :id="'hour-' + Math.pow(2, index)"
      :d="path"
    />
    
    <path
      v-for="(path, index) in minutesPaths"
      class="minute"
      :class="{
        active: minutes & Math.pow(2, index),
      }"
      :id="'minute-' + Math.pow(2, index)"
      :d="path"
    />
    
    <circle
      v-for="(circle, index) in secondsCircles"
      class="second"
      :class="{
        active: seconds >= index,
      }"
      r="5"
      :cx="circle.cx"
      :cy="circle.cy"
    />
  </svg>

  <div class="form-row mt-3">
    <div class="col">
      <input
        v-model="hours"
        type="number"
        class="form-control text-right"
        max="23"
        min="0"
        @input="stop"
      >
    </div>
    <div class="col">
      <input
        v-model="minutes"
        type="number"
        class="form-control text-right"
        max="59"
        min="0"
        @input="stop"
      >
    </div>
    <div class="col">
      <input
        v-model="seconds"
        type="number"
        class="form-control text-right"
        max="59"
        min="0"
        @input="stop"
      >
    </div>
    <div class="col">
      <button
        class="btn"
        :class="{
          'btn-primary': !started,
          'btn-secondary': started,
        }"
        @click="toggle"
      >
        {{ started ? 'Stop' : 'Start' }}
      </button>
    </div>
  </div>
</div>

CSS

#watch-face {
  display: block;
  background-color: #000000;
  border-radius: 50%;
}

.hour, .minute, .second {
  fill: #000000;
  transition: all 0.3s ease-in-out;
}

.hour.active {
  fill: #DD2C00;
}

.minute.active {
  fill: #FF5722;
}

.second.active {
  fill: #FF9800;
}

.container {
  max-width: 350px;
}

Babel + JSX

new Vue({
	el: '#app',

	methods: {
  	updateDate() {
    	if (this.started) {
        setTimeout(this.updateDate, 1000);
        [this.hours, this.minutes, this.seconds] = (new Date()).toString()
          .match(/[0-9]{2}:[0-9]{2}:[0-9]{2}/)[0]
          .split(':')
          .map(parseFloat);
      }
    },
    toggle() {
    	this.started = !this.started;
      if (this.started) {
      	this.updateDate();
      }
    },
    stop() {
    	this.started = false;
    }
  },
  
  created() {
  	this.updateDate();
  },
  
    data: {
    hours: 0,
    minutes: 0,
    seconds: 0,
    started: true,
    // NOTE: A partir de aquĂ­ es todo morralla para pintar el svg
  	hoursPaths: [
      'M273.4,121h0a5.1,5.1,0,0,1-6.3-3A115.1,115.1,0,0,0,166.8,45.2a4.9,4.9,0,0,1-4.7-5.1h0a5,5,0,0,1,5.2-4.9,125,125,0,0,1,109.1,79.2A5,5,0,0,1,273.4,121Z',
      'M285,160a124.7,124.7,0,0,1-45.7,96.6,5,5,0,0,1-7.1-.8h0a4.9,4.9,0,0,1,.8-6.9A115.2,115.2,0,0,0,271.3,131a5,5,0,0,1,3.4-6.1h0a5.1,5.1,0,0,1,6.3,3.5A126.7,126.7,0,0,1,285,160Z',
      'M228.8,258.2a5.1,5.1,0,0,1-1.4,7.1,125.1,125.1,0,0,1-134.8,0,5.1,5.1,0,0,1-1.4-7.1h0a5,5,0,0,1,6.8-1.3,115.2,115.2,0,0,0,124,0,5,5,0,0,1,6.8,1.3Z',
      'M87.8,255.8h0a5,5,0,0,1-7.1.8A124.7,124.7,0,0,1,35,160a126.7,126.7,0,0,1,4-31.6,5.1,5.1,0,0,1,6.3-3.5h0a5,5,0,0,1,3.4,6.1A115.2,115.2,0,0,0,87,248.9,4.9,4.9,0,0,1,87.8,255.8Z',
      'M153.2,45.2A115.1,115.1,0,0,0,52.9,118a5.1,5.1,0,0,1-6.3,3h0a5,5,0,0,1-3-6.6A125,125,0,0,1,152.7,35.2a5,5,0,0,1,5.2,4.9h0A4.9,4.9,0,0,1,153.2,45.2Z',
    ],
    minutesPaths: [
      'M275.6,90.5h0a4.9,4.9,0,0,1-6.7-1.6A130,130,0,0,0,167.1,30.2a5,5,0,0,1-4.7-5.1h0a5,5,0,0,1,5.2-4.9A140.3,140.3,0,0,1,277.3,83.5,5,5,0,0,1,275.6,90.5Z',
      'M300,160a138.7,138.7,0,0,1-15.1,63.3,4.9,4.9,0,0,1-6.9,2.1h0a4.9,4.9,0,0,1-2-6.6,130.5,130.5,0,0,0,0-117.6,4.9,4.9,0,0,1,2-6.6h0a4.9,4.9,0,0,1,6.9,2.1A138.7,138.7,0,0,1,300,160Z',
     ...