fabricjs / fabric.js

Javascript Canvas Library, SVG-to-Canvas (& canvas-to-SVG) Parser
http://fabricjs.com
Other
28.93k stars 3.51k forks source link

[Bug]: When I have a custom attribute with "type" in it, I get an error `Error: fabric: No class registered for any` #10001

Closed hqw567 closed 2 months ago

hqw567 commented 3 months ago

CheckList

Version

6.0.2

In What environments are you experiencing the problem?

Chrome

Node Version (if applicable)

None

Link To Reproduction

https://github.com/hqw567/fabric-issues-react

Steps To Reproduce

  1. Custom attributes contain "type"

Expected Behavior

Custom attributes contain any attributes without error

Actual Behavior

When I have a custom attribute with "type" in it, I get an error Error: fabric: No class registered for any

Error Message & Stack Trace

No response

hqw567 commented 3 months ago
import * as fabric from 'fabric'
import { useEffect, useRef } from 'react'
import dataJson from './data.json'
const App = () => {
  const canvasRef = useRef()

  useEffect(() => {
    if (!canvasRef.current) return
    const canvas = new fabric.Canvas(canvasRef.current)

    dataJson.objects.forEach((item) => {
      // issues 1: When I have a custom attribute with "type" in it, I get an error `Error: fabric: No class registered for any`
      //
      // Comment the following code to see the error
      delete item.myData.type
    })

    // issues 2: When using it in react, there will still be an error message `TypeError: Cannot read properties of undefined (reading 'clearRect')`
    canvas.loadFromJSON(dataJson).then(() => {
      canvas.requestRenderAll()
    })
    return () => {
      canvas.dispose()
    }
  }, [])

  return (
    <canvas
      width={document.body.clientWidth}
      height={document.body.clientHeight}
      ref={canvasRef}
    />
  )
}

export default App
zhe-he commented 3 months ago

https://github.com/fabricjs/fabric.js/blob/8219e923770a3105eddb3c96dd945368582d07a1/src/util/misc/objectEnlive.ts#L158-L166 bug1: The issue here is that during import, it loops through each property and checks if it is an object. If it is, it then checks for a type. Hmm... I think the source code should add an error check.

bug2: The issue is with asynchronous operations. You can solve it by making the following modifications.

const controller = new AbortController(); 
canvas.loadFromJSON(dataJson, undefined, { signal: controller.signal }).then(() => {
      canvas.requestRenderAll()
}).catch(e => {
      console.error(e.message ?? "aborted");
});
return () => {
      controller.abort();
      canvas.dispose()
}
// let flag = false;
// canvas.loadFromJSON(dataJson).then(() => {
      // if (flag) return false;
      // canvas.requestRenderAll();
// })
// return () => {
//      flag = true;
//      canvas.dispose()
// }
hqw567 commented 2 months ago

@zhe-he Thanks for the reply, but issues 1 is still not solved in the latest version. myData.type When I have a custom attribute with "type" in it, I get an error Error: fabric: No class registered for any

hqw567 commented 2 months ago

@zhe-he View online

zhe-he commented 2 months ago

@hqw567 The second-to-last commit's code is good, but the last commit's code was reverted, and the main branch merged the reverted code. So I am also quite confused.

asturur commented 2 months ago

let me see maybe i misunderstood how i used the class registry

asturur commented 2 months ago

Yes sorry i should have added 'hasClass' rather than getClass. I ll fix it quickly

asturur commented 2 months ago

https://github.com/fabricjs/fabric.js/pull/10039

hqw567 commented 2 months ago

@asturur I have upgraded to v6.2.0, The problem is still not solved. There is a new error reported when my custom attribute "myData": { "type": "text" }

   Uncaught TypeError: Cannot read properties of undefined (reading 'split')
    at _Io._splitTextIntoLines (fabric.js?v=32e06e8c:5297:19)
    at _Io._splitText (fabric.js?v=32e06e8c:5007:21)
    at _Io.initDimensions (fabric.js?v=32e06e8c:5011:10)
    at new _Io (fabric.js?v=32e06e8c:5000:216)
    at fabric.js?v=32e06e8c:2155:16
    at async Promise.all (/index 0)
    at async Promise.all (/index 49)
    at async Promise.all (/index 0)
    at async Promise.all (/index 0)
hqw567 commented 2 months ago
{
  "version": "6.0.2",
  "objects": [
    {
      "fontSize": 50,
      "fontWeight": "normal",
      "fontFamily": "Times New Roman",
      "fontStyle": "normal",
      "lineHeight": 1.16,
      "text": "fabric issues",
      "charSpacing": 0,
      "textAlign": "left",
      "styles": [],
      "pathStartOffset": 0,
      "pathSide": "left",
      "pathAlign": "baseline",
      "underline": false,
      "overline": false,
      "linethrough": false,
      "textBackgroundColor": "",
      "direction": "ltr",
      "minWidth": 20,
      "splitByGrapheme": false,
      "type": "Textbox",
      "version": "6.0.2",
      "originX": "left",
      "originY": "top",
      "left": 50,
      "top": 50,
      "width": 119.458,
      "height": 122.04,
      "fill": "black",
      "stroke": null,
      "strokeWidth": 1,
      "strokeDashArray": null,
      "strokeLineCap": "butt",
      "strokeDashOffset": 0,
      "strokeLineJoin": "miter",
      "strokeUniform": false,
      "strokeMiterLimit": 4,
      "scaleX": 1,
      "scaleY": 1,
      "angle": 0,
      "flipX": false,
      "flipY": false,
      "opacity": 1,
      "shadow": null,
      "visible": true,
      "backgroundColor": "lightgrey",
      "fillRule": "nonzero",
      "paintFirst": "fill",
      "globalCompositeOperation": "source-over",
      "skewX": 0,
      "skewY": 0,
      "myData": {
        "type": "text"
      }
    }
  ]
}
zhe-he commented 2 months ago

Well... the new logic now allows custom types to build internal objects. If your type value is 'rect' or 'text', it will be parsed as 'Rect' and 'Text'. So your type values should avoid these.

asturur commented 2 months ago

Or at least they have to serialize differently. I m not sure how you handle unwanted mutations when you restore properties that are custom objects.

hqw567 commented 2 months ago

Can this problem be solved once and for all? @asturur

asturur commented 2 months ago

The current version supports it. Just don't use 'type' with values that are already used by fabricJS classes ( 'rect', 'text', 'image' and so on ). Or if you really have to do that change the type in the normal fabricJS classes and register them with a different name.