Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

draw a polygon #84

Open
jeldev12 opened this issue Sep 13, 2023 · 9 comments
Open

draw a polygon #84

jeldev12 opened this issue Sep 13, 2023 · 9 comments

Comments

@jeldev12
Copy link

Hi Sir, good-day. Is it possible to add or a draw a polygon on top of the image?.

@bytesleo
Copy link
Owner

bytesleo commented Sep 14, 2023

Hi, it sounds interesting, we will keep this feature in mind for future updates 🙌

@jeldev12
Copy link
Author

jeldev12 commented Sep 17, 2023

Hi Sir , I am using your project and modifying some parts particularly to be able to add and draw polygon to the image that was added on the canvas. I would just like to asks if you have an idea how we can solve the issue of being able to add multiple polygons on the canvas and be able to edit the selected polygon and also be able to delete the selected polygon same as on the shapes like square, circle .etc.

I have a working code here which I was able to connect and create polygon and edit it but the thing is I can't solve the adding of multiple polygons and also editing selected polygon and deleting selected polygon. Maybe you have an expertise in fabric js would really be appreciated. Thank you.


getClickCoords(event: any) {
    if (this.isCanvasDrawn && this.isImageDrawn) {
      this.newPt = {
        x: event.layerX,
        y: event.layerY
      };
      this.points.push(this.newPt);
      
      // Create a new fabric.Polygon object with the updated points
      const newPolygon = this.polygon
      
      // Set the fill color for the new polygon
      newPolygon.fill = this.hexToRGBA(this.selectedColor, 0.5);
      
      // Remove the old polygon (if it exists) and add the new one to the canvas
      if (this.polygon) {
        this.canvas.remove(this.polygon);
      }
      this.canvas.add(newPolygon);
      
      // Update this.polygon to the newPolygon for future reference
      this.polygon = newPolygon;
    }
  }

  public edit() {
    function polygonPositionHandler(dim, finalMatrix, fabricObject) {
      let x =
          fabricObject.points[this.pointIndex].x - fabricObject.pathOffset.x,
        y = fabricObject.points[this.pointIndex].y - fabricObject.pathOffset.y;
      return fabric.util.transformPoint(
        new fabric.Point(x, y),
        fabric.util.multiplyTransformMatrices(
          fabricObject.canvas.viewportTransform,
          fabricObject.calcTransformMatrix()
        )
      );
    }
    function anchorWrapper(anchorIndex, fn) {
      return function(eventData, transform, x, y) {
        var fabricObject = transform.target,
          absolutePoint = fabric.util.transformPoint(
            new fabric.Point(
              fabricObject.points[anchorIndex].x - fabricObject.pathOffset.x,
              fabricObject.points[anchorIndex].y - fabricObject.pathOffset.y
            ),
            fabricObject.calcTransformMatrix()
          ),
          actionPerformed = fn(eventData, transform, x, y),
          newDim = fabricObject._setPositionDimensions({}),
          polygonBaseSize = fabricObject._getNonTransformedDimensions(),
          newX =
            (fabricObject.points[anchorIndex].x - fabricObject.pathOffset.x) /
            polygonBaseSize.x,
          newY =
            (fabricObject.points[anchorIndex].y - fabricObject.pathOffset.y) /
            polygonBaseSize.y;
        fabricObject.setPositionByOrigin(absolutePoint, newX + 0.5, newY + 0.5);
        return actionPerformed;
      };
    }
    function actionHandler(eventData, transform, x, y) {
      var polygon = transform.target,
        currentControl = polygon.controls[polygon.__corner],
        mouseLocalPosition = polygon.toLocalPoint(
          new fabric.Point(x, y),
          'center',
          'center'
        ),
        polygonBaseSize = polygon._getNonTransformedDimensions(),
        size = polygon._getTransformedDimensions(0, 0),
        finalPointPosition = {
          x:
            (mouseLocalPosition.x * polygonBaseSize.x) / size.x +
            polygon.pathOffset.x,
          y:
            (mouseLocalPosition.y * polygonBaseSize.y) / size.y +
            polygon.pathOffset.y
        };
      polygon.points[currentControl.pointIndex] = finalPointPosition;
      return true;
    }
    let poly = this.canvas.getObjects()[0];
    this.canvas.setActiveObject(poly);
    poly.edit = !poly.edit;
    if (poly.edit) {
      let lastControl = poly.points.length - 1;
      poly.cornerStyle = 'circle';
      poly.cornerColor = 'red ';
      poly.controls = poly.points.reduce(function(acc, point, index) {
        acc['p' + index] = new fabric['Control']({
          pointIndex: index,
          positionHandler: polygonPositionHandler,
          actionHandler: anchorWrapper(
            index > 0 ? index - 1 : lastControl,
            actionHandler
          ),
          actionName: 'modifyPolygon'
        });
        return acc;
      }, {});
    }

    poly.hasBorders = !poly.edit;
    this.canvas.requestRenderAll();
  }

@Saqib92
Copy link
Contributor

Saqib92 commented Sep 17, 2023

why are you referencing using:

// Update this.polygon to the newPolygon for future reference
this.polygon = newPolygon;

Current delete function should delete select polygon. and edit polygon (selecting any point on selected polygon should be able to change it). Can you make example stackblitz for better understanding of your issue.

@Saqib92
Copy link
Contributor

Saqib92 commented Sep 17, 2023

the issue of Edit is:
let poly = this.canvas.getObjects()[0]; // you are selecting 1st object on canvas.
it should be let poly = this.canvas.getActiveObject(); // with this you will be able to Edit selected polygon.

@jeldev12
Copy link
Author

@Saqib92 Hi Sir, good day. So basically, I am creating this app based on Mr. Kevoj angular editor using fabric js. So as you can see on the first screenshot. I have this feature where I can add image on the canvas and then there is a menu on the left side for me to add different shapes like square, circle etc and be able to change the color and the size and also be able to delete the shapes.

FIRST SCREENSHOT
image

SECOND SCREENSHOT
image

Now when it comes to the shapes like square, rectable, triangle and circle I already have made it work and it working fine. My current issue is that the I cant make the polygon work the same as those existing shapes.

What I want to achieve is be able to draw a polygon which now is working. (just the draw). So when I click the polygon item from the menu I should be able to draw a polygon and have a button set the created polygon as completed so that I can click in the menu again and be able to create another polygon. Next is be able to select from the created polygon in the canvas and be able to move, edit or delete it. As you can see on the screenshot I have a progress now where I can draw and edit but not the multiple functionality where in we can create multiple polygon and select one to edit or delete.

THIRD SCREENSHOT
image

This is the stackblitz I created but it does not full work because I am not really familiar with the blitz tool but I have all the code

https://stackblitz.com/edit/angular-ivy-fbiqgw?file=src%2Fapp%2Fapp.component.ts,src%2Fapp%2Fapp.component.html,src%2Fapp%2Fapp.module.ts

and for the dialog where In I uses a color picker here is the code

<color-sketch [width]="200" (onChange)="handleChange($event)"></color-sketch>


export class ColorPickerDialogComponent implements OnInit {

  constructor(private dialogRef: MatDialogRef<ColorPickerDialogComponent>, private sanitizer: DomSanitizer) {}


  
  color: Object;
  hexColor: String;
  rgbaColor: Object;
  @HostBinding('class') headerClass: SafeStyle;
  handleChange($event: ColorEvent) {
    this.color = $event.color;
    this.hexColor = $event.color.hex;
    this.rgbaColor = $event.color.rgb;
    this.headerClass = this.sanitizer.bypassSecurityTrustStyle('background-color:'+ this.hexColor +';');
    this.dialogRef.close(this.hexColor );
  }

  ngOnInit(): void {
  }

}

Thank you for the help and ideas. Much Appreciated.

@jeldev12
Copy link
Author

to your question on what I am referencing using: this.polygon = newPolygon;

is

The issue I am facing that time with the fill color getting darker each time getClickCoords is called is likely because I am adding the same polygon object (this.polygon) to the canvas each time, and then modifying its fill color. This means that each time I add the polygon, it retains its previous fill color, and the new fill color is layered on top of the old one.

To solve this issue, I created a new fabric.Polygon object each time getClickCoords is being called.

@jeldev12
Copy link
Author

let poly = this.canvas.getObjects()[0];

let poly = this.canvas.getActiveObject(); causes the following issue Invalid or undefined 'poly' object.

@Saqib92
Copy link
Contributor

Saqib92 commented Sep 20, 2023

Your stackblitz link is very messy. Please update it with minimal code i.e only polygon with an image.

@jeldev12
Copy link
Author

Hi Sir, I was able to fix the following issues. Thank you for the idea and help @Saqib92 . Very much appreciated.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants