Рендеринг/возврат холста HTML5 в ReactJS
Я пытаюсь сделать холст с помощью React. Графика внутри холста также будет обрабатываться с помощью метода Reacts render
.
В текущем коде выполняется визуализация холста с графикой, которую я хочу. Но я ищу способ вернуть холст с моей графикой из метода render
. Причина, по которой я хочу это, - это то, что я хочу, чтобы это работало в "Реагировать".
В идеале я бы хотел, чтобы мой код был примерно таким:
return(
<div>
<canvas id='my_canvas_with_graphics_rendered_in_react'></canvas>
</div>
);
Во-первых, я хочу знать, возможно ли это. Или я должен искать альтернативу.
Возможно, я пропустил пункт "Реакт", если это так, пожалуйста, дайте мне знать. Надеюсь, что есть решение, потому что из того, что я прочитал, React рекламирует себя как V
в MVC
. Вот почему, если это возможно, это было бы идеальным решением для того, что я пытаюсь сделать. Мне не пришлось бы беспокоиться об рендеринге внутри моего холста. Я просто предоставил данные компоненту, и React повторно изменил бы эти изменения.
Я отмечен в инструкции return
, где я считаю, что правильный код должен идти.
Код HTML
:
<div id='wrapper'>
<canvas id='canvas'></canvas>
</div>
Код jsx
:
var MyCanvas = React.createClass({
render:function(){
var line = this.props.lines;
var ctx = this.props.canvas.getContext("2d");
ctx.strokeStyle = 'rgba(0,0,0,0.5)';
ctx.beginPath();
ctx.moveTo(line[0].x0, line[0].y0);
// .... more code .....
ctx.stroke();
return(
<div>
/* *********************************
??? RETURN MY RENDERED CANVAS
WITH GRAPHIC LINES. ????
This is where I want to return the canvas
********************************* */
</div>
);
}
});
var wrapper = document.getElementById('wrapper');
var canvas = document.getElementById('canvas');
var line1 = { x0: 0, y0: 10, x1: 20, y1: 30 };
var line2 = { x0: 40, y0: 50, x1: 60, y1: 70 };
var myCanvas = <MyCanvas canvas={ canvas } lines={ [line1, line2] } />;
React.render(myCanvas, wrapper);
Надеюсь, я поняла.
Ответы
Ответ 1
Ваша единственная ошибка в том, что вы не знакомы с реакциями ref.
попробуйте следующее:
class ConnectionChart extends React.Component {
componentDidMount() {
let canvas = ReactDOM.findDOMNode(this.refs.myCanvas);
let ctx = canvas.getContext('2d');
ctx.fillStyle = 'rgb(200,0,0)';
ctx.fillRect(10, 10, 55, 50);
}
render() {
return (
<div>
<canvas ref="myCanvas" />
</div>
);
}
}
Возможно, вы избавились от стиля ES6, но вы поняли эту идею.
Из-за того, что u может рисовать и другими методами ^ ^
Ответ 2
Вместо использования canvas
в вашем методе render
вы сделаете что-то вроде этого:
var MyCanvas = React.createClass({
componentDidMount: function () {
React.getDOMNode(this).appendChild(this.props.canvas);
},
render: function() {
return <div />;
}
});
Вы просто визуализируете пустой div
и ждете, пока React не смонтирует это. Когда вы монтируете, вы добавляете свой холст к фактическому DOM node, созданному React.
Причиной этого является то, что метод render
возвращает только виртуальные узлы DOM, которые React затем переводит на реальные узлы DOM. И поскольку у вас есть реальный DOM node, вы не можете преобразовать его в виртуальный node. Другая причина заключается в том, что вы должны возвращать только узлы из render
, которые управляют элементами React. И поскольку вы управляете холстом из-за контроля Reacts, вы должны использовать реальный DOM apis, чтобы управлять им.
Ответ 3
Ключ переопределяет правильные методы жизненного цикла React для рисования. Метод render создает элемент DOM холста, и вы можете добавить обратный вызов refs
, чтобы установить ссылку на него, но вам нужно подождать, пока компонент не будет смонтирован для рисования на холсте.
Вот пример, в котором используется обратный вызов, как рекомендуют рекомендации React. Он предназначен для визуализации статического (неанимированного) графического компонента на основе реквизита и обновлений при изменении реквизита. Он также подписывается на событие изменения размера окна, чтобы его можно было динамически масштабировать с помощью CSS (например, width: 100%
). Этот пример основан на коде из этого Gist.
export default class CanvasComponent extends React.Component {
constructor(props) {
super(props);
this._resizeHandler = () => {
/* Allows CSS to determine size of canvas */
this.canvas.width = this.canvas.clientWidth;
this.canvas.height = this.canvas.clientHeight;
this.clearAndDraw();
}
}
componentDidMount() {
window.addEventListener('resize', this._resizeHandler);
/* Allows CSS to determine size of canvas */
this.canvas.width = this.canvas.clientWidth;
this.canvas.height = this.canvas.clientHeight;
this.clearAndDraw();
}
componentWillUnmount() {
window.removeEventListener('resize', this._resizeHandler);
}
componentDidUpdate(prevProps, prevState) {
if (this.props.secondRect !== prevProps.secondRect) {
this.clearAndDraw();
}
}
clearAndDraw() {
const ctx = this.canvas.getContext('2d');
if (ctx) {
ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
this.draw(ctx);
}
}
draw(ctx) {
ctx.fillStyle = 'rgb(200, 0, 0)';
ctx.fillRect(10, 10, 50, 50);
if (this.props.secondRect) {
ctx.fillStyle = 'rgba(0, 0, 200, 0.5)';
ctx.fillRect(30, 30, 50, 50);
}
}
render() {
return (
<canvas ref={canvas => this.canvas = canvas} />
);
}
}
Вы можете установить опору secondRect
из родительского компонента или установить его из состояния, чтобы увидеть обновление компонента при обновлении prop. Вы можете расширить эту идею, чтобы создать какой-либо обработчик данных, управляемый данными, например диаграмму или график.