You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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个核心问题导致功能失效:

  1. 图层冲突:HTML中同时放置了<img>底图和P5画布,且draw()函数又重复绘制底图,导致画布完全覆盖底层图片,像素修改效果被反复覆盖
  2. 性能与逻辑冗余:reveal()中先绘制黑色椭圆再修改像素属于无效操作;循环中反复调用revealImage.get(x,y)会大幅降低性能
  3. 尺寸不匹配:固定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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 01:22:03