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

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

こちらの続きです。

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

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

今回はアニメーションは使っておりません。



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°になるときに考慮が必要になります。


おわりに

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

コメント

このブログの人気の投稿

投稿時間:2021-06-17 05:05:34 RSSフィード2021-06-17 05:00 分まとめ(1274件)

投稿時間:2021-06-20 02:06:12 RSSフィード2021-06-20 02:00 分まとめ(3871件)

投稿時間:2020-12-01 09:41:49 RSSフィード2020-12-01 09:00 分まとめ(69件)