Commit 4c90d4ea authored by Porter Libby's avatar Porter Libby
Browse files

Merge branch 'master' into dev

parents 008b984a 1b951f88
# DATAVIS TOOL 2.0 # DATAVIS TOOL 2
Porter Libby
[![GitHub issues](https://img.shields.io/github/issues/probably-not-porter/datavis)](https://github.com/probably-not-porter/datavis/issues) [![GitHub issues](https://img.shields.io/github/issues/probably-not-porter/datavis)](https://github.com/probably-not-porter/datavis/issues)
[![GitHub license](https://img.shields.io/github/license/probably-not-porter/datavis)](https://github.com/probably-not-porter/datavis/blob/master/LICENSE) [![GitHub license](https://img.shields.io/github/license/probably-not-porter/datavis)](https://github.com/probably-not-porter/datavis/blob/master/LICENSE)
![GitHub repo size](https://img.shields.io/github/repo-size/probably-not-porter/datavis)
A visualization tool for the IFS database using Node.js and the ArcGIS api. Uses queries to fetch data from the Earlham Field Science database and show that data in a graph format, as well as a map format. The goal of this application is to be useful for both information purposes, as well as for field work purposes. This requires that the app be usable on an android device, so that field data can be visualized in real time, but the tool must also be user-friendly enough that someone unfamiliar with the work could use it to look at data from a particular IFS trip.
## Usage
This app is set up to be usable on both mobile and desktop platforms. Keep in mind that whatever machine is hosting the Node server might need to be connected to the same network that your Database is set up on.
A visualization tool for the IFS database using Node.js and the ArcGIS api. Uses queries to fetch data from the Earlham Field Science database and show that data in a graph format, as well as a map format. It is possible to have the database and this tool running on the same machine, which would allow users to access the front-end of the tool from either the device running both programs, or any device connected to the same LAN as the host device.
## Running Locally First, the <strong>Data view</strong> will open, which can be used to select a specific set of data to view. Once a selection has been made, the user has the option to create a <strong>permalink</strong>, which can be used to return to the same query again, or <strong>export a .csv file</strong> of the data selected, which can be used with a few other processing tools. Once a selection is complete, the <strong>Graph View</strong> and <strong>Map view</strong> will light up to show the user that there is new data to be viewed.
This app is set up to be usable on both mobile and desktop platforms.
### Desktop Usage
### Desktop Setup
1. clone repository and enter parent directory 1. clone repository and enter parent directory
2. Follow the format below to create a `.env` file. 2. Follow the format below to create a `.env` file.
3. use `npm install` to add dependencies to node_modules folder 3. use `npm install` to add dependencies to node_modules folder
4. use `node index.js` to start a local development server 4. use `node index.js` to start a local development server
5. open `localhost:3000` in your favorite browser! 5. open `localhost:3000` in your favorite browser!
### Mobile Usage ### Mobile Setup
1. Install a UNIX terminal emulator like [Termux (Android)](https://play.google.com/store/apps/details?id=com.termux&hl=en_US). 1. Install a UNIX terminal emulator like [Termux (Android)](https://play.google.com/store/apps/details?id=com.termux&hl=en_US).
2. Install some basic tools in the emulator: 2. Install some basic tools in the emulator:
a. ```pkg install git``` 1. ```pkg install git```
b. ```pkg install nodejs``` 2. ```pkg install nodejs```
c. ```pkg install nano``` 3. ```pkg install nano```
4. clone the repository. 4. clone the repository.
3. Follow the format below to create a `.env` file. 3. Follow the format below to create a `.env` file.
4. Use `npm install` inside the directory to install dependencies. 4. Use `npm install` inside the directory to install dependencies.
5. Use `node index.js` to run the server. 5. Use `node index.js` to run the server.
6. open `localhost:3000` in your browser. 6. open `localhost:3000` in your browser.
## .env file should look like: ## Format template for .env file
``` ```
DB_NAME=[database user name] DB_NAME=[database user name]
DB_HOST=[database host name] DB_HOST=[database host name]
...@@ -34,8 +45,10 @@ DB_PASSWORD=[databse password] ...@@ -34,8 +45,10 @@ DB_PASSWORD=[databse password]
DB_PORT=[database port] DB_PORT=[database port]
``` ```
## Dependencies ## Node Dependencies
- "ejs": "^2.7.1", - dotenv@^8.1.0
- "express": "^4.17.1", - ejs@ ^2.7.1
- "restful-api": "^0.1.8" - express@^4.17.1
- pg@^7.12.1
- restful-api@^0.1.8
const express = require('express'); const express = require('express');
const app = express(); const app = express();
const q = require('./queries'); const q = require('./queries');
...@@ -20,7 +19,10 @@ app.get('/sites', q.getSites); ...@@ -20,7 +19,10 @@ app.get('/sites', q.getSites);
app.get('/sectors', q.getSectors); app.get('/sectors', q.getSectors);
app.get('/spots', q.getSpots); app.get('/spots', q.getSpots);
app.get('/readings', q.getReadings); app.get('/readings', q.getReadings);
app.get('/streamingsplatforms', q.getStreamingsPlatforms);
app.get('/streamingsdates', q.getStreamingsDates);
app.get('/streamings', q.getStreamings); app.get('/streamings', q.getStreamings);
////////// //////////
......
...@@ -3,17 +3,19 @@ ...@@ -3,17 +3,19 @@
margin: 0; margin: 0;
height: 100%; height: 100%;
width: 100%; width: 100%;
font-family: 'Open Sans', sans-serif;
position: absolute;
} }
#data{ #data{
margin-top: 100px; margin-top: 120px;
text-align: center; text-align: center;
margin-bottom: 100px; padding-bottom: 100px;
} }
h1{ h1{
font-size: 20px; font-size: 20px;
} }
h1 span{ h1 span{
color: gray; color: var(--themeh);
text-align: right; text-align: right;
} }
.data-catagory{ .data-catagory{
...@@ -22,11 +24,17 @@ h1 span{ ...@@ -22,11 +24,17 @@ h1 span{
max-width: 90%; max-width: 90%;
margin: 0px auto; margin: 0px auto;
cursor: pointer; cursor: pointer;
background-color: #eee; background-color: var(--theme3);
color: var(--themeh);
border-radius: 3px; border-radius: 3px;
margin-bottom: 10px;
-webkit-box-shadow: 10px 10px 5px -6px rgba(0,0,0,0.1);
-moz-box-shadow: 10px 10px 5px -6px rgba(0,0,0,0.1);
box-shadow: 10px 10px 5px -6px rgba(0,0,0,0.1);
} }
.data-header{ .data-header{
background-color: #ddd; background-color: var(--theme2);
color: var(--themeh);
padding-top: 3px; padding-top: 3px;
padding-bottom: 3px; padding-bottom: 3px;
width: 100%; width: 100%;
...@@ -36,7 +44,6 @@ h1 span{ ...@@ -36,7 +44,6 @@ h1 span{
border-top-right-radius: 3px; border-top-right-radius: 3px;
} }
.elem-div{ .elem-div{
margin-top: 10px;
max-width: 40%; max-width: 40%;
width: 300px; width: 300px;
display: inline-block; display: inline-block;
...@@ -44,7 +51,9 @@ h1 span{ ...@@ -44,7 +51,9 @@ h1 span{
border-radius: 3px; border-radius: 3px;
padding-left: 30px; padding-left: 30px;
text-align: left; text-align: left;
margin: 1%; margin-bottom:10px;
margin-left: 5px;
margin-right: 5px;
} }
@media only screen and (max-width: 800px) { @media only screen and (max-width: 800px) {
.elem-div{ .elem-div{
...@@ -53,17 +62,19 @@ h1 span{ ...@@ -53,17 +62,19 @@ h1 span{
} }
} }
.elem-1{ .elem-1{
background-color: #ccc; background-color: var(--theme4);
} }
.elem-0{ .elem-0{
background-color: #ccc; background-color: var(--theme4);
} }
input[type="radio"]:checked+label{ input[type="radio"]:checked+label{
font-weight: bold; font-weight: bold;
text-decoration: underline; text-decoration: underline;
} }
input[type="radio"]:checked{ input[type="radio"]:checked{
background-color: #cbf7cb; background-color: white;
color: green;
font-size: 20px;
} }
.form-radio .form-radio
{ {
...@@ -73,7 +84,7 @@ input[type="radio"]:checked{ ...@@ -73,7 +84,7 @@ input[type="radio"]:checked{
display: inline-block; display: inline-block;
position: relative; position: relative;
background-color: #f1f1f1; background-color: #f1f1f1;
color: #666; color: var(--themeh);
top: 10px; top: 10px;
height: 30px; height: 30px;
width: 30px; width: 30px;
...@@ -94,7 +105,7 @@ input[type="radio"]:checked{ ...@@ -94,7 +105,7 @@ input[type="radio"]:checked{
} }
.form-radio:hover .form-radio:hover
{ {
background-color: #f7f7f7; background-color: var(--theme4);
} }
.form-radio:checked .form-radio:checked
{ {
...@@ -103,53 +114,155 @@ input[type="radio"]:checked{ ...@@ -103,53 +114,155 @@ input[type="radio"]:checked{
label label
{ {
font: 15px/1.7 'Open Sans', sans-serif; font: 15px/1.7 'Open Sans', sans-serif;
color: #333; color: var(--themep);
-webkit-font-smoothing: antialiased; -webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale; -moz-osx-font-smoothing: grayscale;
cursor: pointer; cursor: pointer;
} }
#data-prompt-box{ #data-prompt-box{
background-color: #888; background-color: var(--theme1);
color: white; color: var(--theme1);
position: fixed; position: fixed;
bottom: 0px; bottom: 0px;
padding-top: 30px; padding-top: 30px;
padding-bottom: 30px; padding-bottom: 30px;
width: 100%; width: 100%;
height: 40px;
}
#data-prompt-box #text{
height: 20px;
width: 100%;
}
#data-prompt-box #buttons{
text-align: left;
background-color: var(--theme1);
width: 100%;
height: 20px;
} }
#data-prompt{ #data-prompt{
transition-duration: 1s; transition-duration: 1s;
} }
#prompt-text #data-prompt{
background: -webkit-linear-gradient(white,lightgray);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
font-size: 17px;
}
#button_permalink{
margin-left: 20px;
position: absolute;
bottom:0px;
color: gray;
font-size: 20px;
background-color: #ddd;
opacity:1.0;
border-top-right-radius: 10px;
border-top-left-radius: 10px;
padding: 5px;
}
#button_permalink:disabled
{
background-color: #999;
opacity:0.1;
}
#button_permalink:hover{
background-color: #bbb;
}
#button_csv{
margin-left: 20px;
position: absolute;
bottom:0px;
color: gray;
font-size: 20px;
background-color: #ddd;
opacity:1.0;
border-top-right-radius: 10px;
border-top-left-radius: 10px;
padding: 5px;
}
#button_csv:disabled
{
background-color: #999;
opacity:0.1;
}
#button_csv:hover{
background-color: #bbb;
}
#button_details{
margin-left: 20px;
position: absolute;
bottom:0px;
color: gray;
font-size: 20px;
background-color: #ddd;
opacity:0.5;
border-top-right-radius: 10px;
border-top-left-radius: 10px;
padding: 5px;
}
#button_details:hover{
background-color: #bbb;
}
.data-catagory-simple .detailed_info{
display: none;
}
.data-catagory-detail .detailed_info{
display: inline;
}
.lds-hourglass { .lds-ellipsis {
display: inline-block; display: inline-block;
position: relative; position: relative;
width: 64px; width: 64px;
height: 64px; height: 64px;
} }
.lds-hourglass:after { .lds-ellipsis div {
content: " "; position: absolute;
display: block; top: 27px;
width: 11px;
height: 11px;
border-radius: 50%; border-radius: 50%;
width: 0; background: #000;
height: 0; animation-timing-function: cubic-bezier(0, 1, 1, 0);
margin: 6px; }
box-sizing: border-box; .lds-ellipsis div:nth-child(1) {
border: 26px solid #fff; left: 6px;
border-color: #fff transparent #fff transparent; animation: lds-ellipsis1 0.6s infinite;
animation: lds-hourglass 1.2s infinite; }
.lds-ellipsis div:nth-child(2) {
left: 6px;
animation: lds-ellipsis2 0.6s infinite;
}
.lds-ellipsis div:nth-child(3) {
left: 26px;
animation: lds-ellipsis2 0.6s infinite;
} }
@keyframes lds-hourglass { .lds-ellipsis div:nth-child(4) {
left: 45px;
animation: lds-ellipsis3 0.6s infinite;
}
@keyframes lds-ellipsis1 {
0% { 0% {
transform: rotate(0); transform: scale(0);
animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19); }
100% {
transform: scale(1);
} }
50% { }
transform: rotate(900deg); @keyframes lds-ellipsis3 {
animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1); 0% {
transform: scale(1);
} }
100% { 100% {
transform: rotate(1800deg); transform: scale(0);
} }
} }
\ No newline at end of file @keyframes lds-ellipsis2 {
0% {
transform: translate(0, 0);
}
100% {
transform: translate(19px, 0);
}
}
#graphView{ #graphView{
padding: 0; padding: 0;
margin: 0; margin: 0;
height: 100%; height: 100vh;
padding-top: 0vh;
width: 100%; width: 100%;
} }
@media only screen and (max-width: 800px) {
#graphView{
height: 90vh;
padding-top: 10vh;
}
}
#graph{ #graph{
width: 100%; width: 100%;
height: 100%; height: 100%;
......
:root {
/*
These are the themes for the program. Modifying these here should affect the color scheme of the whole tool
*/
--datacolor1: #1D976C;
--datacolor2:#93F9B9;
--theme1: #444;
--theme2: #888;
--theme3: #bbb;
--theme4: #ddd;
--themeh: white;
--themep: black;
}
html, body, #viewDiv{ html, body, #viewDiv{
padding: 0; padding: 0;
margin: 0; margin: 0;
...@@ -7,7 +22,7 @@ html, body, #viewDiv{ ...@@ -7,7 +22,7 @@ html, body, #viewDiv{
#navcontrols{ #navcontrols{
width: 200px; width: 200px;
height: 200px; height: 75px;
margin-left: 12px; margin-left: 12px;
margin-top: 10px; margin-top: 10px;
display:block; display:block;
...@@ -19,19 +34,127 @@ html, body, #viewDiv{ ...@@ -19,19 +34,127 @@ html, body, #viewDiv{
bottom:0; bottom:0;
text-align: center; text-align: center;
} }
#nav-view-button{ .nav-view-button{
vertical-align: top; vertical-align: top;
padding: 10px; padding: 10px;
margin-top: 0px; margin-top: 0px;
border-radius: 10px; border-radius: 10px;
border: 1px solid black border: 1px solid var(--theme2);
-webkit-box-shadow: 10px 10px 5px -4px rgba(0,0,0,0.35);
-moz-box-shadow: 10px 10px 5px -4px rgba(0,0,0,0.35);
box-shadow: 10px 10px 5px -4px rgba(0,0,0,0.35);
} }
#nav-view-button:hover{ .nav-view-button:hover{
background-color: lightgray; background-color: var(--theme3);
} }
.nav-button-idle{ .nav-button-idle{
background-color: white; background-color: var(--theme4);
} }
.nav-button-select{ .nav-button-select{
background-color: gray; background-color: var(--theme2);
}
#loading{
width: 100vw;
height: 100vh;
float:left;
position: fixed;
text-align: center;
z-index:12;
background-color: rgba(255,255,255,0.7);
top:0px;
}
.tooltip {
position: relative;
display: inline-block;
}
.tooltip .tooltiptext {
visibility: hidden;
background-color: rgba(0,0,0,0.4);
color: #fff;
text-align: center;
border-radius: 6px;
padding: 5px 5px;
width: 150px;
margin-left: 65px;
margin-top: -40px;
/* Position the tooltip */
position: absolute;
z-index: 4;
}
.tooltip:hover .tooltiptext {
visibility: initial;
} }
.tooltip2 {
position: relative;
display: inline-block;
}
.tooltip2 .tooltiptext {
visibility: hidden;
background-color: rgba(0,0,0,0.4);
color: #fff;
text-align: center;
border-radius: 6px;
padding: 5px 5px;
width: 150px;
margin-left: -162px;
margin-top: 25px;
/* Position the tooltip */
position: absolute;
z-index: 4;
}
.tooltip2:hover .tooltiptext {
visibility: initial;
}
@media only screen and (max-width: 800px) {
.tooltip .tooltiptext{
visibility: hidden;
}
.tooltip:hover .tooltiptext{
visibility: hidden;
}
.tooltip2 .tooltiptext{
visibility: hidden;
}
.tooltip2:hover .tooltiptext{
visibility: hidden;
}
}
.new_data_button {
color: #FFFFFF;
cursor: pointer;
display: inline-block;
-webkit-animation: glowing 1500ms infinite;
-moz-animation: glowing 1500ms infinite;
-o-animation: glowing 1500ms infinite;
animation: glowing 1500ms infinite;