羊皮纸书页大幅重构
This commit is contained in:
parent
613ff14595
commit
f7863ef77c
@ -22128,35 +22128,569 @@ let time=0
|
||||
this.pagemax = 1
|
||||
this.page = 0
|
||||
|
||||
}
|
||||
paperTexture() {
|
||||
|
||||
|
||||
}
|
||||
paperTexture(dir) {
|
||||
const textureCanvas = document.createElement('canvas');
|
||||
textureCanvas.width = 325;
|
||||
textureCanvas.height = 400;
|
||||
const textureCtx = textureCanvas.getContext('2d');
|
||||
|
||||
// 填充浅色背景
|
||||
textureCtx.fillStyle = '#f8f4e6';
|
||||
textureCtx.fillRect(0, 0, 325, 400);
|
||||
// 生成羊皮纸基础色(更精细的暖色调范围)
|
||||
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);
|
||||
|
||||
for (let i = 0; i < 1000; i++) {
|
||||
const x = Math.random() * 325;
|
||||
const y = Math.random() * 400;
|
||||
const radius = Math.random() * 2;
|
||||
const alpha = Math.random() * 0.1
|
||||
textureCtx.beginPath();
|
||||
textureCtx.arc(x, y, radius, 0, Math.PI * 2);
|
||||
textureCtx.fillStyle = `rgba(100, 80, 60, ${alpha})`;
|
||||
textureCtx.fill();
|
||||
// 生成有机噪点纹理(模拟羊皮纸纤维)
|
||||
const noiseData = textureCtx.createImageData(325, 400);
|
||||
for (let i = 0; i < noiseData.data.length; i += 4) {
|
||||
// Perlin噪声生成更自然的纹理
|
||||
const x = (i / 4) % 325;
|
||||
const y = Math.floor((i / 4) / 325);
|
||||
const noiseVal = this.perlinNoise(x / 50, y / 50) * 0.5 +
|
||||
this.perlinNoise(x / 20, y / 20) * 0.3 +
|
||||
this.perlinNoise(x / 5, y / 5) * 0.2;
|
||||
|
||||
// 基于噪声调整颜色
|
||||
const hueVar = noiseVal * 10;
|
||||
const satVar = noiseVal * 15;
|
||||
const lightVar = noiseVal * 8;
|
||||
|
||||
noiseData.data[i] = this.HSLtoRGB(
|
||||
(baseHue + hueVar) % 360,
|
||||
Math.max(10, Math.min(70, baseSaturation + satVar)),
|
||||
Math.max(70, Math.min(98, baseLightness + lightVar))
|
||||
).r;
|
||||
noiseData.data[i + 1] = this.HSLtoRGB(
|
||||
(baseHue + hueVar) % 360,
|
||||
Math.max(10, Math.min(70, baseSaturation + satVar)),
|
||||
Math.max(70, Math.min(98, baseLightness + lightVar))
|
||||
).g;
|
||||
noiseData.data[i + 2] = this.HSLtoRGB(
|
||||
(baseHue + hueVar) % 360,
|
||||
Math.max(10, Math.min(70, baseSaturation + satVar)),
|
||||
Math.max(70, Math.min(98, baseLightness + lightVar))
|
||||
).b;
|
||||
noiseData.data[i + 3] = 255;
|
||||
}
|
||||
textureCtx.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();
|
||||
// 更自然的边缘破损效果
|
||||
const addEdgeTears = () => {
|
||||
const tearCount = Math.floor(Math.random() * 4) + 2;
|
||||
|
||||
for (let i = 0; i < tearCount; i++) {
|
||||
const size = 5 + Math.random() * 12;
|
||||
const roughness = 2 + Math.random() * 3;
|
||||
|
||||
if (dir === "left") {
|
||||
// 左侧边缘破损
|
||||
if (Math.random() > 0.3) {
|
||||
const y = Math.random() * 350 + 25;
|
||||
createOrganicTear(0, y, size, Math.PI / 2, roughness);
|
||||
} else {
|
||||
const x = Math.random() * 50;
|
||||
const y = Math.random() > 0.5 ? 0 : 400;
|
||||
createOrganicTear(x, y, size * 0.7, Math.random() > 0.5 ? 0 : Math.PI, roughness);
|
||||
}
|
||||
} else {
|
||||
// 右侧边缘破损
|
||||
if (Math.random() > 0.3) {
|
||||
const y = Math.random() * 350 + 25;
|
||||
createOrganicTear(325, y, size, -Math.PI / 2, roughness);
|
||||
} else {
|
||||
const x = 275 + Math.random() * 50;
|
||||
const y = Math.random() > 0.5 ? 0 : 400;
|
||||
createOrganicTear(x, y, size * 0.7, Math.random() > 0.5 ? 0 : Math.PI, roughness);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function createOrganicTear(x, y, size, angle, roughness) {
|
||||
const points = [];
|
||||
const steps = 10 + Math.floor(Math.random() * 10);
|
||||
|
||||
// 生成有机形状的点
|
||||
for (let i = 0; i <= steps; i++) {
|
||||
const t = i / steps;
|
||||
const r = size * (0.8 + Math.random() * 0.4);
|
||||
const a = angle + Math.PI + t * Math.PI;
|
||||
const noiseX = (Math.random() * 2 - 1) * roughness;
|
||||
const noiseY = (Math.random() * 2 - 1) * roughness;
|
||||
|
||||
points.push({
|
||||
x: x + r * Math.cos(a) * (0.5 + t * 0.5) + noiseX,
|
||||
y: y + r * Math.sin(a) * (0.5 + t * 0.5) + noiseY
|
||||
});
|
||||
}
|
||||
|
||||
// 绘制破损形状
|
||||
textureCtx.beginPath();
|
||||
textureCtx.moveTo(x, y);
|
||||
points.forEach(p => textureCtx.lineTo(p.x, p.y));
|
||||
textureCtx.closePath();
|
||||
|
||||
// 破损内部阴影
|
||||
textureCtx.fillStyle = `rgba(140, 110, 80, ${0.08 + Math.random()*0.07})`;
|
||||
textureCtx.fill();
|
||||
|
||||
// 破损边缘线
|
||||
textureCtx.lineWidth = 0.3 + Math.random() * 0.4;
|
||||
textureCtx.strokeStyle = `rgba(100, 80, 60, ${0.4 + Math.random()*0.2})`;
|
||||
textureCtx.stroke();
|
||||
|
||||
// 添加一些细节线条
|
||||
for (let j = 0; j < 2; j++) {
|
||||
textureCtx.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);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
textureCtx.lineWidth = 0.1 + Math.random() * 0.2;
|
||||
textureCtx.strokeStyle = `rgba(120, 90, 70, ${0.2 + Math.random()*0.1})`;
|
||||
textureCtx.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 shadowCanvas = document.createElement('canvas');
|
||||
shadowCanvas.width = 325;
|
||||
shadowCanvas.height = 400;
|
||||
const shadowCtx = shadowCanvas.getContext('2d');
|
||||
|
||||
// 计算每个像素的阴影强度
|
||||
const gradientData = shadowCtx.createImageData(325, 400);
|
||||
for (let i = 0; i < gradientData.data.length; i += 4) {
|
||||
const x = (i / 4) % 325;
|
||||
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;
|
||||
|
||||
// 根据方向调整左右阴影强度
|
||||
let leftShadowIntensity = 0.7;
|
||||
let rightShadowIntensity = 0.7;
|
||||
|
||||
if (dir === "left") {
|
||||
rightShadowIntensity *= 0.6; // 削弱右侧阴影
|
||||
} else if (dir === "right") {
|
||||
leftShadowIntensity *= 0.6; // 削弱左侧阴影
|
||||
}
|
||||
|
||||
// 计算角部距离
|
||||
const tlDist = Math.sqrt(x * x + y * y) / (shadowSize * 1.4);
|
||||
const trDist = Math.sqrt((325 - x) * (325 - x) + y * y) / (shadowSize * 1.4);
|
||||
const blDist = Math.sqrt(x * x + (400 - y) * (400 - y)) / (shadowSize * 1.4);
|
||||
const brDist = Math.sqrt((325 - x) * (325 - x) + (400 - y) * (400 - y)) / (shadowSize * 1.4);
|
||||
|
||||
// 综合阴影强度
|
||||
let shadowAlpha = 0;
|
||||
|
||||
// 左侧阴影计算
|
||||
if (leftDist < 1) {
|
||||
shadowAlpha = Math.max(shadowAlpha, leftShadowIntensity * (1 - leftDist));
|
||||
}
|
||||
|
||||
// 右侧阴影计算
|
||||
if (rightDist < 1) {
|
||||
shadowAlpha = Math.max(shadowAlpha, rightShadowIntensity * (1 - rightDist));
|
||||
}
|
||||
|
||||
// 顶部和底部阴影(保持不变)
|
||||
if (topDist < 1) {
|
||||
shadowAlpha = Math.max(shadowAlpha, 0.7 * (1 - topDist));
|
||||
}
|
||||
if (bottomDist < 1) {
|
||||
shadowAlpha = Math.max(shadowAlpha, 0.7 * (1 - bottomDist));
|
||||
}
|
||||
|
||||
// 角部阴影(取相邻两边强度的中间值)
|
||||
if (tlDist < 1) {
|
||||
const cornerAlpha = (leftShadowIntensity + 0.7) / 2 * (1 - tlDist);
|
||||
shadowAlpha = Math.max(shadowAlpha, cornerAlpha);
|
||||
}
|
||||
if (trDist < 1) {
|
||||
const cornerAlpha = (rightShadowIntensity + 0.7) / 2 * (1 - trDist);
|
||||
shadowAlpha = Math.max(shadowAlpha, cornerAlpha);
|
||||
}
|
||||
if (blDist < 1) {
|
||||
const cornerAlpha = (leftShadowIntensity + 0.7) / 2 * (1 - blDist);
|
||||
shadowAlpha = Math.max(shadowAlpha, cornerAlpha);
|
||||
}
|
||||
if (brDist < 1) {
|
||||
const cornerAlpha = (rightShadowIntensity + 0.7) / 2 * (1 - brDist);
|
||||
shadowAlpha = Math.max(shadowAlpha, cornerAlpha);
|
||||
}
|
||||
|
||||
// 限制最大透明度
|
||||
shadowAlpha = Math.min(0.6, shadowAlpha);
|
||||
|
||||
// 转换为RGB
|
||||
const rgb = this.HSLtoRGB(shadowHue, shadowSaturation, shadowLightness);
|
||||
|
||||
gradientData.data[i] = rgb.r;
|
||||
gradientData.data[i + 1] = rgb.g;
|
||||
gradientData.data[i + 2] = rgb.b;
|
||||
gradientData.data[i + 3] = shadowAlpha * 255;
|
||||
}
|
||||
|
||||
shadowCtx.putImageData(gradientData, 0, 0);
|
||||
|
||||
// 应用阴影
|
||||
textureCtx.globalCompositeOperation = 'multiply';
|
||||
textureCtx.drawImage(shadowCanvas, 0, 0);
|
||||
textureCtx.globalCompositeOperation = 'source-over';
|
||||
}
|
||||
addMasterfulEdgeShadows(dir);
|
||||
|
||||
// 3. 超真实细节系统
|
||||
const addHyperRealisticDetails = () => {
|
||||
// 3.1 纤维纹理(模拟羊皮纸纤维)
|
||||
for (let i = 0; i < 2000; i++) {
|
||||
const x = Math.random() * 325;
|
||||
const y = Math.random() * 400;
|
||||
const length = 1 + Math.random() * 4;
|
||||
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(
|
||||
x + Math.cos(angle) * length,
|
||||
y + Math.sin(angle) * length
|
||||
);
|
||||
|
||||
textureCtx.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();
|
||||
}
|
||||
|
||||
// 3.2 自然划痕系统
|
||||
for (let i = 0; i < 10 + Math.random() * 10; i++) {
|
||||
const scratchLength = 15 + Math.random() * 60;
|
||||
const startX = Math.random() * 325;
|
||||
const startY = Math.random() * 400;
|
||||
const angle = Math.random() * Math.PI * 2;
|
||||
const curveIntensity = 5 + Math.random() * 10;
|
||||
|
||||
// 主划痕路径
|
||||
textureCtx.beginPath();
|
||||
textureCtx.moveTo(startX, startY);
|
||||
|
||||
// 贝塞尔曲线控制点
|
||||
const cp1x = startX + Math.cos(angle) * scratchLength * 0.3 + (Math.random() - 0.5) * curveIntensity;
|
||||
const cp1y = startY + Math.sin(angle) * scratchLength * 0.3 + (Math.random() - 0.5) * curveIntensity;
|
||||
const cp2x = startX + Math.cos(angle) * scratchLength * 0.7 + (Math.random() - 0.5) * curveIntensity;
|
||||
const cp2y = startY + Math.sin(angle) * scratchLength * 0.7 + (Math.random() - 0.5) * curveIntensity;
|
||||
const endX = startX + Math.cos(angle) * scratchLength;
|
||||
const endY = startY + Math.sin(angle) * scratchLength;
|
||||
|
||||
textureCtx.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(
|
||||
${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();
|
||||
|
||||
// 划痕高光(模拟凹陷)
|
||||
if (Math.random() > 0.3) {
|
||||
textureCtx.beginPath();
|
||||
textureCtx.moveTo(
|
||||
startX + (Math.random() - 0.5) * lineWidth * 2,
|
||||
startY + (Math.random() - 0.5) * lineWidth * 2
|
||||
);
|
||||
textureCtx.bezierCurveTo(
|
||||
cp1x + (Math.random() - 0.5) * lineWidth * 2,
|
||||
cp1y + (Math.random() - 0.5) * lineWidth * 2,
|
||||
cp2x + (Math.random() - 0.5) * lineWidth * 2,
|
||||
cp2y + (Math.random() - 0.5) * lineWidth * 2,
|
||||
endX + (Math.random() - 0.5) * lineWidth * 2,
|
||||
endY + (Math.random() - 0.5) * lineWidth * 2
|
||||
);
|
||||
|
||||
textureCtx.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();
|
||||
}
|
||||
}
|
||||
|
||||
// 3.3 专业级污渍系统
|
||||
for (let i = 0; i < 3 + Math.random() * 5; i++) {
|
||||
const stainType = Math.floor(Math.random() * 3); // 0: 液体污渍, 1: 指纹, 2: 老化斑点
|
||||
|
||||
|
||||
if (stainType === 1) {
|
||||
// 指纹污渍
|
||||
const centerX = Math.random() * 325;
|
||||
const centerY = Math.random() * 400;
|
||||
const size = 10 + Math.random() * 15;
|
||||
const rotation = Math.random() * Math.PI * 2;
|
||||
|
||||
// 指纹纹路
|
||||
for (let j = 0; j < 15 + Math.random() * 10; j++) {
|
||||
const radius = size * (0.3 + Math.random() * 0.7);
|
||||
const angle = (j / 15) * Math.PI * 2 + rotation;
|
||||
const width = size * (0.03 + Math.random() * 0.05);
|
||||
|
||||
textureCtx.beginPath();
|
||||
textureCtx.arc(
|
||||
centerX + Math.cos(angle) * radius * 0.5,
|
||||
centerY + Math.sin(angle) * radius * 0.5,
|
||||
width, 0, Math.PI * 2
|
||||
);
|
||||
|
||||
textureCtx.fillStyle = `hsla(
|
||||
${baseHue - 5 + Math.random() * 10},
|
||||
${baseSaturation + 5}%,
|
||||
${baseLightness * 0.8}%,
|
||||
${0.1 + Math.random() * 0.05}
|
||||
)`;
|
||||
textureCtx.fill();
|
||||
}
|
||||
} else {
|
||||
// 老化斑点
|
||||
const centerX = Math.random() * 325;
|
||||
const centerY = Math.random() * 400;
|
||||
const size = 5 + Math.random() * 15;
|
||||
const points = 8 + Math.floor(Math.random() * 6);
|
||||
|
||||
textureCtx.beginPath();
|
||||
textureCtx.moveTo(
|
||||
centerX + size * Math.cos(0),
|
||||
centerY + size * Math.sin(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(
|
||||
centerX + radius * Math.cos(angle),
|
||||
centerY + radius * Math.sin(angle)
|
||||
);
|
||||
}
|
||||
textureCtx.closePath();
|
||||
|
||||
const gradient = textureCtx.createRadialGradient(
|
||||
centerX, centerY, 0,
|
||||
centerX, centerY, size * 1.2
|
||||
);
|
||||
gradient.addColorStop(0, `hsla(
|
||||
${baseHue - 15 + Math.random() * 20},
|
||||
${baseSaturation + 20}%,
|
||||
${baseLightness * 0.5}%,
|
||||
${0.2 + Math.random() * 0.1}
|
||||
)`);
|
||||
gradient.addColorStop(1, 'hsla(0, 0%, 0%, 0)');
|
||||
|
||||
textureCtx.fillStyle = gradient;
|
||||
textureCtx.fill();
|
||||
}
|
||||
}
|
||||
};
|
||||
addHyperRealisticDetails();
|
||||
|
||||
return textureCanvas;
|
||||
}
|
||||
|
||||
// 辅助函数(需要在类中定义)
|
||||
/**
|
||||
* 2D Perlin噪声生成器
|
||||
* @param {number} x x坐标
|
||||
* @param {number} y y坐标
|
||||
* @returns {number} 噪声值(-1到1之间)
|
||||
*/
|
||||
perlinNoise(x, y) {
|
||||
// 梯度向量表
|
||||
const grad3 = [
|
||||
[1, 1, 0],
|
||||
[-1, 1, 0],
|
||||
[1, -1, 0],
|
||||
[-1, -1, 0],
|
||||
[1, 0, 1],
|
||||
[-1, 0, 1],
|
||||
[1, 0, -1],
|
||||
[-1, 0, -1],
|
||||
[0, 1, 1],
|
||||
[0, -1, 1],
|
||||
[0, 1, -1],
|
||||
[0, -1, -1]
|
||||
];
|
||||
|
||||
// 置换表(随机排列0-255)
|
||||
if (!this.perm) {
|
||||
this.perm = new Array(512);
|
||||
for (let i = 0; i < 256; i++) {
|
||||
this.perm[i] = this.perm[i + 256] = Math.floor(Math.random() * 256);
|
||||
}
|
||||
}
|
||||
|
||||
// 辅助函数
|
||||
const dot = (g, x, y) => g[0] * x + g[1] * y;
|
||||
const fade = t => t * t * t * (t * (t * 6 - 15) + 10);
|
||||
const lerp = (a, b, t) => a + t * (b - a);
|
||||
|
||||
// 确定单元方块
|
||||
const X = Math.floor(x) & 255;
|
||||
const Y = Math.floor(y) & 255;
|
||||
|
||||
// 相对单元方块的坐标
|
||||
x -= Math.floor(x);
|
||||
y -= Math.floor(y);
|
||||
|
||||
// 计算四个角落的梯度贡献
|
||||
const n00 = dot(grad3[this.perm[X + this.perm[Y]] % 12], x, y);
|
||||
const n01 = dot(grad3[this.perm[X + this.perm[Y + 1]] % 12], x, y - 1);
|
||||
const n10 = dot(grad3[this.perm[X + 1 + this.perm[Y]] % 12], x - 1, y);
|
||||
const n11 = dot(grad3[this.perm[X + 1 + this.perm[Y + 1]] % 12], x - 1, y - 1);
|
||||
|
||||
// 使用缓和曲线插值
|
||||
const u = fade(x);
|
||||
const v = fade(y);
|
||||
|
||||
return lerp(
|
||||
lerp(n00, n10, u),
|
||||
lerp(n01, n11, u),
|
||||
v
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* HSL颜色空间转RGB
|
||||
* @param {number} h 色相(0-360)
|
||||
* @param {number} s 饱和度(0-100)
|
||||
* @param {number} l 亮度(0-100)
|
||||
* @returns {Object} {r, g, b} 各通道值(0-255)
|
||||
*/
|
||||
HSLtoRGB(h, s, l) {
|
||||
h /= 360;
|
||||
s /= 100;
|
||||
l /= 100;
|
||||
|
||||
let r, g, b;
|
||||
|
||||
if (s === 0) {
|
||||
r = g = b = l; // 灰度
|
||||
} else {
|
||||
const hue2rgb = (p, q, t) => {
|
||||
if (t < 0) t += 1;
|
||||
if (t > 1) t -= 1;
|
||||
if (t < 1 / 6) return p + (q - p) * 6 * t;
|
||||
if (t < 1 / 2) return q;
|
||||
if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6;
|
||||
return p;
|
||||
};
|
||||
|
||||
const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
|
||||
const p = 2 * l - q;
|
||||
|
||||
r = hue2rgb(p, q, h + 1 / 3);
|
||||
g = hue2rgb(p, q, h);
|
||||
b = hue2rgb(p, q, h - 1 / 3);
|
||||
}
|
||||
|
||||
return {
|
||||
r: Math.round(r * 255),
|
||||
g: Math.round(g * 255),
|
||||
b: Math.round(b * 255)
|
||||
};
|
||||
}
|
||||
background() {
|
||||
book.style.display = "block"
|
||||
this.leftbackground = this.paperTexture('left')
|
||||
this.rightbackground = this.paperTexture('right')
|
||||
if (core.domStyle.isVertical) { //对竖屏进行绘制坐标变换,只需要考虑横屏绘制,竖屏将自适应转置
|
||||
core.maps._setHDCanvasSize(ctx, 416, 676)
|
||||
ctx.save(); //保存设置
|
||||
@ -22184,11 +22718,42 @@ let time=0
|
||||
ctx.lineTo(676 - dx, 0)
|
||||
ctx.lineTo(676, dy)
|
||||
ctx.closePath()
|
||||
ctx.fillStyle = "#e0d6c2"
|
||||
ctx.fill()
|
||||
|
||||
core.drawImage(ctx, this.paperTexture(), 0, 0, 325, 400, dx, 0, this.width, this.height)
|
||||
core.drawImage(ctx, this.paperTexture(), 0, 0, 325, 400, dx + this.width, 0, this.width, this.height)
|
||||
ctx.strokeStyle = `rgb(${248*0.7}, ${244*0.7}, ${230*0.7})`;
|
||||
ctx.beginPath()
|
||||
ctx.moveTo(2, 100)
|
||||
ctx.lineTo(2, 130)
|
||||
ctx.stroke()
|
||||
ctx.beginPath()
|
||||
ctx.moveTo(5, 20)
|
||||
ctx.lineTo(5, 30)
|
||||
ctx.stroke()
|
||||
ctx.beginPath()
|
||||
ctx.moveTo(6, 240)
|
||||
ctx.lineTo(6, 260)
|
||||
ctx.stroke()
|
||||
ctx.beginPath()
|
||||
ctx.moveTo(10, 340)
|
||||
ctx.lineTo(10, 360)
|
||||
ctx.stroke()
|
||||
ctx.beginPath()
|
||||
ctx.moveTo(665, 100)
|
||||
ctx.lineTo(665, 130)
|
||||
ctx.stroke()
|
||||
ctx.beginPath()
|
||||
ctx.moveTo(670, 190)
|
||||
ctx.lineTo(670, 160)
|
||||
ctx.stroke()
|
||||
ctx.beginPath()
|
||||
ctx.moveTo(671, 20)
|
||||
ctx.lineTo(671, 130)
|
||||
ctx.stroke()
|
||||
ctx.beginPath()
|
||||
ctx.moveTo(673, 350)
|
||||
ctx.lineTo(673, 370)
|
||||
ctx.stroke()
|
||||
core.drawImage(ctx, this.leftbackground, 0, 0, 325, 400, dx, 0, this.width, this.height)
|
||||
core.drawImage(ctx, this.rightbackground, 0, 0, 325, 400, dx + this.width, 0, this.width, this.height)
|
||||
|
||||
ctx.beginPath()
|
||||
ctx.moveTo(0, 416)
|
||||
@ -22204,8 +22769,41 @@ let time=0
|
||||
ctx.lineTo(338, this.height)
|
||||
ctx.lineTo(338 + dx, 416)
|
||||
ctx.closePath()
|
||||
ctx.fillStyle = '#706b61'
|
||||
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