Anonymous
Рендеринг введенного пользователем текста в виде концентрических кругов
Сообщение
Anonymous » 20 янв 2026, 18:13
У меня на странице есть раздел «Круг благодарности».
Желаемый дизайн приведен ниже:
Идея состоит в том, что на странице будет поле ввода, в которое пользователь сможет ввести свое имя, и когда он нажмет кнопку отправки, имя будет в этом поле. справа.
Я пробовал так:
Код: Выделить всё
const canvas = document.getElementById('gratitude-circle');
const ctx = canvas.getContext('2d');
const form = document.getElementById('gratitude-form');
const input = document.getElementById('name-input');
const centerX = canvas.width / 2;
const centerY = canvas.height / 2;
const circleRadius = 250;
const minTextGap = 10; // Minimum gap between texts
const names = [];
function clearCircle() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
// Draw decorative wreath (stylized circle with leaves)
ctx.save();
ctx.beginPath();
ctx.arc(centerX, centerY, circleRadius, 0, 2 * Math.PI);
ctx.strokeStyle = '#7bbf8e';
ctx.lineWidth = 4;
ctx.shadowColor = '#b8e2c8';
ctx.shadowBlur = 8;
ctx.stroke();
ctx.restore();
// Draw simple leaf accents (simulate wreath)
for (let i = 0; i < 24; i++) {
const angle = (i / 24) * 2 * Math.PI;
const leafX = centerX + (circleRadius - 18) * Math.cos(angle);
const leafY = centerY + (circleRadius - 18) * Math.sin(angle);
ctx.save();
ctx.translate(leafX, leafY);
ctx.rotate(angle + Math.PI / 2);
ctx.beginPath();
ctx.moveTo(0, 0);
ctx.quadraticCurveTo(6, 8, 0, 18);
ctx.quadraticCurveTo(-6, 8, 0, 0);
ctx.fillStyle = '#b8e2c8';
ctx.globalAlpha = 0.7;
ctx.fill();
ctx.globalAlpha = 1;
ctx.restore();
}
// Draw central message
ctx.save();
ctx.font = '28px Segoe UI, Arial';
ctx.fillStyle = '#7bbf8e';
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
ctx.fillText('Thank you', centerX, centerY - 28);
ctx.font = 'bold 32px Segoe UI, Arial';
ctx.fillStyle = '#4a8c6b';
ctx.fillText('for being part', centerX, centerY + 4);
ctx.font = '28px Segoe UI, Arial';
ctx.fillStyle = '#7bbf8e';
ctx.fillText('of our story.', centerX, centerY + 36);
ctx.restore();
}
function drawNames() {
clearCircle();
if (names.length === 0) return;
// Place names along the circumference
const totalNames = names.length;
const fontSize = 22;
ctx.font = 'bold 22px Segoe UI, Arial';
let totalArcLength = 0;
let nameArcLengths = [];
// First, measure arc length for each name
for (let i = 0; i < totalNames; i++) {
const name = names[i];
const textWidth = ctx.measureText(name).width;
// Arc length = width / radius
const arc = textWidth / circleRadius;
nameArcLengths.push(arc);
totalArcLength += arc;
}
// Calculate starting angle so names are centered
let gap = minTextGap / circleRadius;
let totalGap = gap * totalNames;
let startAngle = -totalArcLength / 2 - totalGap / 2;
let angle = startAngle;
for (let i = 0; i < totalNames; i++) {
const name = names[i];
const arc = nameArcLengths[i];
const theta = angle + arc / 2;
const x = centerX + circleRadius * Math.cos(theta);
const y = centerY + circleRadius * Math.sin(theta);
ctx.save();
ctx.translate(x, y);
ctx.rotate(theta + Math.PI / 2);
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
ctx.fillStyle = '#333';
ctx.fillText(name, 0, 0);
ctx.restore();
angle += arc + gap;
}
}
form.addEventListener('submit', function(e) {
e.preventDefault();
const name = input.value.trim();
if (name && names.length < 100) { // Limit to avoid overfilling
names.push(name);
drawNames();
input.value = '';
}
});
clearCircle();
Код: Выделить всё
body {
background: #fff7f3;
font-family: 'Segoe UI', Arial, sans-serif;
margin: 0;
padding: 0;
}
.container {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
min-height: 100vh;
}
#gratitude-form {
margin-bottom: 32px;
display: flex;
gap: 12px;
}
#name-input {
padding: 10px 16px;
border-radius: 20px;
border: 1px solid #b2b2b2;
font-size: 1.1rem;
outline: none;
}
#gratitude-form button {
padding: 10px 20px;
border-radius: 20px;
border: none;
background: #7bbf8e;
color: #fff;
font-size: 1.1rem;
cursor: pointer;
transition: background 0.2s;
}
#gratitude-form button:hover {
background: #5fa06e;
}
.circle-area {
background: transparent;
display: flex;
align-items: center;
justify-content: center;
}
#gratitude-circle {
background: transparent;
display: block;
border-radius: 50%;
box-shadow: 0 0 0 2px #e0e0e0;
}
Но результат выглядит так:
Есть ли какой-нибудь способ разработать такую динамическую область?
Подробнее здесь:
https://stackoverflow.com/questions/795 ... ic-circles
1768922011
Anonymous
У меня на странице есть раздел «Круг благодарности». Желаемый дизайн приведен ниже: [img]https://i.sstatic.net/JDAhlz2C.webp[/img] Идея состоит в том, что на странице будет поле ввода, в которое пользователь сможет ввести свое имя, и когда он нажмет кнопку отправки, имя будет в этом поле. справа. Я пробовал так: [code]const canvas = document.getElementById('gratitude-circle'); const ctx = canvas.getContext('2d'); const form = document.getElementById('gratitude-form'); const input = document.getElementById('name-input'); const centerX = canvas.width / 2; const centerY = canvas.height / 2; const circleRadius = 250; const minTextGap = 10; // Minimum gap between texts const names = []; function clearCircle() { ctx.clearRect(0, 0, canvas.width, canvas.height); // Draw decorative wreath (stylized circle with leaves) ctx.save(); ctx.beginPath(); ctx.arc(centerX, centerY, circleRadius, 0, 2 * Math.PI); ctx.strokeStyle = '#7bbf8e'; ctx.lineWidth = 4; ctx.shadowColor = '#b8e2c8'; ctx.shadowBlur = 8; ctx.stroke(); ctx.restore(); // Draw simple leaf accents (simulate wreath) for (let i = 0; i < 24; i++) { const angle = (i / 24) * 2 * Math.PI; const leafX = centerX + (circleRadius - 18) * Math.cos(angle); const leafY = centerY + (circleRadius - 18) * Math.sin(angle); ctx.save(); ctx.translate(leafX, leafY); ctx.rotate(angle + Math.PI / 2); ctx.beginPath(); ctx.moveTo(0, 0); ctx.quadraticCurveTo(6, 8, 0, 18); ctx.quadraticCurveTo(-6, 8, 0, 0); ctx.fillStyle = '#b8e2c8'; ctx.globalAlpha = 0.7; ctx.fill(); ctx.globalAlpha = 1; ctx.restore(); } // Draw central message ctx.save(); ctx.font = '28px Segoe UI, Arial'; ctx.fillStyle = '#7bbf8e'; ctx.textAlign = 'center'; ctx.textBaseline = 'middle'; ctx.fillText('Thank you', centerX, centerY - 28); ctx.font = 'bold 32px Segoe UI, Arial'; ctx.fillStyle = '#4a8c6b'; ctx.fillText('for being part', centerX, centerY + 4); ctx.font = '28px Segoe UI, Arial'; ctx.fillStyle = '#7bbf8e'; ctx.fillText('of our story.', centerX, centerY + 36); ctx.restore(); } function drawNames() { clearCircle(); if (names.length === 0) return; // Place names along the circumference const totalNames = names.length; const fontSize = 22; ctx.font = 'bold 22px Segoe UI, Arial'; let totalArcLength = 0; let nameArcLengths = []; // First, measure arc length for each name for (let i = 0; i < totalNames; i++) { const name = names[i]; const textWidth = ctx.measureText(name).width; // Arc length = width / radius const arc = textWidth / circleRadius; nameArcLengths.push(arc); totalArcLength += arc; } // Calculate starting angle so names are centered let gap = minTextGap / circleRadius; let totalGap = gap * totalNames; let startAngle = -totalArcLength / 2 - totalGap / 2; let angle = startAngle; for (let i = 0; i < totalNames; i++) { const name = names[i]; const arc = nameArcLengths[i]; const theta = angle + arc / 2; const x = centerX + circleRadius * Math.cos(theta); const y = centerY + circleRadius * Math.sin(theta); ctx.save(); ctx.translate(x, y); ctx.rotate(theta + Math.PI / 2); ctx.textAlign = 'center'; ctx.textBaseline = 'middle'; ctx.fillStyle = '#333'; ctx.fillText(name, 0, 0); ctx.restore(); angle += arc + gap; } } form.addEventListener('submit', function(e) { e.preventDefault(); const name = input.value.trim(); if (name && names.length < 100) { // Limit to avoid overfilling names.push(name); drawNames(); input.value = ''; } }); clearCircle();[/code] [code]body { background: #fff7f3; font-family: 'Segoe UI', Arial, sans-serif; margin: 0; padding: 0; } .container { display: flex; flex-direction: column; align-items: center; justify-content: center; min-height: 100vh; } #gratitude-form { margin-bottom: 32px; display: flex; gap: 12px; } #name-input { padding: 10px 16px; border-radius: 20px; border: 1px solid #b2b2b2; font-size: 1.1rem; outline: none; } #gratitude-form button { padding: 10px 20px; border-radius: 20px; border: none; background: #7bbf8e; color: #fff; font-size: 1.1rem; cursor: pointer; transition: background 0.2s; } #gratitude-form button:hover { background: #5fa06e; } .circle-area { background: transparent; display: flex; align-items: center; justify-content: center; } #gratitude-circle { background: transparent; display: block; border-radius: 50%; box-shadow: 0 0 0 2px #e0e0e0; }[/code] [code] Add Name [/code] Но результат выглядит так: [img]https://i.sstatic.net/f5g2KCp6.webp[/img] Есть ли какой-нибудь способ разработать такую динамическую область? Подробнее здесь: [url]https://stackoverflow.com/questions/79598919/rendering-user-input-text-in-concentric-circles[/url]