105 lines
3.1 KiB
TypeScript
105 lines
3.1 KiB
TypeScript
import { useEffect, useRef } from 'react';
|
|
import { BADGE_MAP, PROFILE_DIMENSIONS } from './badges';
|
|
import type { DimensionScore } from './ReportPage';
|
|
|
|
interface Props {
|
|
badgeDimension: string;
|
|
scores: DimensionScore[];
|
|
/** 玩家自取称呼(C1-01 profile.name),空串时只显示编号 */
|
|
playerName?: string;
|
|
}
|
|
|
|
/** 分享卡:canvas 生成 PNG 下载(勋章 + 7 维分数) */
|
|
export function ShareCard({ badgeDimension, scores, playerName }: Props) {
|
|
const canvasRef = useRef<HTMLCanvasElement>(null);
|
|
|
|
useEffect(() => {
|
|
draw();
|
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
}, [scores, badgeDimension, playerName]);
|
|
|
|
function draw(): HTMLCanvasElement {
|
|
const canvas = canvasRef.current!;
|
|
const ctx = canvas.getContext('2d')!;
|
|
const W = 640;
|
|
const H = 960;
|
|
canvas.width = W;
|
|
canvas.height = H;
|
|
|
|
const badge = BADGE_MAP[badgeDimension] ?? { title: '档案采集员', flavor: '' };
|
|
const dim = PROFILE_DIMENSIONS.find((d) => d.id === badgeDimension);
|
|
|
|
// 背景渐变(美术占位)
|
|
const bg = ctx.createLinearGradient(0, 0, W, H);
|
|
bg.addColorStop(0, '#1a1626');
|
|
bg.addColorStop(1, '#3a2a4a');
|
|
ctx.fillStyle = bg;
|
|
ctx.fillRect(0, 0, W, H);
|
|
|
|
ctx.textAlign = 'center';
|
|
ctx.fillStyle = '#c9b48a';
|
|
ctx.font = '28px serif';
|
|
ctx.fillText('苍梧疑冢 · 人格画像', W / 2, 80);
|
|
ctx.font = '22px serif';
|
|
ctx.fillText(`C-2049${playerName ? `「${playerName}」` : ''}的档案`, W / 2, 118);
|
|
|
|
// 勋章圆
|
|
ctx.beginPath();
|
|
ctx.arc(W / 2, 220, 70, 0, Math.PI * 2);
|
|
ctx.fillStyle = '#d4a96a';
|
|
ctx.fill();
|
|
ctx.fillStyle = '#1a1626';
|
|
ctx.font = 'bold 44px serif';
|
|
ctx.fillText('勋', W / 2, 236);
|
|
|
|
ctx.fillStyle = '#f0e6d2';
|
|
ctx.font = 'bold 40px serif';
|
|
ctx.fillText(badge.title, W / 2, 360);
|
|
ctx.fillStyle = '#b0a490';
|
|
ctx.font = '22px serif';
|
|
ctx.fillText(badge.flavor, W / 2, 400);
|
|
if (dim) {
|
|
ctx.font = '20px serif';
|
|
ctx.fillText(`—— 实测维度:${dim.label} ——`, W / 2, 440);
|
|
}
|
|
|
|
// 7 维分数条
|
|
ctx.textAlign = 'left';
|
|
scores.forEach((s, i) => {
|
|
const y = 510 + i * 56;
|
|
ctx.fillStyle = '#d8ccb8';
|
|
ctx.font = '22px serif';
|
|
ctx.fillText(s.label, 80, y);
|
|
ctx.fillStyle = '#4a3f5a';
|
|
ctx.fillRect(260, y - 16, 240, 18);
|
|
ctx.fillStyle = '#d4a96a';
|
|
ctx.fillRect(260, y - 16, (240 * s.score) / s.max, 18);
|
|
ctx.fillStyle = '#d8ccb8';
|
|
ctx.fillText(s.score.toFixed(1), 520, y);
|
|
});
|
|
|
|
ctx.textAlign = 'center';
|
|
ctx.fillStyle = '#8a7f6a';
|
|
ctx.font = '18px serif';
|
|
ctx.fillText('每个选择都是实测,没有自报。', W / 2, H - 40);
|
|
return canvas;
|
|
}
|
|
|
|
function download() {
|
|
const canvas = draw();
|
|
const a = document.createElement('a');
|
|
a.href = canvas.toDataURL('image/png');
|
|
a.download = '苍梧疑冢-勋章分享卡.png';
|
|
a.click();
|
|
}
|
|
|
|
return (
|
|
<div className="share-card">
|
|
<canvas ref={canvasRef} className="share-canvas" width={640} height={960} />
|
|
<button className="primary" onClick={download}>
|
|
下载分享卡 PNG
|
|
</button>
|
|
</div>
|
|
);
|
|
}
|