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

PaperJS遍历路径点位置报错:Cannot read property 'point' of undefined

解决PaperJS波动动画中的"Cannot read property 'point' of undefined"错误及点不动画问题

我看到你在用PaperJS实现波动动画时遇到了两个头疼的问题:循环到i>=2时抛出Cannot read property 'point' of undefined错误,同时不是所有路径点都在正常动。让我帮你拆解问题并给出修复方案:

问题根源

  1. 路径简化导致段数丢失:你调用了path1.simplify(1),这个方法会根据设定的阈值移除路径上的"冗余"段。你的初始路径有4个点,但simplify(1)的阈值太小,直接把部分原始段合并了,导致路径的segments长度小于4。当你用固定的segmentsArray.length(4)作为循环次数时,自然会访问到不存在的segments[i],触发错误。
  2. 动画基准坐标错误:你计算波动范围时用的是初始segmentsArray里的原始坐标,但路径已经经过缩放和位移,当前点的实际坐标和原始坐标差异很大,这会导致动画位置完全不符合预期,甚至看起来部分点没在动。

解决方案

1. 保留原始路径段数

要么直接移除simplify()调用(如果不需要路径简化),要么调大阈值(比如改成simplify(10)),确保路径始终保留初始的4个段。你可以在初始化后打印console.log(path1.segments.length)确认段数是否符合预期。

2. 基于当前点坐标计算波动范围

不要用原始的segmentsArray坐标作为基准,而是用每个路径点当前的x/y值来计算波动的最小/最大值,这样动画会在当前点的基础上自然波动,效果更合理。

3. 用路径实际的segments长度作为循环上限

避免硬编码循环次数,改用path1.segments.length(三个路径是克隆来的,段数完全一致),这样即使后续路径段数变化,循环也不会越界。

修改后的完整代码

var path1; var path2; var path3; 
var startX = 100; var endX = 100; 
var minValX = 30; var maxValX = 30; 
var minValY = 10; var maxValY = 10; 
var minVel = 3; var maxVel = 3.5; 
var interval = 1000; var time = 2; 
var segmentsArray = [[30, 92], [37, 45], [90, 50], [80, 120]]; 
var offsetVal1; var offsetVal2; 
var scaleArr = [1.4,1.3,1.2]; 
var ease = SlowMo.ease.config(0.1, 0.3, false); 
var circle_points1=null; var circle_points2=null; var circle_points3=null; 

window.onload = function() { 
  paper.setup('myCanvas'); 
  path1 = new Path({ 
    segments: segmentsArray, 
    strokeColor: 'black', 
    strokeWidth: 0.1, 
    closed: true, 
    opacity:0 
  }); 
  path1.fullySelected = false; 
  path1.position.x += startX; 
  path1.position.y += startX; 
  path1.smooth(); 
  // 移除simplify调用,或改为simplify(10)以保留原始4个段
  // path1.simplify(1); 
  path1.scale(scaleArr[0]); 
  path2 = path1.clone(); 
  path2.scale(scaleArr[1]); 
  path3 = path2.clone(); 
  path3.scale(scaleArr[2]); 

  path1.fillColor = '#ececec'; 
  path1.strokeWidth = 10; 
  path1.strokeColor = '#ddd'; 

  setTimeout(initFadeIn, interval); 
  setInterval(shapeAnimation, interval); 
} 

function initFadeIn(){ 
  var ease = Power4.easeOut; 
  TweenMax.to(path1, time, { opacity: 1, ease: ease, force3D: true}); 
  TweenMax.to(path2, time, { opacity: 1, ease: ease, force3D: true}); 
  TweenMax.to(path3, time, { opacity: 1, ease: ease, force3D: true}); 
} 

function shapeAnimation(){ 
  var timeShape = getRandomArbitrary(minVel, maxVel); 
  // 用路径实际的segments长度作为循环上限
  for(var i=0; i<path1.segments.length; i++){ 
    circle_points1 = path1.segments[i].point; 
    circle_points2 = path2.segments[i].point; 
    circle_points3 = path3.segments[i].point; 

    // 基于当前点坐标计算波动范围
    var minX = circle_points1.x - minValX; 
    var maxX = circle_points1.x + maxValX; 
    var minY = circle_points1.y - minValY; 
    var maxY = circle_points1.y + maxValY; 

    gapX = getRandomArbitrary(minX, maxX); 
    gapY = getRandomArbitrary(minY, maxY); 

    TweenMax.to(circle_points1, timeShape, { x: gapX, y: gapY, ease: ease, force3D: true}); 
    TweenMax.to(circle_points2, timeShape, { x: gapX, y: gapY, ease: ease, force3D: true}); 
    TweenMax.to(circle_points3, timeShape, { x: gapX, y: gapY, ease: ease, force3D: true}); 
  } 
} 

function getRandomArbitrary(min, max) { 
  var val = Math.round(Math.random() * (max - min) + min); 
  return val; 
}

额外小贴士

如果你想让三个路径的波动效果有差异,可以为每个路径单独计算gapX和gapY,而不是共用同一组值,这样动画会更有层次感。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 07:24:55