P5.js鼠标光标半径内显示底层图片功能故障求助
问题描述
我用HTML、CSS和JavaScript结合P5.js写了一段代码,想实现鼠标按下时,在光标半径范围内显示另一张图片的效果,但功能没法正常运行。以下是我的代码:
HTML代码
<!DOCTYPE html> <html> <head> <title>p5.js Image Reveal on Hover</title> <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.0/p5.js"></script> <script src="sketch.js"></script> <link rel="stylesheet" type="text/css" href="style.css"> </head> <body> <div class="container"> <img class="base-image" src="https://png.pngtree.com/png-vector/20220620/ourmid/pngtree-white-cloud-weather-climate-png-image_5215887.png"> <canvas id="canvas"></canvas> </div> </body> </html>
CSS代码
.container { position: relative; } .base-image { position: absolute; top: 0; left: 0; } canvas { position: absolute; top: 0; left: 0; }
JavaScript代码
let canvas; let baseImage; let revealImage; let revealRadius = 50; function preload() { baseImage = loadImage('https://png.pngtree.com/png-vector/20220620/ourmid/pngtree-white-cloud-weather-climate-png-image_5215887.png'); revealImage = loadImage('https://png.pngtree.com/png-vector/20220620/ourmid/pngtree-cloud-weather-climate-free-cutout-nature-png-image_5215871.png'); } function setup() { canvas = createCanvas(500, 500); canvas.parent('canvas'); } function draw() { background(255); image(baseImage, 0, 0, width, height); if (mouseIsPressed) { reveal(); } } function reveal() { noStroke(); fill(0); ellipse(mouseX, mouseY, revealRadius, revealRadius); loadPixels(); for (let x = 0; x < width; x++) { for (let y = 0; y < height; y++) { let d = dist(x, y, mouseX, mouseY); if (d <= revealRadius / 2) { let index = (x + y * width) * 4; pixels[index] = red(revealImage.get(x, y)); pixels[index + 1] = green(revealImage.get(x, y)); pixels[index + 2] = blue(revealImage.get(x, y)); pixels[index + 3] = 255; } } } updatePixels(); }
问题分析与修复方案
你的代码存在3个核心问题导致功能失效:
- 图层冲突:HTML中同时放置了
<img>底图和P5画布,且draw()函数又重复绘制底图,导致画布完全覆盖底层图片,像素修改效果被反复覆盖 - 性能与逻辑冗余:
reveal()中先绘制黑色椭圆再修改像素属于无效操作;循环中反复调用revealImage.get(x,y)会大幅降低性能 - 尺寸不匹配:固定500x500的画布尺寸与加载图片的实际尺寸不一致,会导致显示错位
修复后的完整代码
HTML(移除冗余img标签)
<!DOCTYPE html> <html> <head> <title>p5.js Image Reveal on Hover</title> <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.0/p5.js"></script> <script src="sketch.js"></script> <link rel="stylesheet" type="text/css" href="style.css"> </head> <body> <div class="container"> <canvas id="canvas"></canvas> </div> </body> </html>
CSS(无需修改)
.container { position: relative; } canvas { position: absolute; top: 0; left: 0; }
JavaScript(优化逻辑与性能)
let canvas; let baseImage; let revealImage; let revealRadius = 50; let revealPixels; // 预存显示图片的像素数据 function preload() { baseImage = loadImage('https://png.pngtree.com/png-vector/20220620/ourmid/pngtree-white-cloud-weather-climate-png-image_5215887.png'); revealImage = loadImage('https://png.pngtree.com/png-vector/20220620/ourmid/pngtree-cloud-weather-climate-free-cutout-nature-png-image_5215871.png'); } function setup() { // 用图片实际尺寸创建画布,避免错位 canvas = createCanvas(baseImage.width, baseImage.height); canvas.parent('canvas'); // 预加载显示图片的像素数组,提升循环性能 revealImage.loadPixels(); revealPixels = revealImage.pixels; } function draw() { // 每次绘制先渲染底图 image(baseImage, 0, 0); if (mouseIsPressed) { reveal(); } } function reveal() { loadPixels(); // 缩小循环范围到圆形区域边界,减少无效计算 const startX = max(0, mouseX - revealRadius/2); const endX = min(width, mouseX + revealRadius/2); const startY = max(0, mouseY - revealRadius/2); const endY = min(height, mouseY + revealRadius/2); for (let x = startX; x < endX; x++) { for (let y = startY; y < endY; y++) { let d = dist(x, y, mouseX, mouseY); if (d <= revealRadius / 2) { let index = (x + y * width) * 4; // 直接从预存像素数组取值,避免重复调用get() pixels[index] = revealPixels[index]; pixels[index + 1] = revealPixels[index + 1]; pixels[index + 2] = revealPixels[index + 2]; pixels[index + 3] = revealPixels[index + 3]; // 保留原图片透明度 } } } updatePixels(); }
修复要点说明
- 移除HTML中冗余的
<img>标签,所有图像由P5画布统一处理,避免图层冲突 - 画布尺寸匹配图片实际尺寸,解决显示错位问题
- 预加载显示图片的像素数组,避免循环中反复调用
get(),大幅提升性能 - 缩小循环范围到圆形区域边界内,减少不必要的计算
- 保留显示图片的原始透明度,效果更自然
- 移除无效的黑色椭圆绘制代码
内容的提问来源于stack exchange,提问作者Ian Cross
相关产品推荐
相关产品推荐

