Изучение того, может ли вам выгодно использовать библиотеку D3.js с проектом React.
Когда меня спросили о том, как создать пользовательскую графику в виде диаграммы в приложении React, моей первой реакцией было предложить библиотеку D3.js. Позже, однако, я задался вопросом, что предоставляет D3.js, а React - нет.
Предварительные требования
Во-первых, вам необходимо базовое понимание D3.js. Я собирался написать руководство по D3.js и вместо этого нашел отличный ресурс.
Во-вторых, вам необходимо базовое понимание React. Я написал руководство по React.
Повторное внедрение примера Enter, Update, Exit
В статье Enter, Update, Exit представлен простой D3.js пример, иллюстрирующий основные функции D3.js. Нажатие кнопки Добавить элемент создает полосы, а нажатие на полосы удаляет их.
Мы можем легко повторно реализовать это приложение с помощью React.
Давайте сравним решения D3.js и React. Оба решения предоставляют механизм для динамического построения шаблона элементов DOM; шаблон.
D3.js: ./js/main.js
... selection.enter() .append("div").attr("class", "bar") .style("height", function(d){ return d; }) .style("margin-top", function(d){ return maxHeight - d; }) .on("click", function(e, i){ dataset.splice(i, 1); update(); }); ...
React: ./react-introduction/src/Bar.js
... const Bar = ({ height, onClick, position }) => ( <div className="bar" style={{ height, marginTop: MAX_HEIGHT - height }} onClick={() => onClick(position)} /> ); ...
Оба обеспечивают управление слушателем. При взаимодействии с веб-приложением и удалении элементов DOM необходимо также удалить все прикрепленные прослушиватели событий. В противном случае у вас будет утечка памяти.
В итоге основные функции D3.js доступны в React.
Реализация трех маленьких кругов
Предыдущий пример не был очень графическим; Итак, давайте рассмотрим повторную реализацию еще одного примера с использованием элементов масштабируемой векторной графики (SVG).
Основные функции приложения React следующие:
React: ./react-three-little-circles/src/App.js
... const App = () => ( <svg width="720" height="120"> { DATA.map((o, i) => ( <circle key={i} cx={(i * 100) + 30} cy="60" r={Math.sqrt(o)} style={{ fill: 'steelblue' }} /> ))} </svg> ); ...
Поскольку элементы SVG - это просто элементы DOM, с ними легко реализовать решение React.
Переходы
Возможно, мы обнаружим, что переходы D3.js трудно повторно реализовать в React.
примечание. Если вы не знакомы с переходами D3.js, ознакомьтесь со статьей Работа с переходами.
Сначала мы добавляем следующие строки в пример Enter, Exit, Update, чтобы реализовать базовый цветовой переход.
D3.js: ./d3-introduction-transitions/js/main.js
... .transition() .style('background-color', 'red') .duration(2000); ...
Одно интересное наблюдение заключается в том, что переход реализован в JavaScript, то есть без использования переходов или анимации CSS. Вы можете убедиться в этом, изучив элемент в Инструментах разработчика Chrome; наблюдая за изменением цвета фона.
Поскольку цветовые переходы легко реализовать в CSS, это довольно просто реализовать в React. Решение состоит в том, чтобы переключить класс, который запускает переход CSS после монтирования компонента Bar.
React: ./react-introduction-transitions/src/Bar.js
... class Bar extends Component { constructor(props) { super(props); this.state = { active: false, }; } componentDidMount() { window.setTimeout(() => { this.setState({ active: true, }); }, 0); } render() { const { height, onClick, position } = this.props; const { active } = this.state; return ( <div className={`bar${active ? ' bar--active' : ''}`} style={{ height, marginTop: MAX_HEIGHT - height}} onClick={() => onClick(position)} /> ); } } ...
Анимация SVG
Один из ключей к поиску примера, в котором мы могли бы использовать D3.js в нашем проекте React, можно найти в Руководстве по SVG-анимации (SMIL) .
SVG можно стилизовать и анимировать с помощью CSS (слайды). По сути, любое преобразование или анимация перехода, которая может быть применена к элементу HTML, также может быть применена к элементу SVG. Но есть некоторые свойства SVG, которые нельзя анимировать с помощью CSS, но которые можно анимировать с помощью SVG.
Сара Суэйдан - Уловки CSS
Между прочим, в статье также указывается, что стандарт SMIL умирает и что ответ - JavaScript.
Радиус SVG круга определяется атрибутом r; не CSS. Таким образом, это пример, когда использование CSS для перехода / анимации не будет работать для анимации радиуса круга SVG.
примечание: я не мог придумать другого простого способа CSS для имитации анимации радиуса круга SVG; играл с различными преобразованиями CSS.
Давайте посмотрим, как мы сделаем это в D3.js, анимировав наш пример Три маленьких кружочка.
Ключевой код добавлял следующее:
D3.js: d3-three-little-circle-transitions / js / main.js
... .transition() .attr('r', function(d) { return (2 * Math.sqrt(d)); }) .duration(2000); ...
Здесь у нас есть пример, в котором нам может потребоваться использовать D3.js в нашем проекте React.
React + D3.js
Чтобы проиллюстрировать совместное использование React и D3.js, мы реорганизуем нашу повторную реализацию React Enter, Update, Exit Example путем включения D3.js.
Сначала мы устанавливаем D3.js в наш проект React; выполнение следующего из корня приложения.
yarn add d3
Ключ состоит в том, чтобы обернуть код D3.js в компонент React и использовать жизненный цикл компонента React для запуска D3.js рендеринг.
React: ./react-d3-introduction/src/Chart.js
import React, { Component } from 'react'; import { PropTypes } from 'prop-types'; import { select } from "d3-selection"; import 'd3-transition'; import { MAX_HEIGHT } from './strings'; class Chart extends Component { constructor(props) { super(props); this.update = this.update.bind(this); } componentDidMount() { const { dataset } = this.props; this.update(dataset); } componentWillReceiveProps({ dataset }) { this.update(dataset); } shouldComponentUpdate() { return false; } update(dataset) { const { onClick } = this.props; const selection = select("#chart") .selectAll(".bar").data(dataset) .style("height", function(d){ // HAvE TO USE PX WITH NPM VERSION return `${d.toString()}px`; }) .style("margin-top", function(d){ return `${(MAX_HEIGHT - d).toString()}px`; }); selection.enter() .append("div").attr("class", "bar") .style("height", function(d){ return `${d.toString()}px`; }) .style("margin-top", function(d){ return `${(MAX_HEIGHT - d).toString()}px`; }) .on("click", function(_, i) { onClick(i); }) .transition() .style('background-color', 'red') .duration(2000); selection.exit().remove(); } render() { return ( <div id="chart" /> ); } } Chart.propTypes = { dataset: PropTypes.array.isRequired, onClick: PropTypes.func.isRequired, } export default Chart;
примечание: хотя полная библиотека D3.js довольно велика, мы добавили только те функции, которые мы используем. В результате мы увеличили размер развернутого кода JavaScript с 158 КБ до 207 КБ (примерно 50 КБ).
Подведение итогов
Мы изучили примеры, в которых можно было бы использовать React для решения проблем, для решения которых мы могли обратиться к D3.js. Мы нашли образец примеров анимации атрибутов SVG, где D3.js имеет мощные функции, которые нелегко воспроизвести с помощью React. И, наконец, мы создали приложение React, которое включает D3.js для выполнения специального рендеринга.