Search code examples
javascripthtmlcanvasresizefabricjs

Resizing a canvas element via dragging the edges


I'm trying to make it so users of my site can resize their canvas by simply dragging the sides of it. I'm using Fabric.js which allows me to resize elements from within the canvas but I need to resize the actual canvas itself. I'm fine with using any new libraries you recommend.

This image should help you understand a bit more of what I want.

As a side note, the Fabric.js team have an interactive toolbox here for you to experiment if you need it.


Solution

    1. Put your fabric.js canvas in a wrapper div.
    2. Make the wrapper resizable. Here I'm using CSS resize. It only adds a bottom-left corner as a resize control but it's good enough for the sake of the demo. To have all the edges as controls you can try something like this.
    3. Detect the wrapper's size change. Ideally, you would use something like ResizeObserver. However, since browser support is still about 80% at the time of posting this, you might feel the need to use a polyfill or write something specific to your case. A simple setInterval with size check might prove to be sufficient.
    4. When the wrapper's size changes, set new fabric.js canvas dimensions via setWidth() and setHeight().

    const canvas = new fabric.Canvas('c')
    
    canvas.add(new fabric.Rect({
      width: 100,
      height: 100,
      fill: 'red',
      left: 100,
      top: 50,
    }))
    
    const canvasWrapper = document.getElementById('wrapper')
    // initial dimensions
    canvasWrapper.style.width = '300px'
    canvasWrapper.style.height = '150px'
    
    let width
    let height
    setInterval(() => {
      const newWidth = canvasWrapper.clientWidth
      const newHeight = canvasWrapper.clientHeight
      if (newWidth !== width || newHeight !== height) {
        width = newWidth
        height = newHeight
        canvas.setWidth(newWidth)
        canvas.setHeight(newHeight)
      }
    }, 100)
    #wrapper {
        border: solid 1px black;
        resize: both;
        overflow: hidden;
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/3.6.2/fabric.min.js"></script>
    <div id="wrapper">
      <canvas id="c"></canvas>
    </div>