完成図
使い方
- Addボタンを押す
- 要素の出力したい角度を入力
- 要素を欲しい数だけ繰り返し追加する
- Generationボタンを押す
- Start Animationボタンを押す
注意点
Addボタンで追加した要素を後から変更した場合は必ずGenerationボタンを押すこと
code
こちらを基に応用させたものである
HTML
index.html
<div id="selects">
<div>
<button onclick="startAnimation()">Start Animation</button>
<button onclick="all_reset()">Reset Animation</button>
</div>
<div id="list"></div>
<button id="addButton">Add</button>
<button id="generationButton">Generation</button>
</div>
<div id="circle" class="circle"></div>
CSS
index.css
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: 200px;
height: 200px;
display: grid;
grid-template-columns: 1fr;
grid-template-rows: 1fr;
grid-column: 2/5;
grid-row: 2/5;
background-color: gray; /* 円の背景色 */
border-radius: 50%; /* 円形にする */
position: relative;
overflow: hidden;
}
JS
index.js
// ランダムな色を生成する関数
function getRandomColor() {
// 0 から 255 の間のランダムな整数を生成して、RGB値を作成する
var r = Math.floor(Math.random() * 256);
var g = Math.floor(Math.random() * 256);
var b = Math.floor(Math.random() * 256);
// RGB値をCSSの色の形式に変換して返す
return 'rgb(' + r + ',' + g + ',' + b + ')';
}
// addボタンがクリックされたときの処理
document.getElementById('addButton').addEventListener('click', function() {
var list = document.getElementById('list');
var newItem = document.createElement('div');
var newIndex = list.children.length + 1;
newItem.innerHTML = `
<label for="title${newIndex}_percent">角度を入力</label>
<input type="number" class="percent" id="title${newIndex}_percent" name="title${newIndex}_percent">
`;
list.appendChild(newItem);
// 追加された要素の数値入力フィールドを取得
var newNumberInput = document.getElementById('title' + newIndex + '_percent');
// 追加された要素の数値入力フィールドが空でない場合、ボタンを有効にする
if (!newNumberInput.value.trim()) {
document.getElementById('addButton').disabled = true;
} else {
document.getElementById('addButton').disabled = false;
}
// 追加された要素の数値入力フィールドの値が変更されるたびにチェックする
newNumberInput.addEventListener('input', function() {
if (!this.value.trim()) {
document.getElementById('addButton').disabled = true;
} else {
document.getElementById('addButton').disabled = false;
}
});
});
document.getElementById('generationButton').addEventListener('click', function() {
var circle = document.getElementById('circle');
circle.innerHTML = ''; // 円を空にする
var len = document.getElementById('list').children.length;
var rotates = 0;
// 360度を超えるかどうかをチェック
var check = 0;
for (var k = 1; k <= len; k++) {
var timeInput = document.getElementById('title' + k + '_percent');
check += Number(timeInput.value);
if (check > 360) {
alert("360度を超えています. 値を再入力してください");
return;
}
}
// 各要素を生成
for (var t = 1; t <= len; t++) {
var timeInput = document.getElementById('title' + t + '_percent');
var color = getRandomColor();
var count = Math.ceil(Number(timeInput.value) / 60); // 60度ごとの要素の数
for (var i = 0; i < count; i++) {
var newIndex_c = circle.children.length + 1;
var newTriangle = document.createElement('div');
newTriangle.style.height = '0';
newTriangle.style.width = '0';
newTriangle.style.display = 'grid';
newTriangle.style.gridColumn = '1/2';
newTriangle.style.gridRow = '1/2';
var angle = (i + 1) * 60; // 60度ごとの角度
var myangle = Math.min(Number(timeInput.value) - i * 60, 60); // 残りの角度
console.log("rotates: " + rotates + " myangle: " + myangle);
newTriangle.style.transform = 'translate(calc(200px / 2), calc(200px / 2 - 200px * 1.25 * cos(var(--angle) * 1deg))) rotate(' + rotates + 'deg)';
newTriangle.style.transformOrigin = 'left bottom';
newTriangle.style.borderRight = 'calc(200px * 1.25 * sin(calc(var(--angle) * 1deg))) solid transparent';
newTriangle.style.borderTop = 'calc(200px * 1.25 * cos(calc(var(--angle) * 1deg))) solid ' + color;
newTriangle.classList.add('triangle' + newIndex_c);
newTriangle.id = 'triangle' + newIndex_c;
newTriangle.setAttribute('data-myangle', myangle);
circle.appendChild(newTriangle);
rotates += myangle;
}
}
});
var reset_times = true; // アニメーションをリセットするかどうかのフラグ
var animatnow = false; // アニメーション中かどうかのフラグ
// アニメーション開始関数
function startAnimation() {
smoothTransition(360, 10);
}
// アニメーション関数(滑らかに移動する関数)
function smoothTransition() {
animatnow = true;
var currentAngle = 0; // 現在の角度
var frames = 100; // アニメーションのフレーム数
var duration = 1000; // アニメーションの期間(大まかな)
var interval = duration / frames; // フレーム間の間隔(ミリ秒)
var increment = (360 - currentAngle) / frames; // 各フレームでの角度の増加量
var circle = document.getElementById('circle');
var newIndex_c = circle.children.length + 1;
var animation = setInterval(function() {
// 現在の角度を更新
currentAngle += increment;
for(var i = 1; i < newIndex_c; i++){
console.log('changeAngle:' + i)
changeAngle(currentAngle, i); // changeAngle の実行結果を取得
}
// アニメーションが終了(リセット)したらクリアする
if (currentAngle >= 360 || !reset_times) {
if(!reset_times){
reset_angle();
}
animatnow = false;
reset_times = true;
clearInterval(animation);
}
}, interval);
}
// 角度を変更する関数
function changeAngle(angle, i){
var timeInput = document.getElementById('triangle' + i);
console.log("changeAngle:" + i)
var timeValue = timeInput.getAttribute('data-myangle');
console.log("timeValue:" + timeValue + " i:" + i)
// 既に設定された角度の合計を計算
var per = 0;
if(i>1){
for (var j = 1; j < i; j++) {
var timeInput_j = document.getElementById('triangle' + j);
var timeValue_j = timeInput_j.getAttribute('data-myangle');
per += Number(timeValue_j);
}
}
angle = Number(angle);
console.log("per:" + per + " timeValue:" + timeValue + " angle:" + angle + " i:" + i)
if(angle >= Number(timeValue) + per){
document.getElementById('triangle' + i).style.setProperty('--angle', Number(timeValue) + 0.1);
}else{
if(0>angle - per){
document.getElementById('triangle' + i).style.setProperty('--angle', 0);
}else{
document.getElementById('triangle' + i).style.setProperty('--angle', angle - per);
}
}
}
// アニメーション終了関数(角度をリセットする関数)
function reset_angle(){
var circle = document.getElementById('circle');
var newIndex_c = circle.children.length + 1;
for(var i = 1; i < newIndex_c; i++){
document.getElementById('triangle' + i).style.setProperty('--angle', 0);
}
}
// 初期化
function all_reset(){
if(animatnow){
reset_times = false;
}else{
reset_angle();
}
}