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

如何用p5js实现椭圆沿多点线段移动及鼠标悬停精准显示?

单椭圆移动实现方案

你现在出现多个椭圆的核心原因有两个:

  1. p5.js默认画布是叠加绘制模式,之前绘制的椭圆不会自动消失
  2. 你的绘图逻辑放在了点位遍历的循环内,每个点位都会触发一次椭圆绘制

修正方法如下:

  • 调整draw()函数的执行顺序:每帧开头先调用background(255)清空整个画布,之后按顺序绘制坐标轴、所有线段,最后仅绘制1个当前位置的椭圆,保证每帧只保留最新的椭圆
  • 提前预处理CSV数据,把所有日期对应的画布坐标整合成一个全局的路径数组,不要在遍历点位的循环里做绘图操作
  • 全局单独维护动画进度变量pct,每帧仅计算一次当前进度对应的坐标,再绘制单个椭圆

鼠标悬停坐标映射方案

map()方法的核心逻辑是把一个数值从原始区间线性映射到目标区间,你可以按以下步骤实现悬停定位:

  1. 先确定图表的X轴边界:比如图表左侧起始X坐标为chartXMin,右侧结束X坐标为chartXMax,对应日期范围是当月第一天dayMin到当月最后一天dayMax
  2. 把鼠标X坐标映射为对应日期:const hoverDay = constrain(map(mouseX, chartXMin, chartXMax, dayMin, dayMax), dayMin, dayMax),这里用constrain限制日期不会超出当月范围
  3. 遍历路径点找到该日期对应的线段区间,计算区间内的百分比:const segmentPct = map(hoverDay, 区间左端点日期, 区间右端点日期, 0, 1)
  4. 用百分比计算对应Y坐标,直接在该位置绘制椭圆即可

核心优化代码示例

// 全局变量定义
let path = []; // 预处理后的路径点数组,每个元素结构:{x:画布X坐标, y:画布Y坐标, day:对应日期}
let animPct = 0; // 动画进度变量
const chartXMin = 50; // 替换为你的图表左侧X坐标
const chartXMax = 750; // 替换为你的图表右侧X坐标
const dayMin = 1; // 替换为你的数据起始日期
const dayMax = 31; // 替换为你的数据结束日期

function preload() {
  // 在这里加载CSV数据,提前计算所有点的画布坐标存入path数组,避免每帧重复计算
}

function draw() {
  // 每帧先清屏
  background(255);
  // 绘制所有底图元素:坐标轴、全部线段
  drawAllChartLines();

  // ===== 自动动画模式(要使用悬停模式就注释这段)=====
  animPct += 0.005; // 数值越大动画速度越快
  if (animPct > 1) animPct = 0; // 播放完从头循环
  const animPos = getPosByPct(animPct);
  drawEllipse(animPos.x, animPos.y, 10);

  // ===== 鼠标悬停模式(要使用动画模式就注释这段)=====
  // if (mouseX >= chartXMin && mouseX <= chartXMax) {
  //   const hoverDay = constrain(map(mouseX, chartXMin, chartXMax, dayMin, dayMax), dayMin, dayMax);
  //   const hoverPos = getPosByDay(hoverDay);
  //   drawEllipse(hoverPos.x, hoverPos.y, 10);
  // }
}

// 根据全局动画进度获取当前坐标
function getPosByPct(pct) {
  const totalSeg = path.length - 1;
  const segIndex = floor(pct * totalSeg);
  const segPct = pct * totalSeg - segIndex;
  return {
    x: lerp(path[segIndex].x, path[segIndex+1].x, segPct),
    y: lerp(path[segIndex].y, path[segIndex+1].y, segPct)
  }
}

// 根据输入日期获取对应路径上的坐标
function getPosByDay(day) {
  for (let i = 0; i < path.length - 1; i++) {
    if (path[i].day <= day && path[i+1].day >= day) {
      const segPct = map(day, path[i].day, path[i+1].day, 0, 1);
      return {
        x: lerp(path[i].x, path[i+1].x, segPct),
        y: lerp(path[i].y, path[i+1].y, segPct)
      }
    }
  }
  return day < path[0].day ? path[0] : path[path.length - 1];
}

// 你的原有绘图方法保留即可
this.drawEllipse = function(ellipseX, ellipseY, size) {
  fill('black');
  ellipse(ellipseX, ellipseY, size);
};

原有代码问题修正

  • 你重复声明了beginY变量,会导致变量值异常,删掉多余的声明即可
  • 不要在点位遍历的循环内执行绘图操作,所有绘图逻辑统一放在draw()函数中按顺序执行

内容的提问来源于stack exchange,提问作者soyNstacks

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.06 03:09:03