Сделать линию поперечной в горизонтальном направлении на основе кадров в секунду, используя requestanimationframe - PullRequest
0 голосов
/ 26 августа 2018

У меня есть линия (которая является div), помещенная поверх холста (здесь не имеет значения).Предположим, у меня есть видеоплеер, воспроизводящий видео со скоростью 25 кадров в секунду.При воспроизведении видео эта линия и расположение холста должны работать как вторичная временная шкала.Я хочу, чтобы линия проходила плавно (без рывков и скачков).Я решил это до того момента, когда линия движется синхронно со временем видео.Но переход линии нервный.Я двигаю линию кадра тиски.

Мой код:

var fps = 25;
var now;
var then = Date.now();
var interval = 1000/fps;
var delta;

var myReq;

class App extends Component {

    state = {
        playing: false,
        xPos: 1,
        line1_xStart: 700,
        line1_xEnd: 700,
        isMouseDown: false,
        player: {},
        startX:0

    }

    componentDidMount() {
        canvas = document.getElementsByTagName("canvas")[0];
        ctx = canvas.getContext("2d");

        w = canvas.width;
        h = canvas.height;

        ctx.fillStyle = "#808891";
        this.init()

    }

    componentWillUpdate(nextProps, nextState){

    }

    init = ()=> {
        this.initVideoJS()
    }

    initVideoJS = ()=> {
        let x
        myPlayer = videojs('video-el');

        myPlayer.on('play', ()=>{
            this.draw()
            }
        )
        myPlayer.on("timeupdate", () => {
            duration = myPlayer.duration()
            currentTime = myPlayer.currentTime();
            x = duration
            //console.log(x)
            this.setState({line1_xEnd: 700 + (currentTime * document.getElementById("DemoCanvas").offsetWidth/duration)}, ()=>{
                console.log(this.state.line1_xEnd)
            })
        })
    }

    draw = () => {

        let totalFrames = myPlayer.duration() * 25


        now = Date.now();
        delta = now - then;

        if(this.state.startX < 900){

            if (delta > interval) {
                counter = counter + 1
                console.log("counter is " + counter)
                // update time stuffs

                // Just `then = now` is not enough.
                // Lets say we set fps at 10 which means
                // each frame must take 100ms
                // Now frame executes in 16ms (60fps) so
                // the loop iterates 7 times (16*7 = 112ms) until
                // delta > interval === true
                // Eventually this lowers down the FPS as
                // 112*10 = 1120ms (NOT 1000ms).
                // So we have to get rid of that extra 12ms
                // by subtracting delta (112) % interval (100).
                // Hope that makes sense.
                then = now - (delta % (interval));

                this.setState({ startX: this.state.startX + ((900/(totalFrames)))})

                // ... Code for Drawing the Frame ...
            }
        }

        window.requestAnimationFrame(this.draw);


    }

    handlePlay() {

    }

    render() {
        return (
            <div>
                <video id="video-el" className="video-js"  ref={node => this.video_el = node} controls preload="auto" width="640" height="264"
                       poster="MY_VIDEO_POSTER.jpg" data-setup="{}">
                    <source src="http://techslides.com/demos/sample-videos/small.mp4" type='video/mp4'/>
                </video>

                <div onClick={this.shiftLine.bind(this)}
                     onMouseDown={this.mouseDown.bind(this)}
                     onMouseUp={this.onMouseUp.bind(this)}
                     onMouseMove={this.mouseMove.bind(this)}>
                    <div className="App">
                        <canvas id="DemoCanvas" style={{width: 900, height:"60px"}}></canvas>
                    </div>
                    <div className="line"
                         style={{
                             position: 'absolute',
                             transform: `translate(${this.state.startX}px, 0px)`
                         }}
                    />

                </div>
            </div>

        );
    }
}

Все, что мы делаем, это устанавливаем наши кадры в секунду и интервалы между каждым кадром.В функции рисования мы вычитаем время выполнения нашего последнего кадра из текущего времени, чтобы проверить, превышает ли время, прошедшее с последнего кадра, наш интервал (который основан на fps) или нет.Если условие оценивается как истинное, мы устанавливаем время для нашего текущего кадра, которое будет «временем выполнения последнего кадра» в следующем вызове рисования.

Выше приведен код, который сдвигает линию в каждом кадременять.Видео 5-секундное видео.Я попытался сделать переход плавным путем внесения этого изменения:

draw = () => {

        let totalFrames = myPlayer.duration() * 25


        now = Date.now();
        delta = now - then;

        if(this.state.startX < 900){

            if (delta > interval/2) {
                counter = counter + 1
                console.log("counter is " + counter)
                // update time stuffs

                // Just `then = now` is not enough.
                // Lets say we set fps at 10 which means
                // each frame must take 100ms
                // Now frame executes in 16ms (60fps) so
                // the loop iterates 7 times (16*7 = 112ms) until
                // delta > interval === true
                // Eventually this lowers down the FPS as
                // 112*10 = 1120ms (NOT 1000ms).
                // So we have to get rid of that extra 12ms
                // by subtracting delta (112) % interval (100).
                // Hope that makes sense.
                then = now - (delta % (interval/2));

                this.setState({ startX: this.state.startX + ((900/(totalFrames))/2)})

                // ... Code for Drawing the Frame ...
            }
        }

        window.requestAnimationFrame(this.draw);


    }

Я разделил интервал на 2 и соответственно изменил setState.

Там все еще есть рывок.Это не гладко, как должно быть.

...