在vue3中使用fabricjs导致图形无法缩放的问题解决

9051次阅读 338人点赞 作者: WuBin 发布时间: 2024-04-08 10:16:48
扫码到手机查看

情况说明

首先是官网:http://fabricjs.com/

首先插件版本:使用的是fabric: 5.3.0 vue: 3.3.4

首先我是使用组合API,在外部文件中调用fabricjs。

先说明一下文件目录结构:

edit目录
   |- edit.vue         以下简称vue文件
     |-useFabric.js 以下简称js文件

0、在js文件onmounted中使用响应式变量

<canvas id="c0"></canvas>

import {fabric} from "fabric";
import { ref, onMounted } from 'vue';

const fabricCanvas = ref(null);
onMounted(() => {
     fabricCanvas.value = new fabric.Canvas('c0', {
            backgroundColor: 'purple',
            width: 600,
            height: 600
      });
      fabricCanvas.value.add(
        new fabric.Circle({ 
            radius: 30, 
            fill: '#f55', 
            top: 100, 
            left: 100 })
      );
      console.log('c0', fabricCanvas.value)
})

随后会发现在页面中,可以拖拽图形,但是无法对图形进行缩放、旋转等操作。

已知上面这种情况会不正常,随后我分别做了如下测试。

1、在js文件onmounted中使用普通变量

<canvas id="c1"></canvas>

onMounted(() => {
    let canvas = new fabric.Canvas('c1', {
        backgroundColor: 'black',
        width: 600,
        height: 100
    });
    canvas.add(new fabric.Circle({ radius: 30, fill: '#f55', top: 100, left: 100 }));
    console.log('c1', canvas)
});

结论:发现拖拽、缩放旋转各种功能正常。

2、在vue文件中初始化,并在mounted中使用

<canvas id="canvas-box"></canvas>
<canvas id="c2"></canvas>
<canvas id="c3"></canvas>

data() {
    return {
        c2: null
    }
  },
  mounted() {
      let canvasbox = new fabric.Canvas('canvas-box', {
          backgroundColor: 'yellow',
          width: 600,
          height: 100
      });
      canvasbox.add(new fabric.Circle({ radius: 30, fill: '#f55', top: 100, left: 100 }));
      console.log('canvasbox', canvasbox)

      this.c2 = new fabric.Canvas('c2', {
          backgroundColor: 'blue',
          width: 600,
          height: 100
      });
      this.c2.add(new fabric.Circle({ radius: 30, fill: '#f55', top: 100, left: 100 }));
      console.log('c2', this.c2)

      this.c3 = new fabric.Canvas('c3', {
          backgroundColor: 'pink',
          width: 600,
          height: 100
      });
      this.c3.add(new fabric.Circle({ radius: 30, fill: '#f55', top: 100, left: 100 }));
      console.log('c3', this.c3)
  },

结论:canvasbox、c3中可以正常缩放、旋转,c2则不行

问题解决

我们先来看一下打印出来的变量:

可以明显的看到,无法旋转的两种情况,c2和c0他们都是proxy类型!既是vue3的响应式数据,我随后百度了一下,发现我这个不是个例

使用的是 fabric: 5.3.0 vue: 3.3.4

问题:在项目中,我渲染的矩形和多边形导致无法缩放,只能移动;
新画的没问题,重新渲染就有问题;
【
将[new fabric.Canvas()]对象赋值给vue3reactive,
四周所有的拖拽点失效。
】

最后的解决办法就是:
Fabricjs 不喜欢将 Canvas 转换为代理。解决它的一种方法是使用全局变量而不是使用数据

解决:https://stackoverflow.com/questions/64328552/fabricjs-selection-handles-shown-but-not-clickable-before-selected-together-wit

解决方法就是:我们不要使用响应式数据存放fabricjs的实例化对象,要用普通的变量或者未在data()中注册的this.xx变量进行存放。

或者使用Markraw

import { markRaw } from 'vue';

...
this.canvas = markRaw(new fabric.Canvas(c, {
  width: c.clientWidth,
  height: c.clientHeight
}));
...
this.canvas.add(markRaw(new fabric.Rect({
  top: 20,
  left: 20,
  width: 40,
  height: 40,
  fill: color
})));

markRaw

作用:将一个对象标记为不可以被转化为代理对象。返回该对象本身。

应用场景:

1.有些值不应被设置成响应式时,例如复杂的第三方类库等 

2.当渲染具有不可变数据源的大列表时,跳过响应式转换可以提高性能 

3.在动态渲染组件的时候我们就可以使用 markRaw 包裹。

具体参考:https://www.cnblogs.com/IwishIcould/p/16257095.html

预防英文链接失效,现原帖保存一下

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.

Inthis 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?

回答:

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 removecanvasfrom thedata()declaration, which will make it still accessible throughout the template and code, but not make it reactive.

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>

回答

You can usetoRaw(). The function can change proxy object to common object.

add(color) {
  toRaw(this.canvas).add(new fabric.Rect({
    top: 20,
    left: 20,
    width: 40,
    height: 40,
    fill: color
  }))
}

回答

Alternatively, you can use Vue 3'smarkRaw.

import { markRaw } from 'vue';

...
this.canvas = markRaw(new fabric.Canvas(c, {
  width: c.clientWidth,
  height: c.clientHeight
}));
...
this.canvas.add(markRaw(new fabric.Rect({
  top: 20,
  left: 20,
  width: 40,
  height: 40,
  fill: color
})));

相关资料

点赞 支持一下 觉得不错?客官您就稍微鼓励一下吧!
关键词:fabric
推荐阅读
  • uniapp实现被浏览器唤起的功能

    当用户打开h5链接时候,点击打开app若用户在已经安装过app的情况下直接打开app,若未安装过跳到应用市场下载安装这个功能在实现上主要分为两种场景,从普通浏览器唤醒以及从微信唤醒。

    10049次阅读 659人点赞 发布时间: 2022-12-14 16:34:53 立即查看
  • Vue

    盘点Vue2和Vue3的10种组件通信方式

    Vue中组件通信方式有很多,其中Vue2和Vue3实现起来也会有很多差异;本文将通过选项式API组合式API以及setup三种不同实现方式全面介绍Vue2和Vue3的组件通信方式。

    4675次阅读 346人点赞 发布时间: 2022-08-19 09:40:16 立即查看
  • JS

    几个高级前端常用的API

    推荐4个前端开发中常用的高端API,分别是MutationObserver、IntersectionObserver、getComputedstyle、getBoundingClientRect、requ...

    14754次阅读 967人点赞 发布时间: 2021-11-11 09:39:54 立即查看
  • PHP

    【正则】一些常用的正则表达式总结

    在日常开发中,正则表达式是非常有用的,正则表达式在每个语言中都是可以使用的,他就跟JSON一样,是通用的。了解一些常用的正则表达式,能大大提高你的工作效率。

    13957次阅读 524人点赞 发布时间: 2021-10-09 15:58:58 立即查看
  • 【中文】免费可商用字体下载与考证

    65款免费、可商用、无任何限制中文字体打包下载,这些字体都是经过长期验证,经得住市场考验的,让您规避被无良厂商起诉的风险。

    12703次阅读 1023人点赞 发布时间: 2021-07-05 15:28:45 立即查看
  • Vue

    Vue3开发一个v-loading的自定义指令

    在vue3中实现一个自定义的指令,有助于我们简化开发,简化复用,通过一个指令的调用即可实现一些可高度复用的交互。

    16936次阅读 1356人点赞 发布时间: 2021-07-02 15:58:35 立即查看
  • JS

    关于手机上滚动穿透问题的解决

    当页面出现浮层的时候,滑动浮层的内容,正常情况下预期应该是浮层下边的内容不会滚动;然而事实并非如此。在PC上使用css即可解决,但是在手机端,情况就变的比较复杂,就需要禁止触摸事件才可以。

    15465次阅读 1257人点赞 发布时间: 2021-05-31 09:25:50 立即查看
  • Vue

    Vue+html2canvas截图空白的问题

    在使用vue做信网单页专题时,有海报生成的功能,这里推荐2个插件:一个是html2canvas,构造好DOM然后转canvas进行截图;另外使用vue-canvas-poster(这个截止到2021年3月...

    30556次阅读 2403人点赞 发布时间: 2021-03-02 09:04:51 立即查看
  • Vue

    vue-router4过度动画无效解决方案

    在初次使用vue3+vue-router4时候,先后遇到了过度动画transition进入和退出分别无效的情况,搜遍百度没没找到合适解决方法,包括vue-route4有一些API都进行了变化,以前的一些操...

    26526次阅读 2041人点赞 发布时间: 2021-02-23 13:37:20 立即查看
交流 收藏 目录