時計をSVG化
This commit is contained in:
parent
d05aee19f2
commit
95d0d0047a
@ -1,24 +1,103 @@
|
|||||||
<template>
|
<template>
|
||||||
<canvas class="mk-analog-clock" ref="canvas" width="256" height="256"></canvas>
|
<svg class="mk-analog-clock" viewBox="0 0 10 10" preserveAspectRatio="none">
|
||||||
|
<line v-for="angle, i in graduations"
|
||||||
|
:x1="5 + (Math.sin(angle) * (5 - graduationsPadding))"
|
||||||
|
:y1="5 - (Math.cos(angle) * (5 - graduationsPadding))"
|
||||||
|
:x2="5 + (Math.sin(angle) * ((5 - graduationsPadding) - (i % 5 == 0 ? longGraduationLength : shortGraduationLength)))"
|
||||||
|
:y2="5 - (Math.cos(angle) * ((5 - graduationsPadding) - (i % 5 == 0 ? longGraduationLength : shortGraduationLength)))"
|
||||||
|
:stroke="i % 5 == 0 ? longGraduationColor : shortGraduationColor"
|
||||||
|
stroke-width="0.05"/>
|
||||||
|
|
||||||
|
<line
|
||||||
|
x1="5"
|
||||||
|
y1="5"
|
||||||
|
:x2="5 + (Math.sin(sAngle) * ((sHandLengthRatio * 5) - handsPadding))"
|
||||||
|
:y2="5 - (Math.cos(sAngle) * ((sHandLengthRatio * 5) - handsPadding))"
|
||||||
|
:stroke="sHandColor"
|
||||||
|
stroke-width="0.05"/>
|
||||||
|
<line
|
||||||
|
x1="5"
|
||||||
|
y1="5"
|
||||||
|
:x2="5 + (Math.sin(mAngle) * ((mHandLengthRatio * 5) - handsPadding))"
|
||||||
|
:y2="5 - (Math.cos(mAngle) * ((mHandLengthRatio * 5) - handsPadding))"
|
||||||
|
:stroke="mHandColor"
|
||||||
|
stroke-width="0.1"/>
|
||||||
|
<line
|
||||||
|
x1="5"
|
||||||
|
y1="5"
|
||||||
|
:x2="5 + (Math.sin(hAngle) * ((hHandLengthRatio * 5) - handsPadding))"
|
||||||
|
:y2="5 - (Math.cos(hAngle) * ((hHandLengthRatio * 5) - handsPadding))"
|
||||||
|
:stroke="hHandColor"
|
||||||
|
stroke-width="0.1"/>
|
||||||
|
</svg>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import Vue from 'vue';
|
import Vue from 'vue';
|
||||||
import { themeColor } from '../../../config';
|
import { themeColor } from '../../../config';
|
||||||
|
|
||||||
const Vec2 = function(this: any, x, y) {
|
|
||||||
this.x = x;
|
|
||||||
this.y = y;
|
|
||||||
};
|
|
||||||
|
|
||||||
export default Vue.extend({
|
export default Vue.extend({
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
clock: null
|
now: new Date(),
|
||||||
|
clock: null,
|
||||||
|
|
||||||
|
graduationsPadding: 0.5,
|
||||||
|
longGraduationLength: 0.3,
|
||||||
|
shortGraduationLength: 0.15,
|
||||||
|
handsPadding: 1,
|
||||||
|
hHandLengthRatio: 0.75,
|
||||||
|
mHandLengthRatio: 1,
|
||||||
|
sHandLengthRatio: 1,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
computed: {
|
||||||
|
longGraduationColor(): string {
|
||||||
|
return 'rgba(255, 255, 255, 0.3)';
|
||||||
|
},
|
||||||
|
shortGraduationColor(): string {
|
||||||
|
return 'rgba(255, 255, 255, 0.2)';
|
||||||
|
},
|
||||||
|
sHandColor(): string {
|
||||||
|
return 'rgba(255, 255, 255, 0.5)';
|
||||||
|
},
|
||||||
|
mHandColor(): string {
|
||||||
|
return '#fff';
|
||||||
|
},
|
||||||
|
hHandColor(): string {
|
||||||
|
return themeColor;
|
||||||
|
},
|
||||||
|
|
||||||
|
s(): number {
|
||||||
|
return this.now.getSeconds();
|
||||||
|
},
|
||||||
|
m(): number {
|
||||||
|
return this.now.getMinutes();
|
||||||
|
},
|
||||||
|
h(): number {
|
||||||
|
return this.now.getHours();
|
||||||
|
},
|
||||||
|
hAngle(): number {
|
||||||
|
return Math.PI * (this.h % 12 + this.m / 60) / 6;
|
||||||
|
},
|
||||||
|
mAngle(): number {
|
||||||
|
return Math.PI * (this.m + this.s / 60) / 30;
|
||||||
|
},
|
||||||
|
sAngle(): number {
|
||||||
|
return Math.PI * this.s / 30;
|
||||||
|
},
|
||||||
|
|
||||||
|
graduations(): any {
|
||||||
|
const angles = [];
|
||||||
|
for (let i = 0; i < 60; i++) {
|
||||||
|
const angle = Math.PI * i / 30;
|
||||||
|
angles.push(angle);
|
||||||
|
}
|
||||||
|
|
||||||
|
return angles;
|
||||||
|
}
|
||||||
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
this.tick();
|
|
||||||
this.clock = setInterval(this.tick, 1000);
|
this.clock = setInterval(this.tick, 1000);
|
||||||
},
|
},
|
||||||
beforeDestroy() {
|
beforeDestroy() {
|
||||||
@ -26,75 +105,7 @@ export default Vue.extend({
|
|||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
tick() {
|
tick() {
|
||||||
const canv = this.$refs.canvas as any;
|
this.now = new Date();
|
||||||
|
|
||||||
const now = new Date();
|
|
||||||
const s = now.getSeconds();
|
|
||||||
const m = now.getMinutes();
|
|
||||||
const h = now.getHours();
|
|
||||||
|
|
||||||
const ctx = canv.getContext('2d');
|
|
||||||
const canvW = canv.width;
|
|
||||||
const canvH = canv.height;
|
|
||||||
ctx.clearRect(0, 0, canvW, canvH);
|
|
||||||
|
|
||||||
{ // 背景
|
|
||||||
const center = Math.min((canvW / 2), (canvH / 2));
|
|
||||||
const lineStart = center * 0.90;
|
|
||||||
const shortLineEnd = center * 0.87;
|
|
||||||
const longLineEnd = center * 0.84;
|
|
||||||
for (let i = 0; i < 60; i++) {
|
|
||||||
const angle = Math.PI * i / 30;
|
|
||||||
const uv = new Vec2(Math.sin(angle), -Math.cos(angle));
|
|
||||||
ctx.beginPath();
|
|
||||||
ctx.lineWidth = 1;
|
|
||||||
ctx.moveTo((canvW / 2) + uv.x * lineStart, (canvH / 2) + uv.y * lineStart);
|
|
||||||
if (i % 5 == 0) {
|
|
||||||
ctx.strokeStyle = 'rgba(255, 255, 255, 0.2)';
|
|
||||||
ctx.lineTo((canvW / 2) + uv.x * longLineEnd, (canvH / 2) + uv.y * longLineEnd);
|
|
||||||
} else {
|
|
||||||
ctx.strokeStyle = 'rgba(255, 255, 255, 0.1)';
|
|
||||||
ctx.lineTo((canvW / 2) + uv.x * shortLineEnd, (canvH / 2) + uv.y * shortLineEnd);
|
|
||||||
}
|
|
||||||
ctx.stroke();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
{ // 分
|
|
||||||
const angle = Math.PI * (m + s / 60) / 30;
|
|
||||||
const length = Math.min(canvW, canvH) / 2.6;
|
|
||||||
const uv = new Vec2(Math.sin(angle), -Math.cos(angle));
|
|
||||||
ctx.beginPath();
|
|
||||||
ctx.strokeStyle = '#ffffff';
|
|
||||||
ctx.lineWidth = 2;
|
|
||||||
ctx.moveTo(canvW / 2 - uv.x * length / 5, canvH / 2 - uv.y * length / 5);
|
|
||||||
ctx.lineTo(canvW / 2 + uv.x * length, canvH / 2 + uv.y * length);
|
|
||||||
ctx.stroke();
|
|
||||||
}
|
|
||||||
|
|
||||||
{ // 時
|
|
||||||
const angle = Math.PI * (h % 12 + m / 60) / 6;
|
|
||||||
const length = Math.min(canvW, canvH) / 4;
|
|
||||||
const uv = new Vec2(Math.sin(angle), -Math.cos(angle));
|
|
||||||
ctx.beginPath();
|
|
||||||
ctx.strokeStyle = themeColor;
|
|
||||||
ctx.lineWidth = 2;
|
|
||||||
ctx.moveTo(canvW / 2 - uv.x * length / 5, canvH / 2 - uv.y * length / 5);
|
|
||||||
ctx.lineTo(canvW / 2 + uv.x * length, canvH / 2 + uv.y * length);
|
|
||||||
ctx.stroke();
|
|
||||||
}
|
|
||||||
|
|
||||||
{ // 秒
|
|
||||||
const angle = Math.PI * s / 30;
|
|
||||||
const length = Math.min(canvW, canvH) / 2.6;
|
|
||||||
const uv = new Vec2(Math.sin(angle), -Math.cos(angle));
|
|
||||||
ctx.beginPath();
|
|
||||||
ctx.strokeStyle = 'rgba(255, 255, 255, 0.5)';
|
|
||||||
ctx.lineWidth = 1;
|
|
||||||
ctx.moveTo(canvW / 2 - uv.x * length / 5, canvH / 2 - uv.y * length / 5);
|
|
||||||
ctx.lineTo(canvW / 2 + uv.x * length, canvH / 2 + uv.y * length);
|
|
||||||
ctx.stroke();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
Loading…
Reference in New Issue
Block a user