Search code examples
javascripthtmlfabricjs

Resizing rectangle based on user input


I am trying to resize a rectangle based on the user input, but i get an error saying: Cannot read property 'addEventListener' of null. Do i need to change something in the HTML? I tried moving the script below the body but it didn't work. Seems like everything is alright but it doesn't work.

https://jsfiddle.net/sbLk9zvd/2/


var rect = new fabric.Rect({
  fill: "red",
  width: 300,
  height: 400,
  stroke: "gray",
  strokeWidth: 30,
  fill: "lightgray",
  centeredRotation: true,
  centeredScaling: true,
});

canvas.add(rect);


var Length = document.getElementById("Length");
var Width = document.getElementById("Width");

Length.addEventListener("input", Modify_Length);
Width.addEventListener("input", Modify_Width);

function Modify_Length() {
  var rect = new fabric.Rect({
    fill: "red",
    width: parseFloat(Width.value) || 300,
    height: 400 || parseFloat(Length.value),
    stroke: "gray",
    strokeWidth: 30,
    fill: "lightgray",
    centeredRotation: true,
    centeredScaling: true,
  });
}
function Modify_Width() {
  var rect = new fabric.Rect({
    fill: "red",
    width: parseFloat(Width.value) || 300,
    height: parseFloat(Length.value) || 400,
    stroke: "gray",
    strokeWidth: 30,
    fill: "lightgray",
    centeredRotation: true,
    centeredScaling: true,
  });
}
canvas.renderAll();

Solution

  • There is no need for a separate listener for each element. Just share a single callback function. Also, don't forget to rerender.

    const canvas = new fabric.Canvas("c");
    
    const rect = new fabric.Rect({
      fill: "red",
      width: 200,
      height: 80,
      stroke: "gray",
      strokeWidth: 1,
      fill: "lightgray",
      centeredRotation: true,
      centeredScaling: true,
    });
    
    canvas.on("object:scaling", function() {
      var obj = canvas.getActiveObject(),
        width = obj.width,
        height = obj.height,
        scaleX = obj.scaleX,
        scaleY = obj.scaleY;
    
      obj.set({
        width: width * scaleX,
        height: height * scaleY,
        scaleX: 1,
        scaleY: 1,
      });
    });
    
    rect.setControlsVisibility({
      mt: false,
      mb: false,
      ml: false,
      mr: false,
      bl: false,
      br: false,
      tl: false,
      tr: false,
      mtr: false,
    });
    
    canvas.add(rect);
    
    canvas.centerObject(rect);
    canvas.setActiveObject(rect);
    
    canvas.item(0).lockMovementX = true;
    canvas.item(0).lockMovementY = true;
    
    const width = document.getElementById('width');
    const height = document.getElementById('height');
    
    const adjust = (e) => {
      Object.assign(rect, {
        width: parseFloat(width.value) || 300,
        height: parseFloat(height.value) || 400,
      });
      canvas.renderAll();
    };
    
    width.addEventListener('input', adjust);
    height.addEventListener('input', adjust);
    
    canvas.renderAll();
    label, input {
      display: block;
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/451/fabric.min.js"></script>
    <canvas id="c" width="250" height="120"></canvas>
    <div id="user-input">
      <label for="width">Width:</label>
      <input type="number" id="width" name="width" value="200" />
      <label for="height">Height:</label>
      <input type="number" id="height" name="height" value="80" />
    </div>