プロンプト履歴
1)HTMLのCANVASでJSを使ってパイチャートを作ってください
2)パイチャートに文字も入れてください
3)ボタンを押すと円の中心を中心にして矢印をランダム秒回転して自動的に止まるようにできますか
4)%表示は止めて、最後に止まったところの値(A,B,C,D)を表示してください
5)矢印の中心がずれています。合わせてください。また、当たりが間違っています。
6)もっとたくさん回してから少し演出を入れてストップしてください
7)選択を47都道府県の名前にしてください
8)都道府県が多いので九州と沖縄だけにしてください
9)mp3を効果音として入れてください
https://soundeffect-lab.info/sound/anime/
から適当なmp3をダウンロードし、imagekitにアップロード
10)最後止まった時にも違う効果音を入れてください
11)最後の音の同期をきちんと取ってください
12)回転が止まってしばらくしてwin.mp3が流れます。止まると同時にwin.mp3を流してください
13)矢が止まると同時に最後のメッセージを出して、同時にwin.mp3を鳴らしてください
この後、これでは、うまく同期が取れないと判断し、音の同期は一旦あきらめる
14)県の文字をもう少し大きくして、文字を回転させるのではなく通常の角度で文字を表示してください
15)回すボタンをかっこよく装飾してください
16)メッセージもきれいに装飾してください
<style>
.spin-button {
background: linear-gradient(to bottom, #ffcc00, #ff9900);
border: none;
border-radius: 30px;
padding: 15px 40px;
font-size: 20px;
font-weight: bold;
color: white;
cursor: pointer;
box-shadow: 0 4px 8px rgba(0,0,0,0.2);
transition: transform 0.2s ease, box-shadow 0.2s ease;
}
.spin-button:hover {
transform: scale(1.05);
box-shadow: 0 6px 12px rgba(0,0,0,0.3);
}
.spin-button:active {
transform: scale(0.98);
box-shadow: 0 2px 4px rgba(0,0,0,0.2);
}
.result-message {
margin-top: 20px;
padding: 15px 25px;
font-size: 22px;
font-weight: bold;
color: #333;
background-color: #f8f8f8;
border: 2px solid #ddd;
border-radius: 15px;
text-align: center;
width: fit-content;
margin-left: auto;
margin-right: auto;
box-shadow: 0 4px 10px rgba(0,0,0,0.1);
opacity: 0;
transform: translateY(10px);
transition: opacity 0.5s ease, transform 0.5s ease;
}
.result-message.show {
opacity: 1;
transform: translateY(0);
}
</style>
<canvas id="myCanvas" width="400" height="400" style="border:1px solid #000;"></canvas><br>
<button class="spin-button" onclick="startSpin()">回す</button>
<p id="result" class="result-message"></p>
<audio id="spinSound" src="https://ik.imagekit.io/nlcynsjwm/kirakira.mp3?updatedAt=1751011133800" preload="auto"></audio>
<audio id="winSound" src="https://ik.imagekit.io/nlcynsjwm/win.mp3?updatedAt=1751011365596" preload="auto"></audio>
<script>
const canvas = document.getElementById('myCanvas');
const ctx = canvas.getContext('2d');
const centerX = canvas.width / 2;
const centerY = canvas.height / 2;
const radius = 150;
const spinSound = document.getElementById('spinSound');
const winSound = document.getElementById('winSound');
const prefectures = [
"福岡", "佐賀", "長崎", "熊本",
"大分", "宮崎", "鹿児島", "沖縄"
];
const total = prefectures.length;
let rotation = 0;
let spinning = false;
function drawPieChart() {
const anglePerSlice = 2 * Math.PI / total;
for (let i = 0; i < total; i++) {
const startAngle = i * anglePerSlice;
const endAngle = startAngle + anglePerSlice;
ctx.beginPath();
ctx.moveTo(centerX, centerY);
ctx.arc(centerX, centerY, radius, startAngle, endAngle);
ctx.closePath();
ctx.fillStyle = `hsl(${i * 360 / total}, 70%, 70%)`;
ctx.fill();
const midAngle = (startAngle + endAngle) / 2;
const labelX = centerX + Math.cos(midAngle) * radius * 0.65;
const labelY = centerY + Math.sin(midAngle) * radius * 0.65;
ctx.save();
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
ctx.fillStyle = 'black';
ctx.font = '16px sans-serif';
ctx.fillText(prefectures[i], labelX, labelY);
ctx.restore();
}
}
function drawArrow(angle) {
ctx.save();
ctx.translate(centerX, centerY);
ctx.rotate(angle);
ctx.beginPath();
ctx.moveTo(0, 0);
ctx.lineTo(0, -radius - 20);
ctx.lineWidth = 4;
ctx.strokeStyle = 'black';
ctx.stroke();
ctx.beginPath();
ctx.moveTo(0, -radius - 20);
ctx.lineTo(-8, -radius - 35);
ctx.lineTo(8, -radius - 35);
ctx.closePath();
ctx.fillStyle = 'black';
ctx.fill();
ctx.restore();
}
function draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
drawPieChart();
drawArrow(rotation);
}
function startSpin() {
if (spinning) return;
spinning = true;
document.getElementById("result").textContent = "";
// 効果音再生
spinSound.currentTime = 0;
spinSound.loop = true;
spinSound.play();
const totalSpin = 8 * 2 * Math.PI + Math.random() * 2 * Math.PI;
const duration = 4000;
const start = performance.now();
function animateSpin(time) {
const elapsed = time - start;
const progress = Math.min(elapsed / duration, 1);
const easeOut = 1 - Math.pow(1 - progress, 4);
rotation = easeOut * totalSpin;
draw();
if (progress < 1) {
requestAnimationFrame(animateSpin);
} else {
animateWobbleAndShowResult();
}
}
requestAnimationFrame(animateSpin);
}
function animateWobbleAndShowResult() {
const wobbleRange = 0.08;
const wobbleDecay = 0.95;
let wobbleAmount = wobbleRange;
let direction = 1;
function wobbleStep() {
wobbleAmount *= wobbleDecay;
if (wobbleAmount <= 0.001) {
// 判定(止まる直前に行う)
const anglePerSlice = 2 * Math.PI / total;
let arrowAngle = (rotation - Math.PI / 2) % (2 * Math.PI);
if (arrowAngle < 0) arrowAngle += 2 * Math.PI;
const index = Math.floor(arrowAngle / anglePerSlice);
const selected = prefectures[index];
// 音・メッセージ・描画を同期して実行!
spinSound.pause();
spinSound.currentTime = 0;
winSound.pause();
winSound.currentTime = 0;
winSound.play();
const message = document.getElementById("result");
message.textContent = `止まったのは「${selected}」です!`;
message.classList.remove("show"); // 連続使用に対応
void message.offsetWidth; // 再描画強制
message.classList.add("show");
draw(); // 最後の状態を描画
spinning = false;
return;
}
rotation += direction * wobbleAmount;
direction *= -1;
draw();
requestAnimationFrame(wobbleStep);
}
requestAnimationFrame(wobbleStep);
}
function showResult() {
const anglePerSlice = 2 * Math.PI / total;
let arrowAngle = (rotation - Math.PI / 2) % (2 * Math.PI);
if (arrowAngle < 0) arrowAngle += 2 * Math.PI;
const index = Math.floor(arrowAngle / anglePerSlice);
const selected = prefectures[index];
document.getElementById("result").textContent = `止まったのは「${selected}」です!`;
}
draw(); // 初期描画
</script>