Как непрерывно транслировать видео на холсте в React?

По сути, я пытаюсь использовать https://github.com/cozmo/jsQR в контексте React. Однако canvas захватывает видеопоток только при монтировании компонента. Как мне постоянно транслировать видео, используя реагирующий холст?

import React, { Component } from "react";
import jsQR from "jsqr";

class WebcamStream extends Component {
  constructor(props) {
    super(props);

    this.videoTag = React.createRef();
    this.canvas = React.createRef();

    this.tick = this.tick.bind(this);
  }

  componentDidMount() {
    // getting access to webcam
    navigator.mediaDevices
      .getUserMedia({ video: { facingMode: "environment" } })
      .then(stream => {
        const video = this.videoTag.current;
        video.srcObject = stream;
        video.setAttribute("playsinline", true);
        video.play();
        requestAnimationFrame(this.tick);
      });
  }

  componentDidUpdate() {}

  drawLine(begin, end, color) {
    const canvasElement = this.canvas.current;
    const canvas = canvasElement.getContext("2d");

    canvas.beginPath();
    canvas.moveTo(begin.x, begin.y);
    canvas.lineTo(end.x, end.y);
    canvas.lineWidth = 4;
    canvas.strokeStyle = color;
    canvas.stroke();
  }

  tick() {
    const video = this.videoTag.current;

    const checkVideoState = setInterval(() => {
      if (video.readyState === video.HAVE_ENOUGH_DATA) {
        clearInterval(checkVideoState);

        const canvasElement = this.canvas.current;
        const canvas = canvasElement.getContext("2d");

        canvasElement.height = video.videoHeight;
        canvasElement.width = video.videoWidth;
        canvas.drawImage(
          video,
          0,
          0,
          canvasElement.width,
          canvasElement.height
        );
        let imageData = canvas.getImageData(
          0,
          0,
          canvasElement.width,
          canvasElement.height
        );

        console.info(imageData);

        var code = jsQR(imageData.data, imageData.width, imageData.height);

        if (code) {
          console.info("CODE");
          this.drawLine(
            code.location.topLeftCorner,
            code.location.topRightCorner,
            "#FF3B58"
          );
          this.drawLine(
            code.location.topRightCorner,
            code.location.bottomRightCorner,
            "#FF3B58"
          );
          this.drawLine(
            code.location.bottomRightCorner,
            code.location.bottomLeftCorner,
            "#FF3B58"
          );
          this.drawLine(
            code.location.bottomLeftCorner,
            code.location.topLeftCorner,
            "#FF3B58"
          );
        } else {
        }
      }
    }, 3000);
  }

  render() {
    return (
      <div>
        <video ref = {this.videoTag} width = "400" height = "400" autoPlay />
        <canvas ref = {this.canvas} />
      </div>
    );
  }
}

export default WebcamStream;
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
4
0
2 561
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Хорошо, я понял, что это так же просто, как снова вызвать requestAnimationFrame() внутри tick() метода.

import React, { Component } from "react";
import jsQR from "jsqr";

class WebcamStream extends Component {
  constructor(props) {
    super(props);

    this.state = {
      isVideoLoading: true
    };

    this.videoTag = React.createRef();
    this.canvas = React.createRef();

    this.tick = this.tick.bind(this);
  }

  componentDidMount() {
    // getting access to webcam
    navigator.mediaDevices
      .getUserMedia({ video: { facingMode: "environment" } })
      .then(stream => {
        const video = this.videoTag.current;
        video.srcObject = stream;
        video.setAttribute("playsinline", true);
        video.play();
        requestAnimationFrame(this.tick);
      });
  }

  drawLine(begin, end, color) {
    const canvasElement = this.canvas.current;
    const canvas = canvasElement.getContext("2d");

    canvas.beginPath();
    canvas.moveTo(begin.x, begin.y);
    canvas.lineTo(end.x, end.y);
    canvas.lineWidth = 4;
    canvas.strokeStyle = color;
    canvas.stroke();
  }

  tick() {
    const video = this.videoTag.current;

    const checkVideoState = setInterval(() => {
      if (video.readyState === video.HAVE_ENOUGH_DATA) {
        clearInterval(checkVideoState);

        this.setState({ isVideoLoading: false });

          const canvasElement = this.canvas.current;
          const canvas = canvasElement.getContext("2d");

          canvasElement.height = video.videoHeight;
          canvasElement.width = video.videoWidth;
          canvas.drawImage(
            video,
            0,
            0,
            canvasElement.width,
            canvasElement.height
          );
          let imageData = canvas.getImageData(
            0,
            0,
            canvasElement.width,
            canvasElement.height
          );

          var code = jsQR(imageData.data, imageData.width, imageData.height);

          if (code) {
            this.drawLine(
              code.location.topLeftCorner,
              code.location.topRightCorner,
              "#FF3B58"
            );
            this.drawLine(
              code.location.topRightCorner,
              code.location.bottomRightCorner,
              "#FF3B58"
            );
            this.drawLine(
              code.location.bottomRightCorner,
              code.location.bottomLeftCorner,
              "#FF3B58"
            );
            this.drawLine(
              code.location.bottomLeftCorner,
              code.location.topLeftCorner,
              "#FF3B58"
            );
          } 
        requestAnimationFrame(this.tick);
      }
    }, 1000);
  }

  render() {
    const { isVideoLoading } = this.state;

    return (
      <div>
        <video
          ref = {this.videoTag}
          width = "400"
          height = "400"
          autoPlay
          style = {{ display: "none" }}
        />

        {!isVideoLoading && <canvas ref = {this.canvas} />}

        {isVideoLoading && <p>Please wait while we load the video stream.</p>}
      </div>
    );
  }
}

export default WebcamStream;

Другие вопросы по теме