首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何在React中使用Fabric.js?

如何在React中使用Fabric.js?
EN

Stack Overflow用户
提问于 2016-06-01 17:43:37
回答 6查看 30K关注 0票数 49

我有一个通过Fabric.js使用重度HTML5画布的应用程序。该应用程序是基于Angular 1.x编写的,我计划将其移植到React。我的应用程序允许编写文本和绘制线条、矩形和椭圆。还可以移动、放大、收缩、选择、剪切、复制和粘贴一个或多个这样的对象。还可以使用各种快捷键缩放和平移画布。简而言之,我的应用程序充分利用了Fabric.js。

我找不到太多关于如何将Fabric.js与React一起使用的信息,所以我担心的是: 1.是否可以不进行重大修改;2.它是否有意义,或者我是否应该使用其他对React有更好支持的扩展canvas库?

我能找到的唯一的React+Fabric.js例子是react-komik,但是它比我的应用程序简单得多。我主要关注的是Fabric.js的事件处理和DOM操作,以及它们对React的影响。

似乎还有一个用于React的画布库,称为react-canvas,但与Fabric.js相比,它似乎缺少很多功能。

我必须考虑什么(关于DOM操作、事件处理等)在React应用程序中使用Fabric.js时?

EN

回答 6

Stack Overflow用户

发布于 2016-08-26 01:32:54

我们在我们的应用程序中遇到了同样的问题,即如何在react中使用Fabric.js。我的建议是将fabric视为一个不受控制的组件。拥有fabric实例,你的整个应用程序都可以与之对话并进行fabric调用,然后当有任何变化时,使用.toObject() call将整个fabric状态放入您的Redux存储中。然后,您的React应用程序可以从全局Redux状态读取fabric状态,就像您在任何常规React应用程序中所做的那样。

我在StackOverflow代码编辑器中找不到可以工作的示例,但是here is a JSFiddle example实现了我推荐的模式。

票数 50
EN

Stack Overflow用户

发布于 2016-08-28 06:55:50

我在一个概念验证项目中使用了Fabric,其总体思路与D3相同。请记住,Fabric在DOM元素上操作,而React将数据呈现到DOM中,而后者通常是延迟的。有两件事可以帮助你确保你的代码正常工作:

等待组件挂载完成

为此,请将结构实例化放入componentDidMount

代码语言:javascript
复制
import React, { Component } from 'react';
import { fabric } from 'react-fabricjs';
import styles from './MyComponent.css';

class MyComponent extends Component {
  componentWillMount() {
    // dispatch some actions if you use Redux
  }

  componentDidMount() {
    const canvas = new fabric.Canvas('c');

    // do some stuff with it
  }

  render() {
    return (
      <div className={styles.myComponent}>
        <canvas id="c" />
      </div>
    )
  }
}

将Fabric构造函数放到componentDidMount中可以确保它不会失败,因为在执行此方法时,DOM已经准备好了。(但道具有时不是,如果你使用Redux,只是以防万一)

使用refs计算实际的宽度和高度

Refs是对实际DOM元素的引用。通过使用DOM,您可以对refs执行与DOM元素相同的操作:选择子元素、查找父元素、分配样式属性、计算innerHeightinnerWidth。后者正是您所需要的:

代码语言:javascript
复制
componentDidMount() {
  const canvas = new fabric.Canvas('c', {
    width: this.refs.canvas.clientWidth,
    height: this.refs.canvas.clientHeight
  });

  // do some stuff with it
}

别忘了定义thisrefs属性。为此,您需要一个构造函数。整件事看起来就像

代码语言:javascript
复制
import React, { Component } from 'react';
import { fabric } from 'react-fabricjs';
import styles from './MyComponent.css';

class MyComponent extends Component {
  constructor() {
    super()
    this.refs = {
      canvas: {}
    };
  }

  componentWillMount() {
    // dispatch some actions if you use Redux
  }

  componentDidMount() {
    const canvas = new fabric.Canvas('c', {
      width: this.refs.canvas.clientWidth,
      height: this.refs.canvas.clientHeight
    });

    // do some stuff with it
  }

  render() {
    return (
      <div className={styles.myComponent}>
        <canvas
          id="c"
          ref={node => {
            this.refs.canvas = node;
          } />
      </div>
    )
  }
}

将Fabric与组件状态或属性混合

您可以让Fabric实例对任何组件属性或状态更新做出反应。要使其正常工作,只需在componentDidUpdate上更新Fabric实例(如您所见,您可以将其存储为组件自身属性的一部分)。简单地依赖render函数调用不会有什么真正的帮助,因为呈现的元素都不会在新的属性或新的状态中发生变化。如下所示:

代码语言:javascript
复制
import React, { Component } from 'react';
import { fabric } from 'react-fabricjs';
import styles from './MyComponent.css';

class MyComponent extends Component {
  constructor() {
    this.refs = {
      canvas: {}
    };
  }

  componentWillMount() {
    // dispatch some actions if you use Redux
  }

  componentDidMount() {
    const canvas = new fabric.Canvas('c', {
      width: this.refs.canvas.clientWidth,
      height: this.refs.canvas.clientHeight
    });

    this.fabric = canvas;

    // do some initial stuff with it
  }

  componentDidUpdate() {
    const {
      images = []
    } = this.props;
    const {
      fabric
    } = this;

    // do some stuff as new props or state have been received aka component did update
    images.map((image, index) => {
      fabric.Image.fromURL(image.url, {
        top: 0,
        left: index * 100 // place a new image left to right, every 100px
      });
    });
  }

  render() {
    return (
      <div className={styles.myComponent}>
        <canvas
          id="c"
          ref={node => {
            this.refs.canvas = node;
          } />
      </div>
    )
  }
}

只需将图像渲染替换为所需的代码,这取决于新的组件状态或属性。在渲染新对象之前,也不要忘记清理画布!

票数 21
EN

Stack Overflow用户

发布于 2019-11-17 02:48:18

使用react 16.8或更新版本,您还可以创建自定义钩子:

代码语言:javascript
复制
import React, { useRef, useCallback } from 'react';
const useFabric = (onChange) => {
    const fabricRef = useRef();
    const disposeRef = useRef();
    return useCallback((node) => {
        if (node) {
            fabricRef.current = new fabric.Canvas(node);
            if (onChange) {
                disposeRef.current = onChange(fabricRef.current);
            }
        }
        else if (fabricRef.current) {
            fabricRef.current.dispose();
            if (disposeRef.current) {
                disposeRef.current();
                disposeRef.current = undefined;
            }
        }
    }, []);
};

用法

代码语言:javascript
复制
const FabricDemo = () => {
  const ref = useFabric((fabricCanvas) => {
    console.log(fabricCanvas)
  });
  return <div style={{border: '1px solid red'}}>
    <canvas ref={ref} width={300} height={200} />
  </div>
}
票数 8
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/37565041

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档