Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Fabric JS - How can I move a path's points on the fly?

I have a path with 4 points. I'd like these points to follow objects that I drag around the screen.

I tried updating the path points during the canvas.on('object:moving') so that while an object is being dragged, the path property of my path is being updated. But as soon as I move the objects, the path disappears.

//call the function to update the path points string, then set the path property
 updateUpperArmPath();
    upperArmPath.set({
        path: upperArmPathPoints
    });

//update the upper arm path function
function updateUpperArmPath() {
    pointString = createPathString([
        {x: originCircle.left - originCircle.radius, y: originCircle.top},
        {x: originCircle.left + originCircle.radius, y: originCircle.top},
        {x: jointCircle.left + jointCircle.radius, y: jointCircle.top},
        {x: jointCircle.left - jointCircle.radius, y: jointCircle.top}
    ]);
    upperArmPathPoints = pointString;
}

//function to automatically create a path string from an array of points
 function createPathString(points) {
    var pathString = '';
  
    for (var i = 0; i < points.length; i++) {
      var point = points[i];
      var command = i === 0 ? 'M' : 'L';
      pathString += ' ' + command + ' ' + point.x + ' ' + point.y;
    }
  
    pathString += ' Z';
    return pathString;
  }
like image 446
Brendan Sadaka Avatar asked Dec 11 '25 11:12

Brendan Sadaka


1 Answers

The value passed to the path property must be in the following form:

[
  ["M",100,100],
  ["L",300,100],
  ["L",300,300],
  ["L",100,300],
  ["Z"]
]

Instead of a string: " M 100 100 L 300 100 L 300 300 L 100 300 Z"

Working demo (and updated code):

let canvas = new fabric.Canvas("canvas", {
  width: 500,
  height: 500,
  selection: false
});

var circle1;
var circle2;
var circle3;
var circle4;

var pathPoints = [];
var path;

canvas.on("object:moving", setPath);
canvas.on("object:modified", setPath);

circle1 = new fabric.Circle({
  radius: 20,
  fill: "#ff0000",
  left: 100,
  top: 100,
  originX: "center",
  originY: "center",
  hasControls: false
});

circle2 = new fabric.Circle({
  radius: 20,
  fill: "#00ff00",
  left: 300,
  top: 100,
  originX: "center",
  originY: "center",
  hasControls: false
});

circle3 = new fabric.Circle({
  radius: 20,
  fill: "#0000ff",
  left: 300,
  top: 300,
  originX: "center",
  originY: "center",
  hasControls: false
});

circle4 = new fabric.Circle({
  radius: 20,
  fill: "#880088",
  left: 100,
  top: 300,
  originX: "center",
  originY: "center",
  hasControls: false
});

updatePathPoints();
path = new fabric.Path(pathPoints, {
  fill: "#ffffff",
  selectable: false
});

canvas.add(circle1, circle2, circle3, circle4, path);
canvas.renderAll();

//create path string from array of points
function createPathArray(points) {
  var pathArray = [];
  for (var i = 0; i < points.length; i++) {
    var point = points[i];
    var command = i === 0 ? "M" : "L";
    pathArray.push([command, point.x, point.y])
  }
  pathArray.push(["Z"]);
  return pathArray;
 
}

const pathArray = [];
function updatePathPoints() {
  pathPoints = createPathArray([
    { x: circle1.left, y: circle1.top },
    { x: circle2.left, y: circle2.top },
    { x: circle3.left, y: circle3.top },
    { x: circle4.left, y: circle4.top }
  ]);
  circle1.setCoords();
  circle2.setCoords();
  circle3.setCoords();
  circle4.setCoords();
}

function setPath() {
  updatePathPoints();
  console.log(pathPoints);
  path.set({ path: pathPoints });
  canvas.renderAll();
}
body {
  font-family: system-ui;
  background: #f06d06;
  color: white;
  text-align: center;
}
<!DOCTYPE html>
<html>

<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/5.3.1/fabric.min.js"></script>
  <style>
    canvas {
      border: 1px solid black;
    }
  </style>
</head>

<body>
  <div style="text-align: center;">
    <canvas id="canvas"></canvas>
  </div>
</body>

</html>
like image 112
Kostas Minaidis Avatar answered Dec 13 '25 01:12

Kostas Minaidis