feat: 实现宣纸纹理叠加,使用OffscreenCanvas生成可复用纹理图案

This commit is contained in:
张翔
2026-05-03 19:51:18 +08:00
parent 4ca3eb6c92
commit 9bba35027e
+59
View File
@@ -163,6 +163,59 @@ function getResponsiveConfig(W: number): ResponsiveConfig {
};
}
function generatePaperTexture(size: number): HTMLCanvasElement {
const offscreen = document.createElement('canvas');
offscreen.width = size;
offscreen.height = size;
const octx = offscreen.getContext('2d');
if (!octx) {
return offscreen;
}
octx.fillStyle = '#FAFAF5';
octx.fillRect(0, 0, size, size);
for (let i = 0; i < size * size * 0.15; i++) {
const x = Math.random() * size;
const y = Math.random() * size;
const gray = 200 + Math.floor(Math.random() * 40);
const alpha = 0.02 + Math.random() * 0.04;
octx.fillStyle = `rgba(${gray}, ${gray}, ${gray}, ${alpha})`;
octx.fillRect(x, y, 1, 1);
}
octx.strokeStyle = 'rgba(180, 175, 168, 0.015)';
octx.lineWidth = 0.5;
for (let i = 0; i < size * 0.3; i++) {
const y = Math.random() * size;
const startX = Math.random() * size * 0.3;
const endX = startX + size * (0.1 + Math.random() * 0.4);
octx.beginPath();
octx.moveTo(startX, y);
octx.lineTo(Math.min(endX, size), y + (Math.random() - 0.5) * 2);
octx.stroke();
}
return offscreen;
}
function drawPaperTexture(
ctx: CanvasRenderingContext2D,
W: number,
H: number,
texture: HTMLCanvasElement,
): void {
const pattern = ctx.createPattern(texture, 'repeat');
if (!pattern) {
return;
}
ctx.save();
ctx.fillStyle = pattern;
ctx.globalAlpha = 0.03;
ctx.fillRect(0, 0, W, H);
ctx.restore();
}
function easeInOutCubic(t: number): number {
return t < 0.5 ? 4 * t * t * t : 1 - Math.pow(-2 * t + 2, 3) / 2;
}
@@ -700,6 +753,7 @@ export function InkDataMorph({
const animationRef = useRef<number | undefined>(undefined);
const startTimeRef = useRef<number>(0);
const configRef = useRef<ResponsiveConfig | null>(null);
const paperTextureRef = useRef<HTMLCanvasElement | null>(null);
const shouldReduceMotion = useReducedMotion();
const drawStaticFinal = useCallback(() => {
@@ -773,6 +827,7 @@ export function InkDataMorph({
const config = getResponsiveConfig(W);
configRef.current = config;
particlesRef.current = initParticlesArray(W, H, config);
paperTextureRef.current = generatePaperTexture(config.paperTextureSize);
if (shouldReduceMotion) {
drawStaticFinal();
@@ -810,6 +865,10 @@ export function InkDataMorph({
drawConnections(ctx, particles, config.connectionDistance);
drawInkStrings(ctx, particles, config);
if (paperTextureRef.current) {
drawPaperTexture(ctx, W, H, paperTextureRef.current);
}
if (allComplete) {
animationRef.current = undefined;
return;