Paper.js - generate a collection of movable shapes

I am attempting to use paper.js to create draggable shapes where the index of each shape is provided during dragging.

Unfortunately, I keep encountering an error that says "Uncaught TypeError: Cannot read property 'position' of undefined".

If anyone has any advice or solutions, I would greatly appreciate it.

<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>

Answer №1

Issue

The error you are encountering is related to how variable scoping operates in Javascript. In JavaScript, variables are scoped to the enclosing function or script. When you attempt to drag the circle, the value of i === 5 from the for loop, causing path[i] to be undefined (out of range) within the drag function, resulting in an error.

To delve deeper into this "closure inside loop" issue, refer to this answer.

Resolutions

This solution offers some common fixes for this problem.

ES6 Let

The ES6 let statement serves as a contemporary remedy, bypassing several scope inconsistencies present in the var statement. With variables scoped to the containing block, each iteration of the loop obtains its independent instance of i.

To integrate ES6 features into PaperScript, ensure you initially load a newer version of the Acorn parser (credits to sasensi and Geddes). Then, simply declare let i within the loop:

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.")
  };
}

See a functional Stackblitz here.

Closure Solution

If you prefer not to modify the PaperScript parser, you can employ a closure to capture the index in a fresh function scope:

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);
}

View a working Stackblitz example here.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Mastering Typescript lookup types - effectively limit the properties included in a merge operation with the Partial type

Exploring lookup types, I'm interested in creating a safe-merge utility function that can update an entity of type T with a subset of keys from another object. The objective is to leverage the TypeScript compiler to catch any misspelled properties or ...

Customized function enabling dynamic menu display based on varying screen dimensions

Looking for assistance with JS and jQuery as I am relatively new to it. Any help would be greatly appreciated... I'm currently working on a responsive header where I want to implement onclick functions for mobile and tablet resolutions only. I' ...

How can I incorporate a feature in my Angular application that allows users to switch between different view types, such as days, using JavaScript

Greetings, community! I am currently utilizing version 5 of the fullcalendar library from https://fullcalendar.io/ in my Angular 9 application. I have noticed that the calendar offers various options to change the view type as shown below: https://i.stac ...

true not redirecting to 404 page when axios request fails

I have implemented Axios to access a basic API. My goal is to direct the user to the default Next.js 404 page in case of a failed request with a 404 error code. I have set the notFound boolean to true if the request status is 404. There are a total of 10 u ...

Tips for adjusting the height of a fixed-size child element on the screen using only CSS and JavaScript restrictions

I am faced with a challenge involving two child elements of fixed size: <div class="parent"> <div class="static_child"> </div> <div class="static_child"> </div> </div> .parent { border: 1px solid black; dis ...

What is the best way to access the CSS font-size property using JavaScript?

I've attempted to adjust the font size using this code: document.getElementById("foo").style.fontSize Unfortunately, this code does not return any results. The CSS styles are all defined within the same document and are not in an external stylesheet ...

JavaScript code is functioning properly on Chrome and Internet Explorer, however, it may not be working on FireFox

Despite searching through the console, I am unable to find a solution to this issue. There are two images in play here - one is supposed to appear at specific coordinates while the other should follow the mouse cursor. However, the image intended to track ...

Issue with JQuery's click and submit events not triggering, but change event is working fine

My webpage has a dynamic DOM that includes add and save buttons to interact with elements. Each row also has a remove option for deletion. When a user logs in, the controller redirects them to their homepage in the codeigniter PHP framework. This controlle ...

Storing new li and ul elements to the database by utilizing an array for dynamic saving

I am in the process of creating a user interface for an application where users can add unordered lists and list items by clicking on "add question". I have successfully designed the front end part and here is a preview: However, I am facing difficulties ...

Displaying information based on selection in AngularJSIn this tutorial

I am a beginner in Angularjs and currently working on developing a website. One of the tasks I have is to create a combo box that, when an option is selected, calls a method to load values into a Scope variable and update it. Below is the code I have so fa ...

Mapping Store Fields to JSON Properties in ExtJS: A Complete Guide

I am working with a JSON data object that includes exchange rates information: { "disclaimer": "Exchange rates provided for informational purposes only and do not constitute financial advice of any kind. Although every attempt is made to ensure quality, ...

Angular Typescript error: Trying to assign a value to 'someProperty' property of an undefined object

Within my Article class, I have a property called Image which is structured like this: export class Article { public image:Image; public images: Image[]; } If I decide to comment out this.article.image = new Image(); in the following way: constru ...

Exploring the Potential of CSS Styling within Vue.js

I am in the process of creating a website and I am looking for a way to manage my styles through Vue. I want to be able to utilize CSS with Vue, as the style of .skill-bar serves as the background of the bar, while .skill-bar-fill represents the green fil ...

What is the solution to fixing the JSON parsing error that says 'JSON.parse: bad control character in string literal'?

When sending data from NodeJS Backend to the client, I utilize the following code: res.end(filex.replace("<userdata>", JSON.stringify({name:user.name, uid:user._id, profile:user.profile}) )) //No errors occur here and the object is successfully stri ...

Choose every fourth row in the table

Is there a way to alternate the background colors of selected groups of 4 rows in a table? I want to make one group red and the next group blue. Any suggestions or ideas on how to achieve this? <table> <tr style="background-color: red;"> ...

Angular 2 - synchronizing timer for all users

I have developed a timer that needs to function consistently for all users at the same time. To achieve this, I stored the start_time (timestamp when the timer begins) in my database and implemented the following code snippet to calculate the remaining ti ...

Is there a way to make my code on Google Sheets work across multiple tabs?

My Google Sheets code successfully pulls information from the main tab into my CRM Software every time someone fills out a form online. However, I'm struggling to get the script to run for multiple tabs on the same spreadsheet. I've tried a few s ...

I'm interested in exploring different database implementation patterns in JavaScript. What kinds of approaches can I consider?

As someone who is relatively new to exploring JavaScript, I have been immersed in experimenting with a node test app and MongoDB. I am eager to delve into the database aspect of the app but finding myself uncertain about the most commonly used patterns in ...

New example of how to use the "useSession" syntax in Next Auth

Currently, I am delving into the next-auth documentation and feeling perplexed by the syntax used in the useSession hook. The way it's showcased in the documentation is as follows: const { data: session, status } = useSession() My confusion stems f ...

Cloning a repository does not support Typescript compilation

After creating an Angular2 component, I wanted to share the code with my colleagues. Therefore, I uploaded the code to Github, cloned the repository, ran npm install, and then npm run tsc. However, I encountered the following errors: error TS2318: Cannot ...