").addClass('pano-overlay heading-overlay').append(
$('
').html("X: ").append($("").addClass('az'), "° T"),
$('').html("Y: ").append($("").addClass('el'), "°")
);
var panoWrap = $("").addClass("pano-close-wrap").append(
me._headingBox,
$("
").addClass("pano-overlay timestamp-wrap").append($("
").addClass("timestamp badge badge-light").html(timestamp.toLocaleDateString('en-US', {timeZone:'America/Los_Angeles'})+" "+timestamp.toLocaleTimeString('en-US', {timeZone:'America/Los_Angeles', hour: '2-digit', minute: '2-digit', hourCycle: "h23"})+" PT"),
$("
").attr({
"type":"button",
"class":"btn btn-light timelapseControls expandContract expand",
"title":"Expand"
}).on("click", function(e) {
var btn = $(e.currentTarget);
btn.toggleClass('expand contract');
btn.parent().parent().find('.pano').toggleClass('expanded');
})
));
/*
This is the code I used to do timelapse previously. This is all handled by the CamHistory class now, and I don't anticipate needing it here again.
If it's 2023 and this is still commented out, feel free to delete it.
var timeInput = $(" ")
.attr({"type": "text",
"name": "datetime",
"class": "form-control pano-time",
"data-cam-id": me._camId
}).daterangepicker({
"autoApply": true,
"autoUpdateInput":true,
"singleDatePicker": true,
"maxDate": moment.unix(timestamp),
"timePicker": true,
"locale": {
"format": "MM/DD/YYYY hh:mm A",
"monthNames": [
"January",
"February",
"March",
"April",
"May",
"June",
"July",
"August",
"September",
"October",
"November",
"December"
]
},
"startDate": moment.unix(timestamp),
"endDate": moment.unix(timestamp)
}).on('apply.daterangepicker', (ev, picker) => {
var searchTime = new Date(picker.startDate).getTime() / 1000;
me.getPanoByTimestamp(searchTime);
});
var form = $("")
.addClass("panoSearch")
.append(
$("
").attr({
"type":"button",
"class":"btn btn-dark timelapseControls playPause pause",
"title":"Pause"
}).on("click", (e) => {
var target = $(e.currentTarget);
if (target.hasClass("pause")) {
target.removeClass("pause");
target.addClass("play");
target.attr("title","Play");
clearTimeout(me._tlT);
} else if (target.hasClass("play")) {
target.removeClass("play");
target.addClass("pause");
target.attr("title","Pause");
var idx = target.parents(".panoSearch").find('.next').attr('data-timelapse-index');
me.showTimelapseFrame(idx);
}
}),
$("").attr({
"type":"button",
"class":"btn btn-dark historyControls prev",
"title": "Previous"
}).on("click", (e) => {
if (me._wrap.hasClass("history-mode")) {
var panoId = $(e.currentTarget).attr('data-pano-id');
me.getPanoById(panoId);
} else if (me._wrap.hasClass("timelapse-mode")) {
var idx = $(e.currentTarget).attr('data-timelapse-index');
me.showTimelapseFrame(idx, false);
}
}),
$(" ").attr({
"type":"range",
"class":"timelapseControls lapse-slider",
"min":0,
"max":0,
"value":0
}).on("mousedown", function(e) {
var playPause = me._pano.parents('.pano-display-wrap').find('.playPause');
if (playPause.hasClass('pause')) {
playPause.click();
$(e.currentTarget).attr("data-was-paused", false);
} else {
$(e.currentTarget).attr("data-was-paused", true);
}
}).on("input", function(e) {
var idx = $(e.currentTarget).val();
me.showTimelapseFrame(idx, false);
}).on("change", function(e) {
var idx = $(e.currentTarget).val();
var play = $(e.currentTarget).attr('data-was-paused') == 'false';
me.showTimelapseFrame(idx, play);
if (play) {
me._pano.parents('.pano-display-wrap').find('.playPause').removeClass('play').addClass('pause').attr({"title": "Pause", 'data-was-paused':null});
}
}),
$("").attr({
"type":"button",
"class":"btn btn-dark historyControls next",
"title": "Next"
}).on("click", (e) => {
if (me._wrap.hasClass("history-mode")) {
var panoId = $(e.currentTarget).attr('data-pano-id');
me.getPanoById(panoId);
} else if (me._wrap.hasClass("timelapse-mode")) {
var idx = $(e.currentTarget).attr('data-timelapse-index');
me.showTimelapseFrame(idx, false);
}
}),
$("").attr({
"type":"button",
"class":"btn btn-dark historyControls goToCurrent",
"title": "Go to Current"
}).on("click", function() {
me.goToCurrent();
}),
$(" ")
.attr({"type": "hidden",
"name": "camId",
"value": me._camId}),
timeInput,
);
var timelapseBtn = $("").addClass("timelapse-range btn btn-dark").attr({"data-cam-id":me._camId}).html("Timelapse")
.daterangepicker({
"autoApply": true,
"autoUpdateInput":true,
"maxDate": moment.unix(timestamp),
"timePicker": true,
"opens":'left',
"locale": {
"format": "MM/DD/YYYY hh:mm A",
"monthNames": [
"January",
"February",
"March",
"April",
"May",
"June",
"July",
"August",
"September",
"October",
"November",
"December"
]
},
"startDate": moment.unix(timestamp),
"endDate": moment.unix(timestamp)
}).on('apply.daterangepicker', (ev, picker) => {
var start = new Date(picker.startDate).getTime() / 1000;
var end = new Date(picker.endDate).getTime() / 1000;
me.getPanoTimelapse(start, end);
});
form.append(timelapseBtn);*/
//var testDate = new Date($("form#searchTest input[name='datetime']").val())
//testDate.getTime()/1000
// Again, old, likely irrelevant code. Delete it if it's still here after a while
for(var i in me._data) {
if(camName == "") {
camName = me._data[i][0].cam_name;
//me._wrap.append($(" ").html(camName.replace(/\_/g, " ")));
}
}
me.fillPanoWithData(me._data);
panoWrap.append(me._pano);
me._wrap.append(panoWrap);
me._wrap.on('mouseenter', function(e) {
me._headingBox.show();
me._map._headingLines[me._camId].addTo(me._map._map._map);
}).on('mouseleave', function(e) {
me._headingBox.hide();
me._map._headingLines[me._camId].remove();
}).on('mouseover mousemove', function(e) {
let x = e.offsetX, y = e.offsetY;
let parentPos = $(e.target).parent().position();
let quarterImg = e.target.width/4;
let left = parentPos.left + e.offsetX - quarterImg;
let top = parentPos.top + e.offsetY;
if ($(this).width() - left < me._headingBox.outerWidth()) {
left -= me._headingBox.outerWidth();
}
if ($(this).height() - top < me._headingBox.outerHeight()) {
top -= me._headingBox.outerHeight();
}
/*me._headingBox.css({
"left": left + 'px',
"top": top + 'px'
})*/
});
}
this.fillPanoWithData = function(data) {
/*
Populate the div with patchwork of images
*/
var me = this;
me._pano.html("");
let heightModifier;
if (!me._camCoords) {
let sampData = Object.values(Object.values(me._data)[0])[0];
me._camCoords = {"lat": sampData.cam_lat, "lon": sampData.cam_lon};
}
switch (parseInt(Object.values(Object.values(me._data)[0])[0].camtyp_id)) {
case 1:
case 2:
case 3:
case 4:
heightModifier = 0.8;
break;
case 6:
heightModifier = 0.6006;
break;
case 5:
default:
heightModifier = 0.5625;
break;
}
for(var i in data) {
var panoRow = $("
").addClass("pano-row");
for(var j in data[i]) {
var row = data[i][j];
var xSplit = (row.camtyp_max_fov / 2);
var ySplit = (xSplit * heightModifier);
xSplit = (row.camtyp_class == 'axis' ? xSplit/2 : xSplit);
var tc = (parseFloat(row.cmlg_cam_elevation) + ySplit).toFixed(1);
var bc = (parseFloat(row.cmlg_cam_elevation) - ySplit).toFixed(1);
var lc = (parseFloat(row.cmlg_cam_azimuth) - xSplit).toFixed(1);
var rc = (parseFloat(row.cmlg_cam_azimuth) + xSplit).toFixed(1);
var img = $(" ")
.attr({
"src": s3base+me.screenshotUrl(row),
"alt": "flir camera feed",
})
.data({
"camId": row.cam_id,
"camAz": row.cmlg_cam_azimuth,
"camElev": row.cmlg_cam_elevation,
"camWidth": row.camtyp_max_fov,
"camType": row.camtyp_id,
"camTc": tc,
"camBc": bc,
"camLc": lc,
"camRc": rc,
}).on("load", (e) => {
var img = $(e.target);
var wrap = img.parent();
var t = setTimeout(function() {
wrap.css("width", "auto");
wrap.css("width", row.camtyp_class == 'axis' ? img.outerWidth()/2 : img.outerWidth());
}, 500);
}).on("mouseover mousemove", function(e) {
var data = $(this).data();
let coords = getCoordsFromImageClickEvent(e.originalEvent, data.camAz, data.camElev, data.camWidth, data.camType);
me._headingBox.find('span.az').html(adjustDegrees(coords.xAdj).toFixed(1));
me._headingBox.find('span.el').html(coords.yAdj);
me._map.updateHeadingLine(me._camId, coords.xAdj);
})
var imgWrap = $("
")
.addClass("pano-img-wrap")
.append(img)
/*.append($("
").addClass("pos tc").append($("
").html('Y: ' + tc)))
.append($("
").addClass("pos bc").append($("
").html('Y: ' + bc)))
.append($("
").addClass("pos lc").append($("
").html('X: ' + parseFloat(lc < 360 ? lc : lc - 360).toFixed(1))))
.append($("
").addClass("pos rc").append($("
").html('X: ' + parseFloat(rc < 360 ? rc : rc - 360).toFixed(1))))*/
if (row.camtyp_class == 'axis') imgWrap.css({"overflow":"hidden"})
panoRow.append(imgWrap);
}
me._pano.append(panoRow);
}
}
this.getCamId = function(camData) {
/*
Get the cam ID from the data (It's buried pretty deep into the log, so drill in and find it)
*/
for(var i in camData) {
for(var j in camData[i]) {
return camData[i][j].cam_id;
}
}
}
this.getData = function() {
/*
Get the list of images for the latest pano
*/
var me = this;
var get = new AjaxQuery('api/panoramas/list', 'GET',
{"camId":me._camId},
function(result) {
if(result.code == 0 || result.err != '') {
//
} else if(result.code == 1) {
if (Object.keys(me._data).length > 0) {
var curTimestamp = Object.values(Object.values(me._data)[0])[0].pano_finished;
var newTimestamp = Object.values(Object.values(result.data)[0])[0].pano_finished;
}
if (curTimestamp != newTimestamp || Object.keys(me._data).length == 0) {
me._data = result.data;
me.updatePreview();
clearTimeout(me._i);
me.setupTimer();
}
}
}
)
}
this.getOldestTimestamp = function() {
/*
Get the timestamp of the oldest panorama for this camera (to limit the datetime form element) This will probably need to get moved to CamHistory
*/
var me = this;
var history = new AjaxQuery('api/panoramas/list/history', 'GET',
{"camId":me._camId},
function(result) {
if(result.code == 0 || result.err != '') {
//
} else if(result.code == 1) {
//me.setSearchMin(result.data[me._camId]);
}
}
)
}
this.screenshotUrl = function(panoFrameData) {
var me = this;
var timestamp = new Date(panoFrameData['pano_finished'] * 1000);
var formattedTimestamp = timestamp.toISOString().slice(0,10).replaceAll('-','/');
var prefix = "/data/thumb/"+panoFrameData['cam_id']+"/"+formattedTimestamp+"/"
return prefix+panoFrameData['cmlg_img_name'];
}
this.init = function() {
var me = this;
me._camId = camId;
me._data = Array();
me._output = appendTo;
me._timelapseData = Array();
me._dragBox = false;
me._map = map;
me.setupTimer();
me._wrap = $("").addClass("pano-display-wrap").append(
);
me._output.append(me._wrap);
var id = "cam-" + me._camId + "-pano";
me._pano = $("
")
.addClass("pano")
.attr("id", id)
.on("mousewheel", function(e) {
scrollHorizontally(e, id);
})
this.getData();
window.addEventListener('resize', function() {
me.updatePanoWrap(me._data);
})
}
this.runClock = function() {
/*
Runs every second. Check if it is time to update the panorama. If the next pano is more than 16 minutes past due, only run this every 5 minutes.
*/
return;
var me = this;
var d = new Date();
var curMin = d.getMinutes();
var curSec = d.getTime() / 1000;
/*var countdown = me._refreshAt - curSec;
var countdownStr;
if (countdown > 0) {
countdownStr = Math.floor(countdown / 60) + ":" + Math.floor(countdown % 60).toString().padStart(2, '0');
} else {
countdownStr = "0:00";
}
me._wrap.find('.countdown').html(countdownStr);*/
if(curSec >= me._refreshAt && !me._paused) {
if (curSec - me._refreshAt > 60) {
clearInterval(me._i);
me._i = setInterval(function() {
me.runClock();
}, 10000);
} else if (me._i > 1) {
clearInterval(me._i);
me._i = setInterval(function() {
me.runClock();
}, 1000);
}
this.getData();
}
}
this.setSearchMin = function(oldest) {
/*
Set the minimum datetime for historical data (will be migrated to CamHistory eventually)
*/
var me = this;
var searchField = $("input.pano-time");
var timelapseBtn = $("button.timelapse-range");
searchField.data("daterangepicker").minDate = moment.unix(oldest);
timelapseBtn.data("daterangepicker").minDate = moment.unix(oldest);
}
this.setupTimer = function() {
/*
Set the update clock
*/
return;
var me = this;
me._i = setInterval(function() {
me.runClock();
}, 1000);
}
this.updatePanoWrap = function(data, search = false) {
/*
Update the patchwork panorama with new data
*/
var me = this;
var panoLeft = me._pano.scrollLeft();
var timestamp = Object.values(Object.values(data)[0])[0].pano_finished;
if (!search) {
me._refreshAt = parseInt(timestamp) + 600;
}
if (!me._pano.hasClass("paused") || search) {
me.fillPanoWithData(data);
function scrollLeft(i = 0) {
me._pano.scrollLeft(panoLeft);
if (me._pano.scrollLeft() == 0 && i < 10) {
var t = setTimeout(function() {
scrollLeft(i+1);
}, 1500)
}
}
if (panoLeft != 0) {
var t = setTimeout(function() {
scrollLeft();
}, 1500);
}
}
}
this.updatePreview = function() {
/*
Build/update the pano wrap
*/
var me = this;
if(me._pano.html() == "") {
me.buildPanoWrap(me._data, me._camId);
} else {
me.updatePanoWrap(me._data);
}
}
this.init();
}
function CamScreenshot (camId, map = null, appendTo = $("div#container"), data = null, color = null, link = false) {
var _camId, _parent, _screenshotDiv, _borderColor, _screenshot, _timestampDiv, _linked, _map;
var _data, _tempData;
var _poly, _line;
var _t, _streamButton, _fullscreenButton, _isFullscreen, _zoomSlider, _zoomChanged;
var _camControl, _headingBox, _dragBox;
var _timelapseMode, _timelapseData, _timelapseControls, _tLapse, _paused, _wasPaused;
var _prevFrame, _nextFrame;
this.build = function () {
/*
build the image area
*/
var me = this;
me._screenshot = $("
").addClass("screenshot").on("load", (e) => {
var img = $(e.target);
var wrap = img.parent();
wrap.css("width", "auto");
wrap.css("width", img.outerWidth())
if (me._map._map && me._map._map._map) {
me._map._map._map.invalidateSize();
}
})
$(window).on("resize", function() {
me._screenshot.trigger('load');
})
me._headingBox = $("
").addClass('heading-overlay').append(
$('
').html("X: ").append($("").addClass('az'), "° T"),
$('').html("Y: ").append($("").addClass('el'), "°")
);
if (me._borderColor) {
me._screenshot.css("border-color", me._borderColor);
}
if (me._linked) {
var link = $("").attr({"href":`/cam-console/${me._camId}`}).append(me._screenshot);
}
me._fullscreenButton = $("").addClass('btn btn-light fullscreen-button').append(
$("").addClass("material-icons").html('fullscreen')
).on('click', function() {
me.fullscreenToggle();
});
me._timelapseButton = me._camId == 1007 ? $("").addClass('btn btn-light timelapse-button').append(
$("").addClass("material-icons").html('play_arrow')
).on('click', function() {
if (!me._timelapseMode) {
console.log('timelapse time!');
selectLapseLength.slideToggle();
//me.fullscreenToggle();
} else {
if (me._zoomSlider) {
me._zoomSlider.show();
}
if (me._timelapseControls) {
me._timelapseControls.hide();
}
clearTimeout(me._tLapse);
me._timelapseMode = false;
me._timelapseButton.find('span').html('play_arrow');
me.updateData(me._tempData);
}
}) : '';
let isJeremiah = false;
var selectLapseLength = me._camId == 1007 ? $("").addClass('select-lapse-length').append(
$("
").attr({"value":"900"}).addClass("lapse-length btn btn-light").html("15 minutes"),
$("").attr({"value":"3600"}).addClass("lapse-length btn btn-light").html("1 hour"),
$("").attr({"value":"10800"}).addClass("lapse-length btn btn-light").html("3 hour"),
$("").attr({"value":"21600"}).addClass("lapse-length btn btn-light").html("6 hour"),
$("").attr({"value":"43200"}).addClass("lapse-length btn btn-light").html("12 hour")
) : '';
if (selectLapseLength) {
selectLapseLength.find('.lapse-length').on("click", function (e) {
if (!me._timelapseMode) {
console.log($(e.target).html());
if (me._timelapseControls) {
if (me._paused) {
me._timelapseControls.find('.playpause').click();
}
me._timelapseControls.show();
}
me._timelapseMode = true;
me._timelapseButton.find('span').html("stop");
/*pauseButton.toggleClass("frame-btn");
inciHeader.toggleClass("lapse-mode");
$("div#screenshots").toggleClass("fixed");
me._map._map._map.invalidateSize();*/
if (me._zoomSlider) {
me._zoomSlider.hide();
}
me.getTimelapse($(e.target).val());
selectLapseLength.slideToggle();
}
})
}
let timelapseInit = me._camId == 1007 ? $("").addClass('timelapse-init').append(me._timelapseButton, selectLapseLength) : '';
$(document).on("keyup", function(e) {
if (e.key === "Escape" && me._isFullscreen) {
me.fullscreenToggle();
}
})
me._timestampDiv = $("
").addClass("timestamp badge badge-light");
me._screenshotDiv = $("
").addClass('cam-screenshot').attr("id", "screenshot-"+me._camId).append($("
").addClass('cam-screenshot-wrap').append(link ?? me._screenshot, me._timestampDiv, timelapseInit, me._fullscreenButton, me._headingBox));
if (me._camId == 1007) {
me._timelapseControls = $("
").addClass("timelapse-controls").append(
$("
").addClass('prev btn btn-light').html(
$("").addClass('material-icons').html('chevron_left')
).on("click", function(e) {
if (!me._paused) {
me._timelapseControls.find('.playpause').click();
}
me.showFrame(me._prevFrame);
}),
$("").addClass('playpause btn btn-light').html(
$("").addClass('material-icons').html('pause')
).on("click", function (e) {
me._paused = !me._paused;
$(this).find('span').html(me._paused ? 'play_arrow' : 'pause')
if (me._timelapseMode && !me._paused) {
me.showFrame(me._nextFrame);
} else {
clearTimeout(me._tLapse);
}
}),
$("").addClass('next btn btn-light').html(
$("").addClass('material-icons').html('chevron_right')
).on("click", function(e) {
if (!me._paused) {
me._timelapseControls.find('.playpause').click();
}
me.showFrame(me._nextFrame);
}),
$(" ").attr({"type":"range", "min":"0", "max":"719", "value":"0"}).addClass("slider").on("mousedown", function() {
me._wasPaused = me._paused;
clearTimeout(me._tLapse);
if (!me._paused) {
me._timelapseControls.find('.playpause').click();
}
}).on("input", function(e) {
clearTimeout(me._tLapse);
me.showFrame($(e.target).val());
}).on("change", function() {
clearTimeout(me._tLapse);
if (!me._wasPaused) {
me._timelapseControls.find('.playpause').click();
}
})
).hide();
me._screenshotDiv.find(".cam-screenshot-wrap").append(me._timelapseControls);
}
me._screenshotDiv.on('click', function(e) {
if ($(e.target).hasClass('fullscreen-img')) {
me.fullscreenToggle();
}
});
me._screenshotDiv.on("mouseenter", function(e) {
me._headingBox.show();
me._map._headingLines[me._camId].addTo(me._map._map._map);
}).on("mouseleave", function(e) {
me._headingBox.hide();
me._map._headingLines[me._camId].remove();
}).on('mouseover mousemove', function(e) {
let data = me._data[me._camId];
let coords = getCoordsFromImageClickEvent(e.originalEvent, data.camAzimuth, data.camElevation, data.camViewWidth, data.camType);
me._headingBox.find('span.az').html(coords.xAdj);
me._headingBox.find('span.el').html(coords.yAdj);
let left = e.offsetX, top = e.offsetY;
if ($(this).width() - left < me._headingBox.outerWidth()) {
left -= me._headingBox.outerWidth();
}
if ($(this).height() - top < me._headingBox.outerHeight()) {
top -= me._headingBox.outerHeight();
}
me._map.updateHeadingLine(me._camId, coords.xAdj);
/*me._headingBox.css({
"left": left + 'px',
"top": top + 'px'
})*/
});
me._parent.append(me._screenshotDiv);
if (me._data) {
me.updateData();
}
}
this.screenshotUrl = function() {
var me = this;
var timestamp = new Date(me._data[me._camId].camScreenshotTimestamp * 1000);
var formattedTimestamp = timestamp.toISOString().slice(0,10).replaceAll('-','/');
var prefix = "/data/img/"+me._camId+"/"+formattedTimestamp+"/"
return prefix+me._data[me._camId].camScreenshot;
}
this.getTimelapse = function(seconds) {
var me = this;
var success = function(result) {
if (result.code == 1) {
me._timelapseData = result.data;
me._keys = Object.keys(me._timelapseData);
if (me._keys.length > 0) {
if (me._timelapseControls) {
me._timelapseControls.find("input.slider").attr({
"max": me._keys.length - 1
});
}
me.showFrame(0);
}
}
}
var finish = function () {
}
var fail = function() {
}
var query = new AjaxQuery("/api/getCameraTimelapse", "POST", {cameraIds: me._camId, lapseLength:seconds}, success, finish, fail);
}
this.fullscreenToggle = function() {
var me = this;
if (!me._isFullscreen) {
me._screenshotDiv.addClass('fullscreen-img');
me._fullscreenButton.find('span').html('fullscreen_exit');
me._isFullscreen = true;
$("body").addClass('noScroll');
} else {
me._screenshotDiv.removeClass('fullscreen-img');
me._fullscreenButton.find('span').html('fullscreen');
me._isFullscreen = false;
$("body").removeClass('noScroll');
}
me._screenshot.trigger('load');
}
this.init = function () {
var me = this;
me._camId = camId;
me._map = map;
me._parent = appendTo;
me._data = data;
me._tempData = data;
me._borderColor = color;
me._linked = link;
me._zoomChanged = 0;
me._dragBox = false;
me._isFullscreen = false;
me.build();
}
this.showFrame = function(idx) {
var me = this;
idx = Number(idx);
me._prevFrame = idx-1 >= 0 ? idx-1 : 0;
me._nextFrame = idx+1 < me._keys.length ? idx+1 : me._keys.length-1;
var data = me._timelapseData[me._keys[idx]];
Object.keys(data).forEach((camId) => {
data[camId].camLat = me._data[camId].camLat;
data[camId].camLon = me._data[camId].camLon;
me._data[camId] = data[ camId ];
});
me.updateData();
var newIdx = idx + 1;
var timestamp = new Date(me._keys[idx] * 1000);
//var timestring = (timestamp.getMonth()+1)+"/"+timestamp.getDate()+"/"+timestamp.getFullYear()+" "+(timestamp.getHours()).toString().padStart(2,"0")+":"+(timestamp.getMinutes()).toString().padStart(2,"0")+":"+(timestamp.getSeconds()).toString().padStart(2,"0");
//$("#timestamp").html(timestamp.toLocaleDateString('en-US', {timeZone:'America/Los_Angeles'})+" "+timestamp.toLocaleTimeString('en-US', {hour12: false, timeZone:'America/Los_Angeles'})+" PT");
if (me._timelapseControls) {
me._timelapseControls.find("input.slider").val(idx);
}
if(newIdx >= me._keys.length) {
//$("button.pause").click();
me._nextFrame = 0;
return;
}
me._tLapse = setTimeout(function() {
if (!me._paused) {
me.showFrame(newIdx);
}
}, 300, newIdx);
}
this.updateData = function (data = this._data) {
/*
Update the src of the img
*/
var me = this;
me._data = data;
var timestamp = new Date(me._data[me._camId].camScreenshotTimestamp * 1000);
me._screenshot.attr("src", s3base+me.screenshotUrl());
me._timestampDiv.html(timestamp.toLocaleDateString('en-US', {timeZone:'America/Los_Angeles'})+" "+timestamp.toLocaleTimeString('en-US', {timeZone:'America/Los_Angeles', hour: '2-digit', minute: '2-digit', second: '2-digit', hourCycle: "h23"})+" PT");
if (me._map && me._map._map) {
me._map.updateData(me._data);
/*if (me._poly) {me._poly.remove()};
if (me._line) {me._line.remove()};
me._poly = L.polygon(me._data[me._camId].camPolygon, {color:me._borderColor,stroke: false,fillOpacity:0.4}).addTo(me._map._map._map);
me._line = L.polyline(me._data[me._camId].camHeadingLine, {color:me._borderColor}).addTo(me._map._map._map);
me._map.removeFromArrays(me._poly, me._line);
me._map._polys.push(me._poly);
me._map._lines.push(me._line);*/
} else {
var t = setTimeout(function() {me.updateData()}, 500);
}
}
this.init();
}
function CamThumbnail (camId, appendTo = $("div#container"), data = Array(), checkbox = false) {
var _camId, _parent, _div, _offlineOverlay, _img, _data, _nameSpan, _refreshRate, _inciGallery;
this.build = function() {
/*
Build a camera thumbnail (shown in CamGallery instances)
*/
var me = this;
me._img = $(" ").addClass('thumbnail-img').attr({
"src": me._data.camScreenshot ? s3base+me.thumbUrl() : null
})
me._nameSpan = $("").addClass('cam-name badge badge-light').html(me._data.camName ? me._data.camName.replaceAll(/_/g, " ") : '');
if (me._camId == null) {
me._img.attr({"src":"https://weathernode.net/img/add_black_48dp.svg"}).on("load", function() {
if (!me._parent.parent().is(":visible")) {
var hide = true;
me._parent.parent().show();
}
me._img.css("max-height", me._img.outerWidth() * 0.8);
if (hide) {
me._parent.parent().hide();
}
});
me._nameSpan.html("New Camera");
}
me._div = $("").addClass("cam-option"+(me._data.camOffline && me._data.camActive ? " offline" : " online")).append(
$("
").addClass('cam-thumb').append(
me._img
),
//$("
").addClass('cam-name').append(
me._nameSpan
//)
).on("click", function () {
if (!me._inciGallery) {
window.location.href = "/cam-console/"+(me._camId ?? "new");
}
});
if (!me._data.camActive && me._camId != 'hover') {
me._div.css({"position":"relative"});
var overlay = $("
").addClass("cam-thumbnail-overlay").css({
"position":"absolute",
"display":"flex",
"justify-content":"center",
"align-items":"center",
"width":"100%",
"height":"100%",
"background-color":"rgba(255,255,255,0.7)",
"top":"0px",
"left":"0px",
"z-index":"500"
});
overlay.on("hover")
me._div.append(overlay);
}
me._offlineOverlay = $("
").addClass("offline-thumb").append(
$("").addClass("material-icons").html("wifi_off")
);
let now = new Date();
if (me._data.camScreenshotTimestamp < (now.getTime()/1000) - 120) {
me._div.append(me._offlineOverlay);
} else if (me._offlineOverlay.is(":visible")) {
me._offlineOverlay.remove();
}
me._parent.append(me._div);
}
this.thumbUrl = function() {
var me = this;
var timestamp = new Date(me._data.camScreenshotTimestamp * 1000);
var formattedTimestamp = timestamp.toISOString().slice(0,10).replaceAll('-','/');
var prefix = "/data/thumb/"+me._camId+"/"+formattedTimestamp+"/"
return prefix+me._data.camScreenshot;
}
this.fullSizeUrl = function() {
var me = this;
var timestamp = new Date(me._data.camScreenshotTimestamp * 1000);
var formattedTimestamp = timestamp.toISOString().slice(0,10).replaceAll('-','/');
var prefix = "/data/img/"+me._camId+"/"+formattedTimestamp+"/"
return prefix+me._data.camScreenshot;
}
this.getData = function() {
/*
Get data for this thumbnail (only used if not part of a gallery)
*/
var me = this;
var success = function (result) {
if (result.code == 1) {
me._data = result.data[me._camId];
}
me._t = setTimeout(() => {
me.getData();
}, me._refreshRate);
me.updateData();
}
var finish = function () {
}
var fail = function() {
}
if (!me._paused && me._camId) {
var query = new AjaxQuery("/api/getCameraData", "GET", {cameraIds: [me._camId]}, success, finish, fail);
}
}
this.init = function() {
var me = this;
me._camId = camId;
me._parent = appendTo;
me._data = data;
me._refreshRate = 20000;
me._inciGallery = checkbox;
me.build();
if (Object.keys(me._data).length == 0 && !isNaN(me._camId)) {
me.getData();
}
}
this.updateData = function(data = me._data) {
/*
Update the displayed image/name
*/
var me = this;
me._data = data;
let now = new Date();
if (me._data.camScreenshotTimestamp < (now.getTime()/1000) - 120) {
me._div.append(me._offlineOverlay);
} else if (me._offlineOverlay.is(":visible")) {
me._offlineOverlay.remove();
}
me._img.attr({
"src": me._data.camScreenshot ? (me._div.hasClass('map-hover-thumbnail') ? s3base+me.fullSizeUrl() : s3base+me.thumbUrl()) : null
});
me._nameSpan.html(me._data.camName ? me._data.camName.replace(/_/g, " ") : '');
}
this.init();
}
function getCoordsFromImageClickEvent(e, centerX, centerY, viewWidth, camType) {
let screenshot = $(e.currentTarget);
let w = screenshot.width();
let h = screenshot.height();
let x = e.offsetX;
let y = e.offsetY;
let heightModifier;
switch (parseInt(camType)) {
case 1:
case 2:
case 3:
case 4:
heightModifier = 0.8;
break;
case 6:
heightModifier = 0.6006;
break;
case 5:
default:
heightModifier = 0.5625;
break;
}
viewHeight = viewWidth * heightModifier;
let xAdj = parseFloat(((parseFloat(centerX)-(viewWidth/2)) + ((x/w)*parseFloat(viewWidth))).toFixed(1));
let yAdj = parseFloat(((parseFloat(centerY)+(viewHeight/2)) - ((y/h)*parseFloat(viewHeight))).toFixed(1));
return { xAdj, yAdj };
}