Trying to add IText component to the canvas that will be editable, resizable, rotatable etc.
It can be moved after adding, but cant be interacted in other way no matter what i do
fabric version - 5.3.0
vue.js + TS + Vite
here is my useCanvas composable
import { fabric } from 'fabric'
import { ref, Ref } from 'vue'
import { useElementSize } from '@vueuse/core'
const MIN_CANVAS_HEIGHT = 500
export function useCanvas(
canvasRef: Ref<HTMLCanvasElement | null>,
canvasContainerRef: Ref<HTMLElement | null>,
minHeight = MIN_CANVAS_HEIGHT,
) {
const canvas = ref<fabric.Canvas | null>(null)
const { width: containerWidth, height: containerHeight } =
useElementSize(canvasContainerRef)
const init = () => {
canvas.value = new fabric.Canvas(canvasRef.value, {
width: containerWidth.value,
height: minHeight,
})
}
const addText = (value: string, isEditable = true) => {
if (!canvas.value) return
const text = new fabric.IText(value, {
left: 50,
top: 50,
fill: '#000000',
fontFamily: 'Arial',
fontSize: 24,
fontWeight: 'normal',
editable: isEditable,
centeredRotation: true,
padding: 10,
})
// removing ability to scale without maintaining aspect ratio
text.setControlsVisibility({
mt: false,
mb: false,
ml: false,
mr: false,
})
canvas.value.add(text)
}
}
return {
canvas,
init,
addText,
}
and here is vue component where it is being used
template
<template>
<div ref="editorContainerRef" class="image-editor">
<canvas ref="editorCanvasRef" class="image-editor__canvas" />
<button class="button" type="button" @click="handleTextAdd">
<span>{{ 'add text' }}</span>
</button>
</div>
</template>
script
<script setup lang="ts">
import { ref, onMounted } from 'vue'
import { useCanvas } from './composables'
const DEFAULT_TEXT = 'Your unique signature'
const editorContainerRef = ref<HTMLElement | null>(null)
const editorCanvasRef = ref<HTMLCanvasElement | null>(null)
const canvasInstance = useCanvas(editorCanvasRef, editorContainerRef)
const { init, addText } = canvasInstance
const handleTextAdd = () => {
addText(DEFAULT_TEXT)
}
onMounted(() => {
if (!editorCanvasRef.value) return
init()
})
</script>
As you can see i've already tried to set every property that could possibly affect scaling, rotating and editing ability but it doesn't work
But if i add more than one text to canvas and then select both, each of them begins to work as expected
So what i found is that text isn't interactable until you select it in group and i have no idea what causes that behavior
For those who will face same problem in the future:
The problems goes from Vue reactivity that uses a lot of proxy under the hood, that in that particular case have some conflicts with fabric.js library and causes unexpected behavior
So solution is: remove any reactivity from fabric.Canvas and any fabric.Object you are trying to interact with.
Many hours of research leads to this small change
doesn't work:
const canvas = ref<fabric.Canvas | null>(null)
canvas.value = new fabric.Canvas(canvasRef.value, {
width: containerWidth.value,
height: minHeight,
})
works as expected:
let canvas = null as fabric.Canvas | null
canvas = new fabric.Canvas(canvasRef.value, {
width: containerWidth.value,
height: minHeight,
})