Подтвердить что ты не робот

Как я могу использовать Fabric.js с React?

У меня есть приложение с использованием тяжелого холста HTML5 через Fabric.js. Приложение написано поверх Angular 1.x, и я планирую перенести его на React. Мое приложение позволяет писать текстовые и рисовые линии, прямоугольники и эллипсы. Также возможно перемещать, увеличивать, сжимать, выбирать, вырезать, копировать и вставлять один или несколько таких объектов. Также можно масштабировать и панорамировать холст с помощью различных ярлыков. Короче говоря, мое приложение использует Fabric.js в полной мере.

Я не мог найти много информации о том, как использовать Fabric.js вместе с React, поэтому я обеспокоен тем, что 1. возможно без серьезных изменений и 2. имеет смысл, или я должен использовать некоторые другие обширные библиотека холста, которая лучше поддерживает React?

Единственный пример React + Fabric.js, который я мог найти, был react-komik, который, однако, намного проще, чем мое приложение. Моими основными проблемами являются обработка событий и манипулирование DOM с Fabric.js и их влияние на React.

Кажется, у React есть также холст-библиотека, называемая react-canvas, но, похоже, она не имеет большого количества возможностей по сравнению с Fabric.js.

Что я должен учитывать (в отношении манипуляций DOM, обработки событий и т.д.) при использовании Fabric.js в приложении React?

4b9b3361

Ответ 1

У нас была такая же проблема в нашем приложении, как использовать Fabric.js внутри реакции. Я рекомендую рассматривать ткань как неконтролируемый компонент. Имейте экземпляр .toObject() все ваше приложение, и звоните .toObject() а затем, когда что-то меняется, используйте .toObject() чтобы поместить все .toObject() в ваше хранилище Redux. Тогда ваше приложение React может читать состояние фабрики из вашего глобального состояния Redux, как если бы вы это делали в любом обычном приложении React.

Я не могу получить пример работы в редакторе кода StackOverflow, но вот пример JSFiddle, который реализует шаблон, который я рекомендую.

Ответ 2

Я использовал 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. Вы можете сделать с помощью refs то, что вы можете сделать с элементами DOM, используя DOM API: выбрать детей, найти родителя, назначить свойства стиля, рассчитать innerHeight и innerWidth. Последнее именно то, что вам нужно:

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

  // do some stuff with it
}

Не забудьте определить свойство refs this. Для этого вам понадобится конструктор. Все это будет выглядеть как

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

Просто замените рендеринг изображений кодом, который вам нужен, и это зависит от состояния нового компонента или реквизита. Не забудьте очистить холст, прежде чем на него будут наноситься новые объекты!

Ответ 3

Существует также react-fabricjs пакет, который позволяет использовать объекты ткани в качестве реагирующих компонентов. На самом деле, ответ Ришата включает этот пакет, но я не понимаю, как он должен работать, поскольку в "реакционной ткани" нет "тканевого" объекта (он, вероятно, имел в виду пакет "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;

Ответ 4

Я создал реагирующий на форму редактор для аналогичного случая использования, в котором у Fabric.js была вся необходимая мне функциональность, но было больно поддерживать синхронизацию с моим кодом React/Redux. Он имеет не так много функций, как Fabric, но может быть хорошей заменой для некоторых случаев использования.

Ответ 5

Упс!

Если вы пришли сюда в ожидании ответов о Microsoft Fabric, вы попали не туда. Вы должны искать .

(Нерелевантный и слегка смущающий оригинальный ответ удален.)