LoginSignup
5
7

More than 5 years have passed since last update.

Vueで2つ目に作ったものがなぜかアナログ時計だったお話

Last updated at Posted at 2018-11-03

こちらの続きです。

デジタル時計作ったならやっぱりアナログ時計も作っておかないと…。

というわけで完成品がコチラ。

今回はアニメーションは使っておりません。
各針は角度をミリ秒単位で計算して動かしています。

analog_clock.gif

構成図

analog_clock_pats_discription.PNG

針(Hand)と文字盤(Dials)の2つでアナログ時計(AnalogClock)を構成していきます。

非常にシンプルですね。

Hand

Hand.vue
<template>
    <div class="hand" :class="type" :style="{'transform': 'rotate(' + rotate + 'deg)'}" />
</template>

<script>
export default {
    props: {
        rotate: 0,
        type: ''
    },
}
</script>

<style scoped>
.hand {
    background-color: rgba(255,255,255,0.8);
}

.seconds {
    width: 1px;
    height: 150px;
    transform-origin: 0px 130px;
}

.minutes {
    width: 3px;
    height :150px;
    transform-origin: 1.5px 130px;
}

.hours {
    width: 5px;
    height: 100px;
    transform-origin: 2.5px 80px;
}
</style>

typeで針の種類、秒針(seconds)、分針(minutes)、時針(hours)を指定します。

rotateに針の角度を指定し、styleバインディングで動的に回していきます。

Dials

Dials.vue
<template>
    <div class="dials">
        <div 
            v-for="n in 60" 
            :key="n"
            :style="{
                'top':top(n) + 'px',
                'left': left(n) + 'px',
                'transform': 'rotate(' + rotate(n) + 'deg)'}"
            :class="['scale', {'fifth': n % 5 == 0}]">
            <p v-if="n % 5 == 0" 
               :style="{'transform': 'rotate(' + -rotate(n) + 'deg)'}">
                {{ n / 5 }}
            </p>
        </div>
    </div>
</template>

<script>
export default {
    methods: {
        top(val) {
            return 150 - Math.cos(Math.PI / 30 * val) * 150
        },

        left(val) {
            return 150 + Math.sin(Math.PI / 30 * val) * 150
        },

        rotate(val) {
            return 6 * val
        }
    }
}
</script>

<style scoped>
.dials {
    background-color: #333;
    border-radius: 300px;

    position: relative;

    height: 300px;
    width: 300px;
}

.scale {
    background-color: white;

    position: absolute;

    width: 1px;
    height: 10px;

    transform-origin: left top;

}

.fifth {
    width: 5px;
    height: 20px;
}

.fifth p {
    margin-top: 20px;
    margin-left: -15px;

    color: white;
    font-size: 28px;
    font-weight: bold;
    text-align: center;

    width: 35px;
}
</style>

60個の目盛をループで位置(left, top)と向き(rotate)を計算しながら設定しています。

位置に関しては以下のように高校数学で学んだことを活用します。(懐かしい…)

location_circle.png

あとは5の倍数で目盛を太くして文字を表示しているだけです。

AnalogClock

AnalogClock.vue
<template>
    <div class="clock">
        <dials />
        <hand class="hand seconds" type="seconds" :rotate="seconds"/>
        <hand class="hand minutes" type="minutes" :rotate="minutes" />
        <hand class="hand hours"   type="hours"   :rotate="hours"/>
    </div>
</template>

<script>
import Hand from './Hand'
import Dials from './Dials'
import moment from 'moment'

export default {
    components: {
        Hand,
        Dials
    },

    data() {
        return {
            intervalId: undefined,
            time: undefined
        }
    },

    computed: {
        seconds() {
            let ss = moment(this.time).seconds()
            let nn = moment(this.time).milliseconds()
            return 6 * (ss + nn / 1000) 
        },

        minutes() {
            let mm = moment(this.time).minutes()
            return 6 * (mm + this.seconds / 360)
        },

        hours() {
            let hh = moment(this.time).hours()
            return 30 * (hh + this.minutes / 360)
        }
    },

    methods: {
        setTime() {
            this.intervalId = setInterval(() => {
                this.time = new Date()
            }, 10)
        }
    },

    mounted() {
        this.setTime()
    },

    beforeDestroy() {
        clearInterval(this.intervalId)
    },
}
</script>

<style scoped>
.clock {
    position: relative;
}

.hand {
    position: absolute;
}

.seconds {
    left: 150px;
    top: 20px;
}

.minutes {
    left: 149px;
    top: 20px;
}

.hours {
    left: 148px;
    top: 70px;
}
</style>

時刻の取得についてはデジタル時計編を参照してください。

針の動きを滑らかにするためにミリ秒を含めて角度の計算をしています。

簡単に解説をすると、例えば秒針の場合、秒の値だけだと0°→6°→12°→… というように角度が飛んでしまいます。
それをミリ秒を含めることで補完しています。

transitionでも滑らかに動かせますが、360°になるときに考慮が必要になります。

おわりに

さすがにもう時計シリーズはいいかな…。

5
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
7