paper.js - 创建可拖动形状数组

paper.js - create array of draggable shapes

我正在尝试在 paper.js 中创建一组形状。每个形状都应该是可拖动的,并且在拖动过程中给出该形状的索引。

我尝试了以下代码,但我只收到消息“Uncaught TypeError: Cannot read 属性 'position' of undefined”。

感谢收到的任何帮助。

<canvas id = "canvas_1" > < /canvas>
<script src = "https://cdnjs.cloudflare.com/ajax/libs/paper.js/0.12.11/paper-full.min.js" > < /script>

<script type = "text/paperscript" canvas = "canvas_1" >
  var path = [];

  for (i = 0; i < 5; i++) {

    path[i] = new Path.Circle({
      center: view.center,
      radius: 30,
      fillColor: 'blue'
    });

    path[i].onMouseDrag = function(event) {
      path[i].position += event.delta;
      console.log("shape " + i + " is being dragged.")
    }

  }

</script>

问题

您的错误归结为 variable scoping 在 Javascript 中的工作方式:变量的范围限定为包含函数或脚本 。当您开始拖动圆圈时,for 循环中的 i === 5,因此 path[i] 在拖动函数中未定义(越界)。因此,你的错误。

如果您想了解更多信息,this answer 提供了对这个“闭包内循环”问题的深入研究。

解决方案

This answer 提供了一些针对此问题的常见解决方案。

ES6 让

ES6 let statement 是这个问题的现代解决方案,避免了 var 语句的许多范围“怪癖”。 包含块的变量作用域,因此循环的每次通过都会获得自己的 i.

实例

要在 PaperScript 中使用 ES6 功能,您首先需要 load a newer version of the Acorn parser (感谢 sasensi 和 Geddes)。然后简单地在循环中声明let i

var path = [];

for (let i = 0; i < 5; i++) {
  path[i] = new Path.Circle({
    center: view.center,
    radius: 30,
    fillColor: 'blue'
  });
  path[i].onMouseDrag = function(event) {
    path[i].position += event.delta;
    console.log("shape " + i + " is being dragged.")
  };
}

Here is a working Stackblitz.

关闭

无需修改 PaperScript 解析器,您可以使用 closure 在新函数范围内捕获索引:

var path = [];

function createMouseDragHandler(index) {
  return function(event) {
    path[index].position += event.delta;
    console.log("shape " + index + " is being dragged.")
  };
}

for (var i = 0; i < 5; i++) {
  path[i] = new Path.Circle({
    center: view.center,
    radius: 30,
    fillColor: 'blue'
  });
  path[i].onMouseDrag = createMouseDragHandler(i);
}

Here is a working Stackblitz.