Видео HTML5: Canvas Mirror медленно

Моя функциональность работает нормально, но после нескольких циклов она замедляется, а «зеркальное» видео немного заикается.

Есть ли способ сделать это быстрее/плавнее?

Я хотел бы понять, правильно ли я выбрал способ зеркалирования видео.

У меня есть путь к клипу в css, и их должно быть 3, на которых у меня есть видео внутри зеркального отображения. Поначалу выглядит очень хорошо, но затем, после нескольких циклов, зеркальные видео начинают работать медленно и

Пожалуйста помоги.

document.addEventListener('DOMContentLoaded', function(){
    var v = document.getElementById('video1');
    var canvasBottom = document.getElementById('mycanvasbottom');
    var canvasLeft = document.getElementById('mycanvasleft');
    var canvasRight = document.getElementById('mycanvasright');
  
    var contextB = canvasBottom.getContext('2d');
    var contextL = canvasLeft.getContext('2d');
    var contextR = canvasRight.getContext('2d');

    var cw = 640;
    var ch = 480;
    canvasBottom.width = cw;
    canvasBottom.height = ch;
    canvasLeft.width = cw;
    canvasLeft.height = ch;
    canvasRight.width = cw;
    canvasRight.height = ch
  
    v.addEventListener('timeupdate', function(){
        draw(this,contextL,cw,ch);
        draw(this,contextR,cw,ch);
        draw(this,contextB,cw,ch);
    },false);
      

},false);

function draw(v,c,w,h) {
    if(v.paused || v.ended) return false;
    c.drawImage(v,0,0,w,h);
    setTimeout(draw,20,v,c,w,h);
}
#mycanvasbottom {
    position: absolute;
    margin: 0 auto;
    top: 0;
    bottom: 0;
    left: 0;
    right: 0;
    width: 75%;
    height: 75%;
    -webkit-filter: grayscale(1);
    clip-path: polygon(0 100%, 50% 50%, 100% 100%);
}
#mycanvasleft {
    position: absolute;
    margin: 0 auto;
    top: 0;
    bottom: 0;
    left: 0;
    right: 0;
    width: 75%;
    height: 75%;
    -webkit-filter: grayscale(1);
    clip-path: polygon(0 0, 50% 50%, 0 100%);
}
#mycanvasright {
    position: absolute;
    margin: 0 auto;
    top: 0;
    bottom: 0;
    left: 0;
    right: 0;
    width: 75%;
    height: 75%;
    -webkit-filter: grayscale(1);
    clip-path: polygon(100% 0, 50% 50%, 100% 100%);
}

#video1 {
    position: absolute;
    left: 0; 
}
<canvas id='mycanvasbottom' ></canvas>
<canvas id='mycanvasleft' ></canvas>
<canvas id='mycanvasright' ></canvas>

<video id='video1' autoplay muted loop width='320' >
	<source src="http://media.w3.org/2010/05/sintel/trailer.mp4" type="video/mp4"  />
</video>
Формы c голосовым вводом в React с помощью Speechly
Формы c голосовым вводом в React с помощью Speechly
Пытались ли вы когда-нибудь заполнить веб-форму в области электронной коммерции, которая требует много кликов и выбора? Вас попросят заполнить дату,...
В чем разница между Promise и Observable?
В чем разница между Promise и Observable?
Разберитесь в этом вопросе, и вы значительно повысите уровень своей компетенции.
Сравнение структур данных: Массивы и объекты в Javascript
Сравнение структур данных: Массивы и объекты в Javascript
Итак, вы изучили основы JavaScript и хотите перейти к изучению структур данных. Мотивация для изучения/понимания Структур данных может быть разной,...
Создание собственной системы электронной коммерции на базе Keystone.js - настройка среды и базовые модели
Создание собственной системы электронной коммерции на базе Keystone.js - настройка среды и базовые модели
Прошлая статья была первой из цикла статей о создании системы электронной коммерции с использованием Keystone.js, и она была посвящена главным образом...
Приложение для отслеживания бюджета на React js для начинающих
Приложение для отслеживания бюджета на React js для начинающих
Обучение на практике - это проверенная тема для достижения успеха в любой области. Если вы знаете контекст фразы "Практика делает человека...
Стоит ли использовать React в 2022 году?
Стоит ли использовать React в 2022 году?
В 2022 году мы все слышим о трендах фронтенда (React, Vue), но мы не знаем, почему мы должны использовать эти фреймворки, когда их использовать, а...
1
0
295
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

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

Во-первых, событие «timeupdate» запускается несколько раз, поэтому вы на самом деле вызываете отрисовку гораздо чаще, чем хотите. По этой причине он начинает лагать - много операций выполняется в секунду. Вы, вероятно, можете прослушивать события «play» и «pause» (запускаются после выполнения методов play() и pause(); событие «play» также вызывается, когда начинается видео, поэтому вам не нужно вызывать его вручную, его все равно уволят). Затем вы можете вручную обрабатывать цикл рисования. Это должно решить вашу проблему (я смог воспроизвести, и это исправляет эффект замедления).

Кроме того, вот несколько советов, которые вы можете рассмотреть:

  1. НЕ используйте setTimeout() для анимации, особенно при работе с холстом. Прочтите о window.requestAnimationFrame(), который намного лучше, и рассмотрите возможность его использования.
  2. Вы можете рассмотреть множество оптимизаций в этом коде, например, создание элементов холста в вашем коде (чтобы избавиться от идентификаторов), использование Object.assign() для добавления нескольких свойств к объекту в одной строке, введение циклов. Объем этого кода резко уменьшится. Это не обязательно, но всегда полезно поддерживать качество кода. Просто - меньше работы в будущем.

С уважением и хорошего дня!

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

let lastAnimationFrameRequestId = 0;

document.addEventListener('DOMContentLoaded', function () {
    const cw = 640;
    const ch = 480;
    const video = document.getElementById('video1');
    const canvases = [];
    const clipPaths = [
        'clip-path: polygon(0 100%, 50% 50%, 100% 100%)',
        'clip-path: polygon(0 0, 50% 50%, 0 100%);',
        'clip-path: polygon(100% 0, 50% 50%, 100% 100%)'
    ];

    clipPaths.forEach((clipPath) => {
        const canvas = Object.assign(document.createElement('canvas'), { className: 'my-canvas', style: clipPath, width: cw, height: ch });
        canvases.push(canvas);
        document.body.appendChild(canvas);
    });

    video.addEventListener('play', () => window.requestAnimationFrame(() => draw(video, canvases)));
    video.addEventListener('pause', () => window.cancelAnimationFrame(lastAnimationFrameRequestId));
});

function draw(video, canvases) {
    canvases.forEach((canvas) => {
      canvas.getContext('2d').drawImage(video, 0, 0, canvas.width, canvas.height);
    });
    lastAnimationFrameRequestId = window.requestAnimationFrame(() => draw(video, canvases));
}
.my-canvas {
    position: absolute;
    margin: 0 auto;
    top: 0;
    bottom: 0;
    left: 0;
    right: 0;
    width: 75%;
    height: 75%;
    -webkit-filter: grayscale(1);
}
<video id='video1' autoplay muted loop width='320'>
    <source src="http://media.w3.org/2010/05/sintel/trailer.mp4" type="video/mp4" />
</video>

Большое спасибо за этот подробный, хорошо объясненный ответ. Я действительно оценил. Без вас было бы невозможно достичь этого за миллион лет!

user173420 23.05.2019 14:59

Вы знаете, как добавить эффект размытия на холст слева и справа? клип-путь: полигон (100% 0, 50% 50%, 100% 100%); фильтр: размытие (4px); Что-то вроде этого? похоже немного тормозит форма

user173420 23.05.2019 15:02

Старый добрый друг при работе с JS — это console.log() — часто для меня это самый полезный инструмент для отладки JS. Просто, всегда работает. Попробуйте изменить CSS, свойство -webkit-filter с "-webkit-filter: оттенки серого (1);" на «-webkit-filter: оттенки серого (1) размытие (4 пикселя);». Вы можете смешивать несколько фильтров, просто разделяя их пробелом. Также может потребоваться добавить «-moz-filter» и «filter» для совместимости с браузером.

Mike Sar 23.05.2019 15:26

Не могли бы вы помочь мне с шириной что-то еще? Что делать, если у меня есть другое видео, и я хочу воспроизвести холст с другим видео? будет ли это работать без дублирования кода?

user173420 23.05.2019 17:15

Не дублируйте код! Если вам нужно повторно использовать какую-то часть, извлеките ее в функцию, а затем вызовите ее с нужным элементом. Эта строка «const video = document.getElementById('video1');» необходимо параметризовать. Подумайте об этом и немного поиграйте с этим.

Mike Sar 24.05.2019 10:12

Привет, Майк, я собрал кое-какой код для демо, codepen.io/davide77/pen/vwpKxN?editors=1010, не мог бы ты проверить, правильно ли я это сделал?

user173420 28.05.2019 12:19

Привет, Майк, ты знаешь, как заставить его работать в сафари?

user173420 13.06.2019 10:20

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