Commit a1ee423c authored by Porter Libby's avatar Porter Libby
Browse files
parents 09fc5e7c 9ff1701d
...@@ -15,6 +15,50 @@ The `public/js` folder contains all the client-side JS: ...@@ -15,6 +15,50 @@ The `public/js` folder contains all the client-side JS:
- **public / js / map.js** - handles creation of maps and points for the `map` view. Uses ARC GIS JS API. - **public / js / map.js** - handles creation of maps and points for the `map` view. Uses ARC GIS JS API.
- **public / js / util.js** - handles odd things, such as generation of `HTML` for the template, and disabling/enabling views. - **public / js / util.js** - handles odd things, such as generation of `HTML` for the template, and disabling/enabling views.
## Creating a new PSQL Query
The process of adding new server-side queries and allowing the client-side to access those functions, without providing access to the data, can be a little tricky. I have outlined the process I use here in the hopes that it will be helpful.
1. In `queries.js` create a new function to get information using a programmed query string. This should look something like the example below:
```js
...
const getSomething = (request, response) => {
var query = 'SELECT something from SOMETABLE;'
serverOut(query); // print the query text
pool.query(query, (error, results) => {
if (error) {
throw error // error from query string
}
response.status(200).json(results.rows) // return the results
})
}
module.exports = {
...
getSomething, // this must match the route in index.js
...
}
```
2. In `index.js`, create a route so that the client-side will be able to access the routes in `queries.js`. This should look something like this:
```js
app.get('/something', q.getSomething); // should match the name in module.exports
```
3. We can now access the route from client-side. For example, in the file `public/js/data.js`. This should look something like this:
```js
function getSomthing(){
$.ajax({
type: 'GET',
url: '/something', // should match the name in index.js
success: function(response) {
console.table(response); // show the full result
// a renderer could be made to use this data here
},
error: function(xhr, status, err) {
console.log(xhr.responseText); // if query fails
}
});
}
```
## HTML Template ## HTML Template
For style and `CSS` information, refer to the [ customization guide](CUSTOM.md). For style and `CSS` information, refer to the [ customization guide](CUSTOM.md).
HTML template exists in `views/index.ejs`. HTML template exists in `views/index.ejs`.
\ No newline at end of file
...@@ -68,7 +68,7 @@ h1 span{ ...@@ -68,7 +68,7 @@ h1 span{
} }
} }
.elem-1{ .elem-1{
background-color: var(--theme4); background-color: #aaa;
} }
.elem-0{ .elem-0{
background-color: var(--theme4); background-color: var(--theme4);
...@@ -275,9 +275,23 @@ label ...@@ -275,9 +275,23 @@ label
.data-catagory-simple .detailed_info{ .data-catagory-simple .detailed_info{
display: none; display: none;
} }
.data-catagory-simple .detailed_info_2{
display: none;
}
.data-catagory-detail .detailed_info{ .data-catagory-detail .detailed_info{
display: inline; display: inline;
} }
.data-catagory-detail .detailed_info_2{
display: none;
}
.data-catagory-detail-2 .detailed_info{
display: none;
}
.data-catagory-detail-2 .detailed_info_2{
display: inline;
}
.lds-ellipsis { .lds-ellipsis {
display: inline-block; display: inline-block;
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
var query_type = null; // 0 = reading, 1 = streaming var query_type = null; // 0 = reading, 1 = streaming
var query_selection = [null,null,null,null,null,null]; // trip, site, sector, spot/host, platform, date var query_selection = [null,null,null,null,null,null]; // trip, site, sector, spot/host, platform, date
var query_data = null; var query_data = null;
var details_mode = 0;
var placeholderHTML = "<div style='float: left; width: 100%; height: 100%; text-align:center; padding-top:20px;color: var(--themep)'>Organizing numbers...</div><div class='lds-ellipsis'><div></div><div></div><div></div><div></div></div>"; var placeholderHTML = "<div style='float: left; width: 100%; height: 100%; text-align:center; padding-top:20px;color: var(--themep)'>Organizing numbers...</div><div class='lds-ellipsis'><div></div><div></div><div></div><div></div></div>";
...@@ -26,14 +27,14 @@ This is the entry point so that both of these options in the descision tree can ...@@ -26,14 +27,14 @@ This is the entry point so that both of these options in the descision tree can
*/ */
function setReading(){ function setReading(){
query_type = 0; query_type = 0;
resetElements(['trips','sites','sectors','spots','streamingplatform','streamingdates','streaming','readingplatform','readingdates','reading']); resetElements(['trips','sites','sectors','spots','streaminghost','streamingplatform','streamingdates','streaming','readingplatform','readingdates','reading']);
document.getElementById("button_permalink").disabled = true; document.getElementById("button_permalink").disabled = true;
document.getElementById("button_csv").disabled = true; document.getElementById("button_csv").disabled = true;
getTrips(); // get top level of data and render to the next block on the form getTrips(); // get top level of data and render to the next block on the form
} }
function setStreaming(){ function setStreaming(){
query_type = 1; query_type = 1;
resetElements(['trips','sites','sectors','spots','streamingplatform','streamingdates','streaming','readingplatform','readingdates','reading']); resetElements(['trips','sites','sectors','spots','streaminghost','streamingplatform','streamingdates','streaming','readingplatform','readingdates','reading']);
document.getElementById("button_permalink").disabled = true; document.getElementById("button_permalink").disabled = true;
document.getElementById("button_csv").disabled = true; document.getElementById("button_csv").disabled = true;
getTrips(); // get top level of data and render to the next block on the form getTrips(); // get top level of data and render to the next block on the form
...@@ -64,13 +65,17 @@ function getTrips(){ ...@@ -64,13 +65,17 @@ function getTrips(){
success: function(response) { success: function(response) {
var tripnames = []; var tripnames = [];
var tripids = []; var tripids = [];
var r_count = [];
var s_count = [];
for(x = 0; x < response.length; x++){ for(x = 0; x < response.length; x++){
tripids.push(response[x].tripid); tripids.push(response[x].tripid);
tripnames.push(response[x].tripname); tripnames.push(response[x].tripname);
r_count.push(response[x].r_count);
s_count.push(response[x].s_count);
} }
console.info('TRIPS'); console.info('TRIPS');
console.table(response); console.table(response);
renderTrips(tripnames, tripids); renderTrips(tripnames, tripids, r_count, s_count);
}, },
error: function(xhr, status, err) { error: function(xhr, status, err) {
console.log(xhr.responseText); console.log(xhr.responseText);
...@@ -98,13 +103,17 @@ function getSites(trip_id){ ...@@ -98,13 +103,17 @@ function getSites(trip_id){
success: function(response) { success: function(response) {
var sitenames = []; var sitenames = [];
var siteids = []; var siteids = [];
var r_count = [];
var s_count = [];
for(x = 0; x < response.length; x++){ for(x = 0; x < response.length; x++){
sitenames.push(response[x].sitename); sitenames.push(response[x].sitename);
siteids.push(response[x].siteid); siteids.push(response[x].siteid);
r_count.push(response[x].r_count);
s_count.push(response[x].s_count);
} }
console.info('SITES'); console.info('SITES');
console.table(response); console.table(response);
renderSites(sitenames, siteids); renderSites(sitenames, siteids, r_count, s_count);
}, },
error: function(xhr, status, err) { error: function(xhr, status, err) {
console.log(xhr.responseText); console.log(xhr.responseText);
...@@ -132,13 +141,17 @@ function getSectors(site_id){ ...@@ -132,13 +141,17 @@ function getSectors(site_id){
success: function(response) { success: function(response) {
var sectornames = []; var sectornames = [];
var sectorids = []; var sectorids = [];
var r_count = [];
var s_count = [];
for(x = 0; x < response.length; x++){ for(x = 0; x < response.length; x++){
sectornames.push(response[x].sectorname); sectornames.push(response[x].sectorname);
sectorids.push(response[x].sectorid); sectorids.push(response[x].sectorid);
r_count.push(response[x].r_count);
s_count.push(response[x].s_count);
} }
console.info('SECTORS'); console.info('SECTORS');
console.table(response); console.table(response);
renderSectors(sectornames, sectorids); renderSectors(sectornames, sectorids, r_count, s_count);
}, },
error: function(xhr, status, err) { error: function(xhr, status, err) {
console.log(xhr.responseText); console.log(xhr.responseText);
...@@ -166,12 +179,16 @@ function getSpots(sector_id){ ...@@ -166,12 +179,16 @@ function getSpots(sector_id){
data: {sectorid: sector_id, siteid: query_selection[1], tripid: query_selection[0]}, data: {sectorid: sector_id, siteid: query_selection[1], tripid: query_selection[0]},
success: function(response) { success: function(response) {
var spotids = []; var spotids = [];
var r_count = [];
var s_count = [];
for(x = 0; x < response.length; x++){ for(x = 0; x < response.length; x++){
spotids.push(response[x].spotid); spotids.push(response[x].spotid);
r_count.push(response[x].r_count);
s_count.push(response[x].s_count);
} }
console.info('SPOTS'); console.info('SPOTS');
console.table(response); console.table(response);
renderSpots(spotids); renderSpots(spotids, r_count, s_count);
}, },
error: function(xhr, status, err) { error: function(xhr, status, err) {
console.log(xhr.responseText); console.log(xhr.responseText);
...@@ -313,12 +330,14 @@ function getStreamingsHosts(sector_id){ ...@@ -313,12 +330,14 @@ function getStreamingsHosts(sector_id){
data: {sectorid: sector_id, siteid: query_selection[1], tripid: query_selection[0]}, data: {sectorid: sector_id, siteid: query_selection[1], tripid: query_selection[0]},
success: function(response) { success: function(response) {
var hosts = []; var hosts = [];
var s_count = [];
for(x = 0; x < response.length; x++){ for(x = 0; x < response.length; x++){
hosts.push(response[x]); hosts.push(response[x]);
s_count.push(response[x].s_count)
} }
console.info('DATA - HOSTS'); console.info('DATA - HOSTS');
console.table(response); console.table(response);
renderStreamingsHosts(hosts); renderStreamingsHosts(hosts, s_count);
}, },
error: function(xhr, status, err) { error: function(xhr, status, err) {
console.log(xhr.responseText); console.log(xhr.responseText);
...@@ -445,7 +464,7 @@ to create a radiobutton. ...@@ -445,7 +464,7 @@ to create a radiobutton.
When a get function returns its data, it sends it to a render function if it needs to be selected from. When a get function returns its data, it sends it to a render function if it needs to be selected from.
*/ */
function renderTrips(tripnames, tripids){ function renderTrips(tripnames, tripids, r_count, s_count){
var container = document.getElementById('trips'); var container = document.getElementById('trips');
container.innerHTML = ''; container.innerHTML = '';
if (container.childElementCount == 0){ // dont override selections with navigation if (container.childElementCount == 0){ // dont override selections with navigation
...@@ -454,13 +473,13 @@ function renderTrips(tripnames, tripids){ ...@@ -454,13 +473,13 @@ function renderTrips(tripnames, tripids){
trips_ls.id = 'trips-ls'; trips_ls.id = 'trips-ls';
for(x = 0; x < tripnames.length; x++){ for(x = 0; x < tripnames.length; x++){
var elem = createRadioElementTrips((x % 2),'trips', false, tripnames[x],tripids[x]); // util function var elem = createRadioElementTrips((x % 2),'trips', [r_count[x], s_count[x]], tripnames[x],tripids[x]); // util function
trips_ls.innerHTML += elem; trips_ls.innerHTML += elem;
} }
container.append(trips_ls); container.append(trips_ls);
} }
} }
function renderSites(sitenames, siteids){ function renderSites(sitenames, siteids, r_count, s_count){
var container = document.getElementById('sites'); var container = document.getElementById('sites');
container.innerHTML = ""; container.innerHTML = "";
container.innerHTML += "<div onclick='togglediv(" + '"#sites-ls","sites-button"' + ")' class='data-header'><h1>Sites <span id='sites-button'>-</span></h1></div>"; container.innerHTML += "<div onclick='togglediv(" + '"#sites-ls","sites-button"' + ")' class='data-header'><h1>Sites <span id='sites-button'>-</span></h1></div>";
...@@ -468,12 +487,12 @@ function renderSites(sitenames, siteids){ ...@@ -468,12 +487,12 @@ function renderSites(sitenames, siteids){
sites_ls.id = 'sites-ls'; sites_ls.id = 'sites-ls';
for(x = 0; x < sitenames.length; x++){ for(x = 0; x < sitenames.length; x++){
var elem = createRadioElementSites((x % 2),'sites', false, sitenames[x],siteids[x]); // util function var elem = createRadioElementSites((x % 2),'sites', [r_count[x], s_count[x]], sitenames[x],siteids[x]); // util function
sites_ls.innerHTML += elem; sites_ls.innerHTML += elem;
} }
container.append(sites_ls); container.append(sites_ls);
} }
function renderSectors(sectornames, sectorids){ function renderSectors(sectornames, sectorids, r_count, s_count){
var container = document.getElementById('sectors'); var container = document.getElementById('sectors');
container.innerHTML = ""; container.innerHTML = "";
...@@ -483,7 +502,7 @@ function renderSectors(sectornames, sectorids){ ...@@ -483,7 +502,7 @@ function renderSectors(sectornames, sectorids){
sectors_ls.id = 'sectors-ls'; sectors_ls.id = 'sectors-ls';
for(x = 0; x < sectornames.length; x++){ for(x = 0; x < sectornames.length; x++){
var elem = createRadioElementSectors((x % 2),'sectors', false, sectornames[x], sectorids[x]); // util function var elem = createRadioElementSectors((x % 2),'sectors', [r_count[x], s_count[x]], sectornames[x], sectorids[x]); // util function
sectors_ls.innerHTML += elem; sectors_ls.innerHTML += elem;
} }
container.append(sectors_ls); container.append(sectors_ls);
...@@ -493,7 +512,7 @@ function renderSectors(sectornames, sectorids){ ...@@ -493,7 +512,7 @@ function renderSectors(sectornames, sectorids){
} }
function renderSpots(spotids){ function renderSpots(spotids, r_count, s_count){
var container = document.getElementById('spots'); var container = document.getElementById('spots');
container.innerHTML = ""; container.innerHTML = "";
if (spotids.length != 0){ if (spotids.length != 0){
...@@ -502,7 +521,7 @@ function renderSpots(spotids){ ...@@ -502,7 +521,7 @@ function renderSpots(spotids){
spots_ls.id = 'spots-ls'; spots_ls.id = 'spots-ls';
for(x = 0; x < spotids.length; x++){ for(x = 0; x < spotids.length; x++){
var elem = createRadioElementSpots((x % 2),'spots', false, spotids[x], spotids[x]); // util function var elem = createRadioElementSpots((x % 2),'spots', [r_count[x], s_count[x]], spotids[x], spotids[x]); // util function
spots_ls.innerHTML += elem; spots_ls.innerHTML += elem;
} }
container.append(spots_ls); container.append(spots_ls);
...@@ -510,7 +529,7 @@ function renderSpots(spotids){ ...@@ -510,7 +529,7 @@ function renderSpots(spotids){
document.getElementById('data-prompt').innerHTML = "No Spots found for this sector" document.getElementById('data-prompt').innerHTML = "No Spots found for this sector"
} }
} }
function renderStreamingsHosts(hosts){ function renderStreamingsHosts(hosts,s_count){
if (streamings.length != 0){ if (streamings.length != 0){
var container = document.getElementById('streaminghost'); var container = document.getElementById('streaminghost');
container.innerHTML = ""; container.innerHTML = "";
...@@ -522,7 +541,7 @@ function renderStreamingsHosts(hosts){ ...@@ -522,7 +541,7 @@ function renderStreamingsHosts(hosts){
if (hosts[x].hostname){ if (hosts[x].hostname){
hostname = hosts[x].hostname.toString() hostname = hosts[x].hostname.toString()
} }
var elem = createRadioElementStreamingsHosts((x % 2),'hosts', false, hosts[x].hostid, hostname ); // util function var elem = createRadioElementStreamingsHosts((x % 2),'hosts', s_count[x], hosts[x].hostid, hostname ); // util function
streamingshosts_ls.innerHTML += elem; streamingshosts_ls.innerHTML += elem;
} }
container.append(streamingshosts_ls); container.append(streamingshosts_ls);
......
...@@ -45,8 +45,15 @@ function switchToData(){ ...@@ -45,8 +45,15 @@ function switchToData(){
// TEAMPLATES FOR DOM PIECES // TEAMPLATES FOR DOM PIECES
// generalized formula // generalized formula
function createRadioElement(name, id, label, f){ function createRadioElement(name, id, label, f, count=999){
var radioHtml = '<div class="elem-div elem-0">'
var radioHtml = '<div class="elem-div elem-'
if (count == 0){
radioHtml += "1"
}else{
radioHtml += "0"
}
radioHtml += '">';
if (typeof id === 'string' || id instanceof String){ if (typeof id === 'string' || id instanceof String){
radioHtml += '<input class="data-radio form-radio" onchange="'+ f +'('; radioHtml += '<input class="data-radio form-radio" onchange="'+ f +'(';
radioHtml += "'" + id + "'"; radioHtml += "'" + id + "'";
...@@ -56,6 +63,7 @@ function createRadioElement(name, id, label, f){ ...@@ -56,6 +63,7 @@ function createRadioElement(name, id, label, f){
} }
radioHtml += '<label for="' + label + '">'; radioHtml += '<label for="' + label + '">';
radioHtml += '<strong>'+ label + "</strong>"; radioHtml += '<strong>'+ label + "</strong>";
radioHtml += '<span class="detailed_info_2"> (' + count +' values)</span>';
radioHtml += '<span class="detailed_info"> (ID: ' + id +')</span>'; radioHtml += '<span class="detailed_info"> (ID: ' + id +')</span>';
radioHtml += '</label></div>'; radioHtml += '</label></div>';
...@@ -63,27 +71,34 @@ function createRadioElement(name, id, label, f){ ...@@ -63,27 +71,34 @@ function createRadioElement(name, id, label, f){
} }
// take information from data.js and write it into html // take information from data.js and write it into html
function createRadioElementTrips( mode, name, checked, label, id ) { function createRadioElementTrips( mode, name, count, label, id ) {
var f = "getSites"; var f = "getSites";
return createRadioElement(name, id, label, f); return createRadioElement(name, id, label, f, count[query_type]);
} }
function createRadioElementSites( mode, name, checked, label, id ) { function createRadioElementSites( mode, name, count, label, id ) {
var f = "getSectors"; var f = "getSectors";
return createRadioElement(name, id, label, f); return createRadioElement(name, id, label, f, count[query_type]);
} }
// this one is different since it changes for reading and streaming // this one is different since it changes for reading and streaming
function createRadioElementSectors( mode, name, checked, label, id ) { function createRadioElementSectors( mode, name, count, label, id ) {
var f = "getSpots"; // if reading var f = "getSpots"; // if reading
if (query_type == 1){ // if streaming if (query_type == 1){ // if streaming
f = "getStreamingsHosts"; f = "getStreamingsHosts";
} }
return createRadioElement(name, id, label, f); return createRadioElement(name, id, label, f, count[query_type]);
} }
function createRadioElementSpots( mode, name, checked, label,id ) { function createRadioElementSpots( mode, name, count, label,id ) {
var f = "getReadings"; var f = "getReadings";
var radioHtml = '<div class="elem-div elem-';
//return createRadioElement(name, id, label, f); //return createRadioElement(name, id, label, f);
var radioHtml = '<div class="elem-div elem-0">' if (count == 0){
radioHtml += '1">';
}else{
radioHtml += '0">';
}
if (typeof id === 'string' || id instanceof String){ if (typeof id === 'string' || id instanceof String){
radioHtml += '<input class="data-radio form-check" onchange="'+ f +'('; radioHtml += '<input class="data-radio form-check" onchange="'+ f +'(';
radioHtml += "'" + id + "'"; radioHtml += "'" + id + "'";
...@@ -94,13 +109,14 @@ function createRadioElementSpots( mode, name, checked, label,id ) { ...@@ -94,13 +109,14 @@ function createRadioElementSpots( mode, name, checked, label,id ) {
radioHtml += '<label for="' + label + '">'; radioHtml += '<label for="' + label + '">';
radioHtml += '<strong>'+ label + "</strong>"; radioHtml += '<strong>'+ label + "</strong>";
radioHtml += '<span class="detailed_info"> (ID: ' + id +')</span>'; radioHtml += '<span class="detailed_info"> (ID: ' + id +')</span>';
radioHtml += '<span class="detailed_info_2"> (' + count[query_type] +' values)</span>';
radioHtml += '</label></div>'; radioHtml += '</label></div>';
return radioHtml; return radioHtml;
} }
function createRadioElementStreamingsHosts( mode, name, checked, id, label ) { function createRadioElementStreamingsHosts( mode, name, count, id, label ) {
var f = "getStreamingsPlatforms"; var f = "getStreamingsPlatforms";
return createRadioElement(name, id, label, f); return createRadioElement(name, id, label, f, count);
} }
function createRadioElementStreamingsPlatforms( mode, name, checked, id, label ) { function createRadioElementStreamingsPlatforms( mode, name, checked, id, label ) {
var f = "getStreamingsDates"; var f = "getStreamingsDates";
...@@ -259,19 +275,30 @@ function removeQuery(){ ...@@ -259,19 +275,30 @@ function removeQuery(){
base = current.split('?')[0]; base = current.split('?')[0];
location.replace(base); location.replace(base);
} }
function toggleDetails(){ function toggleDetails(){ // details_mode located in data.js
console.log('bruh')
console.log(details_mode)
var all = document.getElementsByClassName('data-catagory'); var all = document.getElementsByClassName('data-catagory');
console.log(all)
for (var i = 0; i < all.length; i++) { for (var i = 0; i < all.length; i++) {
if (all[i].classList.contains('data-catagory-simple')){ if (details_mode == 0){
all[i].classList.remove('data-catagory-simple'); all[i].classList.remove('data-catagory-simple');
all[i].classList.add('data-catagory-detail'); all[i].classList.add('data-catagory-detail');
$("#button_details").css("opacity", "1.0"); $("#button_details").css("opacity", "1.0");
}else{ }else if (details_mode == 1){
all[i].classList.add('data-catagory-simple');
all[i].classList.remove('data-catagory-detail'); all[i].classList.remove('data-catagory-detail');
all[i].classList.add('data-catagory-detail-2');
$("#button_details").css("opacity", "1.0");
}else {
all[i].classList.remove('data-catagory-detail-2');
all[i].classList.add('data-catagory-simple');
$("#button_details").css("opacity", "0.5"); $("#button_details").css("opacity", "0.5");
} }
} }
details_mode = (details_mode + 1) % 3;
} }
function createCSV(){ function createCSV(){
const rows = [["tripid","platformid","sensorid","hostid","recordtime","value_1","quality","latitude","longitude","elevation","accuracy","satellites","value_2","value_3","siteid","sectorid","value_4","value_5","value_6"]]; const rows = [["tripid","platformid","sensorid","hostid","recordtime","value_1","quality","latitude","longitude","elevation","accuracy","satellites","value_2","value_3","siteid","sectorid","value_4","value_5","value_6"]];
......
...@@ -23,7 +23,10 @@ const pool = new Pool({ ...@@ -23,7 +23,10 @@ const pool = new Pool({
}) })
const getTrips = (request, response) => { const getTrips = (request, response) => {
var query = "SELECT tripName, tripID from fieldday_trip;"; var query = "SELECT tripName, tripID, "
+ "(SELECT COUNT(*) FROM fieldday_streaming WHERE tripid=fieldday_trip.tripid) AS s_count, " // get s_count and r_count as the number of nodes in the subtree of each
+ "(SELECT COUNT(*) FROM fieldday_reading WHERE tripid=fieldday_trip.tripid) AS r_count"
+ " from fieldday_trip;";
serverOut(query); serverOut(query);
pool.query(query, (error, results) => { pool.query(query, (error, results) => {
...@@ -34,7 +37,10 @@ const getTrips = (request, response) => { ...@@ -34,7 +37,10 @@ const getTrips = (request, response) => {
}) })
} }
const getSites = (request, response) => { const getSites = (request, response) => {
var query = 'SELECT siteName, siteID from fieldday_site where tripid='+ (request.query.id) + ';'; var query = 'SELECT siteName, siteID, '
+ "(SELECT COUNT(*) FROM fieldday_streaming WHERE tripid="+ (request.query.id) +" AND siteid=fieldday_site.siteid) AS s_count, " // get s_count and r_count as the number of nodes in the subtree of each
+ "(SELECT COUNT(*) FROM fieldday_reading WHERE tripid="+ (request.query.id) +" AND siteid=fieldday_site.siteid) AS r_count"
+' from fieldday_site where tripid='+ (request.query.id) + ';';