完成品
時間の中に入力する値は1~99であることを前提にしている
code
HTML
index.html
<body>
<div id="selects">
<div>
<label for="radius">半径:</label>
<input type="range" id="radius" name="radius" min="50" max="500" value="200" oninput="changeRadius(this.value);">
</div>
<!-- 追加:ボタン -->
<div>
<button onclick="startAnimation()">Start Animation</button>
<button onclick="all_reset()">Reset Animation</button>
</div>
<div>
<label for="radius">時間:</label>
<input type="number" id="time" name="time" min="1" max="99" value="60" oninput="changeTimes(this.value);">
</div>
</div>
<div class="circle2">
<div class="triangle1" id="triangle1"></div>
<div class="triangle2" id="triangle2"></div>
<div class="triangle3" id="triangle3"></div>
<div class="triangle4" id="triangle4"></div>
<div class="triangle5" id="triangle5"></div>
<div class="triangle6" id="triangle6"></div>
</div>
<!-- 追加:秒数表示 -->
<div class="circle">
</div>
<div id="count_box">
<p id="currentSeconds">0</p>
</div>
</body>
CSS
細かな説明が気になる方は以下を参照ください
index.css
:root {
--radius: 200px; /* デフォルトの半径を定義 */
}
body {
display: grid;
place-items: center;
height: calc(100vh - 16px);
width: calc(100vw - 16px);
grid-template-columns: repeat(5, 1fr);
grid-template-rows: repeat(5, 1fr);
}
#selects {
height: 100%;
width: 100%;
grid-column: 1/6;
grid-row: 1/2;
display: grid;
align-items: center;
justify-content: center;
padding: 20px;
}
.circle {
width: 175px;
height: 175px;
display: grid;
grid-template-columns: 1fr;
grid-template-rows: 1fr;
grid-column: 2/5;
grid-row: 2/5;
background-color: black; /* 円の背景色 */
border-radius: 50%; /* 円形にする */
position: relative;
}
.circle2 {
width: 200px;
height: 200px;
display: grid;
grid-template-columns: 1fr;
grid-template-rows: 1fr;
grid-column: 2/5;
grid-row: 2/5;
background-color: red; /* 円の背景色 */
border-radius: 50%; /* 円形にする */
position: relative;
overflow: hidden;
}
.triangle1{
height: auto;
width: auto;
display: grid;
grid-column: 1/2;
grid-row: 1/2;
}
.triangle2{
height: auto;
width: auto;
display: grid;
grid-column: 1/2;
grid-row: 1/2;
}
.triangle3{
height: auto;
width: auto;
display: grid;
grid-column: 1/2;
grid-row: 1/2;
}
.triangle4{
height: auto;
width: auto;
display: grid;
grid-column: 1/2;
grid-row: 1/2;
}
.triangle5{
height: auto;
width: auto;
display: grid;
grid-column: 1/2;
grid-row: 1/2;
}
.triangle6{
height: auto;
width: auto;
display: grid;
grid-column: 1/2;
grid-row: 1/2;
}
.triangle1::before {
content: "";
width: 0;
height: 0;
grid-column: 1/2;
grid-row: 1/2;
transform: translate(calc(var(--radius) / 2), calc(var(--radius) / 2 - var(--radius) * 1.25 * cos(calc(var(--angle) * 1deg))));
transform-origin: left bottom; /* 中心を縦横の中心に設定 */
border-right: calc(var(--radius) * 1.25 * sin(calc(var(--angle) * 1deg))) solid transparent;
border-top: calc(var(--radius) * 1.25 * cos(calc(var(--angle) * 1deg))) solid #f3c87d;
}
.triangle2::before {
content: "";
width: 0;
height: 0;
grid-column: 1/2;
grid-row: 1/2;
transform-origin: left bottom; /* 中心を縦横の中心に設定 */
transform: translate(calc(var(--radius) / 2), calc(var(--radius) / 2 - var(--radius) * 1.25 * cos(calc(var(--angle) * 1deg)))) rotate(60deg);
border-right: calc(var(--radius) * 1.25 * sin(calc(var(--angle) * 1deg))) solid transparent;
border-top: calc(var(--radius) * 1.25 * cos(calc(var(--angle) * 1deg))) solid #f3c87d;
}
.triangle3::before {
content: "";
width: 0;
height: 0;
grid-column: 1/2;
grid-row: 1/2;
transform-origin: left bottom; /* 中心を縦横の中心に設定 */
transform: translate(calc(var(--radius) / 2), calc(var(--radius) / 2 - var(--radius) * 1.25 * cos(calc(var(--angle) * 1deg)))) rotate(120deg);
border-right: calc(var(--radius) * 1.25 * sin(calc(var(--angle) * 1deg))) solid transparent;
border-top: calc(var(--radius) * 1.25 * cos(calc(var(--angle) * 1deg))) solid #f3c87d;
}
.triangle4::before {
content: "";
width: 0;
height: 0;
grid-column: 1/2;
grid-row: 1/2;
transform-origin: left bottom; /* 中心を縦横の中心に設定 */
transform: translate(calc(var(--radius) / 2), calc(var(--radius) / 2 - var(--radius) * 1.25 * cos(calc(var(--angle) * 1deg)))) rotate(180deg);
border-right: calc(var(--radius) * 1.25 * sin(calc(var(--angle) * 1deg))) solid transparent;
border-top: calc(var(--radius) * 1.25 * cos(calc(var(--angle) * 1deg))) solid #f3c87d;
}
.triangle5::before {
content: "";
width: 0;
height: 0;
grid-column: 1/2;
grid-row: 1/2;
transform-origin: left bottom; /* 中心を縦横の中心に設定 */
transform: translate(calc(var(--radius) / 2), calc(var(--radius) / 2 - var(--radius) * 1.25 * cos(calc(var(--angle) * 1deg)))) rotate(240deg);
border-right: calc(var(--radius) * 1.25 * sin(calc(var(--angle) * 1deg))) solid transparent;
border-top: calc(var(--radius) * 1.25 * cos(calc(var(--angle) * 1deg))) solid #f3c87d;
}
.triangle6::before {
content: "";
width: 0;
height: 0;
grid-column: 1/2;
grid-row: 1/2;
transform-origin: left bottom; /* 中心を縦横の中心に設定 */
transform: translate(calc(var(--radius) / 2), calc(var(--radius) / 2 - var(--radius) * 1.25 * cos(calc(var(--angle) * 1deg)))) rotate(300deg);
border-right: calc(var(--radius) * 1.25 * sin(calc(var(--angle) * 1deg))) solid transparent;
border-top: calc(var(--radius) * 1.25 * cos(calc(var(--angle) * 1deg))) solid #f3c87d;
}
.currentSeconds{
grid-column: 1/2;
grid-row: 1/2;
}
#count_box{
display: grid;
place-items: center;
height: var(--radius);
width: var(--radius);
grid-column: 2/5;
grid-row: 2/5;
font-size: calc(var(--radius) / 2);
font-weight: bold;
z-index: 1;
}
p{
color: white;
margin: 0;
}
JS
smoothTransition()
で滑らかなアニメーショにする際,正確な時間を表示するためにスタート時刻との差から計算した角度をchangeAngle(angle, times_animat)
で使用している.
index.js
var times = 60; // 残り時間
changeTimes(times);
var reset_times = false; // アニメーションをリセットするかどうか
// 時間を変更する関数
function changeTimes(time){
updateCurrentSeconds(time);
}
// アニメーション開始関数
function startAnimation() {
if(!reset_times){
reset_times = true;
smoothTransition(); // 360度までの滑らかな遷移
}
}
// 秒数を表示する関数
function updateCurrentSeconds(seconds) {
document.getElementById('currentSeconds').textContent = Math.floor(seconds);
}
// 中心角を変更する関数
function changeAngle(angle, times_animat){
if(angle < 65){
document.getElementById('triangle1').style.setProperty('--angle', angle);
}else if(angle < 125){
document.getElementById('triangle2').style.setProperty('--angle', angle - 60);
}else if(angle < 185){
document.getElementById('triangle3').style.setProperty('--angle', angle - 120);
}else if(angle < 245){
document.getElementById('triangle4').style.setProperty('--angle', angle - 180);
}else if(angle < 305){
document.getElementById('triangle5').style.setProperty('--angle', angle - 240);
}else if(angle < 360){
if(angle < 360){
document.getElementById('triangle6').style.setProperty('--angle', angle - 300);
}else{
document.getElementById('triangle6').style.setProperty('--angle', 65);
}
}else{
reset_angle();
}
// 現在の秒数を更新
if (times_animat - (angle / 360 * times_animat) > 0) {
updateCurrentSeconds(times_animat - (angle / 360 * times_animat));
} else {
updateCurrentSeconds(0);
}
}
// 中心角のリセット
function reset_angle(){
document.getElementById('triangle1').style.setProperty('--angle', 0);
document.getElementById('triangle2').style.setProperty('--angle', 0);
document.getElementById('triangle3').style.setProperty('--angle', 0);
document.getElementById('triangle4').style.setProperty('--angle', 0);
document.getElementById('triangle5').style.setProperty('--angle', 0);
document.getElementById('triangle6').style.setProperty('--angle', 0);
return true;
}
// 初期化
function all_reset(){
reset_times = false;
}
// 滑らかなアニメーション
function smoothTransition() {
var currentAngle = 0; // 現在の角度
var times_animat = document.getElementById('time').value; // カウント時間
var duration = 1000 * times_animat; // アニメーションの期間(ミリ秒)
var startTime = performance.now(); // アニメーションの開始時間
var animation = setInterval(function() {
var elapsed = performance.now() - startTime; // 経過時間
// 現在の角度を更新
currentAngle = (360) * (elapsed / duration);
// 中心角を計算して更新
changeAngle(currentAngle, times_animat);
// アニメーションが終了したら終了
if (elapsed >= duration || !reset_times) {
clearInterval(animation);
updateCurrentSeconds(times_animat);
reset_angle();
reset_times = false;
}
}, 1000 / 60); // 60 FPSでアニメーション
}