Search code examples
fabricjsvuejs3

Fabricjs, selection handles shown but not clickable before selected together with other shapes


I'm trying to develop a vue.js component to draw shapes with fabricjs. After a rectangle been drawn, it is selectable, but can't be resized or rotated with the selection handle, which is not what I was expecting. I think it has something to do with vue.js 3, because everything works with vue.js 2.

In this demo at JSFiddle, corner handles won't work on rectangles, untill after you have selected the rectangle together with other shapes.


<div id="app">
<canvas ref="c"></canvas>
<div>
<button type="button" @click="add('red')">
Add
</button>
Select the blue rectangle. The corner handles are visible but not working.
Now, click "add“, then select both rectangles. Then just select any single item, now the corner handles are working.
</div>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/4.2.0/fabric.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/3.0.0/vue.global.js"></script>


var vm = Vue.createApp({
  data: () => ({
    canvas: null
  }),
  mounted: function() {
    var c = this.$refs.c
    this.canvas = new fabric.Canvas(c, {
      width: c.clientWidth,
      height: c.clientHeight
    });
    this.add('blue')
  },
  methods: {
    add(color) {
      this.canvas.add(new fabric.Rect({
        top: 20,
        left: 20,
        width: 40,
        height: 40,
        fill: color
      }))
    }
  }
}).mount('#app');

// Select the blue rectangle. The corner handles are visible but not working.
// Now, click "add", then select both rectangles. 
// Then just select any single item, now the corner handles are working. 

How do I work around this while sticking to vue.js 3?


Solution

  • Fabricjs does not like having the canvas converted to a proxy. One way to get around it is to use a global variable instead of using the data. You can also just remove canvas from the data() declaration, which will make it still accessible throughout the template and code, but not make it reactive.

    Example:

    var vm = Vue.createApp({
      mounted: function() {
        var c = this.$refs.c
        this.canvas = new fabric.Canvas(c, {
          width: c.clientWidth,
          height: c.clientHeight
        });
        this.add('blue')
      },
      methods: {
        add(color) {
          this.canvas.add(new fabric.Rect({
            top: 20,
            left: 20,
            width: 40,
            height: 40,
            fill: color
          }))
        }
      }
    }).mount('#app');
    <div id="app">
      <canvas ref="c"></canvas>
      <div>
        <button type="button" @click="add('red')">
          Add
        </button>
        Select the blue rectangle. The corner handles are visible but not working.
        Now, click "add“, then select both rectangles. Then just select any single item, now the corner handles are working.
      </div>
    </div>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/4.1.0/fabric.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/3.0.0/vue.global.prod.js"></script>