ac9a0e4cbe
The Config and Advanced setting pages received changes to use the new setSetting() function which looks after creating or updated the setting in the required config files. Optionally it also specification of a command to run after saving the settings. Some variables like models, audio formats and frequency shift tools were also moved into common.php Service Controls page received changes with the replacement of the actual command to execute with a sort of shorthand human friendly version e.g. service <action> <service_name> -- service restart livestream.service These commands map to the original commands in serviceMaintenance() so this could be called through the API without needing the full-blown commend. views.php was updated to accommodate this also System Controls page received a small change to make the process checking for new git updates or getting the last commit hash a single function call. Include and Exclude species updated to use getFilePath() to generate a path to the required file instead of the hard coded path Views.php also received similar treatment with replacing some hard coded paths with generated paths, but logic changes to handle the change in running service commands
595 lines
23 KiB
PHP
595 lines
23 KiB
PHP
<?php
|
|
include_once "./scripts/common.php";
|
|
|
|
if($kiosk == true) {
|
|
echo "<div style='margin-top:20px' class=\"centered\"><h1><a><img class=\"topimage\" src=\"images/bnp.png\"></a></h1></div>
|
|
</div><div class=\"centered\"><h3>$site_name</h3></div><hr>";
|
|
}
|
|
|
|
$totalcount_data = getDetectionCountAll();
|
|
if($totalcount_data['success'] == False){
|
|
echo $totalcount_data['message'];
|
|
header("refresh: 0;");
|
|
}
|
|
$totalcount = $totalcount_data['data'];
|
|
|
|
|
|
$todaycount_data = getDetectionCountToday();
|
|
if($todaycount_data['success'] == False){
|
|
echo $todaycount_data['message'];
|
|
header("refresh: 0;");
|
|
}
|
|
$todaycount = $todaycount_data['data'];
|
|
|
|
|
|
$hourcount_data = getDetectionCountLastHour();
|
|
if($hourcount_data['success'] == False){
|
|
echo $hourcount_data['message'];
|
|
header("refresh: 0;");
|
|
}
|
|
$hourcount = $hourcount_data['data'];
|
|
|
|
|
|
$mostrecent_data = getMostRecentDetection();
|
|
if($mostrecent_data['success'] == False){
|
|
echo $mostrecent_data['message'];
|
|
header("refresh: 0;");
|
|
}
|
|
$mostrecent = $mostrecent_data['data'];
|
|
|
|
|
|
$todayspeciestally_data = getSpeciesTalley();
|
|
if($todayspeciestally_data['success'] == False){
|
|
echo $todayspeciestally_data['message'];
|
|
header("refresh: 0;");
|
|
}
|
|
$todayspeciestally = $todayspeciestally_data['data'];
|
|
|
|
|
|
$totalspeciestally_data = getAllSpeciesTalley();
|
|
if($totalspeciestally_data['success'] == False){
|
|
echo $totalspeciestally_data['message'];
|
|
header("refresh: 0;");
|
|
}
|
|
$totalspeciestally = $totalspeciestally_data['data'];
|
|
|
|
|
|
if(isset($_GET['comname'])) {
|
|
$birdName = $_GET['comname'];
|
|
$birdName = str_replace("_", " ", $birdName);
|
|
|
|
echo getBirdDetectionStats($birdName)['data'];
|
|
|
|
die();
|
|
|
|
}
|
|
|
|
|
|
if(isset($_GET['ajax_detections']) && $_GET['ajax_detections'] == "true" ) {
|
|
$result0 = getTodaysDetections($_GET['display_limit'], $_GET['searchterm'], $_GET['hard_limit']);
|
|
|
|
if($result0['success'] == False){
|
|
echo $result0['message'];
|
|
header("refresh: 0;");
|
|
}
|
|
$result0 = $result0['data'];
|
|
?> <table>
|
|
<?php
|
|
|
|
$iterations = 0;
|
|
$lines=null;
|
|
$licenses_urls = array();
|
|
|
|
foreach($result0 as $todaytable)
|
|
{
|
|
$iterations++;
|
|
|
|
//Get the flickr image for this detection
|
|
$flickr_Image = getFlickrImage($todaytable);
|
|
|
|
if ($flickr_Image['image_found']) {
|
|
//Remap the data from returned data into an array that is referenced in our HTML
|
|
//to save have to rewrite or adjust it
|
|
$flickr_Image_data = $flickr_Image['data'];
|
|
|
|
$image = [
|
|
0 => $flickr_Image_data['Com_Name_clean'],
|
|
1 => $flickr_Image_data['photos'][0]['image_url'],
|
|
2 => $flickr_Image_data['photos'][0]['photo_title'],
|
|
3 => $flickr_Image_data['photos'][0]['modal_text'],
|
|
4 => $flickr_Image_data['photos'][0]['author_link'],
|
|
5 => $flickr_Image_data['photos'][0]['license_url']
|
|
];
|
|
}
|
|
|
|
//Fill in the missing variables as they're not created at each loop anymore, getFlickrImage generates this data now as per what the orignal loop did
|
|
$filename = $flickr_Image_data['filename_path'];
|
|
$filename_formatted = $flickr_Image_data['filename_formatted'];
|
|
$sciname = $flickr_Image_data['Sci_Name_clean'];
|
|
$comname =$flickr_Image_data['Com_Name_clean'];
|
|
|
|
?>
|
|
<?php if(isset($_GET['display_limit']) && is_numeric($_GET['display_limit'])){ ?>
|
|
<tr class="relative" id="<?php echo $iterations; ?>">
|
|
<td class="relative">
|
|
<img style='cursor:pointer;right:45px' src='images/delete.svg' onclick='deleteDetection("<?php echo $filename_formatted; ?>")' class="copyimage" width=25 title='Delete Detection'>
|
|
<a target="_blank" href="index.php?filename=<?php echo $todaytable['File_Name']; ?>"><img class="copyimage" title="Open in new tab" width=25 src="images/copy.png"></a>
|
|
|
|
|
|
<div class="centered_image_container">
|
|
<?php if(!empty($config["FLICKR_API_KEY"]) && strlen($image[2]) > 0) { ?>
|
|
<img onclick='setModalText(<?php echo $iterations; ?>,"<?php echo urlencode($image[2]); ?>", "<?php echo $image[3]; ?>", "<?php echo $image[4]; ?>", "<?php echo $image[1]; ?>", "<?php echo $image[5]; ?>")' src="<?php echo $image[1]; ?>" class="img1">
|
|
<?php } ?>
|
|
|
|
<?php echo $todaytable['Time'];?><br>
|
|
<b><a class="a2" href="https://allaboutbirds.org/guide/<?php echo $comname;?>" target="top"><?php echo $todaytable['Com_Name'];?></a></b><img style="height: 1em;cursor:pointer" title="View species stats" onclick="generateMiniGraph(this, '<?php echo $comname; ?>')" width=25 src="images/chart.svg"><br>
|
|
<a class="a2" href="https://wikipedia.org/wiki/<?php echo $sciname;?>" target="top"><i><?php echo $todaytable['Sci_Name'];?></i></a><br>
|
|
<b>Confidence:</b> <?php echo round((float)round($todaytable['Confidence'],2) * 100 ) . '%';?><br></div><br>
|
|
<video onplay='setLiveStreamVolume(0)' onended='setLiveStreamVolume(1)' onpause='setLiveStreamVolume(1)' controls poster="<?php echo $filename.".png";?>" preload="none" title="<?php echo $filename;?>"><source preload="none" src="<?php echo $filename;?>"></video>
|
|
</td>
|
|
<?php } else { //legacy mode ?>
|
|
<tr class="relative" id="<?php echo $iterations; ?>">
|
|
<td><?php if($_GET['kiosk'] == true) { echo relativeTime(strtotime($todaytable['Time'])); } else {echo $todaytable['Time'];}?><br></td>
|
|
<td id="recent_detection_middle_td">
|
|
<div>
|
|
<div>
|
|
<?php if(!empty($config["FLICKR_API_KEY"]) && (isset($_GET['hard_limit']) || $_GET['kiosk'] == true) && strlen($image[2]) > 0) { ?>
|
|
<img style="float:left;height:75px;" onclick='setModalText(<?php echo $iterations; ?>,"<?php echo urlencode($image[2]); ?>", "<?php echo $image[3]; ?>", "<?php echo $image[4]; ?>", "<?php echo $image[1]; ?>", "<?php echo $image[5]; ?>")' src="<?php echo $image[1]; ?>" id="birdimage" class="img1">
|
|
<?php } ?>
|
|
</div>
|
|
<div>
|
|
<b><a class="a2" <?php if($_GET['kiosk'] == false){?>href="https://allaboutbirds.org/guide/<?php echo $comname;?>"<?php } else {echo "style='color:blue;'";} ?> target="top"><?php echo $todaytable['Com_Name'];?></a></b>
|
|
<?php
|
|
//If on mobile, add in a icon to link off to the recording so the user can see more info
|
|
if (isset($_GET['mobile'])) {
|
|
?>
|
|
<br>
|
|
<img style="height: 1em;cursor:pointer;float:unset;display:inline" title="View species stats" onclick="generateMiniGraph(this, '<?php echo $comname; ?>')" width=25 src="images/chart.svg">
|
|
<a target="_blank" href="index.php?filename=<?php echo $todaytable['File_Name']; ?>"><img style="height: 1em;cursor:pointer;float:unset;display:inline" class="copyimage-mobile" title="Open in new tab" width=16 src="images/copy.png"></a>'
|
|
<?php
|
|
}else{
|
|
//Else just put the species stats icon
|
|
?>
|
|
<img style="height: 1em;cursor:pointer;float:unset;display:inline" title="View species stats" onclick="generateMiniGraph(this, '<?php echo $comname; ?>')" width=25 src="images/chart.svg">
|
|
<?php
|
|
}
|
|
?>
|
|
<br>
|
|
<a class="a2" <?php if($_GET['kiosk'] == false){?>href="https://wikipedia.org/wiki/<?php echo $sciname;?>"<?php } else {echo "style='color:blue;'";} ?> target="top"><i><?php echo $todaytable['Sci_Name'];?></i></a><br>
|
|
</div>
|
|
</div>
|
|
</td>
|
|
<td><b>Confidence:</b> <?php echo round((float)round($todaytable['Confidence'],2) * 100 ) . '%';?><br></td>
|
|
<?php if(!isset($_GET['mobile'])) { ?>
|
|
<td style="min-width:180px"><audio controls preload="none" title="<?php echo $filename;?>"><source preload="none" src="<?php echo $filename;?>"></audio></td>
|
|
<?php } ?>
|
|
<?php } ?>
|
|
<?php }?>
|
|
</tr>
|
|
</table>
|
|
|
|
<?php
|
|
if($iterations == 0) {
|
|
echo "<h3>No Detections For Today.</h3>";
|
|
}
|
|
|
|
// don't show the button if there's no more detections to be displayed, we're at the end of the list
|
|
if($iterations >= 40 && isset($_GET['display_limit']) && is_numeric($_GET['display_limit'])) { ?>
|
|
<center>
|
|
<button class="loadmore" onclick="loadDetections(<?php echo $_GET['display_limit'] + 40; ?>, this);" value="Today's Detections">Load 40 More...</button>
|
|
</center>
|
|
<?php }
|
|
|
|
die();
|
|
}
|
|
|
|
if(isset($_GET['today_stats'])) {
|
|
?>
|
|
<table>
|
|
<tr>
|
|
<th>Total</th>
|
|
<th>Today</th>
|
|
<th>Last Hour</th>
|
|
<th>Unique Species Total</th>
|
|
<th>Unique Species Today</th>
|
|
</tr>
|
|
<tr>
|
|
<td><?php echo $totalcount['COUNT(*)'];?></td>
|
|
<form action="" method="GET">
|
|
<td><input type="hidden" name="view" value="Recordings"><?php if($kiosk == false){?><button type="submit" name="date" value="<?php echo date('Y-m-d');?>"><?php echo $todaycount['COUNT(*)'];?></button><?php } else { echo $todaycount['COUNT(*)']; }?></td>
|
|
</form>
|
|
<td><?php echo $hourcount['COUNT(*)'];?></td>
|
|
<form action="" method="GET">
|
|
<td><?php if($kiosk == false){?><button type="submit" name="view" value="Species Stats"><?php echo $totalspeciestally['COUNT(DISTINCT(Com_Name))'];?></button><?php }else { echo $totalspeciestally['COUNT(DISTINCT(Com_Name))']; }?></td>
|
|
</form>
|
|
<form action="" method="GET">
|
|
<td><input type="hidden" name="view" value="Recordings"><?php if($kiosk == false){?><button type="submit" name="date" value="<?php echo date('Y-m-d');?>"><?php echo $todayspeciestally['COUNT(DISTINCT(Com_Name))'];?></button><?php } else { echo $todayspeciestally['COUNT(DISTINCT(Com_Name))']; }?></td>
|
|
</form>
|
|
</tr>
|
|
</table>
|
|
<?php
|
|
die();
|
|
}
|
|
|
|
?>
|
|
|
|
<!DOCTYPE html>
|
|
<html lang="en">
|
|
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
<title>BirdNET-Pi DB</title>
|
|
<style>
|
|
</style>
|
|
</head>
|
|
<div class="viewdb">
|
|
<dialog style="margin-top: 5px;max-height: 95vh;
|
|
overflow-y: auto;overscroll-behavior:contain" id="attribution-dialog">
|
|
<h1 id="modalHeading"></h1>
|
|
<p id="modalText"></p>
|
|
<button style="font-weight:bold;color:blue" onclick="hideDialog()">Close</button>
|
|
<button style="font-weight:bold;color:blue" onclick="if(confirm('Are you sure you want to blacklist this image?')) { blacklistImage(); }">Blacklist this image</button>
|
|
</dialog>
|
|
<script src="static/dialog-polyfill.js"></script>
|
|
<script src="static/Chart.bundle.js"></script>
|
|
<script src="static/chartjs-plugin-trendline.min.js"></script>
|
|
|
|
<script>
|
|
function deleteDetection(filename,copylink=false) {
|
|
if (confirm("Are you sure you want to delete this detection from the database?") == true) {
|
|
const xhttp = new XMLHttpRequest();
|
|
xhttp.onload = function() {
|
|
if(this.responseText == "OK"){
|
|
if(copylink == true) {
|
|
window.top.close();
|
|
} else {
|
|
location.reload();
|
|
}
|
|
} else {
|
|
alert("Database busy.")
|
|
}
|
|
}
|
|
xhttp.open("GET", "play.php?deletefile="+filename, true);
|
|
xhttp.send();
|
|
}
|
|
}
|
|
|
|
var last_photo_link;
|
|
var dialog = document.querySelector('dialog');
|
|
dialogPolyfill.registerDialog(dialog);
|
|
|
|
function showDialog() {
|
|
document.getElementById('attribution-dialog').showModal();
|
|
}
|
|
|
|
function hideDialog() {
|
|
document.getElementById('attribution-dialog').close();
|
|
}
|
|
|
|
function blacklistImage() {
|
|
const match = last_photo_link.match(/\d+$/); // match one or more digits
|
|
const result = match ? match[0] : null; // extract the first match or return null if no match is found
|
|
console.log(last_photo_link)
|
|
const xhttp = new XMLHttpRequest();
|
|
xhttp.onload = function() {
|
|
if(this.responseText.length > 0) {
|
|
location.reload();
|
|
}
|
|
}
|
|
xhttp.open("GET", "overview.php?blacklistimage="+result, true);
|
|
xhttp.send();
|
|
|
|
}
|
|
|
|
function setModalText(iter, title, text, authorlink, photolink, licenseurl) {
|
|
document.getElementById('modalHeading').innerHTML = "Photo: \""+decodeURIComponent(title.replaceAll("+"," "))+"\" Attribution";
|
|
<?php if($kiosk == false) { ?>
|
|
document.getElementById('modalText').innerHTML = "<div><img style='border-radius:5px;max-height: calc(100vh - 15rem);display: block;margin: 0 auto;' src='"+photolink+"'></div><br><div style='white-space:nowrap'>Image link: <a target='_blank' href="+text+">"+text+"</a><br>Author link: <a target='_blank' href="+authorlink+">"+authorlink+"</a><br>License URL: <a href="+licenseurl+" target='_blank'>"+licenseurl+"</a></div>";
|
|
<?php } else { ?>
|
|
document.getElementById('modalText').innerHTML = "<div><img style='border-radius:5px;max-height: calc(100vh - 15rem);display: block;margin: 0 auto;' src='"+photolink+"'></div><br><div style='white-space:nowrap'>Image link: <a target='_blank'>"+text+"</a><br>Author link: <a target='_blank'>"+authorlink+"</a><br>License URL: <a target='_blank'>"+licenseurl+"</a></div>";
|
|
<?php } ?>
|
|
last_photo_link = text;
|
|
showDialog();
|
|
}
|
|
</script>
|
|
<h3>Number of Detections</h3>
|
|
<div id="todaystats"><table>
|
|
<tr>
|
|
<th>Total</th>
|
|
<th>Today</th>
|
|
<th>Last Hour</th>
|
|
<th>Unique Species Total</th>
|
|
<th>Unique Species Today</th>
|
|
</tr>
|
|
<tr>
|
|
<td><?php echo $totalcount['COUNT(*)'];?></td>
|
|
<form action="" method="GET">
|
|
<td><input type="hidden" name="view" value="Recordings"><?php if($kiosk == false){?><button type="submit" name="date" value="<?php echo date('Y-m-d');?>"><?php echo $todaycount['COUNT(*)'];?></button><?php } else { echo $todaycount['COUNT(*)']; }?></td>
|
|
</form>
|
|
<td><?php echo $hourcount['COUNT(*)'];?></td>
|
|
<form action="" method="GET">
|
|
<td><?php if($kiosk == false){?><button type="submit" name="view" value="Species Stats"><?php echo $totalspeciestally['COUNT(DISTINCT(Com_Name))'];?></button><?php }else { echo $totalspeciestally['COUNT(DISTINCT(Com_Name))']; }?></td>
|
|
</form>
|
|
<form action="" method="GET">
|
|
<td><input type="hidden" name="view" value="Recordings"><?php if($kiosk == false){?><button type="submit" name="date" value="<?php echo date('Y-m-d');?>"><?php echo $todayspeciestally['COUNT(DISTINCT(Com_Name))'];?></button><?php } else { echo $todayspeciestally['COUNT(DISTINCT(Com_Name))']; }?></td>
|
|
</form>
|
|
</tr>
|
|
</table></div>
|
|
|
|
|
|
<h3>Today's Detections <?php if($kiosk == false) { ?>— <input autocomplete="off" size="11" type="text" placeholder="Search..." id="searchterm" name="searchterm"><?php } ?></h3>
|
|
|
|
<div style="padding-bottom:10px" id="detections_table"><h3>Loading...</h3></div>
|
|
|
|
<?php if($kiosk == false) { ?>
|
|
<button onclick="switchViews(this);" class="legacyview">Legacy view</button>
|
|
<?php } ?>
|
|
|
|
</div>
|
|
|
|
<?php if($kiosk == true) { ?>
|
|
<script>
|
|
const scrollToTop = () => {
|
|
const c = document.documentElement.scrollTop || document.body.scrollTop;
|
|
if (c > 0) {
|
|
window.requestAnimationFrame(scrollToTop);
|
|
window.scrollTo(0, c - c / 8);
|
|
}
|
|
};
|
|
</script>
|
|
<button onclick="scrollToTop();" style="background-color: #dbffeb;padding: 20px;position: fixed;bottom: 5%;right: 5%;transition:box-shadow 280ms cubic-bezier(0.4, 0, 0.2, 1);box-shadow:0px 3px 1px -2px rgb(0 0 0 / 20%), 0px 2px 2px 0px rgb(0 0 0 / 14%), 0px 1px 5px 0px rgb(0 0 0 / 12%);">Scroll To Top</button>
|
|
<?php } ?>
|
|
|
|
<script>
|
|
|
|
var timer = '';
|
|
searchterm = "";
|
|
|
|
<?php if($kiosk == false) { ?>
|
|
document.getElementById("searchterm").onkeydown = (function(e) {
|
|
if (e.key === "Enter") {
|
|
clearTimeout(timer);
|
|
searchDetections(document.getElementById("searchterm").value);
|
|
document.getElementById("searchterm").blur();
|
|
} else {
|
|
/*
|
|
clearTimeout(timer);
|
|
timer = setTimeout(function() {
|
|
searchDetections(document.getElementById("searchterm").value);
|
|
|
|
setTimeout(function() {
|
|
// search auto submitted and now the user is probably scrolling, get the keyboard out of the way & prevent browser from jumping to the top when a video is played
|
|
document.getElementById("searchterm").blur();
|
|
}, 2000);
|
|
}, 1000);
|
|
*/
|
|
}
|
|
});
|
|
<?php } ?>
|
|
|
|
function switchViews(element) {
|
|
if(searchterm == ""){
|
|
document.getElementById("detections_table").innerHTML = "<h3>Loading <?php echo $todaycount['COUNT(*)']; ?> detections...</h3>";
|
|
} else {
|
|
document.getElementById("detections_table").innerHTML = "<h3>Loading...</h3>";
|
|
}
|
|
if(element.innerHTML == "Legacy view") {
|
|
element.innerHTML = "Normal view";
|
|
loadDetections(undefined);
|
|
} else if(element.innerHTML == "Normal view") {
|
|
element.innerHTML = "Legacy view";
|
|
loadDetections(40);
|
|
}
|
|
}
|
|
function searchDetections(searchvalue) {
|
|
document.getElementById("detections_table").innerHTML = "<h3>Loading...</h3>";
|
|
searchterm = searchvalue;
|
|
if(document.getElementsByClassName('legacyview')[0].innerHTML == "Normal view") {
|
|
loadDetections(undefined,undefined);
|
|
} else {
|
|
loadDetections(40,undefined);
|
|
}
|
|
}
|
|
function loadDetections(detections_limit, element=undefined) {
|
|
const xhttp = new XMLHttpRequest();
|
|
xhttp.onload = function() {
|
|
<?php if($kiosk == false) { ?>
|
|
document.getElementsByClassName("legacyview")[0].style.display="unset";
|
|
<?php } ?>
|
|
if(typeof element !== "undefined")
|
|
{
|
|
element.remove();
|
|
document.getElementById("detections_table").innerHTML+= this.responseText;
|
|
} else {
|
|
document.getElementById("detections_table").innerHTML= this.responseText;
|
|
}
|
|
|
|
}
|
|
if(searchterm != ""){
|
|
xhttp.open("GET", "todays_detections.php?ajax_detections=true&display_limit="+detections_limit+"&searchterm="+searchterm, true);
|
|
} else {
|
|
<?php if($kiosk == true) { ?>
|
|
xhttp.open("GET", "todays_detections.php?ajax_detections=true&display_limit="+detections_limit+"&kiosk=true", true);
|
|
<?php } else { ?>
|
|
xhttp.open("GET", "todays_detections.php?ajax_detections=true&display_limit="+detections_limit, true);
|
|
<?php } ?>
|
|
}
|
|
xhttp.send();
|
|
}
|
|
function refreshTodayStats() {
|
|
const xhttp = new XMLHttpRequest();
|
|
xhttp.onload = function() {
|
|
if(this.responseText.length > 0 && !this.responseText.includes("Database is busy")) {
|
|
document.getElementById("todaystats").innerHTML = this.responseText;
|
|
}
|
|
}
|
|
xhttp.open("GET", "todays_detections.php?today_stats=true", true);
|
|
xhttp.send();
|
|
}
|
|
window.addEventListener("load", function(){
|
|
<?php if($kiosk == true) { ?>
|
|
document.getElementById("myTopnav").remove();
|
|
loadDetections(undefined);
|
|
refreshTodayStats();
|
|
// refresh the kiosk detection list every minute
|
|
setTimeout(function() {
|
|
loadDetections(undefined);
|
|
refreshTodayStats();
|
|
}, 60000);
|
|
<?php } else { ?>
|
|
loadDetections(40);
|
|
<?php } ?>
|
|
});
|
|
</script>
|
|
|
|
<style>
|
|
.tooltip {
|
|
background-color: white;
|
|
border: 1px solid #ccc;
|
|
box-shadow: 0 0 10px rgba(0, 0, 0, 0.5);
|
|
padding: 10px;
|
|
transition: opacity 0.2s ease-in-out;
|
|
}
|
|
</style>
|
|
|
|
<script>
|
|
function generateMiniGraph(elem, comname) {
|
|
// Make an AJAX call to fetch the number of detections for the bird species
|
|
var xhr = new XMLHttpRequest();
|
|
xhr.open('GET', '/todays_detections.php?comname=' + comname);
|
|
xhr.onload = function() {
|
|
if (xhr.status === 200) {
|
|
var detections = JSON.parse(xhr.responseText);
|
|
|
|
console.log(detections)
|
|
|
|
// Create a div element for the chart window
|
|
var chartWindow = document.createElement('div');
|
|
chartWindow.className = "chartdiv"
|
|
chartWindow.style.position = 'fixed';
|
|
chartWindow.style.top = '0%';
|
|
chartWindow.style.left = '50%';
|
|
chartWindow.style.width = window.innerWidth < 700 ? '40%' : '20%';
|
|
chartWindow.style.height = window.innerWidth < 700 ? '25%' : '16%';
|
|
chartWindow.style.backgroundColor = '#fff';
|
|
chartWindow.style.zIndex = '9999';
|
|
chartWindow.style.overflow = 'auto';
|
|
chartWindow.style.borderRadius = '5px';
|
|
chartWindow.style.boxShadow = '0 4px 8px rgba(0, 0, 0, 0.2)';
|
|
|
|
document.body.appendChild(chartWindow);
|
|
|
|
|
|
// Create a canvas element for the chart
|
|
var canvas = document.createElement('canvas');
|
|
canvas.width = chartWindow.offsetWidth;
|
|
canvas.height = chartWindow.offsetHeight;
|
|
chartWindow.appendChild(canvas);
|
|
|
|
// Create a new Chart.js chart
|
|
var ctx = canvas.getContext('2d');
|
|
var chart = new Chart(ctx, {
|
|
type: 'line',
|
|
data: {
|
|
labels: detections.map(item => item.date),
|
|
datasets: [{
|
|
label: 'Detections',
|
|
data: detections.map(item => item.count),
|
|
backgroundColor: '#9fe29b',
|
|
borderColor: '#77c487',
|
|
borderWidth: 1,
|
|
lineTension: 0.3, // Add smoothing to the line
|
|
pointRadius: 1, // Make the data points smaller
|
|
pointHitRadius: 10, // Increase the area around data points for mouse events
|
|
|
|
trendlineLinear: {
|
|
style: "rgba(55, 99, 64, 0.5)",
|
|
lineStyle: "solid",
|
|
width: 1.5
|
|
}
|
|
|
|
}]
|
|
},
|
|
options: {
|
|
layout: {
|
|
padding: {
|
|
right: 10
|
|
}
|
|
},
|
|
title: {
|
|
display: true,
|
|
text: 'Detections Over 30d'
|
|
},
|
|
legend: {
|
|
display: false
|
|
},
|
|
scales: {
|
|
xAxes: [{
|
|
display: false,
|
|
gridLines: {
|
|
display: false // Hide the gridlines on the x-axis
|
|
},
|
|
ticks: {
|
|
autoSkip: true,
|
|
maxTicksLimit: 2
|
|
}
|
|
}],
|
|
yAxes: [{
|
|
gridLines: {
|
|
display: false // Hide the gridlines on the y-axis
|
|
},
|
|
ticks: {
|
|
beginAtZero: true,
|
|
precision: 0,
|
|
stepSize: 1
|
|
}
|
|
}]
|
|
}
|
|
}
|
|
});
|
|
|
|
// Position the chart window to the right of the button
|
|
var buttonRect = elem.getBoundingClientRect();
|
|
var chartRect = chartWindow.getBoundingClientRect();
|
|
if (window.innerWidth < 700) {
|
|
chartWindow.style.left = 'calc(75% - ' + (chartRect.width / 2) + 'px)';
|
|
} else {
|
|
chartWindow.style.left = (buttonRect.right + 10) + 'px';
|
|
}
|
|
|
|
// Calculate the top position of the chart to center it with the button
|
|
var buttonCenter = buttonRect.top + (buttonRect.height / 2);
|
|
var chartHeight = chartWindow.offsetHeight;
|
|
var chartTop = buttonCenter - (chartHeight / 2);
|
|
chartWindow.style.top = chartTop + 'px';
|
|
|
|
// Add a close button to the chart window
|
|
var closeButton = document.createElement('button');
|
|
closeButton.id = "chartcb";
|
|
closeButton.innerText = 'X';
|
|
closeButton.style.position = 'absolute';
|
|
closeButton.style.top = '5px';
|
|
closeButton.style.right = '5px';
|
|
closeButton.addEventListener('click', function() {
|
|
document.body.removeChild(chartWindow);
|
|
});
|
|
chartWindow.appendChild(closeButton);
|
|
}
|
|
};
|
|
xhr.send();
|
|
}
|
|
|
|
// Listen for the scroll event on the window object
|
|
window.addEventListener('scroll', function() {
|
|
// Get all chart elements
|
|
var charts = document.querySelectorAll('.chartdiv');
|
|
|
|
// Loop through all chart elements and remove them
|
|
charts.forEach(function(chart) {
|
|
chart.parentNode.removeChild(chart);
|
|
});
|
|
});
|
|
|
|
</script>
|