feat: 实现宣纸纹理叠加,使用OffscreenCanvas生成可复用纹理图案
This commit is contained in:
@@ -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 {
|
function easeInOutCubic(t: number): number {
|
||||||
return t < 0.5 ? 4 * t * t * t : 1 - Math.pow(-2 * t + 2, 3) / 2;
|
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 animationRef = useRef<number | undefined>(undefined);
|
||||||
const startTimeRef = useRef<number>(0);
|
const startTimeRef = useRef<number>(0);
|
||||||
const configRef = useRef<ResponsiveConfig | null>(null);
|
const configRef = useRef<ResponsiveConfig | null>(null);
|
||||||
|
const paperTextureRef = useRef<HTMLCanvasElement | null>(null);
|
||||||
const shouldReduceMotion = useReducedMotion();
|
const shouldReduceMotion = useReducedMotion();
|
||||||
|
|
||||||
const drawStaticFinal = useCallback(() => {
|
const drawStaticFinal = useCallback(() => {
|
||||||
@@ -773,6 +827,7 @@ export function InkDataMorph({
|
|||||||
const config = getResponsiveConfig(W);
|
const config = getResponsiveConfig(W);
|
||||||
configRef.current = config;
|
configRef.current = config;
|
||||||
particlesRef.current = initParticlesArray(W, H, config);
|
particlesRef.current = initParticlesArray(W, H, config);
|
||||||
|
paperTextureRef.current = generatePaperTexture(config.paperTextureSize);
|
||||||
|
|
||||||
if (shouldReduceMotion) {
|
if (shouldReduceMotion) {
|
||||||
drawStaticFinal();
|
drawStaticFinal();
|
||||||
@@ -810,6 +865,10 @@ export function InkDataMorph({
|
|||||||
drawConnections(ctx, particles, config.connectionDistance);
|
drawConnections(ctx, particles, config.connectionDistance);
|
||||||
drawInkStrings(ctx, particles, config);
|
drawInkStrings(ctx, particles, config);
|
||||||
|
|
||||||
|
if (paperTextureRef.current) {
|
||||||
|
drawPaperTexture(ctx, W, H, paperTextureRef.current);
|
||||||
|
}
|
||||||
|
|
||||||
if (allComplete) {
|
if (allComplete) {
|
||||||
animationRef.current = undefined;
|
animationRef.current = undefined;
|
||||||
return;
|
return;
|
||||||
|
|||||||
Reference in New Issue
Block a user