PaperJS遍历路径点位置报错:Cannot read property 'point' of undefined
解决PaperJS波动动画中的"Cannot read property 'point' of undefined"错误及点不动画问题
我看到你在用PaperJS实现波动动画时遇到了两个头疼的问题:循环到i>=2时抛出Cannot read property 'point' of undefined错误,同时不是所有路径点都在正常动。让我帮你拆解问题并给出修复方案:
问题根源
- 路径简化导致段数丢失:你调用了
path1.simplify(1),这个方法会根据设定的阈值移除路径上的"冗余"段。你的初始路径有4个点,但simplify(1)的阈值太小,直接把部分原始段合并了,导致路径的segments长度小于4。当你用固定的segmentsArray.length(4)作为循环次数时,自然会访问到不存在的segments[i],触发错误。 - 动画基准坐标错误:你计算波动范围时用的是初始
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
相关产品推荐
相关产品推荐

