From ea5120fded08da0998d01c89a26cbdbc4be7de55 Mon Sep 17 00:00:00 2001 From: Moe Date: Sun, 5 Dec 2021 21:57:12 -0800 Subject: [PATCH] show available jpeg frames over video rows with mouseover --- web/assets/css/bs5.videoPlayer.css | 24 ++++ web/assets/js/bs5.recentVideos.js | 9 +- web/assets/js/bs5.videos.js | 176 +++++++++++++++++++++-------- 3 files changed, 157 insertions(+), 52 deletions(-) diff --git a/web/assets/css/bs5.videoPlayer.css b/web/assets/css/bs5.videoPlayer.css index 46bea314..54f593c7 100644 --- a/web/assets/css/bs5.videoPlayer.css +++ b/web/assets/css/bs5.videoPlayer.css @@ -29,3 +29,27 @@ .tab-videoPlayer:hover .tab-videoPlayer-event-objects { display: none; } + +/* video-time-strip */ +.video-time-img { + background-size: cover; + background-position: center; + min-height:400px; +} +.video-time-img:not(.video-time-no-img) .card-body:hover { + background: rgba(0,0,0,0.9); + color: #fff; +} +.video-time-strip { + min-height: 30px; + position: relative; +} +.video-time-needle { + position: absolute; + border-left: 3px solid #1f80f9; + height: 100%; + transition: none; +} +.video-time-needle-event { + border-left: 3px solid #828282; +} diff --git a/web/assets/js/bs5.recentVideos.js b/web/assets/js/bs5.recentVideos.js index e213a8c5..dc46a8bf 100644 --- a/web/assets/js/bs5.recentVideos.js +++ b/web/assets/js/bs5.recentVideos.js @@ -2,8 +2,12 @@ $(document).ready(function(){ var theBlock = $('#recentVideos') var theList = $('#recentVideosList') var monitorList = theBlock.find('.monitors_list') - function drawRowToList(row,toBegin){ + function drawRowToList(row,toBegin,returnLastChild){ theList[toBegin ? 'prepend' : 'append'](createVideoRow(row)) + if(returnLastChild){ + var theChildren = theList.children() + return toBegin ? theChildren.first() : theChildren.last() + } } function loadVideos(options,callback){ theList.empty(); @@ -11,7 +15,8 @@ $(document).ready(function(){ var html = `` var videos = data.videos || {} $.each(videos,function(n,row){ - drawRowToList(row) + var createdCardCarrier = drawRowToList(row,false,true) + bindFrameFindingByMouseMove(createdCardCarrier,row) }) getCountOfEvents({ monitorId: options.monitorId, diff --git a/web/assets/js/bs5.videos.js b/web/assets/js/bs5.videos.js index cf7344fe..757a713a 100644 --- a/web/assets/js/bs5.videos.js +++ b/web/assets/js/bs5.videos.js @@ -32,7 +32,7 @@ function createVideoLinks(video){ video.details = details return video } -function applyEventListToVideos(videos,events){ +function applyDataListToVideos(videos,events,keyName,reverseList){ var updatedVideos = videos.concat([]) var currentEvents = events.concat([]) updatedVideos.forEach(function(video){ @@ -46,39 +46,109 @@ function applyEventListToVideos(videos,events){ currentEvents.splice(index, 1) } }) - video.events = videoEvents + if(reverseList)videoEvents = videoEvents.reverse() + video[keyName || 'events'] = videoEvents }) return updatedVideos } -function createVideoRow(row,classOverride){ - var possibleEventFrames = '' - var hasRows = row.events && row.events.length > 0 - if(hasRows){ - var eventMatrixHtml = `` - var objectsFound = {} - eventMatrixHtml += ` - - - - - ` - $.each(([]).concat(row.events).splice(0,11),function(n,theEvent){ - var imagePath = `${formattedTimeForFilename(theEvent.time,false,'YYYY-MM-DD')}/${formattedTimeForFilename(theEvent.time,false,'YYYY-MM-DDTHH-mm-ss')}.jpg` - possibleEventFrames += `
` - }) - $.each(row.events,function(n,theEvent){ - $.each(theEvent.details.matrices,function(n,matrix){ - if(!objectsFound[matrix.tag])objectsFound[matrix.tag] = 1 - ++objectsFound[matrix.tag] +function applyTimelapseFramesListToVideos(videos,events,keyName,reverseList){ + var thisApiPrefix = getApiPrefix() + '/timelapse/' + $user.ke + '/' + var newVideos = applyDataListToVideos(videos,events,keyName,reverseList) + newVideos.forEach(function(video){ + video.timelapseFrames.forEach(function(row){ + var apiURL = thisApiPrefix + row.mid + row.href = libURL + apiURL + '/' + row.filename.split('T')[0] + '/' + row.filename + }) + }) + return newVideos +} +function getFrameOnVideoRow(percentageInward,video){ + var startTime = new Date(video.time) + var endTime = new Date(video.end) + var timeDifference = endTime - startTime + var timeInward = timeDifference / (100 / percentageInward) + var timeAdded = new Date(startTime.getTime() + timeInward) // ms + // video.timelapseFrames.forEach(function(row){ + // var isValid = new Date(row.time) > timeAdded + // console.log(new Date(row.time),timeAdded) + // if(isValid)console.log(row.time) + // + // }) + var foundFrame = video.timelapseFrames.find(function(row){ + return new Date(row.time) > timeAdded + }); + return foundFrame +} +function bindFrameFindingByMouseMove(createdCardCarrier,video){ + var createdCardElement = createdCardCarrier.find('.card').first() + var timeImg = createdCardElement.find('.video-time-img') + var timeStrip = createdCardElement.find('.video-time-strip') + var timeNeedleSeeker = createdCardElement.find('.video-time-needle-seeker') + if(video.timelapseFrames.length > 0){ + createdCardElement.on('mousemove',function(evt){ + var offest = createdCardElement.offset() + var elementWidth = createdCardElement.width() + 2 + var amountMoved = evt.pageX - offest.left + var percentMoved = amountMoved / elementWidth * 100 + var frameFound = getFrameOnVideoRow(percentMoved,video) + if(frameFound){ + timeImg.css('background-image',`url(${frameFound.href})`) + } + timeNeedleSeeker.css('left',`${amountMoved}px`) + }) + timeImg.css('background-image',`url(${getFrameOnVideoRow(1,video).href})`) + }else{ + if(video.events.length === 0){ + timeStrip.hide() + }else{ + var eventMatrixHtml = `` + var objectsFound = {} + eventMatrixHtml += ` +
${lang.Events}${row.events.length}
+ + + + ` + $.each(([]).concat(video.events).splice(0,11),function(n,theEvent){ + var imagePath = `${formattedTimeForFilename(theEvent.time,false,'YYYY-MM-DD')}/${formattedTimeForFilename(theEvent.time,false,'YYYY-MM-DDTHH-mm-ss')}.jpg` + possibleEventFrames += `
` }) - }) - $.each(objectsFound,function(tag,count){ - eventMatrixHtml += ` - - - ` - }) - eventMatrixHtml += `
${lang.Events}${video.events.length}
${tag}${count}
` + $.each(video.events,function(n,theEvent){ + $.each(theEvent.details.matrices,function(n,matrix){ + if(!objectsFound[matrix.tag])objectsFound[matrix.tag] = 1 + ++objectsFound[matrix.tag] + }) + }) + $.each(objectsFound,function(tag,count){ + eventMatrixHtml += ` + ${tag} + ${count} + ` + }) + eventMatrixHtml += `` + timeStrip.append(eventMatrixHtml) + } + timeImg.css('min-height',`auto`).addClass('video-time-no-img') + } +} +function getPercentOfTimePositionFromVideo(video,theEvent){ + var startTime = new Date(video.time) + var endTime = new Date(video.end) + var eventTime = new Date(theEvent.time) + var rangeMax = endTime - startTime + var eventMs = eventTime - startTime + var percentChanged = eventMs / rangeMax * 100 + + console.log(`percentChanged`,percentChanged) + return percentChanged +} +function createVideoRow(row,classOverride){ + var eventMatrixHtml = `` + if(row.events && row.events.length > 0){ + $.each(row.events,function(n,theEvent){ + var leftPercent = getPercentOfTimePositionFromVideo(row,theEvent) + eventMatrixHtml += `
` + }) } var videoEndpoint = getLocation() + '/' + $user.auth_token + '/videos/' + $user.ke + '/' + row.mid + '/' + row.filename return ` @@ -94,25 +164,27 @@ function createVideoRow(row,classOverride){ -
-
-
- ${moment(row.time).fromNow()} +
+
+
+
+ ${moment(row.time).fromNow()} +
+
+ ~${durationBetweenTimes(row.time,row.end)} ${lang.Minutes} +
-
- ~${durationBetweenTimes(row.time,row.end)} ${lang.Minutes} +
+
+
${lang.Started} : ${formattedTime(row.time,true)}
+
${lang.Ended} : ${formattedTime(row.end,true)}
+
-
-
-
${lang.Started} : ${formattedTime(row.time,true)}
-
${lang.Ended} : ${formattedTime(row.end,true)}
-
-
-
${possibleEventFrames}
-
` @@ -148,12 +220,16 @@ function getVideos(options,callback){ } $.getJSON(`${getApiPrefix(`videos`)}${monitorId ? `/${monitorId}` : ''}?${requestQueries.concat([`limit=${limit}`]).join('&')}`,function(data){ var videos = data.videos - $.getJSON(`${getApiPrefix(`events`)}${monitorId ? `/${monitorId}` : ''}?${requestQueries.join('&')}`,function(eventData){ - var newVideos = applyEventListToVideos(videos,eventData) - $.each(newVideos,function(n,video){ - loadVideoData(video) + $.getJSON(`${getApiPrefix(`timelapse`)}${monitorId ? `/${monitorId}` : ''}?${requestQueries.join('&')}`,function(timelapseFrames){ + $.getJSON(`${getApiPrefix(`events`)}${monitorId ? `/${monitorId}` : ''}?${requestQueries.join('&')}`,function(eventData){ + console.log(timelapseFrames) + var newVideos = applyDataListToVideos(videos,eventData) + newVideos = applyTimelapseFramesListToVideos(newVideos,timelapseFrames,'timelapseFrames',true) + $.each(newVideos,function(n,video){ + loadVideoData(video) + }) + callback({videos: newVideos}) }) - callback({videos: newVideos}) }) }) }