javascript - 有没有办法在 React 中每次状态更改时不重新加载 Canvas 的一部分?

标签 javascript reactjs canvas html5-canvas

我刚刚将 react-color 模块添加到此 Canvas 页面。当用户选择一种颜色时,strokeStyle 会正确更改为该颜色,但它也会重置整个 Canvas ,使其成为一张白板。有什么方法可以改变这个,这样只是颜色本身改变,但 Canvas 不重置?我尝试添加 shouldComponentUpdate 但这只使得颜色根本没有改变。

import React from 'react';
import { Layer, Stage, Image } from 'react-konva';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import { GithubPicker } from 'react-color';

class Canvas extends React.Component {
  constructor(props) {
    super(props);
    this.canvasEvent = this.canvasEvent.bind(this);
    this.props.socket.on('canvas_update', data => {
      const idToUpdate = data.canvasId == 1 ? 'drawing2' : 'drawing1';
      const node = document.createElement('p');
      const textNode = document.createTextNode('test');
      node.appendChild(textNode);
      document.getElementById(idToUpdate).appendChild(node);
      console.log(data.canvasJSON);
      this.updateKonva(idToUpdate, data.canvasJSON);

      //this.renderDisabledKonva(undefined, data.canvasJSON, data.canvasId);
    });
    this.state = {
      background: '#fff',
    };
  }

  canvasEvent(canvasJSON) {
    this.props.socket.emit('canvas_event', { roomId: this.props.roomId, canvasJSON: canvasJSON, canvasId: this.props.canvasId }, () => {});
  }

  handleChangeComplete = (color) => {
    this.setState({ background: color.hex });
  };

  renderTools() {
    return (
      <div className="tool">
        Tool:
        <select id="tool">
          <option value="brush">Brush</option>
          <option value="eraser">Eraser</option>
        </select>
      </div>
    );
  }

  renderKonva(container) {
    const that = this;
    const width = 400; // window.innerWidth;
    const height = 400; // window.innerHeight - 25;
    // first we need Konva core things: stage and layer
    const stage = new Konva.Stage({
      container: `drawing${this.props.canvasId}`,
      width: width,
      height: height
    });
    const layer = new Konva.Layer({});
    stage.add(layer);
    // then we are going to draw into special canvas element
    const canvas = document.createElement('canvas');
    canvas.width = stage.width() / 1.5;
    canvas.height = stage.height() / 1.5;
    // created canvas we can add to layer as 'Konva.Image' element
    let image = new Konva.Image({
      image: canvas,
      x: stage.width() / 6,
      y: stage.height() / 6,
      stroke: '#05AFF2',
      shadowBlur: 5,
    });
    layer.add(image);
    stage.draw();
    // Now we need to get access to context element
    const context = canvas.getContext('2d');
    context.strokeStyle = this.state.background;
    context.lineJoin = 'round';
    context.lineWidth = 5;
    let isPaint = false;
    let lastPointerPosition;
    let mode = 'brush';
    // now we need to bind some events
    // we need to start drawing on mousedown
    // and stop drawing on mouseup
    stage.on('contentMousedown.proto', () => {
      isPaint = true;
      lastPointerPosition = stage.getPointerPosition();
    });
    stage.on('contentMouseup.proto', () => {
      isPaint = false;
    });
    // and core function - drawing
    stage.on('contentMousemove.proto', () => {
      if (!isPaint) {
        return;
      }
      if (mode === 'brush') {
        context.lineWidth = 5;
        context.globalCompositeOperation = 'source-over';
      }
      if (mode === 'eraser') {
        context.lineWidth = 15;
        context.globalCompositeOperation = 'destination-out';
      }
      context.beginPath();
      let localPos = {
        x: lastPointerPosition.x - image.x(),
        y: lastPointerPosition.y - image.y(),
      };
      context.moveTo(localPos.x, localPos.y);
      const pos = stage.getPointerPosition();
      localPos = {
        x: pos.x - image.x(),
        y: pos.y - image.y(),
      };
      context.lineTo(localPos.x, localPos.y);
      context.closePath();
      context.stroke();
      lastPointerPosition = pos;
      layer.draw();

      const dataURL = stage.toDataURL();
      // window.open(dataURL);
      that.canvasEvent(dataURL);
      // that.canvasEvent(stage.toJSON());
      // console.log(layer);
    });
    const select = document.getElementById('tool');
    select.addEventListener('change', () => {
      mode = select.value;
    });
  }

  render() {
    return (
      <div className="container">
        {this.renderTools()}
        <GithubPicker onChangeComplete={this.handleChangeComplete} color={this.state.background} />
        <div id={'drawing' + this.props.canvasId} ref={ref => this.renderKonva(ref)} />
      </div>
    );
  }
}

const mapStateToProps = state => ({
  isAuthenticated: state.authReducer.isAuthenticated,
  user: state.authReducer,
  roomId: state.roomReducer.currentUserRoom,
});

const mapDispatchToProps = dispatch => bindActionCreators({}, dispatch);

export default connect(mapStateToProps, mapDispatchToProps)(Canvas);

最佳答案

我可以想出几种方法来解决这个问题:

  1. 如果您想保留任何类型的信息,只需将其添加到状态中即可。在重新渲染期间,只需引用状态即可确保事物仍按原样渲染。
  2. 将事物分解为更小的组件并向其中添加shouldComponentUpdate。不断分解事物,直到获得所需的精细控制。请记住,此函数还将下一个 props 和下一个状态作为参数传递,因此您可以观察这些属性,并且仅在与组件相关的内容发生更改时才进行渲染,否则返回 false。

注意:如果您正在使用外部库,react-color,并且您试图阻止它的某些组件渲染,但无权访问它,您可以在它周围放置一个包装组件纯粹是为了控制渲染条件。

我希望这有帮助!

关于javascript - 有没有办法在 React 中每次状态更改时不重新加载 Canvas 的一部分?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45356983/

相关文章:

javascript - 如何避免在 React 上遍历?

android - 无法访问 Cloud Firestore 后端。连接失败 1 次

javascript - history.push() 和使用 react-router 的自定义 URL 参数

javascript - 如何根据网格线的宽度在带有 alpha channel 的 Canvas 中绘制网格?

html5 Canvas : draw together

javascript - HTML Canvas,如何停止程序直到收到 Canvas 上的点击?

javascript - 如何在以下图像之间添加下一个选项?

javascript - ThreeJS 场景以 60FPS 运行,但让我的粉丝兴奋不已,最终崩溃了

javascript - 为什么 String.replace() 不适用于事件?

javascript - 对某些链接执行无索引、无关注