手册改为曲面
This commit is contained in:
parent
f7863ef77c
commit
4940314d0f
@ -22136,20 +22136,64 @@ let time=0
|
||||
textureCanvas.width = 325;
|
||||
textureCanvas.height = 400;
|
||||
const textureCtx = textureCanvas.getContext('2d');
|
||||
// 创建弯曲路径函数(复用)
|
||||
const createCurvedPath = (ctx, offsetY = 0) => {
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(0, 20 + offsetY);
|
||||
|
||||
// 上边缘曲线
|
||||
const cp1x = 325 * 0.5;
|
||||
const cp1y = offsetY;
|
||||
ctx.quadraticCurveTo(cp1x, cp1y, 325, 20 + offsetY);
|
||||
|
||||
// 右侧直线
|
||||
ctx.lineTo(325, 400 + offsetY);
|
||||
|
||||
// 下边缘曲线
|
||||
const cp2x = 325 * 0.5;
|
||||
const cp2y = 380 + offsetY;
|
||||
ctx.quadraticCurveTo(cp2x, cp2y, 0, 400 + offsetY);
|
||||
|
||||
// 左侧直线
|
||||
ctx.closePath();
|
||||
};
|
||||
|
||||
// 创建弯曲书页的蒙版
|
||||
const createPageCurveMask = () => {
|
||||
const curveCanvas = document.createElement('canvas');
|
||||
curveCanvas.width = 325;
|
||||
curveCanvas.height = 400;
|
||||
const curveCtx = curveCanvas.getContext('2d');
|
||||
curveCtx.clearRect(0, 0, 325, 400);
|
||||
|
||||
createCurvedPath(curveCtx);
|
||||
curveCtx.fillStyle = 'white';
|
||||
curveCtx.fill();
|
||||
|
||||
return curveCanvas;
|
||||
};
|
||||
|
||||
|
||||
// 创建书页内容 (400px高,居中放置)
|
||||
const createPageContent = () => {
|
||||
const contentCanvas = document.createElement('canvas');
|
||||
contentCanvas.width = 325;
|
||||
contentCanvas.height = 400;
|
||||
const contentCtx = contentCanvas.getContext('2d');
|
||||
|
||||
// 生成羊皮纸基础色(更精细的暖色调范围)
|
||||
const baseHue = 45; // 35-60黄色到橙色范围
|
||||
const baseSaturation = 40; // 25-50%饱和度
|
||||
const baseLightness = 85; // 80-95%亮度
|
||||
|
||||
// 1. 创建高度自然的基底纹理
|
||||
// 创建高度自然的基底纹理
|
||||
const createOrganicBase = () => {
|
||||
// 基础底色(轻微噪点纹理)
|
||||
textureCtx.fillStyle = `hsl(${baseHue}, ${baseSaturation}%, ${baseLightness}%)`;
|
||||
textureCtx.fillRect(0, 0, 325, 400);
|
||||
contentCtx.fillStyle = `hsl(${baseHue}, ${baseSaturation}%, ${baseLightness}%)`;
|
||||
contentCtx.fillRect(0, 0, 325, 400);
|
||||
|
||||
// 生成有机噪点纹理(模拟羊皮纸纤维)
|
||||
const noiseData = textureCtx.createImageData(325, 400);
|
||||
const noiseData = contentCtx.createImageData(325, 400);
|
||||
for (let i = 0; i < noiseData.data.length; i += 4) {
|
||||
// Perlin噪声生成更自然的纹理
|
||||
const x = (i / 4) % 325;
|
||||
@ -22180,52 +22224,8 @@ let time=0
|
||||
).b;
|
||||
noiseData.data[i + 3] = 255;
|
||||
}
|
||||
textureCtx.putImageData(noiseData, 0, 0);
|
||||
contentCtx.putImageData(noiseData, 0, 0);
|
||||
|
||||
// 添加手工染色效果(不规则色斑)
|
||||
/*for (let i = 0; i < 8 + Math.random() * 5; i++) {
|
||||
const centerX = Math.random() * 325;
|
||||
const centerY = Math.random() * 400;
|
||||
const radius = 30 + Math.random() * 70;
|
||||
const hueVar = (Math.random() - 0.5) * 15;
|
||||
const satVar = (Math.random() - 0.5) * 20;
|
||||
const lightVar = (Math.random() - 0.5) * 12;
|
||||
|
||||
// 创建有机形状的渐变
|
||||
const gradient = textureCtx.createRadialGradient(
|
||||
centerX, centerY, 0,
|
||||
centerX + (Math.random() - 0.5) * 20,
|
||||
centerY + (Math.random() - 0.5) * 20,
|
||||
radius * (0.8 + Math.random() * 0.4)
|
||||
);
|
||||
|
||||
gradient.addColorStop(0, `hsla(
|
||||
${baseHue + hueVar},
|
||||
${baseSaturation + satVar}%,
|
||||
${baseLightness + lightVar}%,
|
||||
${0.2 + Math.random() * 0.3}
|
||||
)`);
|
||||
gradient.addColorStop(1, 'hsla(0, 0%, 0%, 0)');
|
||||
|
||||
textureCtx.fillStyle = gradient;
|
||||
textureCtx.beginPath();
|
||||
// 有机形状绘制(非正圆)
|
||||
const points = 12 + Math.floor(Math.random() * 8);
|
||||
textureCtx.moveTo(
|
||||
centerX + radius * Math.cos(0),
|
||||
centerY + radius * Math.sin(0)
|
||||
);
|
||||
for (let j = 1; j <= points; j++) {
|
||||
const angle = (j / points) * Math.PI * 2;
|
||||
const dist = radius * (0.7 + Math.random() * 0.6);
|
||||
textureCtx.lineTo(
|
||||
centerX + dist * Math.cos(angle),
|
||||
centerY + dist * Math.sin(angle)
|
||||
);
|
||||
}
|
||||
textureCtx.closePath();
|
||||
textureCtx.fill();
|
||||
}*/
|
||||
};
|
||||
createOrganicBase();
|
||||
// 更自然的边缘破损效果
|
||||
@ -22278,57 +22278,66 @@ let time=0
|
||||
}
|
||||
|
||||
// 绘制破损形状
|
||||
textureCtx.beginPath();
|
||||
textureCtx.moveTo(x, y);
|
||||
points.forEach(p => textureCtx.lineTo(p.x, p.y));
|
||||
textureCtx.closePath();
|
||||
contentCtx.beginPath();
|
||||
contentCtx.moveTo(x, y);
|
||||
points.forEach(p => contentCtx.lineTo(p.x, p.y));
|
||||
contentCtx.closePath();
|
||||
|
||||
// 破损内部阴影
|
||||
textureCtx.fillStyle = `rgba(140, 110, 80, ${0.08 + Math.random()*0.07})`;
|
||||
textureCtx.fill();
|
||||
contentCtx.fillStyle = `rgba(140, 110, 80, ${0.08 + Math.random()*0.07})`;
|
||||
contentCtx.fill();
|
||||
|
||||
// 破损边缘线
|
||||
textureCtx.lineWidth = 0.3 + Math.random() * 0.4;
|
||||
textureCtx.strokeStyle = `rgba(100, 80, 60, ${0.4 + Math.random()*0.2})`;
|
||||
textureCtx.stroke();
|
||||
contentCtx.lineWidth = 0.3 + Math.random() * 0.4;
|
||||
contentCtx.strokeStyle = `rgba(100, 80, 60, ${0.4 + Math.random()*0.2})`;
|
||||
contentCtx.stroke();
|
||||
|
||||
// 添加一些细节线条
|
||||
for (let j = 0; j < 2; j++) {
|
||||
textureCtx.beginPath();
|
||||
contentCtx.beginPath();
|
||||
const detailX = x + (points[0].x - x) * 0.3 * (j + 1);
|
||||
const detailY = y + (points[0].y - y) * 0.3 * (j + 1);
|
||||
textureCtx.moveTo(detailX, detailY);
|
||||
contentCtx.moveTo(detailX, detailY);
|
||||
|
||||
for (let k = 1; k < points.length; k++) {
|
||||
const p = points[k];
|
||||
const toX = x + (p.x - x) * 0.3 * (j + 1);
|
||||
const toY = y + (p.y - y) * 0.3 * (j + 1);
|
||||
textureCtx.lineTo(toX, toY);
|
||||
contentCtx.lineTo(toX, toY);
|
||||
}
|
||||
|
||||
textureCtx.lineWidth = 0.1 + Math.random() * 0.2;
|
||||
textureCtx.strokeStyle = `rgba(120, 90, 70, ${0.2 + Math.random()*0.1})`;
|
||||
textureCtx.stroke();
|
||||
contentCtx.lineWidth = 0.1 + Math.random() * 0.2;
|
||||
contentCtx.strokeStyle = `rgba(120, 90, 70, ${0.2 + Math.random()*0.1})`;
|
||||
contentCtx.stroke();
|
||||
}
|
||||
}
|
||||
};
|
||||
addEdgeTears();
|
||||
// 2. 完美四角阴影系统
|
||||
/**
|
||||
* 根据方向调整边缘阴影强度
|
||||
* 根据方向调整边缘阴影强度,适配弯曲蒙版
|
||||
* @param {string} dir 方向参数('left'或'right')
|
||||
*/
|
||||
const addMasterfulEdgeShadows = (dir) => {
|
||||
const shadowHue = baseHue - 8;
|
||||
const shadowSaturation = baseSaturation + 15;
|
||||
const shadowLightness = baseLightness * 0.55;
|
||||
const shadowSize = 35 + Math.random() * 15;
|
||||
const shadowSize = 35;
|
||||
|
||||
const shadowCanvas = document.createElement('canvas');
|
||||
shadowCanvas.width = 325;
|
||||
shadowCanvas.height = 400;
|
||||
const shadowCtx = shadowCanvas.getContext('2d');
|
||||
|
||||
// 创建临时canvas用于检测弯曲区域
|
||||
const tempCanvas = document.createElement('canvas');
|
||||
tempCanvas.width = 325;
|
||||
tempCanvas.height = 400;
|
||||
const tempCtx = tempCanvas.getContext('2d');
|
||||
createCurvedPath(tempCtx);
|
||||
tempCtx.fillStyle = 'white';
|
||||
tempCtx.fill();
|
||||
const maskData = tempCtx.getImageData(0, 0, 325, 400).data;
|
||||
|
||||
// 计算每个像素的阴影强度
|
||||
const gradientData = shadowCtx.createImageData(325, 400);
|
||||
for (let i = 0; i < gradientData.data.length; i += 4) {
|
||||
@ -22336,10 +22345,10 @@ let time=0
|
||||
const y = Math.floor((i / 4) / 325);
|
||||
|
||||
// 基础距离计算
|
||||
const leftDist = x / shadowSize;
|
||||
const rightDist = (325 - x) / shadowSize;
|
||||
const topDist = y / shadowSize;
|
||||
const bottomDist = (400 - y) / shadowSize;
|
||||
const leftDist = x / shadowSize * (dir === "left" ? 1 : 0.7);
|
||||
const rightDist = (325 - x) / shadowSize * (dir === "left" ? 0.7 : 1);
|
||||
const topDist = (y - Math.abs(x - 162.5) / 162.5 * 20) / shadowSize;
|
||||
const bottomDist = (400 - y - (1 - Math.abs(x - 162.5) / 162.5) * 20) / shadowSize;
|
||||
|
||||
// 根据方向调整左右阴影强度
|
||||
let leftShadowIntensity = 0.7;
|
||||
@ -22370,12 +22379,14 @@ let time=0
|
||||
shadowAlpha = Math.max(shadowAlpha, rightShadowIntensity * (1 - rightDist));
|
||||
}
|
||||
|
||||
// 顶部和底部阴影(保持不变)
|
||||
// 顶部和底部阴影(根据弯曲路径调整)
|
||||
if (topDist < 1) {
|
||||
shadowAlpha = Math.max(shadowAlpha, 0.7 * (1 - topDist));
|
||||
|
||||
shadowAlpha = Math.max(shadowAlpha, (1 - topDist) * 0.7);
|
||||
}
|
||||
if (bottomDist < 1) {
|
||||
shadowAlpha = Math.max(shadowAlpha, 0.7 * (1 - bottomDist));
|
||||
|
||||
shadowAlpha = Math.max(shadowAlpha, (1 - bottomDist) * 0.7);
|
||||
}
|
||||
|
||||
// 角部阴影(取相邻两边强度的中间值)
|
||||
@ -22410,14 +22421,39 @@ let time=0
|
||||
|
||||
shadowCtx.putImageData(gradientData, 0, 0);
|
||||
|
||||
const createHighlight = () => {
|
||||
const highlightCanvas = document.createElement('canvas');
|
||||
highlightCanvas.width = 325;
|
||||
highlightCanvas.height = 400;
|
||||
const highlightCtx = highlightCanvas.getContext('2d');
|
||||
highlightCtx.clearRect(0, 0, 325, 400);
|
||||
|
||||
// 根据方向设置高光位置
|
||||
const gradient = dir === 'right' ?
|
||||
highlightCtx.createLinearGradient(10, 0, 50, 0) :
|
||||
highlightCtx.createLinearGradient(275, 0, 315, 0);
|
||||
|
||||
gradient.addColorStop(0, 'rgba(255,255,255,0)');
|
||||
gradient.addColorStop(0.5, 'rgba(255,255,255,0.5)');
|
||||
gradient.addColorStop(1, 'rgba(255,255,255,0)');
|
||||
|
||||
highlightCtx.fillStyle = gradient;
|
||||
highlightCtx.fillRect(dir === 'right' ? 10 : 275, 0, 40, 400);
|
||||
|
||||
|
||||
return highlightCanvas;
|
||||
};
|
||||
|
||||
// 应用阴影
|
||||
textureCtx.globalCompositeOperation = 'multiply';
|
||||
textureCtx.drawImage(shadowCanvas, 0, 0);
|
||||
textureCtx.globalCompositeOperation = 'source-over';
|
||||
contentCtx.globalCompositeOperation = 'multiply';
|
||||
contentCtx.drawImage(shadowCanvas, 0, 0);
|
||||
contentCtx.globalCompositeOperation = 'source-over'
|
||||
//应用高光
|
||||
contentCtx.drawImage(createHighlight(), 0, 0)
|
||||
}
|
||||
addMasterfulEdgeShadows(dir);
|
||||
|
||||
// 3. 超真实细节系统
|
||||
// 超真实细节系统
|
||||
const addHyperRealisticDetails = () => {
|
||||
// 3.1 纤维纹理(模拟羊皮纸纤维)
|
||||
for (let i = 0; i < 2000; i++) {
|
||||
@ -22427,24 +22463,24 @@ let time=0
|
||||
const angle = Math.random() * Math.PI * 2;
|
||||
const lightVar = (Math.random() > 0.5 ? 5 : -5) * (0.5 + Math.random());
|
||||
|
||||
textureCtx.beginPath();
|
||||
textureCtx.moveTo(x, y);
|
||||
textureCtx.lineTo(
|
||||
contentCtx.beginPath();
|
||||
contentCtx.moveTo(x, y);
|
||||
contentCtx.lineTo(
|
||||
x + Math.cos(angle) * length,
|
||||
y + Math.sin(angle) * length
|
||||
);
|
||||
|
||||
textureCtx.strokeStyle = `hsla(
|
||||
contentCtx.strokeStyle = `hsla(
|
||||
${baseHue + (Math.random() - 0.5) * 8},
|
||||
${baseSaturation * (0.7 + Math.random() * 0.6)}%,
|
||||
${baseLightness + lightVar}%,
|
||||
${0.03 + Math.random() * 0.04}
|
||||
)`;
|
||||
textureCtx.lineWidth = 0.2 + Math.random() * 0.3;
|
||||
textureCtx.stroke();
|
||||
contentCtx.lineWidth = 0.2 + Math.random() * 0.3;
|
||||
contentCtx.stroke();
|
||||
}
|
||||
|
||||
// 3.2 自然划痕系统
|
||||
// 自然划痕系统
|
||||
for (let i = 0; i < 10 + Math.random() * 10; i++) {
|
||||
const scratchLength = 15 + Math.random() * 60;
|
||||
const startX = Math.random() * 325;
|
||||
@ -22453,8 +22489,8 @@ let time=0
|
||||
const curveIntensity = 5 + Math.random() * 10;
|
||||
|
||||
// 主划痕路径
|
||||
textureCtx.beginPath();
|
||||
textureCtx.moveTo(startX, startY);
|
||||
contentCtx.beginPath();
|
||||
contentCtx.moveTo(startX, startY);
|
||||
|
||||
// 贝塞尔曲线控制点
|
||||
const cp1x = startX + Math.cos(angle) * scratchLength * 0.3 + (Math.random() - 0.5) * curveIntensity;
|
||||
@ -22464,30 +22500,30 @@ let time=0
|
||||
const endX = startX + Math.cos(angle) * scratchLength;
|
||||
const endY = startY + Math.sin(angle) * scratchLength;
|
||||
|
||||
textureCtx.bezierCurveTo(cp1x, cp1y, cp2x, cp2y, endX, endY);
|
||||
contentCtx.bezierCurveTo(cp1x, cp1y, cp2x, cp2y, endX, endY);
|
||||
|
||||
// 划痕样式(宽度变化)
|
||||
const lineWidth = 0.1 + Math.random() * 0.4;
|
||||
const scratchDarkness = 0.6 + Math.random() * 0.3;
|
||||
|
||||
textureCtx.strokeStyle = `hsla(
|
||||
contentCtx.strokeStyle = `hsla(
|
||||
${baseHue - 5 + Math.random() * 10},
|
||||
${baseSaturation + 5 + Math.random() * 15}%,
|
||||
${baseLightness * scratchDarkness}%,
|
||||
${0.4 + Math.random() * 0.3}
|
||||
)`;
|
||||
textureCtx.lineWidth = lineWidth;
|
||||
textureCtx.lineCap = 'round';
|
||||
textureCtx.stroke();
|
||||
contentCtx.lineWidth = lineWidth;
|
||||
contentCtx.lineCap = 'round';
|
||||
contentCtx.stroke();
|
||||
|
||||
// 划痕高光(模拟凹陷)
|
||||
if (Math.random() > 0.3) {
|
||||
textureCtx.beginPath();
|
||||
textureCtx.moveTo(
|
||||
contentCtx.beginPath();
|
||||
contentCtx.moveTo(
|
||||
startX + (Math.random() - 0.5) * lineWidth * 2,
|
||||
startY + (Math.random() - 0.5) * lineWidth * 2
|
||||
);
|
||||
textureCtx.bezierCurveTo(
|
||||
contentCtx.bezierCurveTo(
|
||||
cp1x + (Math.random() - 0.5) * lineWidth * 2,
|
||||
cp1y + (Math.random() - 0.5) * lineWidth * 2,
|
||||
cp2x + (Math.random() - 0.5) * lineWidth * 2,
|
||||
@ -22496,18 +22532,18 @@ let time=0
|
||||
endY + (Math.random() - 0.5) * lineWidth * 2
|
||||
);
|
||||
|
||||
textureCtx.strokeStyle = `hsla(
|
||||
contentCtx.strokeStyle = `hsla(
|
||||
${baseHue + 5 + Math.random() * 5},
|
||||
${baseSaturation * 0.7}%,
|
||||
${baseLightness * 1.1}%,
|
||||
${0.2 + Math.random() * 0.1}
|
||||
)`;
|
||||
textureCtx.lineWidth = lineWidth * 0.7;
|
||||
textureCtx.stroke();
|
||||
contentCtx.lineWidth = lineWidth * 0.7;
|
||||
contentCtx.stroke();
|
||||
}
|
||||
}
|
||||
|
||||
// 3.3 专业级污渍系统
|
||||
// 专业级污渍系统
|
||||
for (let i = 0; i < 3 + Math.random() * 5; i++) {
|
||||
const stainType = Math.floor(Math.random() * 3); // 0: 液体污渍, 1: 指纹, 2: 老化斑点
|
||||
|
||||
@ -22525,20 +22561,20 @@ let time=0
|
||||
const angle = (j / 15) * Math.PI * 2 + rotation;
|
||||
const width = size * (0.03 + Math.random() * 0.05);
|
||||
|
||||
textureCtx.beginPath();
|
||||
textureCtx.arc(
|
||||
contentCtx.beginPath();
|
||||
contentCtx.arc(
|
||||
centerX + Math.cos(angle) * radius * 0.5,
|
||||
centerY + Math.sin(angle) * radius * 0.5,
|
||||
width, 0, Math.PI * 2
|
||||
);
|
||||
|
||||
textureCtx.fillStyle = `hsla(
|
||||
contentCtx.fillStyle = `hsla(
|
||||
${baseHue - 5 + Math.random() * 10},
|
||||
${baseSaturation + 5}%,
|
||||
${baseLightness * 0.8}%,
|
||||
${0.1 + Math.random() * 0.05}
|
||||
)`;
|
||||
textureCtx.fill();
|
||||
contentCtx.fill();
|
||||
}
|
||||
} else {
|
||||
// 老化斑点
|
||||
@ -22547,8 +22583,8 @@ let time=0
|
||||
const size = 5 + Math.random() * 15;
|
||||
const points = 8 + Math.floor(Math.random() * 6);
|
||||
|
||||
textureCtx.beginPath();
|
||||
textureCtx.moveTo(
|
||||
contentCtx.beginPath();
|
||||
contentCtx.moveTo(
|
||||
centerX + size * Math.cos(0),
|
||||
centerY + size * Math.sin(0)
|
||||
);
|
||||
@ -22556,14 +22592,14 @@ let time=0
|
||||
for (let j = 1; j <= points; j++) {
|
||||
const angle = (j / points) * Math.PI * 2;
|
||||
const radius = size * (0.7 + Math.random() * 0.6);
|
||||
textureCtx.lineTo(
|
||||
contentCtx.lineTo(
|
||||
centerX + radius * Math.cos(angle),
|
||||
centerY + radius * Math.sin(angle)
|
||||
);
|
||||
}
|
||||
textureCtx.closePath();
|
||||
contentCtx.closePath();
|
||||
|
||||
const gradient = textureCtx.createRadialGradient(
|
||||
const gradient = contentCtx.createRadialGradient(
|
||||
centerX, centerY, 0,
|
||||
centerX, centerY, size * 1.2
|
||||
);
|
||||
@ -22575,13 +22611,80 @@ let time=0
|
||||
)`);
|
||||
gradient.addColorStop(1, 'hsla(0, 0%, 0%, 0)');
|
||||
|
||||
textureCtx.fillStyle = gradient;
|
||||
textureCtx.fill();
|
||||
contentCtx.fillStyle = gradient;
|
||||
contentCtx.fill();
|
||||
}
|
||||
}
|
||||
};
|
||||
addHyperRealisticDetails();
|
||||
|
||||
return contentCanvas;
|
||||
};
|
||||
|
||||
// 创建弯曲阴影(新增)
|
||||
const createCurvedShadow = () => {
|
||||
const shadowCanvas = document.createElement('canvas');
|
||||
shadowCanvas.width = 325;
|
||||
shadowCanvas.height = 400;
|
||||
const shadowCtx = shadowCanvas.getContext('2d');
|
||||
shadowCtx.clearRect(0, 0, 325, 400);
|
||||
|
||||
// 绘制顶部阴影(跟随曲线)
|
||||
const topShadow = shadowCtx.createLinearGradient(0, 0, 0, 50);
|
||||
topShadow.addColorStop(0, 'rgba(0,0,0,0.25)');
|
||||
topShadow.addColorStop(1, 'rgba(0,0,0,0)');
|
||||
|
||||
shadowCtx.save();
|
||||
createCurvedPath(shadowCtx);
|
||||
shadowCtx.clip();
|
||||
shadowCtx.fillStyle = topShadow;
|
||||
shadowCtx.fillRect(0, 0, 325, 50);
|
||||
shadowCtx.restore();
|
||||
|
||||
// 绘制底部阴影(跟随曲线)
|
||||
const bottomShadow = shadowCtx.createLinearGradient(0, 350, 0, 400);
|
||||
bottomShadow.addColorStop(0, 'rgba(0,0,0,0)');
|
||||
bottomShadow.addColorStop(1, 'rgba(0,0,0,0.25)');
|
||||
|
||||
shadowCtx.save();
|
||||
createCurvedPath(shadowCtx);
|
||||
shadowCtx.clip();
|
||||
shadowCtx.fillStyle = bottomShadow;
|
||||
shadowCtx.fillRect(0, 350, 325, 50);
|
||||
shadowCtx.restore();
|
||||
|
||||
return shadowCanvas;
|
||||
};
|
||||
|
||||
// 应用弯曲变形
|
||||
const applyPageCurve = (content, mask, shadow) => {
|
||||
const resultCanvas = document.createElement('canvas');
|
||||
resultCanvas.width = 325;
|
||||
resultCanvas.height = 400;
|
||||
const resultCtx = resultCanvas.getContext('2d');
|
||||
resultCtx.clearRect(0, 0, 325, 400);
|
||||
|
||||
// 先绘制阴影(在内容下方)
|
||||
resultCtx.drawImage(shadow, 0, 0);
|
||||
|
||||
// 绘制内容并应用蒙版
|
||||
resultCtx.drawImage(content, 0, 10);
|
||||
resultCtx.globalCompositeOperation = 'destination-in';
|
||||
resultCtx.drawImage(mask, 0, 0);
|
||||
resultCtx.globalCompositeOperation = 'source-over';
|
||||
|
||||
return resultCanvas;
|
||||
};
|
||||
|
||||
// 主流程
|
||||
const mask = createPageCurveMask();
|
||||
const content = createPageContent();
|
||||
const shadow = createCurvedShadow();
|
||||
const curvedPage = applyPageCurve(content, mask, shadow);
|
||||
|
||||
// 最终绘制
|
||||
textureCtx.drawImage(curvedPage, 0, 0);
|
||||
|
||||
return textureCanvas;
|
||||
}
|
||||
|
||||
@ -22707,26 +22810,26 @@ let time=0
|
||||
dy = 416 - this.height
|
||||
ctx.moveTo(0, 416)
|
||||
ctx.lineTo(dx, this.height)
|
||||
ctx.lineTo(dx, 0)
|
||||
ctx.lineTo(0, dy)
|
||||
ctx.lineTo(dx, 20)
|
||||
ctx.lineTo(0, dy + 20)
|
||||
ctx.closePath()
|
||||
ctx.fillStyle = "#e0d6c2"
|
||||
ctx.fillStyle = `rgb(${248*0.7}, ${244*0.7}, ${230*0.7})`
|
||||
ctx.fill()
|
||||
ctx.beginPath()
|
||||
ctx.moveTo(676, 416)
|
||||
ctx.lineTo(676 - dx, this.height)
|
||||
ctx.lineTo(676 - dx, 0)
|
||||
ctx.lineTo(676, dy)
|
||||
ctx.lineTo(676 - dx, 20)
|
||||
ctx.lineTo(676, dy + 20)
|
||||
ctx.closePath()
|
||||
ctx.fill()
|
||||
ctx.strokeStyle = `rgb(${248*0.7}, ${244*0.7}, ${230*0.7})`;
|
||||
ctx.strokeStyle = `rgb(${248*0.5}, ${244*0.5}, ${230*0.5})`;
|
||||
ctx.beginPath()
|
||||
ctx.moveTo(2, 100)
|
||||
ctx.lineTo(2, 130)
|
||||
ctx.stroke()
|
||||
ctx.beginPath()
|
||||
ctx.moveTo(5, 20)
|
||||
ctx.lineTo(5, 30)
|
||||
ctx.moveTo(5, 320)
|
||||
ctx.lineTo(5, 290)
|
||||
ctx.stroke()
|
||||
ctx.beginPath()
|
||||
ctx.moveTo(6, 240)
|
||||
@ -22745,7 +22848,7 @@ let time=0
|
||||
ctx.lineTo(670, 160)
|
||||
ctx.stroke()
|
||||
ctx.beginPath()
|
||||
ctx.moveTo(671, 20)
|
||||
ctx.moveTo(671, 50)
|
||||
ctx.lineTo(671, 130)
|
||||
ctx.stroke()
|
||||
ctx.beginPath()
|
||||
@ -22758,50 +22861,15 @@ let time=0
|
||||
ctx.beginPath()
|
||||
ctx.moveTo(0, 416)
|
||||
ctx.lineTo(dx, this.height)
|
||||
ctx.lineTo(338, this.height)
|
||||
ctx.lineTo(this.width, 416)
|
||||
ctx.quadraticCurveTo(this.width / 2 + dx, this.height - 20, 338, this.height)
|
||||
ctx.quadraticCurveTo(this.width * 3 / 2 + dx, this.height - 20, 676 - dx, this.height)
|
||||
ctx.lineTo(676, 416)
|
||||
ctx.quadraticCurveTo(676 - this.width / 2, 396, 676 - this.width, 416)
|
||||
ctx.quadraticCurveTo(338, 406, this.width, 416)
|
||||
ctx.quadraticCurveTo(this.width / 2, 396, 0, 416)
|
||||
ctx.closePath()
|
||||
ctx.fillStyle = '#706b61'
|
||||
ctx.fill()
|
||||
ctx.beginPath()
|
||||
ctx.moveTo(676, 416)
|
||||
ctx.lineTo(676 - dx, this.height)
|
||||
ctx.lineTo(338, this.height)
|
||||
ctx.lineTo(338 + dx, 416)
|
||||
ctx.closePath()
|
||||
ctx.fill()
|
||||
ctx.beginPath()
|
||||
ctx.moveTo(20, 402)
|
||||
ctx.lineTo(50, 402)
|
||||
ctx.stroke()
|
||||
ctx.beginPath()
|
||||
ctx.moveTo(180, 405)
|
||||
ctx.lineTo(220, 405)
|
||||
ctx.stroke()
|
||||
ctx.beginPath()
|
||||
ctx.moveTo(40, 409)
|
||||
ctx.lineTo(80, 409)
|
||||
ctx.stroke()
|
||||
ctx.beginPath()
|
||||
ctx.moveTo(268, 412)
|
||||
ctx.lineTo(290, 412)
|
||||
ctx.stroke()
|
||||
ctx.beginPath()
|
||||
ctx.moveTo(430, 403)
|
||||
ctx.lineTo(470, 403)
|
||||
ctx.stroke()
|
||||
ctx.beginPath()
|
||||
ctx.moveTo(510, 407)
|
||||
ctx.lineTo(530, 407)
|
||||
ctx.stroke()
|
||||
ctx.beginPath()
|
||||
ctx.moveTo(350, 414)
|
||||
ctx.lineTo(370, 414)
|
||||
ctx.stroke()
|
||||
ctx.beginPath()
|
||||
ctx.moveTo(602, 411)
|
||||
ctx.lineTo(610, 411)
|
||||
ctx.stroke()
|
||||
|
||||
|
||||
ctx.restore(); //恢复变换前的坐标,否则将连续转置
|
||||
|
Loading…
Reference in New Issue
Block a user