Skip to content
Snippets Groups Projects
Commit 7101ec3f authored by Georgi's avatar Georgi
Browse files

Added the timeline visualization to the dashboard, moved all javascript...

Added the timeline visualization to the dashboard, moved all javascript functions to a separate helper script
parent 599ab8e5
No related branches found
No related tags found
No related merge requests found
Pipeline #9400 failed
......@@ -33,28 +33,23 @@
}
</style>
<a href='{{ action('MarkController@timeline', ["period" => 3600]) }}'
class='btn btn-primary'>
<i class="fas fa-expand"></i> Test
</a>
<div class="container-fluid" id="container">
<div class="row">
<div class="col-12 card" id="timeline" style="justify-content: center; align-items: center;">
</div>
</div>
<div class="row">
<div class="col-4 card">
<h4 class="card-header text-center">RawData Entries</h4>
<div class="card-body justify-content-center text-center" id="data-donut"></div>
</div>
<div class="col-4 card">
<h4 class="card-header text-center">Evidence Entries</h4>
<div class="card-body justify-content-center text-center" id="evidence-donut"></div>
<div class="col-8 card">
<h4 class="card-header text-center">Timeline
<select class="form-select form-select-sm" id="timeline-period">
<option selected>Time period</option>
<option value="1">2 hours</option>
<option value="2">1 hour</option>
<option value="3">30 min</option>
</select>
<button id="timeline_refresh" class="btn btn-primary btn-sm" >Refresh <i class="fas fa-redo"></i></button>
</h4>
<div class="card-body justify-content-center text-center" id="timeline"></div>
</div>
<div class="col-4 card">
<h4 class="card-header text-center">Evidence per Agent
<button id="donut-button" class="btn btn-primary btn-sm" >Show Detailed View</button>
<button id="donut-button" class="btn btn-primary btn-sm" >Show Detailed View <i class="fas fa-expand"></i></button>
</h4>
<div class="card-body justify-content-center text-center" id="evidence-count">
</div>
......@@ -67,7 +62,7 @@
<div id="detail-donut"></div>
</div>
</div>
<div class="row vh-50">
<div class="row vh-100">
<div class="col-sm-auto col-md-auto col-lg-auto col-xl-auto card">
<div class="card-body">
<h3 class="card-title">Available Agents <i class="fas fa-info-circle"></i></h3>
......@@ -109,48 +104,54 @@
var evidence_count = document.getElementById("evidence-count");
var detail_evidence_count = document.getElementById("detail-donut");
var agents = @json($graph_elements);
var agents_data = [];
console.log(agents);
agents.forEach(function (arrayItem){
var name = arrayItem.name;
agents_data.push({value:50, label: name});
})
agents_data.push({value:10, label: "detection.frequency"});
agents_data.push({value:100, label: "detection.geooutlier"});
window.addEventListener('DOMContentLoaded', function() {
//get the dbstatus data
var url = "/app/dbstatus";
var request = $.get(url);
request.done(function(response) {
//when the request is done, load the half-donut visualizations
drawHalfDonut(response["db.data.count"], 1000000, rawdata_container);
drawHalfDonut(response["db.evidence.count"], 1000000, evidence_container);
//create the button to show/hide the detailed evidences per agent donut visualization
var donut_button = document.getElementById("donut-button");
$("#donut-button").click(function() {
$(this).toggleClass('btn-primary btn-secondary');
$("#evidence-count-big").toggle();
$(this).text(function(i, text) {
return text === "Hide" ? "Show Detailed View" : "Hide";
//get timeline
//Initialize the timeline
$.get(
'dashboard/timeline/3600',
function(data) {
//create the timeline evidences and sort them
var timeline_evidences = create_timeline_evidences(data).sort((a, b) => (a.time > b.time ? 1 : -1));
//create the donut evidences
var donut_evidences = create_donut_evidences(timeline_evidences);
//console.log(timeline_evidences);
var svg_container = document.getElementById("timeline");
var info_container = document.getElementById("evidence-count-big");
LineChart(timeline_evidences,svg_container,info_container, {
x: d => d.time,
y: d => d.amount,
z: d => d.label,
ev_data: d => d.evidences,
yLabel: "Amount",
width: window.innerWidth,
height: 500,
color: "steelblue"
})
//create the button to show/hide the detailed evidences per agent donut visualization
var donut_button = document.getElementById("donut-button");
$("#donut-button").click(function() {
$(this).toggleClass('btn-primary btn-secondary');
$("#evidence-count-big").toggle();
$(this).text(function(i, text) {
return text === "Hide" ? "Show Detailed View" : "Hide";
});
});
});
//create the small evidences per agent donut visualization
new SimpleDonut({
element: evidence_count,
width: 700,
height: 200,
data: agents_data
});
DetailDonut(agents_data, detail_evidence_count);
});
@include('scripts.half-donut-script')
@include('scripts.simple-donut-script')
@include('scripts.detail-donut-script');
//create the small evidences per agent donut visualization
new SimpleDonut({
element: evidence_count,
width: 700,
height: 300,
data: donut_evidences
});
DetailDonut(donut_evidences, detail_evidence_count);
}
)
});
</script>
<script type="text/javascript">
var json_elements = @json($graph_elements);
var container = document.getElementById("visualization");
//keep the ID of the interval function set for the refresh time
......@@ -162,6 +163,8 @@
//add the EventListener to the Agent search button to display the rank listing
var agent_search_name = name + "_search";
document.getElementById(agent_search_name).addEventListener("click", function () {
//clear the refreshing interval
clearInterval(refresh_interval_id);
var ranking_url = "ranking/" + name;
//load the html of a page into the given container
load_ranking_html(container, ranking_url);
......@@ -189,36 +192,11 @@
});
})
async function load_ranking_html(container, url) {
//d3.select(container).select("svg").remove();
clearContent(container.id);
var url_as_html = await fetchHtmlAsText(url);
const document = new DOMParser().parseFromString(url_as_html, 'text/html');
//remove the redundant bubble and radar buttons from the loaded document
var fs_bubble_button = document.getElementById("fullscreen_bubble_button");
fs_bubble_button.parentNode.removeChild(fs_bubble_button);
var fs_radar_button = document.getElementById("fullscreen_radar_button");
fs_radar_button.parentNode.removeChild(fs_radar_button);
//get the main part of the HTML and set it to the innerHTML of the container
const main = document.getElementsByTagName("main")[0];
//console.log(main);
container.innerHTML = main.innerHTML;
}
async function fetchHtmlAsText(url) {
const response = await fetch(url);
return await response.text();
}
function clearContent(elementID) {
var div = document.getElementById(elementID);
while(div.firstChild) {
div.removeChild(div.lastChild);
}
}
@include('scripts.line-chart')
@include('scripts.simple-donut-script')
@include('scripts.detail-donut-script')
@include('scripts.bubble-script')
@include('scripts.helper-functions')
</script>
@endsection
\ No newline at end of file
@extends('layouts.app')
@section('content')
<html>
<h1 class="text-center">Timeline</h1>
<div style="width: 100%; height: 800px" id="svg-container">
</div>
<div style="width: 100%; height: 800px" id="info-container">
<div style="width: 100%; height: 800px" id="info-container" style="display: none">
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/7.1.1/d3.min.js" integrity="sha512-COTaPOlz12cG4fSfcBsxZsjauBAyldqp+8FQUM/dZHm+ts/jR4AFoJhCqxy8K10Jrf3pojfsbq7fAPTb1XaVkg==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
......@@ -57,4 +55,4 @@
</script>
@endsection
\ No newline at end of file
</html>
\ No newline at end of file
//method to parse the data used for the timeline and package it to be displayed
function create_timeline_evidences(data) {
var period = data.period;
var interval = data.interval;
var evidences = data.evidences;
var agents = data.agents;
var current_time = Date.now();
//go through the array of Evidence arrays and create a new array with the data to be displayed
const timeline_evidences = [];
for (var i = 0; i < evidences.length; i++) {
var bin = evidences[i];
//get the time for this specific bin
var bin_timestamp = current_time - ((period * 1000) - (interval * i * 1000));
//loop over the bin and extract all evidences for the given agent and create a new evidence for the timeline
for (var a = 0; a < agents.length; a++) {
var filtered_ev = [];
(bin === null) ? filtered_ev = [] : filtered_ev = bin.filter(ev => ev.label === agents[a].label);
const timeline_evidence = {"label" : agents[a].label,
"amount" : filtered_ev.length,
"evidences" : filtered_ev,
"time" : bin_timestamp};
timeline_evidences.push(timeline_evidence);
}
}
return timeline_evidences;
}
//method for counting number of evidences per agent in the database to be used by the donut chart
function create_donut_evidences(data) {
const donut_evidences = [];
//loop over the items in the data recieved
data.forEach(function(item) {
var temp = {value: item.amount, label: item.label};
//check if an evidence with the same label as temp already exists
const duplicate = donut_evidences.some(evidence => evidence.label == temp.label);
//if no donut evidences have been created, make a new one
if (!duplicate) {
donut_evidences.push(temp);
//else loop over the evidences created to see if one exists already and update its value
} else {
donut_evidences.forEach(function(evidence) {
if (evidence.label == temp.label) {
evidence.value = evidence.value + temp.value;
}
})
}
});
return donut_evidences;
}
async function load_ranking_html(container, url) {
//d3.select(container).select("svg").remove();
clearContent(container.id);
var url_as_html = await fetchHtmlAsText(url);
const document = new DOMParser().parseFromString(url_as_html, 'text/html');
//remove the redundant bubble and radar buttons from the loaded document
var fs_bubble_button = document.getElementById("fullscreen_bubble_button");
fs_bubble_button.parentNode.removeChild(fs_bubble_button);
var fs_radar_button = document.getElementById("fullscreen_radar_button");
fs_radar_button.parentNode.removeChild(fs_radar_button);
//get the main part of the HTML and set it to the innerHTML of the container
const main = document.getElementsByTagName("main")[0];
//console.log(main);
container.innerHTML = main.innerHTML;
}
async function fetchHtmlAsText(url) {
const response = await fetch(url);
return await response.text();
}
function clearContent(elementID) {
var div = document.getElementById(elementID);
while(div.firstChild) {
div.removeChild(div.lastChild);
}
}
\ No newline at end of file
......@@ -76,7 +76,7 @@ function LineChart(data, timeline_container, info_container, {
.on("pointerenter", pointerentered)
.on("pointermove", pointermoved)
.on("pointerleave", pointerleft)
.on("click", mouseclicked)
// .on("click", mouseclicked)
.on("touchstart", event => event.preventDefault());
svg.append("g")
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment