small visual changes

This commit is contained in:
2026-06-09 16:18:37 +09:00
parent 65e16f3502
commit e62b68ede6
2 changed files with 55 additions and 23 deletions

View File

@@ -25,18 +25,37 @@
let grandTotal = $derived(Object.values(continentTotals).reduce((a, b) => a + b, 0)); let grandTotal = $derived(Object.values(continentTotals).reduce((a, b) => a + b, 0));
let pct = $derived(grandTotal > 0 ? Math.round(total / grandTotal * 100) : 0); let pct = $derived(grandTotal > 0 ? Math.round(total / grandTotal * 100) : 0);
let donutStyle = $derived.by(() => { let segments = $derived.by(() => {
if (total === 0) return 'background: #e2e8f0'; if (total === 0) return [];
const segs = [];
let deg = 0; let deg = 0;
const stops = [];
for (const cont of CONTINENTS) { for (const cont of CONTINENTS) {
const angle = counts[cont] / total * 360; const angle = counts[cont] / total * 360;
if (angle > 0) { if (angle > 0) {
stops.push(`${continentColors[cont]} ${deg}deg ${deg + angle}deg`); const startDeg = deg;
const endDeg = deg + angle;
const midDeg = (startDeg + endDeg) / 2;
const rad = (midDeg - 90) * Math.PI / 180;
const sr = (startDeg - 90) * Math.PI / 180;
const er = (endDeg - 90) * Math.PI / 180;
const cx = 90, cy = 90, outerR = 65, innerR = 30;
const x1 = cx + outerR * Math.cos(sr);
const y1 = cy + outerR * Math.sin(sr);
const x2 = cx + outerR * Math.cos(er);
const y2 = cy + outerR * Math.sin(er);
const x3 = cx + innerR * Math.cos(er);
const y3 = cy + innerR * Math.sin(er);
const x4 = cx + innerR * Math.cos(sr);
const y4 = cy + innerR * Math.sin(sr);
const largeArc = angle > 180 ? 1 : 0;
const path = `M ${x1} ${y1} A ${outerR} ${outerR} 0 ${largeArc} 1 ${x2} ${y2} L ${x3} ${y3} A ${innerR} ${innerR} 0 ${largeArc} 0 ${x4} ${y4} Z`;
const lx = cx + 82 * Math.cos(rad);
const ly = cy + 82 * Math.sin(rad);
segs.push({ cont, color: continentColors[cont], path, lx, ly, angle });
deg += angle; deg += angle;
} }
} }
return `background: conic-gradient(${stops.join(', ')})`; return segs;
}); });
</script> </script>
@@ -64,9 +83,22 @@
{/each} {/each}
<div class="donut-wrap"> <div class="donut-wrap">
<div class="donut" style={donutStyle}> {#if segments.length > 0}
<div class="donut-hole"></div> <svg viewBox="0 0 180 180" class="donut-svg">
</div> {#each segments as seg}
<g class="seg-group">
<path d={seg.path} fill={seg.color} />
<text x={seg.lx} y={seg.ly} text-anchor="middle" dominant-baseline="middle" class="donut-label" style="font-size: {seg.angle < 20 ? 7 : 9}px">{seg.cont}</text>
</g>
{/each}
<circle cx="90" cy="90" r="30" fill="#f8fafc" />
</svg>
{:else}
<svg viewBox="0 0 180 180" class="donut-svg">
<circle cx="90" cy="90" r="65" fill="#e2e8f0" />
<circle cx="90" cy="90" r="30" fill="#f8fafc" />
</svg>
{/if}
</div> </div>
<div class="divider"></div> <div class="divider"></div>
@@ -177,22 +209,22 @@
margin: 24px 0; margin: 24px 0;
} }
.donut { .donut-svg {
width: 130px; width: 160px;
height: 130px; height: 160px;
border-radius: 50%; filter: drop-shadow(0 2px 4px rgba(0,0,0,0.1));
display: flex;
align-items: center;
justify-content: center;
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
outline: 2px solid #fff;
} }
.donut-hole { .donut-label {
width: 60px; fill: #1f2937;
height: 60px; font-weight: 600;
border-radius: 50%; pointer-events: none;
background: #f8fafc; opacity: 0;
transition: opacity 0.15s ease;
}
.seg-group:hover .donut-label {
opacity: 1;
} }
.disclaimer { .disclaimer {

View File

@@ -135,7 +135,7 @@
.datum(d) .datum(d)
.attr('cx', cx) .attr('cx', cx)
.attr('cy', cy) .attr('cy', cy)
.attr('r', 3) .attr('r', 2)
.attr('fill', getSelected().has(effId(d)) ? '#22c55e' : '#ffffff') .attr('fill', getSelected().has(effId(d)) ? '#22c55e' : '#ffffff')
.attr('stroke', '#94a3b8') .attr('stroke', '#94a3b8')
.attr('stroke-width', 0.5); .attr('stroke-width', 0.5);