preface
The effect came from a screensaver software called World-Clock. I thought it was so interesting that I decided to masturbating myself late at night.
Results the preview
Online preview: Compass clock
Preview screenshot:
implement
The first step is to arrange multiple text elements in a circle, and then rotate the circle at a certain Angle to achieve the effect.
The next step is to implement how to arrange the text in a circle. Once you’ve done that, the rest is easy.
Arrange the text in a circle
Next, let’s implement the outermost “second” step by step. Seconds have 60 elements ranging from 0 to 59, first positioning them in a square div.
<template>
<div class="home">
<! - seconds -- -- >
<div class="box-wrapper">
<div class="circle-box" :style="boxStyle('seconds')">
<span
v-for="(item, index) in secondTexts"
:key="item"
>{{ item }}</span>
</div>
</div>
</div>
</template>
<script>
export default {
name: 'Home'.data() {
return {
secondTexts: [
'zero zero'.'a second'.'two seconds'.'three seconds'.'four seconds'.'five seconds'.'six seconds'.'seven seconds'.'eight seconds'.'nine seconds'.'ten seconds'.'Eleven seconds'.'Twelve seconds'.'Thirteen seconds'.'Fourteen seconds'.'Fifteen seconds'.'Sixteen seconds'.'Seventeen seconds'.'Eighteen seconds'.'Nineteen seconds'.'Twenty seconds'.'Twenty-one seconds'.'Twenty-two seconds'.'twenty-three seconds'.'twenty-four seconds'.'twenty-five seconds'.'Twenty-six seconds'.'Twenty-seven seconds'.'Twenty-eight seconds'.'Twenty-nine seconds'.'Thirty seconds'.'Thirty-one seconds'.'Thirty-two seconds'.'Thirty-three seconds'.'Thirty-four seconds'.'35 seconds'.'Thirty-six seconds'.'Thirty-seven seconds'.'Thirty-eight seconds'.'Thirty-nine seconds'.'Forty seconds'.'Forty-one seconds'.'Forty-two seconds'.'Forty-three seconds'.'Forty-four seconds'.'Forty-five seconds'.'Forty-six seconds'.'Forty-seven seconds'.'Forty-eight seconds'.'Forty-nine seconds'.'Fifty seconds'.'Fifty-one seconds'.'Fifty-two seconds'.'Fifty-three seconds'.'Fifty-four seconds'.'Fifty-five seconds'.'Fifty-six seconds'.'Fifty-seven seconds'.'Fifty-eight seconds'.'Fifty-nine seconds'].// Box size
boxSize: {
seconds: 580}}},methods: {
// Set the width and height of the text box
boxStyle(key) {
return {
width: this.boxSize[key] + 'px'.height: this.boxSize[key] + 'px'}}}}</script>
<style lang="scss" scoped>
.home {
height: 100%;
width: 100%;
background-color: # 000000;
color: #71767D;
position: relative;
min-width: 800px;
min-height: 660px;
padding: 20px 0;
overflow: hidden;
}
.box-wrapper {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
.circle-box {
position: relative;
border: 1px solid red;
}
.circle-box span {
white-space: nowrap;
font-size: 14px;
position: absolute;
}
</style>
Copy the code
Now the text is stacked together after setting absolute positioning, and the next step is to make it circular through position calculation.
From the figure, we know that to arrange text on the circle, we need to know the x-coordinate and y-coordinate of the text elements to point O (center of the circle), that is, the height of a and the length of B, which corresponds to the top and left values we want to set.
We know the radius, that is, half the width of the box, r = 580/2 = 290, and the Angle between each element and the center of the circle, c = (360/60) * I, from which we can figure out the values of a and B according to the mathematical formula. The new code is as follows:
<template>
<div class="home">
<! - seconds -- -- >
<div class="box-wrapper">
<div class="circle-box" :style="boxStyle('seconds')">
<span
v-for="(item, index) in secondTexts"
:key="item"
:style="spanStyle(boxSize.seconds, secondTexts, index)"
>{{ item }}</span>
</div>
</div>
</div>
</template>
<script>
export default {
name: 'Home'.methods: {
spanStyle(size, texts, i) {
const r = size / 2 / / radius
const deg = this.getPerDeg(texts) // The average degree of element spacing
const angle = i * deg / / the Angle
const { a, b } = this.getHypotenuse(r, angle)
const rotateDeg = deg * i // The rotation Angle of the text
return {
top: a + r + 'px'.left: b + r + 'px'.transform: `rotate(${rotateDeg}deg)`.transformOrigin: '0 0'}},// The average degree of element spacing
getPerDeg(texts) {
return 360 / texts.length
},
// Get the Angle and the hypotenuse
getHypotenuse(long, angle) {
// Get radians
let radian = 2 * Math.PI / 360 * angle
return {
a: Math.sin(radian) * long, / / adjacent side
b: Math.cos(radian) * long / / on the edge}}}}</script>
Copy the code
Good effect, then play CV method, the latitude to get up minutes. The new code is as follows:
<template>
<div class="home">
<!-- 分 -->
<div class="box-wrapper">
<div class="circle-box" :style="boxStyle('minutes', minutesDeg)">
<span
v-for="(item, index) in minuteTexts"
:key="item"
:style="spanStyle(boxSize.minutes, minuteTexts, index)"
>{{ item }}</span>
</div>
</div>
<! - seconds -- -- >
<div class="box-wrapper">
<div class="circle-box" :style="boxStyle('seconds', secondsDeg)">
<span
v-for="(item, index) in secondTexts"
:key="item"
:style="spanStyle(boxSize.seconds, secondTexts, index)"
>{{ item }}</span>
</div>
</div>
</div>
</template>
<script>
export default {
name: 'Home'.data() {
return {
secondTexts: [
'zero zero'.'a second'.'two seconds'.'three seconds'.'four seconds'.'five seconds'.'six seconds'.'seven seconds'.'eight seconds'.'nine seconds'.'ten seconds'.'Eleven seconds'.'Twelve seconds'.'Thirteen seconds'.'Fourteen seconds'.'Fifteen seconds'.'Sixteen seconds'.'Seventeen seconds'.'Eighteen seconds'.'Nineteen seconds'.'Twenty seconds'.'Twenty-one seconds'.'Twenty-two seconds'.'twenty-three seconds'.'twenty-four seconds'.'twenty-five seconds'.'Twenty-six seconds'.'Twenty-seven seconds'.'Twenty-eight seconds'.'Twenty-nine seconds'.'Thirty seconds'.'Thirty-one seconds'.'Thirty-two seconds'.'Thirty-three seconds'.'Thirty-four seconds'.'35 seconds'.'Thirty-six seconds'.'Thirty-seven seconds'.'Thirty-eight seconds'.'Thirty-nine seconds'.'Forty seconds'.'Forty-one seconds'.'Forty-two seconds'.'Forty-three seconds'.'Forty-four seconds'.'Forty-five seconds'.'Forty-six seconds'.'Forty-seven seconds'.'Forty-eight seconds'.'Forty-nine seconds'.'Fifty seconds'.'Fifty-one seconds'.'Fifty-two seconds'.'Fifty-three seconds'.'Fifty-four seconds'.'Fifty-five seconds'.'Fifty-six seconds'.'Fifty-seven seconds'.'Fifty-eight seconds'.'Fifty-nine seconds'].minuteTexts: [
'zero zero'.'one'.'binary'.'3'.'four points'.'five'.'six points'.'seven'.'eight'.'nine points'.'very'.'Eleven points'.'Twelve points'.'Thirteen minutes'.'Fourteen points'.'Fifteen minutes'.'Sixteen minutes'.'Seventeen minutes'.'Eighteen points'.'Nineteen cents'.'Twenty minutes'.'Twenty-one points'.'Twenty-two points'.'Twenty-three points'.'Twenty-four minutes'.'Twenty-five minutes'.'Twenty-six points'.'Twenty-seven points'.'Twenty-eight points'.'Twenty-nine points'.'Thirty minutes'.'Thirty-one points'.'Thirty-two points'.'Thirty-three points'.'Thirty-four points'.'Thirty-five minutes'.'Thirty-six minutes'.'Thirty-seven minutes'.'Thirty-eight points'.'Thirty-nine points'.'Forty minutes'.'Forty-one points'.'Forty-two points'.'Forty-three points'.'Forty-four points'.'Forty-five'.'Forty-six minutes'.'Forty-seven minutes'.'Forty-eight points'.'Forty-nine.'.'Fifty points'.'Fifty-one points'.'Fifty-two points'.'Fifty-three points'.'Fifty-four points'.'Fifty-five minutes'.'Fifty-six minutes'.'Fifty-seven points'.'Fifty-eight points'.'Fifty-nine.'].// Box size
boxSize: {
seconds: 580.minutes: 440}}}}</script>
Copy the code
Achieve compass rotation
The new code is as follows:
<template>
<div class="home">
<!-- 分 -->
<div class="box-wrapper">
<div class="circle-box" :style="boxStyle('minutes', minutesDeg)">
<span
v-for="(item, index) in minuteTexts"
:key="item"
:style="spanStyle(boxSize.minutes, minuteTexts, index)"
:class="{'active': index === currentMinutes}"
>{{ item }}</span>
</div>
</div>
<! - seconds -- -- >
<div class="box-wrapper">
<div class="circle-box" :style="boxStyle('seconds', secondsDeg)">
<span
v-for="(item, index) in secondTexts"
:key="item"
:style="spanStyle(boxSize.seconds, secondTexts, index)"
:class="{'active': index === currentSeconds}"
>{{ item }}</span>
</div>
</div>
</div>
</template>
<script>
export default {
name: 'Home'.data() {
return {
currentMinutes: 0.// Current - minute
currentSeconds: 0.// Current - second
minutesDeg: 0.// Current - minute - rotation Angle
secondsDeg: 0.// Current - face - rotation Angle
timer: null / / timer}},mounted() {
this.init()
},
methods: {
init() {
const d = new Date(a)const minutes = d.getMinutes() / / points
const seconds = d.getSeconds() / / SEC.
// The current time
this.currentMinutes = minutes
this.currentSeconds = seconds
/ / Angle
this.minutesDeg = this.currentMinutes * this.getPerDeg(this.minuteTexts)
this.secondsDeg = this.currentSeconds * this.getPerDeg(this.secondTexts)
// Set the timer
this.timer = setInterval(() = > {
this.runClock()
}, 1000)
// Remember to clear the timer
this.$once('hook:beforeDestroy'.() = > {
clearInterval(this.timer)
})
},
boxStyle(key, deg) {
return {
// Set the width and height of the text box
width: this.boxSize[key] + 'px'.height: this.boxSize[key] + 'px'.// Add rotation
transform: `rotate(-${deg}deg)`}},// The average degree of element spacing
getPerDeg(texts) {
return 360 / texts.length
},
runClock() {
const d = new Date(a)const minutes = d.getMinutes() / / points
const seconds = d.getSeconds() / / SEC.
if (this.currentMinutes ! == minutes) {this.currentMinutes = minutes
this.minutesDeg += this.getPerDeg(this.minuteTexts)
}
this.currentSeconds = seconds
this.secondsDeg += this.getPerDeg(this.secondTexts)
}
}
}
</script>
<style lang="scss" scoped>
.circle-box {
position: relative; // Add animation effectstransition: transform 0.4 sease-in-out; } // The text color is white when activated.circle-box span.active {
color: #fff;
}
</style>
Copy the code
At this point, the whole work is almost complete, the rest of the month, day, time and other latitude is to follow the pattern of things, here will not be posted, interested students can go to GitHub to see the full code.
Full code address: GitHub
At the end
That’s the end of this article, thanks for reading, code words are not easy, welcome your likes 👍!!
If there is something wrong with this article, also welcome to comment area to correct, exchange!