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 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
This app is set up to be usable on both mobile and desktop platforms.
### Desktop Usage
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.
### Desktop Setup
1. clone repository and enter parent directory
2. Follow the format below to create a `.env` file.
3. use `npm install` to add dependencies to node_modules folder
4. use `node index.js` to start a local development server
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).
2. Install some basic tools in the emulator:
a. ```pkg install git```
b. ```pkg install nodejs```
c. ```pkg install nano```
1. ```pkg install git```
2. ```pkg install nodejs```
3. ```pkg install nano```
4. clone the repository.
3. Follow the format below to create a `.env` file.
4. Use `npm install` inside the directory to install dependencies.
5. Use `node index.js` to run the server.
6. open `localhost:3000` in your browser.
## .env file should look like:
## Format template for .env file
```
DB_NAME=[database user name]
DB_HOST=[database host name]
......@@ -34,8 +45,10 @@ DB_PASSWORD=[databse password]
DB_PORT=[database port]
```
## Dependencies
- "ejs": "^2.7.1",
- "express": "^4.17.1",
- "restful-api": "^0.1.8"
## Node Dependencies
- dotenv@^8.1.0
- ejs@ ^2.7.1
- express@^4.17.1
- pg@^7.12.1
- restful-api@^0.1.8
const express = require('express');
const app = express();
const q = require('./queries');
......@@ -20,7 +19,10 @@ app.get('/sites', q.getSites);
app.get('/sectors', q.getSectors);
app.get('/spots', q.getSpots);
app.get('/readings', q.getReadings);
app.get('/streamingsplatforms', q.getStreamingsPlatforms);
app.get('/streamingsdates', q.getStreamingsDates);
app.get('/streamings', q.getStreamings);
//////////
......
......@@ -3,17 +3,19 @@
margin: 0;
height: 100%;
width: 100%;
font-family: 'Open Sans', sans-serif;
position: absolute;
}
#data{
margin-top: 100px;
margin-top: 120px;
text-align: center;
margin-bottom: 100px;
padding-bottom: 100px;
}
h1{
font-size: 20px;
}
h1 span{
color: gray;
color: var(--themeh);
text-align: right;
}
.data-catagory{
......@@ -22,11 +24,17 @@ h1 span{
max-width: 90%;
margin: 0px auto;
cursor: pointer;
background-color: #eee;
background-color: var(--theme3);
color: var(--themeh);
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{
background-color: #ddd;
background-color: var(--theme2);
color: var(--themeh);
padding-top: 3px;
padding-bottom: 3px;
width: 100%;
......@@ -36,7 +44,6 @@ h1 span{
border-top-right-radius: 3px;
}
.elem-div{
margin-top: 10px;
max-width: 40%;
width: 300px;
display: inline-block;
......@@ -44,7 +51,9 @@ h1 span{
border-radius: 3px;
padding-left: 30px;
text-align: left;
margin: 1%;
margin-bottom:10px;
margin-left: 5px;
margin-right: 5px;
}
@media only screen and (max-width: 800px) {
.elem-div{
......@@ -53,17 +62,19 @@ h1 span{
}
}
.elem-1{
background-color: #ccc;
background-color: var(--theme4);
}
.elem-0{
background-color: #ccc;
background-color: var(--theme4);
}
input[type="radio"]:checked+label{
font-weight: bold;
text-decoration: underline;
}
input[type="radio"]:checked{
background-color: #cbf7cb;
background-color: white;
color: green;
font-size: 20px;
}
.form-radio
{
......@@ -73,7 +84,7 @@ input[type="radio"]:checked{
display: inline-block;
position: relative;
background-color: #f1f1f1;
color: #666;
color: var(--themeh);
top: 10px;
height: 30px;
width: 30px;
......@@ -94,7 +105,7 @@ input[type="radio"]:checked{
}
.form-radio:hover
{
background-color: #f7f7f7;
background-color: var(--theme4);
}
.form-radio:checked
{
......@@ -103,53 +114,155 @@ input[type="radio"]:checked{
label
{
font: 15px/1.7 'Open Sans', sans-serif;
color: #333;
color: var(--themep);
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
cursor: pointer;
}
#data-prompt-box{
background-color: #888;
color: white;
background-color: var(--theme1);
color: var(--theme1);
position: fixed;
bottom: 0px;
padding-top: 30px;
padding-bottom: 30px;
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{
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;
position: relative;
width: 64px;
height: 64px;
}
.lds-hourglass:after {
content: " ";
display: block;
.lds-ellipsis div {
position: absolute;
top: 27px;
width: 11px;
height: 11px;
border-radius: 50%;
width: 0;
height: 0;
margin: 6px;
box-sizing: border-box;
border: 26px solid #fff;
border-color: #fff transparent #fff transparent;
animation: lds-hourglass 1.2s infinite;
background: #000;
animation-timing-function: cubic-bezier(0, 1, 1, 0);
}
.lds-ellipsis div:nth-child(1) {
left: 6px;
animation: lds-ellipsis1 0.6s 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% {
transform: rotate(0);
animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19);
transform: scale(0);
}
100% {
transform: scale(1);
}
50% {
transform: rotate(900deg);
animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
}
@keyframes lds-ellipsis3 {
0% {
transform: scale(1);
}
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{
padding: 0;
margin: 0;
height: 100%;
height: 100vh;
padding-top: 0vh;
width: 100%;
}
@media only screen and (max-width: 800px) {
#graphView{
height: 90vh;
padding-top: 10vh;
}
}
#graph{
width: 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{
padding: 0;
margin: 0;
......@@ -7,7 +22,7 @@ html, body, #viewDiv{
#navcontrols{
width: 200px;
height: 200px;
height: 75px;
margin-left: 12px;
margin-top: 10px;
display:block;
......@@ -19,19 +34,127 @@ html, body, #viewDiv{
bottom:0;
text-align: center;
}
#nav-view-button{
.nav-view-button{
vertical-align: top;
padding: 10px;
margin-top: 0px;
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{
background-color: lightgray;
.nav-view-button:hover{
background-color: var(--theme3);
}
.nav-button-idle{
background-color: white;
background-color: var(--theme4);
}
.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;
}
@-webkit-keyframes glowing {
0% { background-color: var(--datacolor2);; -webkit-box-shadow: 0 0 3px var(--datacolor2);; }
50% { background-color: var(--datacolor1);; -webkit-box-shadow: 0 0 20px var(--datacolor1);; }
100% { background-color: var(--datacolor2);; -webkit-box-shadow: 0 0 3px var(--datacolor2);; }
}
@-moz-keyframes glowing {
0% { background-color: var(--datacolor2);; -moz-box-shadow: 0 0 3px var(--datacolor2);; }
50% { background-color: var(--datacolor1);; -moz-box-shadow: 0 0 20px var(--datacolor1);; }
100% { background-color: var(--datacolor2);; -moz-box-shadow: 0 0 3px var(--datacolor2);; }
}
@-o-keyframes glowing {
0% { background-color: var(--datacolor2);; box-shadow: 0 0 3px var(--datacolor2);; }
50% { background-color: var(--datacolor1);; box-shadow: 0 0 20px var(--datacolor1);; }
100% { background-color: var(--datacolor2);; box-shadow: 0 0 3px var(--datacolor2);; }
}
@keyframes glowing {
0% { background-color: var(--datacolor2);; box-shadow: 0 0 3px var(--datacolor2);; }
50% { background-color: var(--datacolor1);; box-shadow: 0 0 20px var(--datacolor1);; }
100% { background-color: var(--datacolor2);; box-shadow: 0 0 3px var(--datacolor2);; }
}
\ No newline at end of file
public/img/data-icon.png

2.35 KB | W: | H:

public/img/data-icon.png

2.88 KB | W: | H:

public/img/data-icon.png
public/img/data-icon.png
public/img/data-icon.png
public/img/data-icon.png
  • 2-up
  • Swipe
  • Onion skin
public/img/graph-icon.png

1.04 KB | W: | H:

public/img/graph-icon.png

10.1 KB | W: | H:

public/img/graph-icon.png
public/img/graph-icon.png
public/img/graph-icon.png
public/img/graph-icon.png
  • 2-up
  • Swipe
  • Onion skin
public/img/map-icon.png

10.6 KB | W: | H:

public/img/map-icon.png

1.42 KB | W: | H:

public/img/map-icon.png
public/img/map-icon.png
public/img/map-icon.png
public/img/map-icon.png
  • 2-up
  • Swipe
  • Onion skin
This diff is collapsed.
......@@ -4,417 +4,29 @@
# Porter Libby - 2019 - initial setup
# pelibby16@earlham.edu
#
# Map and Data functions
# Starts the program + general stuff
*/
function ready(){ // placeholder for now
switchToData()
}
function ready(){
switchToData() // set screen to data
// MAP //
base_url = document.location.href; // get base url
var mapstate = 0; // keep track of which map overlay is being used
var default_center = [-13.7055,65.2941]; //default starting coords for the map view
var view = null;
url_parts = base_url.split('?')
url_params = null;
require(["esri/Map", "esri/views/SceneView", "esri/views/MapView", "esri/Graphic", "esri/widgets/BasemapToggle", "esri/widgets/CoordinateConversion", "esri/PopupTemplate" ], function(
Map,
SceneView,
MapView,
Graphic,
BasemapToggle,
CoordinateConversion,
PopupTemplate
) {
var map = new Map({
basemap: "topo"
});
view = new MapView({
center: [-13.68, 65.29],
container: "viewDiv",
map: map,
zoom: 11
});
var basemapToggle = new BasemapToggle({
viewModel: { // autocasts as new BasemapToggleViewModel()
view: view, // The view that provides access to the map's "streets" basemap
nextBasemap: "satellite" // Allows for toggling to the "hybrid" basemap
}
});
var coordinateConversionWidget = new CoordinateConversion({
view: view
});
view.ui.add(basemapToggle, {
position: "bottom-left",
width: 200
});
view.ui.add(coordinateConversionWidget, "bottom-left");
});
function createPoints(points){