如何将Fabric.js与React一起使用?

问题描述 投票:39回答:5

我有一个通过Fabric.js使用大量HTML5画布的应用程序。该应用程序是在Angular 1.x之上编写的,我打算将其迁移到React。我的应用程序允许编写文本和绘制线条,矩形和椭圆。还可以移动,放大,缩小,选择,剪切,复制和粘贴一个或多个这样的对象。也可以使用各种快捷方式缩放和平移画布。简而言之,我的应用程序充分利用了Fabric.js。

我找不到很多关于如何将Fabric.js与React一起使用的信息,所以我关心的是1.它是否可能没有重大修改,2。它是否有意义,或者我应该使用其他广泛的画布库对React有更好的支持?

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

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

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

reactjs fabricjs react-canvas
5个回答
38
投票

我们的应用程序中有关于如何在react内部使用Fabric.js的问题。我的建议是将面料作为一种不受控制的成分。拥有整个应用程序可以与之通信的结构实例并进行结构调用,然后当任何更改时使用.toObject()调用将整个结构状态放入Redux存储中。然后您的React应用程序可以像在任何正常的React应用程序中那样从您的全局Redux状态读取结构状态。

我无法得到一个在StackOverflow代码编辑器中工作的示例,但here is a JSFiddle example实现了我推荐的模式。


17
投票

我已经将Fabric用于概念验证项目,其总体思路与D3相同。请记住,Fabric对DOM元素进行操作,而React将数据呈现为DOM,通常后者是延迟的。有两件事可以帮助您确保代码正常工作:

等到组件安装完毕

为此,将Fabric实例化放入componentDidMount

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 API对使用DOM元素执行的操作进行操作:选择子项,查找父项,指定样式属性,计算innerHeightinnerWidth。后者正是您所需要的:

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

  // do some stuff with it
}

别忘了定义refsthis属性。要做到这一点,你需要一个构造函数。整个事情看起来像

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上。简单地依靠render函数调用将不会真正有用,因为渲染的元素都不会在新的道具或新状态上发生变化。像这样的东西:

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>
    )
  }
}

只需用您需要的代码替换图像渲染,这取决于新的组件状态或道具。在渲染新对象之前,不要忘记清理画布!


2
投票

还有react-fabricjs包,允许您使用织物对象作为反应组件。实际上,Rishat的答案包括这个包,但我不明白它应该如何工作,因为react-fabricjs中没有'fabric'对象(他可能意味着'fabric-webpack'包)。简单的“Hello world”组件的示例:

import React from 'react';
import {Canvas, Text} from 'react-fabricjs';

const HelloFabric = React.createClass({
  render: function() {
    return (
      <Canvas
        width="900"
        height="900">
          <Text
            text="Hello World!"
            left={300}
            top={300}
            fill="#000000"
            fontFamily="Arial"
          />
      </Canvas>
    );
  }
});

export default HelloFabric;

即使您不想使用此包,探索它的代码也可以帮助您了解如何在React中实现Fabric.js。


0
投票

我为类似的用例创建了react-shape-editor,其中Fabric.js具有我需要的所有功能,但与我的React / Redux代码保持同步很痛苦。它没有Fabric那么多的功能,但它可能是一些用例的良好替代品。


-1
投票

Whoops!

如果你来这里期待有关Microsoft Fabric的答案,那你就错了。你应该寻找

(删除了不相关且略显尴尬的原始答案。)

© www.soinside.com 2019 - 2024. All rights reserved.