FabricJS Catch click on object inside group

后端 未结 7 696
感动是毒
感动是毒 2021-01-17 19:06

I have tried many thing like calculating location, handling with the event we do have in original fabricjs. Does any have done this before?

相关标签:
7条回答
  • 2021-01-17 19:21

    In FabricJS once the objects have been assembled into a group the Events are only happening there, even the selected events - so you cannot detect which of the items in the group are being selected. Inside the event handler

    var g = new fabric.Group([ rect, text ], {
    g.on('mousedown', function(e) {
        // Inspect, for a collection of the objects in this group
        this._objects
    });
    

    Even attaching event handlers to the objects before assembly into the group the handlers don't fire :(

    0 讨论(0)
  • 2021-01-17 19:28

    I do not have enough reputation to be able to comment on an existing answer so here goes. I am using v2.X of Fabric and all of the existing solutions do not work. Either console errors for methods that no longer exist or always false in case of containsPoint so I built my own.

    js
    const getSelectedObject = (target, e) => {
      const point = target.canvas.getPointer(e, false);
    
      const objects = findSubTargets(target, []);
    
      const objectIndex = objects
        .reduce((reduction, object, index) => {
          reduction.push(
            getBoundingPoints(
              object,
              index === 0 ? 0 : reduction[0].start.x,
              index === 0 ? 0 : reduction[0].start.y
            )
          );
    
          return reduction;
        }, [])
        .reverse()
        .findIndex((bounds) => pointIsInBounds(point, bounds));
    
      return objects.reverse()[objectIndex];
    };
    

    and the helper functions

    js
    const getBoundingPoints = (object, deltaX, deltaY) => {
      const coords = object.get("aCoords");
    
      const x1 = coords.tl.x + deltaX;
      const y1 = coords.tl.y + deltaY;
      const x2 = coords.br.x + deltaX;
      const y2 = coords.br.y + deltaY;
    
      return {
        start: { x: x1, y: y1 },
        finish: { x: x2, y: y2 }
      };
    };
    
    
    const pointIsInBounds = (point, bounds) => {
      const xIsInBounds = point.x >= bounds.start.x && point.x <= bounds.finish.x;
      const yIsInBounds = point.y >= bounds.start.y && point.y <= bounds.finish.y;
    
      return xIsInBounds && yIsInBounds;
    };
    
    
    const findSubTargets = (target, objects) => {
      if (target.isType("group")) {
        objects.push(target);
        target.forEachObject((object) => findSubTargets(object, objects));
      }
    
      return objects;
    };
    

    I've tested this with simple groups, nested groups and groups inside groups inside groups.

    0 讨论(0)
  • 2021-01-17 19:30

    May be this helps you http://jsfiddle.net/UKbaseduser/Kt9Mk/1/

    $("#1").click(function(){
      ZoomIn('tmp1');
    });
    $("#2").click(function(){
      ZoomOut('tmp1');
    });
    $("#3").click(function(){
      ZoomIn('tmp2');
    });
    $("#4").click(function(){
      ZoomOut('tmp2');
    });
    
    var canvas = new fabric.Canvas('c');
    
    var rect1 = new fabric.Rect({ left: 150, top: 150, width: 100, height: 100, fill: 'green'});
    var rect2 = new fabric.Rect({ left: 250, top: 250, width: 100, height: 100, fill: 'green'});
    rect1.grp='tmp1';
    rect2.grp='tmp1';
    var c = new fabric.Circle({
            left: 200,
            top: 200,
            radius: 50,
            fill: 'red',
            opacity:0.8
          });
    c.grp='tmp2';
    canvas.add(rect1);
    canvas.add(rect2);
    canvas.add(c);
    canvas.renderAll();
    
    function ZoomIn(inGrp){
        var SCALE_FACTOR = 1.2;
        var objects = canvas.getObjects();
        objects.forEach(function(obj){
            if (obj.grp==inGrp){     
                var scaleX = obj.scaleX;
                var scaleY = obj.scaleY;
                var left = obj.left;
                var top = obj.top;
    
                var tempScaleX = scaleX * SCALE_FACTOR;
                var tempScaleY = scaleY * SCALE_FACTOR;
                var tempLeft = left * SCALE_FACTOR;
                var tempTop = top * SCALE_FACTOR;
                obj.scaleX = tempScaleX;
                obj.scaleY = tempScaleY;
                obj.left = tempLeft;
                obj.top = tempTop;
                obj.setCoords();
                }
            });
        canvas.renderAll();
     }
    function ZoomOut(inGrp){
        var SCALE_FACTOR = 1.2;
        var objects = canvas.getObjects();
        objects.forEach(function(obj){
            if (obj.grp==inGrp){     
                var scaleX = obj.scaleX;
                var scaleY = obj.scaleY;
                var left = obj.left;
                var top = obj.top;
    
                var tempScaleX = scaleX * 1/SCALE_FACTOR;
                var tempScaleY = scaleY * 1/SCALE_FACTOR;
                var tempLeft = left * 1/SCALE_FACTOR;
                var tempTop = top * 1/SCALE_FACTOR;
                obj.scaleX = tempScaleX;
                obj.scaleY = tempScaleY;
                obj.left = tempLeft;
                obj.top = tempTop;
                obj.setCoords();
                }
            });
        canvas.renderAll();
     }
    

    Also there is similar discussion going on over here https://groups.google.com/forum/#!topic/fabricjs/hQwHxGfyx6w may be it throws you some pointers.

    0 讨论(0)
  • 2021-01-17 19:30

    This worked for me:

    // create a group
    let group = new fabric.Group([circle, rect], {
        subTargetCheck: true
    });
    
    canvas.on('mouse:down', function (e) {
    // clicked item will be
      console.log(e.subTargets[0])  
    });
    
    0 讨论(0)
  • 2021-01-17 19:34

    It is possible to listen for events on the inner object by adding the option: subTargetCheck: true to the fabric.Group object.

        // create a group
        let group = new fabric.Group([circle, rect], {
            subTargetCheck: true
        });
    
        circle.on('mousedown', function(e) { 
            // e.target should be the circle
            console.log(e.target);
        });
    
    0 讨论(0)
  • 2021-01-17 19:38

    I downloaded fabricjs from asturur repo. build fabric.js file

    node build.js modules=ALL exclude=json,gestures
    

    and it works!

    Then you can use events on objects in the groups.

    canvas._objects[0]._objects[0].on('mousedown', function(e){ this.stroke = 'black'});
    

    In my app i decided to search for events from mousedown callback

    group.on('mousedown', function(e){
        var innerTarget  = group._searchPossibleTargets(e.e);
        console.log(innerTarget);
    });
    
    group._searchPossibleTargets = function(e) {
        var pointer = this.canvas.getPointer(e, true);
        var i = objects.length,
            normalizedPointer = this.canvas._normalizePointer(this, pointer);
    
        while (i--) {
            if (this.canvas._checkTarget(normalizedPointer, this._objects[i])) {
                return this._objects[i];
            }
        }
        return null;
    }
    
    0 讨论(0)
提交回复
热议问题