Is there a way to ensure that only individual objects are selected in FabricJS on the Canvas, rather than a group of objects?

One issue I am facing is with my method for selecting objects on the canvas by clicking a button. How do I ensure that it skips selecting groups and only selects individual objects?

Generating a group of shapes here:

const group = new fabric.Group([
      new fabric.Rect({ width: 100, height: 100, fill: 'red' }),
      new fabric.Rect({ width: 100, height: 100, fill: 'yellow', left: 100 }),
      new fabric.Rect({ width: 100, height: 100, fill: 'blue', top: 100 }),
      new fabric.Rect({
        width: 100,
        height: 100,
        fill: 'green',
        left: 100,
        top: 100
      })
    ])
this.canvas.add(group)

Creating an individual shape:

let rect1 = new fabric.Rect( {
      width: 100,
      height: 100,
      fill: 'transparent',
      stroke: 'blue',
      left: 140
    });
this.canvas.add(rect1)

Creating another individual shape:

let rect2 = new fabric.Rect( {
      width: 100,
      height: 100,
      fill: 'transparent',
      stroke: 'blue',
      left: 240
    });
this.canvas.add(rect2)

My current select method is selecting both the group and individual objects. How can I modify it to only select individual objects and not groups?

multiseleccion(){
    this.canvas?.discardActiveObject();
    
      this.selection = new fabric.ActiveSelection(this.canvas?.getObjects(), {
      canvas: this.canvas
      });
      this.canvas?.setActiveObject(this.selection);
      this.canvas?.requestRenderAll();

Answer №1

When using Fabricjs, the getObjects() method can provide an array of objects, but it doesn't offer a direct way to differentiate between a group and a single shape. However, there is a workaround available. Groups have a unique property called _objects which individual shapes do not possess.

To address this issue, we can iterate over the returned array, identify objects with the _objects property, and remove them accordingly. Subsequently, we can pass the refined array to the setActiveObject() method for further processing.

Here's a demonstration:

var canvas = new fabric.Canvas('c');
const group = new fabric.Group([
    new fabric.Rect({
        width: 100,
        height: 100,
        fill: 'red'
    }),
    ...
])
canvas.add(group);

let rect1 = new fabric.Rect({
    width: 100,
    height: 100,
    fill: 'transparent',
    stroke: 'blue',
    left: 140
});
canvas.add(rect1);
...
multiseleccion();
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/5.2.4/fabric.min.js" integrity="sha512-HkRNCiaZYxQAkHpLFYI90ObSzL0vaIXL8Xe3bM51vhdYI79RDFMLTAsmVH1xVPREmTlUWexgrQMk+c3RBTsLGw==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<canvas id="c" width="400" height="300" style="border:1px solid #ccc"></canvas>

Answer №2

Each element (predefined) within fabric possesses a type property that serves to distinguish one object from another. In this scenario, you have the ability to sort through objects of the 'group' type, which would provide the most streamlined solution.

I've made adjustments to your multiselection function in order to group all canvas objects excluding those classified as groups.

multiselection() {
  this.canvas?.discardActiveObject();

  const objectsWithoutGroups = this.canvas?.getObjects().filter(fabricObject => fabricObject.type !== 'group') || []
  if(objectsWithoutGroups.length) {
    this.selection = new fabric.ActiveSelection(objectsWithoutGroups, {
      canvas: this.canvas
    });
    this.canvas?.setActiveObject(this.selection);
    this.canvas?.requestRenderAll();
  }
}

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

Guide for building a Template-driven formArray in Angular

I am currently implementing a fixed number of checkboxes that are being bound using a for loop. <ul> <li *ngFor="let chk of checkboxes"> <input type="checkbox" [id]="chk.id" [value]="chk.value&q ...

Unable to run `create-react-app` with the `--template typescript` option

Every time I try to execute the following command: npx create-react-app my-app --template typescript only a JavaScript project is created, without any .tsx files. After consulting the CRA's TypeScript guide, it appears that the command requires Node ...

You can easily search and select multiple items from a list using checkboxes with Angular and TypeScript's mat elements

I am in need of a specific feature: An input box for text entry along with a multi-select option using checkboxes all in one place. Unfortunately, I have been unable to find any references or resources for implementing these options using the Angular Mat ...

Components in Angular 5 app hosted on Firebase fail to load

I successfully deployed my Angular 5 app to Firebase using the commands firebase init and firebase deploy. By default, the main page is pulled from the index.html file within the public directory. To ensure that my index.html was displayed, I made a chan ...

When you call Subscribe(), you will receive the output "complete: () => void; 'complete' is defined in this context. What exactly does this signify?

Currently, I am following a tutorial and after meticulously checking and rechecking, I can confidently say that my code matches exactly with the one the professor is using. The tutorial involves creating a simple Single Page Application in Angular using Ty ...

Configuring NextJs routes with multiple parameters

Seeking guidance on structuring files in Nextjs for handling multiple URL parameters. Can anyone offer advice? The given URL structure is: /api/upload?file=${filename}&fileType=${fileType} This is the current file structure: app api upload ...

What are the counterparts of HasValue and .Value in TypeScript?

There is a method in my code: public cancelOperation(OperationId: string): Promise<void> { // some calls } I retrieve OperationId from another function: let operationId = GetOperationId() {} which returns a nullable OperationId, operat ...

Tips on integrating TypeScript into JavaScript

Currently, I am working with a node.js server.js file. var http = require('http'); var port = process.env.port || 1337; http.createServer(function (req, res) { res.writeHead(200, { 'Content-Type': 'text/plain' }); res ...

What is the process for adjusting the color of a mat-divider?

Has anyone been successful in changing the color of mat-divider? I attempted the following but had no luck: component.html <mat-divider class="material-devider"></mat-divider> component.scss .material-devider { color: red } ...

Combining data types to create a unified set of keys found within a complex nested structure

This problem is really testing my patience. No matter what I do, I just can't seem to make it work properly. Here's the closest I've come so far: // Defining a complex type type O = Record<'a', Record<'b' | 'x& ...

Running "npm start" does not automatically recompile or display code changes

My experience with my Angular project has been smooth until today. Surprisingly, without making any changes, the "npm start" command suddenly stopped working properly. The project compiles successfully, but any subsequent code changes do not trigger an aut ...

Exploring the power of Next.js, Styled-components, and leveraging Yandex Metrica Session Replay

I'm currently involved in a project that utilizes Next.js and styled-components. In my [slug].tsx file: export default function ProductDetails({ product }: IProductDetailsProps) { const router = useRouter(); if (router.isFallback) { return ( ...

Tips for transfering variables from an electron application to the backend of an Angular project

My goal is to develop a website and desktop application using the same code base. However, due to some minor differences between the two platforms, I need a way for my Angular app to distinguish whether it has been called from the web or from Electron. I& ...

actions with frontend routing for CRUD operations

Imagine you are creating a simple CRUD todo application. Whether you choose to use Angular, React, or Vue for routing, the setup will be similar: /todos => see all todos /todos/:id => view one todo by id /todos/:id/edit => edit one todo by id /todos/new ...

The name 'Landbot' cannot be located. Have you meant to type '_landbot' instead?

I'm currently in the process of integrating Landbot into my React.js application with TypeScript. I'm following this [doc] 1. However, I'm facing an issue where the code inside useEffect (new Landbot.Container) is causing an error. 'C ...

Is there a way to verify if the database has been successfully saved and the API call has been

I am currently in the process of developing a function that calls two other functions. Function 1 is responsible for saving an object to a database, while function 2 performs an API call. async createMSCalendarEntry(start: Date, end: Date, name: string ...

Styling child elements in Angular using css from its parent element

I have a question: Regarding the structure below <component-parent> <first-child> <second-child> <third-child></third-child> </second-child> </first-child> </component-parent> Now I want t ...

Encountering the issue of receiving "undefined" when utilizing the http .get() method for the first time in Angular 2

When working in Angular, I am attempting to extract data from an endpoint. Below is the service code: export class VideosService { result; constructor(private http: Http, public router: Router) { } getVideos() { this.http.get('http://local ...

What causes socket.io to display the message "Bad handshake method"?

Hey there, I'm currently having some issues with a socket connection. I am using socket.io in the nodejs-express backend and ngx-socket-io in the angular frontend. However, during the connection process, I am receiving a 400 status ({"code": ...

What could be causing the increased build size of my Polymer2 compared to Angular5?

After reading multiple blogs, I decided to go with the polymer2 framework instead of angular. Some sources claimed that Polymer contributes less to the build size for production compared to angular2/5. To test this theory, I created two demo projects - on ...