var cache = cache || {} var layer = 'descriptions' var baseURL = 'https://pad.ma' var imageResolution = 480 async function pandoraAPI(action, data) { var url = baseURL + '/api/' //var url = '/pandoraAPI/' var key = JSON.stringify([action, data]) if (!cache[key]) { var response = await fetch(url, { method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify({ action: action, data: data }) }) cache[key] = await response.json() } return cache[key] } function updatePlayer(video, frame, currentTime, out, src) { var rect = frame.getBoundingClientRect(); video.style.opacity = 0 video.style.top = (rect.top + window.scrollY) + 'px' video.style.display = 'block'; if (src) { video.src = src } //video.poster = frame.querySelector('img').src var muted = video.muted video.muted = true video.currentTime = currentTime video.dataset.in = currentTime video.dataset.out = out video._frame = frame const show = event => { video.style.opacity = 1 video.muted = muted video.removeEventListener('seeked', show) } video.addEventListener('seeked', show) video.play() } function isElementInViewport (el) { var rect = el.getBoundingClientRect(); return ( rect.top >= 0 && rect.left >= 0 && rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) && /* or $(window).height() */ rect.right <= (window.innerWidth || document.documentElement.clientWidth) /* or $(window).width() */ ); } function onVisibilityChange(el, callback) { var old_visible; return function () { var visible = isElementInViewport(el); if (visible != old_visible) { old_visible = visible; if (visible) { el.classList.add('visible') } else { el.classList.remove('visible') } if (typeof callback == 'function') { callback(visible); } } } } function scrollTo(element) { var delta = element.offsetTop - document.scrollingElement.scrollTop, duration = 1000, t = 40, n = duration / t, step = delta / n; function scroll() { if (document.scrollingElement.scrollTop + step > element.offsetTop) { document.scrollingElement.scrollTop = element.offsetTop n = 0 } else { document.scrollingElement.scrollTop += step } n-- if (n) setTimeout(scroll, t) } scroll() } function timeupdate(event) { if (event.target.dataset.out && event.target.dataset.in) { var in_= parseFloat(event.target.dataset.in) var out_= parseFloat(event.target.dataset.out) if (event.target.currentTime >= out_) { /* var next if (event.target._frame) { next = event.target._frame.parentElement.nextSibling if (next) { next = next.querySelector('.frame') } } if (next) { scrollTo(next) } else { event.target.pause() } */ if (config.pause) { event.target.pause() } else { event.target.currentTime = in_ } } } } function formatInfo(config, ascroll) { var h1 = document.createElement('h1') h1.innerHTML = config.title ascroll.appendChild(h1) var h2 = document.createElement('h2') h2.innerHTML = config.byline ascroll.appendChild(h2) var div = document.createElement('div') div.classList.add('intro') div.innerHTML = config.body ascroll.appendChild(div) } function showOverlay(event) { event.stopPropagation() event.preventDefault() document.querySelectorAll('#video-overlay').forEach(element => element.remove()) var video = event.target var rect = video.getBoundingClientRect(); var overlay = document.createElement('div') overlay.id = 'video-overlay' overlay.style.top = video.style.top overlay.style.width = rect.width + 'px' overlay.style.height = rect.height + 'px' overlay.style.position = 'absolute' overlay.style.display = 'flex' overlay.style.alignItems = 'center' overlay.style.justifyContent = 'center' overlay.style.fontSize = '45px' video.controls = false var off = `🔇` var on = `🔊` if (video.muted) { overlay.innerHTML = off } else { overlay.innerHTML = on } overlay.addEventListener('click', event=> { video.muted = !video.muted if (video.muted) { overlay.innerHTML = off } else { overlay.innerHTML = on } }) var timeout = setTimeout(() => { video.controls = false overlay.remove() }, 3000) overlay.addEventListener('mousemove', event=> { clearTimeout(timeout) timeout = setTimeout(() => { video.controls = false overlay.remove() }, 500) }) video.parentElement.appendChild(overlay) } function loadItem(config) { pandoraAPI('get', {id: config.item, keys: [ 'id', 'title', 'layers', 'hue', 'saturation', 'lightness' ]}).then(response => { //var color = `hsl(${response.data.hue}, ${response.data.saturation * 100}%, ${response.data.lightness * 100}%)` var color = `hsl(${response.data.hue}, 70%, 50%)` //document.body.style.background = color var ascroll = document.querySelector('#ascroll') var loaded = false var video = document.createElement('video') video.classList.add('player') video.muted = true video.src = `${baseURL}/${config.item}/480p.webm` video.addEventListener('timeupdate', timeupdate) video.addEventListener('touchstart', showOverlay) video.addEventListener('mouseover', showOverlay) ascroll.appendChild(video) var first formatInfo(config, ascroll) response.data.layers[layer].forEach(annotation => { if (config.user && annotation.user != config.user) { return } if (!first) { first = annotation } var div = document.createElement('div') div.classList.add('annotation') div.innerHTML = `
${annotation.value}
` ascroll.appendChild(div) var frame = div.querySelector('.frame') document.addEventListener('scroll', onVisibilityChange(div.querySelector('.frame'), function(visible) { if (loaded && visible) { updatePlayer(video, frame, annotation['in'], annotation['out']) } })) }) loaded = true let frame = ascroll.querySelector('.annotation .frame') if (frame) { updatePlayer(video, frame, first['in'], first['out']) } }) } function loadEdit(config) { pandoraAPI('getEdit', {id: config.edit, keys: []}).then(response => { var ascroll = document.querySelector('#ascroll') var loaded = false var video = document.createElement('video') video.classList.add('player') video.muted = true video.addEventListener('timeupdate', timeupdate) ascroll.appendChild(video) var first formatInfo(config, ascroll) response.data.clips.forEach(clip => { clip.layers[layer].forEach(annotation => { if (config.user && annotation.user != config.user) { return } if (!first) { first = annotation } var div = document.createElement('div') div.classList.add('annotation') div.innerHTML = `
${clip.title}
${annotation.value}
` ascroll.appendChild(div) var frame = div.querySelector('.frame') document.addEventListener('scroll', onVisibilityChange(div.querySelector('.frame'), function(visible) { var src = `${baseURL}/${annotation.id.split('/')[0]}/480p.webm` if (loaded && visible) { updatePlayer(video, frame, annotation['in'], annotation['out'], src) } })) }) }) loaded = true let frame = ascroll.querySelector('.annotation .frame') if (frame) { var src = `${baseURL}/${first.id.split('/')[0]}/480p.webm` updatePlayer(video, frame, first['in'], first['out'], src) } }) } if (config.item) { loadItem(config) } else if (config.edit) { loadEdit(config) }