fix: stretch wordcloud shapes to fill container using ellipse radii

Changed from square min(w,h) radius to separate rx/ry that use
the full width and height of the container. Shapes now fill the
entire chart area instead of being constrained to a small square.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
hailin 2026-04-05 21:33:16 -07:00
parent e7d7745f74
commit f8ef83506a
1 changed files with 22 additions and 20 deletions

View File

@ -66,25 +66,27 @@ function createShapeMask(shape: string, w: number, h: number): HTMLCanvasElement
ctx.fillStyle = '#fff'; ctx.fillStyle = '#fff';
ctx.fillRect(0, 0, w, h); ctx.fillRect(0, 0, w, h);
// Draw black shape (word area) — fill as much as possible // Draw black shape (word area) — stretch to fill container
ctx.fillStyle = '#000'; ctx.fillStyle = '#000';
const cx = w / 2; const cx = w / 2;
const cy = h / 2; const cy = h / 2;
const r = Math.min(w, h) * 0.48; const rx = w * 0.48; // horizontal radius
const ry = h * 0.48; // vertical radius
switch (shape) { switch (shape) {
case 'circle': case 'circle': {
ctx.beginPath(); ctx.beginPath();
ctx.arc(cx, cy, r, 0, Math.PI * 2); ctx.ellipse(cx, cy, rx, ry, 0, 0, Math.PI * 2);
ctx.fill(); ctx.fill();
break; break;
}
case 'cardioid': { case 'cardioid': {
ctx.beginPath(); ctx.beginPath();
for (let angle = 0; angle < Math.PI * 2; angle += 0.01) { for (let angle = 0; angle < Math.PI * 2; angle += 0.01) {
const rr = r * 0.85 * (1 - Math.sin(angle)); const scale = 0.85 * (1 - Math.sin(angle));
const x = cx + rr * Math.cos(angle); const x = cx + rx * scale * Math.cos(angle);
const y = cy - rr * Math.sin(angle) + r * 0.3; const y = cy - ry * scale * Math.sin(angle) + ry * 0.3;
if (angle === 0) ctx.moveTo(x, y); if (angle === 0) ctx.moveTo(x, y);
else ctx.lineTo(x, y); else ctx.lineTo(x, y);
} }
@ -95,10 +97,10 @@ function createShapeMask(shape: string, w: number, h: number): HTMLCanvasElement
case 'diamond': { case 'diamond': {
ctx.beginPath(); ctx.beginPath();
ctx.moveTo(cx, cy - r); ctx.moveTo(cx, cy - ry);
ctx.lineTo(cx + r, cy); ctx.lineTo(cx + rx, cy);
ctx.lineTo(cx, cy + r); ctx.lineTo(cx, cy + ry);
ctx.lineTo(cx - r, cy); ctx.lineTo(cx - rx, cy);
ctx.closePath(); ctx.closePath();
ctx.fill(); ctx.fill();
break; break;
@ -106,9 +108,9 @@ function createShapeMask(shape: string, w: number, h: number): HTMLCanvasElement
case 'triangle': { case 'triangle': {
ctx.beginPath(); ctx.beginPath();
ctx.moveTo(cx, cy - r); ctx.moveTo(cx, cy - ry);
ctx.lineTo(cx + r * 0.87, cy + r * 0.5); ctx.lineTo(cx + rx, cy + ry);
ctx.lineTo(cx - r * 0.87, cy + r * 0.5); ctx.lineTo(cx - rx, cy + ry);
ctx.closePath(); ctx.closePath();
ctx.fill(); ctx.fill();
break; break;
@ -118,9 +120,10 @@ function createShapeMask(shape: string, w: number, h: number): HTMLCanvasElement
ctx.beginPath(); ctx.beginPath();
for (let i = 0; i < 10; i++) { for (let i = 0; i < 10; i++) {
const angle = (Math.PI / 2) + (i * Math.PI / 5); const angle = (Math.PI / 2) + (i * Math.PI / 5);
const rr = i % 2 === 0 ? r : r * 0.4; const outerX = i % 2 === 0 ? rx : rx * 0.4;
const x = cx + rr * Math.cos(angle); const outerY = i % 2 === 0 ? ry : ry * 0.4;
const y = cy - rr * Math.sin(angle); const x = cx + outerX * Math.cos(angle);
const y = cy - outerY * Math.sin(angle);
if (i === 0) ctx.moveTo(x, y); if (i === 0) ctx.moveTo(x, y);
else ctx.lineTo(x, y); else ctx.lineTo(x, y);
} }
@ -133,8 +136,8 @@ function createShapeMask(shape: string, w: number, h: number): HTMLCanvasElement
ctx.beginPath(); ctx.beginPath();
for (let i = 0; i < 5; i++) { for (let i = 0; i < 5; i++) {
const angle = (Math.PI / 2) + (i * 2 * Math.PI / 5); const angle = (Math.PI / 2) + (i * 2 * Math.PI / 5);
const x = cx + r * Math.cos(angle); const x = cx + rx * Math.cos(angle);
const y = cy - r * Math.sin(angle); const y = cy - ry * Math.sin(angle);
if (i === 0) ctx.moveTo(x, y); if (i === 0) ctx.moveTo(x, y);
else ctx.lineTo(x, y); else ctx.lineTo(x, y);
} }
@ -144,7 +147,6 @@ function createShapeMask(shape: string, w: number, h: number): HTMLCanvasElement
} }
default: default:
// Fallback: fill entire canvas (rectangle)
ctx.fillRect(0, 0, w, h); ctx.fillRect(0, 0, w, h);
break; break;
} }