JSFiddle - React, Tailwind, and code Playground

A/B Looper (Swipe)

by tonytlwu

HTML

<div id="currentTime">00:00.000</div>
<div class="clearfix">
    <div class="pull-left">
        <div>A time: <span id="aTime"></span>

        </div>
        <div>B time: <span id="bTime"></span>

        </div>
    </div>
    <button id="loop" class="btn btn-primary">Jump to A</button>
</div>
<div class="form-inline">
    <div class="checkbox-inline">
        <label>
            <input type="checkbox" id="slowscroll" />Scroll slower</label>
    </div>
    <div class="form-control-static">Play speed:</div>
    <div class="radio-inline">
        <label>
            <input type="radio" value="0.5" name="speed" />&times; 0.5</label>
    </div>
    <div class="radio-inline">
        <label>
            <input type="radio" value="0.75" name="speed" />&times; 0.75</label>
    </div>
    <div class="radio-inline">
        <label>
            <input type="radio" value="1" name="speed" checked />&times; 1</label>
    </div>
    <div class="radio-inline">
        <label>
            <input type="radio" value="2" name="speed" />&times; 2</label>
    </div>
</div>
<div id="aTimeSetter" class="waveScroller"><span class="img"></span>

</div>
<audio id="player" controls="" autobuffer="">
    <!--<source src="http://traffic.libsyn.com/timferriss/final-timferrissshow-TF-5-morning-rituals___128kbps_REVISED.mp3">-->
    <!--<source src="https://ec-media.sndcdn.com/6IXULTM2cJUy.128.mp3?f10880d39085a94a0418a7ef69b03d522cd6dfee9399eeb9a522059e69f0ba3a703f669b3c0f9d3e21f988a5db0ef9dd888459ba7b274bc2d0eac70adc9c5fd45bb8d37c1b">-->
    <source src="https://ia600409.us.archive.org/26/items/TheWinstons-AmenBrother/B_The_Winstons_-_Amen_Brother.mp3">
</audio>
<div id="bTimeSetter" class="waveScroller"><span class="img"></span>

</div>

CSS

html {
    width: 100%;
    height: 100%;
}
body {
    margin: 0;
    position: absolute;
    top: 0;
    right: 0;
    bottom: 0;
    left: 0;
    -webkit-touch-callout: none;
    -webkit-user-select: none;
    -khtml-user-select: none;
    -moz-user-select: none;
    -ms-user-select: none;
    user-select: none;
}
.waveScroller {
    width: 100%;
    height: 174px;
    overflow: hidden;
    position: relative;
    margin-bottom: 10px;
}
.waveScroller:after {
    content:'';
    display: block;
    width: 1px;
    height: 100%;
    background: red;
    position: absolute;
    top: 0;
    left: 50%;
}
.waveScroller .img {
    display: block;
    width: 2280px;
    height: 174px;
    background: url(https://s3.amazonaws.com/f.cl.ly/items/0F242622092Z1145103b/Screenshot%202015-09-19%2018.53.30.png) no-repeat center center;
    position: absolute;
    top: 0;
}
#aTimeSetter .img {
    left: 50%;
}
#bTimeSetter .img {
    right: 50%;
}
#player {
    width: 100%;
}
#currentTime {
    float: right;
    font-family: monospace;
}
#aTime, #bTime {
    font-family: monospace;
}
#loop {
    margin-left: 10px;
    margin-top: 2px;
}
</style> <meta name="viewport" content="width=device-width, initial-scale=1"> <style>

JavaScript

var aTimeDebug = document.getElementById('aTime');
var bTimeDebug = document.getElementById('bTime');
var currentTimeDebug = document.getElementById('currentTime');
if (typeof localStorage.getItem('aTime') === null || typeof localStorage.getItem('aTime') === 'object' || localStorage.getItem('aTime') === 'NaN') localStorage.setItem('aTime', '0');
if (typeof localStorage.getItem('bTime') === null || typeof localStorage.getItem('bTime') === 'object' || localStorage.getItem('bTime') === 'NaN') localStorage.setItem('bTime', '1');
var aTime = parseFloat(localStorage.getItem('aTime'));
var bTime = parseFloat(localStorage.getItem('bTime'));
var player = document.getElementById('player');
var counter = document.getElementById('counterDiv');
var slowscroll = false;
var slowscrollfactor = 0.1;

player.playbackRate = parseFloat($('[name="speed"]:checked').val());
$('[name="speed"]').on('change', function () {
    player.playbackRate = parseFloat($('[name="speed"]:checked').val());
});

var relativeToAbsTime = function (relTime) {
    var sec = (relTime * player.duration) % 60;
    sec = sec.toFixed(3);
    var min = Math.floor(relTime * player.duration / 60);
    if (sec < 10) {
        sec = '0' + sec;
    }
    if (min < 10) {
        min = '0' + min;
    }

    return min + ':' + sec;
};

var isTouch = is_touch_device();

function is_touch_device() {
    try {
        document.createEvent("TouchEvent");
        return true;
    } catch (e) {
        return false;
    }
}

var scrolling = false;
var maxWidth = 2280;
var aPos = 0;
var bPos = 1;
var aStartPos, bStartPos;
var startX;

aTimeDebug.innerHTML = relativeToAbsTime(aTime);
aPos = -aTime * maxWidth;
document.querySelector('#aTimeSetter .img').style.transform = 'translate3d(' + aPos + 'px,0px,0px)';

bTimeDebug.innerHTML = relativeToAbsTime(bTime);
bPos = (1 - bTime) * maxWidth;
document.querySelector('#bTimeSetter .img').style.transform = 'translate3d(' + bPos + 'px,0px,0px)';

var touchStartHandler = function...