fabric.js reset polygon bounding box after a point is moved

34 Views Asked by At

When I move a polyon's point (node) with the mouse, the bounding box does not update to enclose all new points. I've tries every matrix, setCoords(), etc. on this site for days. Fabric's own demo is useless, due to it fails when the polygon is flipped (3+ years and no fix). I just want to edit a polygon by moving it's nodes (points) and/or moving the polygon position without a thousand lines of code. Rotation and resizing is not implemented (no idea how) on the example.

<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head>
<script type="text/javascript" src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
<script type="text/javascript" src="https://unpkg.com/fabric@latest/dist/fabric.js"></script>
<script>
$(document).ready(function() {
  var canvas,points,shape,matrix,nodeNum=0,mouse,orgLeft=0,orgTop=0,nodeX,nodeY,nodes;
  canvas = new fabric.Canvas($('canvas')[0],{ objectCaching:false,preserveObjectStacking:true,perPixelTargetFind:true });

canvas.on('mouse:move', function(e){
  mouse = canvas.getPointer(e);
  $('#debug').text('x:'+parseInt(mouse.x)+' y:'+parseInt(mouse.y));
});

canvas.on('object:moving', function (e) {
  if (e.target && e.target.get('type')=='circle') {
    var node = e.target;
    nodeX = node.getCenterPoint().x; nodeY = node.getCenterPoint().y;
    shape.points[node.nodeNum] = {x:nodeX-(shape.left-orgLeft), y:nodeY-(shape.top-orgTop)};
  }
});

canvas.on('mouse:up', function(e) {
  if (e.target && e.target.get('type')=='circle') { resetPoints(); }
});

points = [{"x":60,"y":40},{"x":100,"y":60},{"x":100,"y":100},{"x":60,"y":120},{"x":20,"y":100},{"x":20,"y":60}];
makePolygon();

function resetPoints() {
  points.forEach((point, i) => { points[i]={x:nodes[i].left,y:nodes[i].top}; });
  makePolygon(); 
}

function makePolygon(e) {
  shape = new fabric.Polygon(points,{selectable:true,objectCaching:false});
  canvas.add(shape); 
  orgLeft = shape.left; orgTop = shape.top;
  addNodes(shape);
  
  nodes.forEach((node, i) => {
    node.on('mouseover', function(e) { node.selectable = true; node.set('fill','green'); canvas.renderAll(); });
    node.on('mouseout', function(e) { node.selectable = false; node.set('fill','red'); canvas.renderAll(); });
  });
  
  shape.on('mousedown', function(e) {nodes.forEach((node, i) => { canvas.remove(node); })});
  shape.on('modified', function() { addNodes(this); resetPoints() });
}

function addNodes(shape) {
  matrix = shape.calcTransformMatrix(); nodeNum=0;
  var transformedPoints = shape.get("points").map(function(p){
    return new fabric.Point( p.x - shape.pathOffset.x, p.y - shape.pathOffset.y);
    }).map(function(p){ return fabric.util.transformPoint(p, matrix); });
  
  nodes = transformedPoints.map(function(p){
    return new fabric.Circle({nodeNum:nodeNum++,shape:'node',left:p.x,top:p.y,radius:9,fill:"red",originX:"center",originY:"center",
    hoverCursor:'pointer',objectCaching:false,hasControls:false,hasBorders:false,selectable:false,opacity:.5});
  });
  canvas.clear().add(shape).add.apply(canvas,nodes).renderAll();
};

}); //end ready
</script>
</head>

<body>
  <canvas id="canvas" class="" width="640" height="512" style="border:1px solid black"></canvas>
  <div id="debug" style="width: 640px; padding: 5px 0 0 5px;">debug:</div>
</body>
</html>

example: example here

0

There are 0 best solutions below