Commit cda79300 authored by Tania Gómez's avatar Tania Gómez

Merge branch 'dev' of http://gitlab.geoint.mx/tapiamcclung/pgserver into dev

parents 0d960904 7d63764e
......@@ -11,6 +11,63 @@ Built on [Node Express](https://expressjs.com/)
* access to a [PostGIS](https://postgis.net) server
* [Node and npm](https://nodejs.org/en/download/)
## PostgreSQL user
User should **only** have SELECT right on tables. You can create one as follows:
```sql
-- Create a group
CREATE ROLE readaccess;
-- Grant access to existing tables
GRANT USAGE ON SCHEMA public TO readaccess;
GRANT SELECT ON ALL TABLES IN SCHEMA public TO readaccess;
-- Grant access to future tables
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT ON TABLES TO readaccess;
-- Create a final user with password
CREATE USER <user> WITH PASSWORD '<pw>';
GRANT readaccess TO <user>;
GRANT SELECT ON ALL TABLES IN SCHEMA public TO <user>;
```
Make sure to edit /etc/postgresql/10/main/pg_hba.conf line
`local all all peer`
to
`local all all md5`
## Apache and NodeJS to serve through port :80
Edit your site on `etc/apache2/sites-enabled`.
Either at the end of your site config or at the end the VirtualHost directive of add the following:
```
<VirtualHost *:80>
...
ProxyRequests on
ProxyPass /[path]/ http://localhost:[port]/[path]/
</VirtualHost>
```
Enable the following apache modules:
```
sudo a2enmod proxy
sudo a2enmod proxy_http
sudo a2enmod proxy_balancer
sudo a2enmod lbmethod_byrequests
```
And restart Apache:
```
sudo service apache2 restart
```
Now you can serve your app through port 80 instead of 8090 or something else.
NodeJS requests will be routed to port 8090 :)
## Installation
If you don't have git, you can donwload [a zip file](https://github.com/anneb/pgserver/archive/master.zip) of the project instead.
......
This diff is collapsed.
......@@ -4,7 +4,8 @@
"description": "PGserver receives, converts and serves geo-data between postgis and http-clients.",
"main": "pgserver.js",
"scripts": {
"start": "nodemon pgserver.js",
"dev": "nodemon pgserver.js",
"start": "node pgserver.js",
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "Anne Blankert, Geodan",
......@@ -15,6 +16,7 @@
"express": "^4.17.1",
"express-fileupload": "^1.1.5",
"morgan": "^1.9.1",
"nodemon": "^1.19.2",
"pg": "^7.12.1",
"swagger-jsdoc": "^3.4.0",
"swagger-ui-express": "^4.0.7"
......
......@@ -6,7 +6,11 @@ const cors = require('cors');
const app = express();
app.use(logger('dev'));
//app.use(logger('dev'));
app.use(logger('combined', {
skip: function (req, res) { return res.statusCode < 400 }
}));
app.use(cors());
app.use('/', express.static(__dirname + '/public'));
......
html {
font-size: 14px;
}
@media (min-width: 768px) {
html {
font-size: 16px;
}
}
.container {
max-width: 960px;
}
.pricing-header {
max-width: 700px;
}
.card-deck .card {
min-width: 220px;
}
.bd-placeholder-img {
font-size: 1.125rem;
text-anchor: middle;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
.zoom img {
transition: all .2s linear;
}
.zoom:hover img {
transform: scale(1.1);
}
@media (min-width: 768px) {
.bd-placeholder-img-lg {
font-size: 3.5rem;
}
}
.hovereffect {
width: 100%;
height: 100%;
float: left;
overflow: hidden;
position: relative;
text-align: center;
cursor: default;
}
.hovereffect .overlay {
width: 100%;
height: 100%;
position: absolute;
overflow: hidden;
top: 0;
left: 0;
/* background-color: rgba(75,75,75,0.7);*/
-webkit-transition: all 0.4s ease-in-out;
transition: all 0.4s ease-in-out;
}
.hovereffect:hover .overlay {
background-color: rgba(75,75,75,0.3);
}
.hovereffect img {
display: block;
position: relative;
}
.hovereffect h2 {
text-transform: uppercase;
color: #fff;
text-align: center;
position: relative;
font-size: 17px;
padding: 10px;
background: rgba(0, 0, 0, 0.6);
-webkit-transform: translateY(45px);
-ms-transform: translateY(45px);
transform: translateY(45px);
-webkit-transition: all 0.4s ease-in-out;
transition: all 0.4s ease-in-out;
}
.hovereffect:hover h2 {
-webkit-transform: translateY(5px);
-ms-transform: translateY(5px);
transform: translateY(5px);
}
.hovereffect a.info {
display: inline-block;
text-decoration: none;
text-transform: uppercase;
color: #fff;
border: 1px solid #fff;
background-color: transparent;
opacity: 0;
filter: alpha(opacity=0);
-webkit-transform: scale(0);
-ms-transform: scale(0);
transform: scale(0);
font-weight: normal;
/*margin: 15px 0 0 0;
padding: 140px 60px 0px 60px;*/
margin: 10px;
padding: 0px 15px;
}
.hovereffect:hover a.info {
opacity: 1;
filter: alpha(opacity=100);
-webkit-transform: scale(1);
-ms-transform: scale(1);
transform: scale(1);
-webkit-transition: all 0.4s ease-in-out;
transition: all 0.4s ease-in-out;
}
.hovereffect a.info:hover {
box-shadow: 0 0 5px #fff;
}
.hovereffect:hover .hoverimg {
opacity: 1;
-webkit-transform: scale(0.9);
-ms-transform: scale(0.9);
transform: scale(0.9);
}
.hoverimg {
opacity: 0;
margin: -15px;
}
.hoverbtn {
margin: -10px;
}
.photo-credit {
position: absolute;
bottom: 0px;
right: 0px;
font-size: 10px;
color: #b2b2b2;
background-color: rgba(0,0,0,0.7);
padding: 2px;
border-radius: .25rem;
}
\ No newline at end of file
<!DOCTYPE html>
<html lang="es">
<head>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<title>Proyecto FORDECyT 2018 - 10</title>
<link rel="stylesheet" type="text/css" href="../css/font-awesome.min.css">
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.8.1/css/all.css"
integrity="sha384-50oBUHEmvpQ+1lW4y57PTFmhCaXp0ML5d60M1M7uH2+nqUivzIebhndOJK28anvf" crossorigin="anonymous">
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css"
integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
<link rel="stylesheet" type="text/css" href="../css/cover_style.css">
<link rel="icon" href="../img/monitoreo.png" sizes="16x16">
</head>
<body>
<nav class="navbar navbar-expand-lg navbar-light bg-light sb-navbar">
<div class="container">
<a class="navbar-brand" href="http://www.centrogeo.org.mx/">
<img src="../img/centrogeo.png" height="70" alt="CentroGeo">
</a>
<a class="mr-sm-2" href="http://conacyt.gob.mx/">
<img src="../img/conacyt.png" height="70" alt="CONACyT">
</a>
</nav>
<div>
<!--<div class="d-flex flex-column flex-md-row align-items-center p-3 px-md-4 mb-3 bg-white border-bottom shadow-sm">
<h5 class="my-0 mr-md-auto font-weight-normal">Centro de Investigaci&oacute;n en Ciencias de Informaci&oacute;n Espacial</h5>
<nav class="my-2 my-md-0 mr-md-3">
<a class="p-2 text-dark" href="#">Features</a>
<a class="p-2 text-dark" href="#">Enterprise</a>
<a class="p-2 text-dark" href="#">Support</a>
<a class="p-2 text-dark" href="#">Pricing</a>
</nav>
<a class="btn btn-outline-primary" href="#">Sign up</a>-->
</div>
<div class="pricing-header px-3 py-3 pt-md-5 pb-md-4 mx-auto text-center">
<h1 class="display-5">Proyecto FORDECyT 2018 - 10</h1>
<p class="lead">An&aacute;lisis y Monitoreo del Crecimiento del Medio Urbano y del
Comportamiento de Cuerpos de Agua desde un Enfoque de Sustentabilidad.
Casos de Estudio: Corredor Metropolitano Centro País y Cuenca del r&iacute;o
Grijalva.</p>
</div>
<div class="container">
<div class="card-deck mb-3 text-center">
<div class="card mb-4 shadow-sm">
<div class="card-header">
<h4 class="my-0 font-weight-normal">R&iacute;o Grijalva</h4>
</div>
<div class="card-body">
<div class="hovereffect zoom">
<img class="card-img"
src="../img/sumidero.jpg" alt="Ca&ntilde;&oacute;n del Sumidero">
<span class="photo-credit">Foto: Gabriela L&oacute;pez</span>
<div class="overlay">
<a class="info" href="../grijalva">
<img class="hoverimg mx-auto d-block" src="../img/cuenca.png" width="325px">
<span class="btn btn-primary hoverbtn" href="../grijalva" role="button">Visitar
sitio</span>
<br><br>
</a>
</div>
</div>
</div>
</div>
<div class="card mb-4 shadow-sm">
<div class="card-header">
<h4 class="my-0 font-weight-normal">Corredor Metropolitano Centro Pa&iacute;s</h4>
</div>
<div class="card-body">
<div class="hovereffect zoom">
<img class="card-img" src="../img/centropais.jpg" alt="CMCP">
<span class="photo-credit">Foto: Lucy Nieto</span>
<div class="overlay">
<a class="info" href="../centropais">
<img class="hoverimg mx-auto d-block" src="../img/cmcp.png" width="325px">
<span class="btn btn-primary hoverbtn" href="../centropais" role="button">Visitar
sitio</span>
<br><br>
</a>
</div>
</div>
</div>
</div>
</div>
<footer class="pt-4 my-md-5 pt-md-5 border-top">
<div class="row">
<div class="col-12 col-md">
<img class="mb-2" src="../img/geoint.png" alt="GeoInt" height="70px">
<small class="d-block mb-3 text-muted">&copy; 2019</small>
</div>
<div class="col-6 col-md">
<h5>Features</h5>
<ul class="list-unstyled text-small">
<li><a class="text-muted" href="#">Cool stuff</a></li>
<li><a class="text-muted" href="#">Random feature</a></li>
<li><a class="text-muted" href="#">Team feature</a></li>
<li><a class="text-muted" href="#">Stuff for developers</a></li>
<li><a class="text-muted" href="#">Another one</a></li>
<li><a class="text-muted" href="#">Last time</a></li>
</ul>
</div>
<div class="col-6 col-md">
<h5>Resources</h5>
<ul class="list-unstyled text-small">
<li><a class="text-muted" href="#">Resource</a></li>
<li><a class="text-muted" href="#">Resource name</a></li>
<li><a class="text-muted" href="#">Another resource</a></li>
<li><a class="text-muted" href="#">Final resource</a></li>
</ul>
</div>
<div class="col-6 col-md">
<h5>Acerca de</h5>
<ul class="list-unstyled text-small">
<li><a class="text-muted" href="#">Equipo</a></li>
<li><a class="text-muted" href="#">Desarrollo</a></li>
<li><a class="text-muted" href="#">Tecnolog&iacute;a</a></li>
<li><a class="text-muted" href="#">Terms</a></li>
</ul>
</div>
</div>
</footer>
</div>
</body>
</html>
\ No newline at end of file
......@@ -18,8 +18,6 @@
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/leaflet.draw/1.0.4/leaflet.draw.css" />
<link rel="stylesheet" type="text/css" href="../css/style.css">
<link rel="icon" href="../img/grijalva.png" sizes="16x16">
<!--<link rel="stylesheet" href="./css/map.css" type="text/css">-->
</head>
<body>
<div id="initial-backdrop">
......@@ -146,7 +144,6 @@
<script src="../js/Leaflet.BeautifyIcon/leaflet-beautify-marker-icon.js"></script>
<script src="../js/L.VisualClick/L.VisualClick.js"></script>
<script src="https://api.mapbox.com/mapbox.js/plugins/leaflet-omnivore/v0.3.1/leaflet-omnivore.min.js"></script>
<script src="https://unpkg.com/leaflet.vectorgrid@latest/dist/Leaflet.VectorGrid.bundled.js"></script>
<script type="text/javascript" src="https://cdn.rawgit.com/nezasa/iso8601-js-period/master/iso8601.min.js"></script>
<script type="text/javascript" src="https://cdn.rawgit.com/socib/Leaflet.TimeDimension/master/dist/leaflet.timedimension.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/chroma-js/2.0.3/chroma.min.js"></script>
......@@ -155,77 +152,10 @@
<script src="https://unpkg.com/mapbox-gl-leaflet/leaflet-mapbox-gl.js"></script>
<script type="text/javascript" src="../js/Leaflet.Sync.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet.draw/1.0.4/leaflet.draw.js"></script>
<script src="https://npmcdn.com/@turf/turf/turf.min.js"></script>
<script type="text/javascript" src="../js/jszip.min.js"></script>
<script src="../js/grijalva_functions.js"></script>
<script src="../js/grijalva_basemap.js"></script>
<script src="../js/grijalva_charts.js"></script>
<!--<script>
var map = new mapboxgl.Map({
'container': 'mapmex',
'zoom': 7,
'center': [-92.28, 17.22], // cuenca Grijalva
'style': {
'version': 8,
'sources': {
'carto-dark': {
'type': 'raster',
'tiles': [
"http://a.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}.png",
"http://b.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}.png",
"http://c.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}.png",
"http://d.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}.png"
]
}
},
'layers': [{
'id': 'carto-dark-layer',
'type': 'raster',
'source': 'carto-dark',
'minzoom': 0,
'maxzoom': 22
}]
}
});
map.addControl(new mapboxgl.NavigationControl());
map.on('load', function() {
map.addLayer({
id: 'abril_2018-tiles',
source: {
type: 'vector',
// "http://localhost:8090/data/" + monthYear + "/mvt/{z}/{x}/{y}?geom_column=geom&columns=" + indicators.join();
tiles: ['http://localhost:8090/data/abril_2018/mvt/{z}/{x}/{y}?geom_column=geom&columns=df'],
maxzoom: 14,
minzoom: 5
},
'source-layer': 'abril_2018',
type: 'fill',
minzoom: 5,
'paint': {
'fill-opacity': 0.7,
'fill-color': [
'interpolate',
['linear'],
['get', 'df'],
1, 'rgba(255, 0, 0, 0.5)', // red
1.3, 'rgba(0, 255, 0, 0.5)', // green
],
'fill-outline-color': [
'interpolate',
['linear'],
['get', 'df'],
1, 'rgba(255, 0, 0, 0.6)', // red
1.3, 'rgba(0, 255, 0, 0.6)', // green
]
}
})
})
</script>-->
</body>
</html>
\ No newline at end of file
......@@ -2,11 +2,11 @@
* Copyright 2019 - All rights reserved.
* Rodrigo Tapia-McClung
*
* August 2019
* August-September 2019
*/
/* globals map, userFiles, userDates, indicators, indicatorVars, indicatorsNames */
/* exported makeIndicatorGraph, getData, getDataInSelection */
/* exported makeIndicatorGraph, getData, updateData, getDataInSelection */
let minDate, maxDate, xLine, yLine;
......@@ -16,145 +16,80 @@ const sortByDateAscending = (a, b) => {
}
//TODO: scale data to appropriate units? m2-> ha? m -> km?
const getData = async (indicator) => {
//let data = [{name: `${indicator}0`, values: []}];
let timeParse = d3.timeParse("%B_%Y");
//timeFormat = d3.timeFormat("%B %Y");
const getData = async () => {
let queryColumns = ["sum(area) as area", "sum(perimeter) as perimeter", "avg(costa) as costa", "avg(df) as df"],
timeParse = d3.timeParse("%B_%Y"),
data = {};
const promises = userFiles.map( async monthYear => {
// get sum of area/perimeter or average of coast/fractal dimension
let queryDB = indicator == "costa" || indicator == "df" ?
`http://localhost:8090/data/query/${monthYear}?columns=avg(${indicator})%20as%20${indicator}` :
`http://localhost:8090/data/query/${monthYear}?columns=sum(${indicator})%20as%20${indicator}`;
indicators.map( indicator => {
data[indicator] = [];
data[indicator].push({name: `${indicator}0`, values: []});
});
const userFilePromises = userFiles.map( async monthYear => {
let queryDB = `../data/query/${monthYear}?columns=${queryColumns.join(",")}`;
const dbData = await d3.json(queryDB);
return {date: timeParse(monthYear), value: dbData[0]};
});
const chartData = await Promise.all(promises);
let data = [{name: `${indicator}0`, values: []}];
chartData.map( monthYear => {
data[0].values.push({
"date": monthYear.date,
"value": +monthYear.value[indicator]
});
const chartData = await Promise.all(userFilePromises);
chartData.map( monthData => {
indicators.map( indicator => {
data[indicator][0].values.push({
"date": monthData.date,
"value": +monthData.value[indicator]
});
data.forEach(d => d.values.sort(sortByDateAscending));
return data;
}
// FIXME: Improve this function. Too many requests: indicators x months x drawn items...
// Find way to make one request and get all indicators per month and drawn item.
// Something like the commented function below.
const getDataInSelection = async (indicator) => {
let timeParse = d3.timeParse("%B_%Y");
let geojson = drawnItems.toGeoJSON(),
data = [];
drawnItemsPromises = geojson.features.map( async (item, i) => {
// set SRID for drawn features
item.geometry.crs = {"type":"name","properties":{"name":"EPSG:4326"}};
data.push({name: indicator + (i + 1), values: []});
let columns = indicator == "costa" || indicator == "df" ?
`avg(${indicator})%20as%20${indicator}` :`sum(${indicator})%20as%20${indicator}`;
let filter = `ST_Intersects(geom, (SELECT ST_Multi(ST_GeomFromGeoJSON('${JSON.stringify(item.geometry)}') ) ) )`
const filePpromises = userFiles.map(async monthYear => {
let queryData = `http://localhost:8090/data/query/${monthYear}?columns=${columns}&filter=${filter}&group=1%3D1`;
const selectionQuery = await d3.json(queryData);
return {date: timeParse(monthYear), value: selectionQuery[0]};
// order data[i].values.date
data[indicator].forEach(d => d.values.sort(sortByDateAscending));
});
const selectionData = await Promise.all(filePpromises);
selectionData.map( itemData => {
let itemDataValue = itemData.value != undefined ? itemData.value[indicator] : 0;
data[i].values.push({date: itemData.date, value: itemDataValue });
});
return data;
});
const drawnItemsData = await Promise.all(drawnItemsPromises);
let data2 = [];
data.map( a => data2.push(a.values)); // flatten array of data[i].values
data2 = [].concat.apply([], data2);
// insert sum of each date to first element of data array with name "column0"
data.unshift({
"name": `${indicator}0`,
"values": d3.nest()
.key( d => d.date)
// return d3.sum or d3.average depending on indicator
.rollup( v => { return indicator == "costa" || indicator == "df" ? d3.mean(v, v => v.value) : d3.sum(v, v => v.value) })
.entries(data2)
// map "key" and "value" from d3.nest().rollup() to date and value
.map( group => {
return {
date: new Date(group.key),
value: group.value
}
})
});
// order data[i].values.date
data.forEach(d => d.values.sort(sortByDateAscending));
return data;
}
/*const getDataInSelection = async () => {
let geojson = drawnItems.toGeoJSON();
let queryColumns = ["sum(area) as area", "sum(perimeter) as perimeter", "avg(costa) as costa", "avg(df) as df"];
let timeParse = d3.timeParse("%B_%Y"),
const getDataInSelection = async () => {
let geojson = drawnItems.toGeoJSON(),
queryColumns = ["sum(area) as area", "sum(perimeter) as perimeter", "avg(costa) as costa", "avg(df) as df"],
timeParse = d3.timeParse("%B_%Y"),
data = {};
indicators.map( indicator => {
data[indicator] = [];
});
//let promises;
// End up with data = {area: Array(0), perimeter: Array(0), length: Array(0), DI: Array(0)}
// Convert drawn items to GeoJSON and check what's inside each one of them
drawnItems.toGeoJSON().features.map( async (item, i) => {
const drawnItemPromises = drawnItems.toGeoJSON().features.map( async (item, i) => {
// set SRID fro drawn features
geojson.features[i].geometry.crs = {"type":"name","properties":{"name":"EPSG:4326"}};
indicators.map( async indicator => {
data[indicator].push({name: indicator + (i + 1), values: []});
});
// End up with data = {area: [{name: "area1", values: []}], perimeter: [{name: "perimeter1", values: []}]...}
//console.log(data)
let filter = `ST_Intersects(geom, (SELECT ST_Multi(ST_GeomFromGeoJSON('${JSON.stringify(geojson.features[i].geometry)}') ) ) )`
const promises = userFiles.map(async monthYear => {
let queryData = `http://localhost:8090/data/query/${monthYear}?columns=${queryColumns.join(",")}&filter=${filter}&group=1%3D1`;
const userFilePromises = userFiles.map(async monthYear => {
let queryData = `../data/query/${monthYear}?columns=${queryColumns.join(",")}&filter=${filter}&group=1%3D1`;
const selectionQuery = await d3.json(queryData);
return {date: timeParse(monthYear), value: selectionQuery[0]};
});
const selectionData = await Promise.all(promises);
// let data = [{name: `${indicator}0`, values: []}];
const selectionData = await Promise.all(userFilePromises);
selectionData.map( itemData => {
//console.log(itemData, i)
indicators.map( indicator => {
data[indicator][i].values.push({date: itemData.date, value: itemData.value[indicator] });
let itemDataValue = itemData.value != undefined ? itemData.value[indicator] : 0;
data[indicator][i].values.push({date: itemData.date, value: itemDataValue });
});
});
});
const drawnItemsData = await Promise.all(drawnItemPromises);
return data;
}*/
}
const summarizeData = async (allData, indicator) => {
/*let dataFull = await allData;
const summarizeData = (allData, indicator) => {
let dataFull = allData;
let data = dataFull[indicator];
let data2 = [];
console.log(allData, data[0]);
data.map( a => { console.log(a); data2.push(a.values)}); // flatten array of data[i].values
data2 = [].concat.apply([], data2);
console.log(data2);*/
allData.then( val => {
let data = val['area'];
let data2 = [];
console.log(val, data);
data.forEach( a => { data2.push(a.values)}); // flatten array of data[i].values
data.map( a => data2.push(a.values)); // flatten array of data[i].values
data2 = [].concat.apply([], data2);
console.log(data2);
})
/*// insert sum of each date to first element of data array with name "column0"
// insert sum of each date to first element of data array with name "column0"
data.unshift({
"name": `${indicator}0`,
"values": d3.nest()
......@@ -171,7 +106,6 @@ const summarizeData = async (allData, indicator) => {
});
// order data[i].values.date
data.forEach(d => d.values.sort(sortByDateAscending));
//console.log(data)*/
return data;
}
......
......@@ -2,7 +2,7 @@
* Copyright 2019 - All rights reserved.
* Rodrigo Tapia-McClung
*
* August 2019
* August-September 2019
*/
/* globals omnivore, Promise, chroma, makeBaseMap, makeIndicatorGraph, getData, getDataInSelection */
......@@ -99,7 +99,7 @@ const sortInitialDateAscending = (a, b) => {
// query available dates on DB
const setupDates = () => {
return new Promise( resolve => {
let layersQuery = "http://localhost:8090/data/list_layers";
let layersQuery = "../data/list_layers";
d3.json(layersQuery).then(layers => {
layers.forEach(layer => {
dateArray.push(timeParse(layer.f_table_name)); // convert filenames to dates
......@@ -305,7 +305,7 @@ const setupMap = (dates) => {
return refMap.unproject(pt, zoom);
}
console.log(userFiles);
//console.log(userFiles);
// query db to get min/max values per month and indicator and store them in an object
queryFiles().then( minmax => {
minmax.map( minmaxMonth => {
......@@ -331,14 +331,51 @@ const queryFiles = () => {
const getMinMax = table => {
return new Promise( resolve => {
let minmaxQuery = `http://localhost:8090/data/query/${table}?columns=${cols.join(", ")}`;
let minmaxQuery = `../data/query/${table}?columns=${cols.join(", ")}`;
d3.json(minmaxQuery).then( minmax => {
resolve(minmax[0]);
});
});
}
const populateMap = (mapData) => {
const populateMap = async (mapData) => {
const chartData = await getData();
// Define charts with reusable components
indicators.map( async (indicator, index) => {
// indicatorVars[indicator].chart gives areaChart, perimeterChart, etc.
// First, make all charts with same general options
indicatorVars[indicator].chart = makeIndicatorGraph()
.width(Math.floor($(indicatorVars[indicator].container)[0].offsetParent.offsetWidth * 0.95))
.height(Math.floor($(indicatorVars[indicator].container)[0].offsetParent.offsetHeight * 0.95))
.lineVariables([`${indicator}0`]) // d.area is used to draw stuff on y axis
.displayName("date") // d.date is used to draw stuff on x axis
.lineAxisLabel("(m)")
.id(indicator)
.xAxisFormat(d3.timeFormat("%b '%y")) // label x axis as mm 'yy
.yAxisFormat(d3.format(indicatorsxAxisFormat[index])) // yAxis label in SI or other
// Then, specify some parameters for each chart
.tooltipUnits(indicatorsUnits[index])
.tooltipFormat(d3.format(indicatorsxAxisFormat[index])) // tooltip format in SI or other
.title(indicatorsUnits[index] == "" ? indicatorsNames[index] :
`${indicatorsNames[index]} (${indicatorsUnits[index]})`);
// Finally, set chart data with async function calling stuff from DB
indicatorVars[indicator].chart.data( chartData[indicator]);
// create chart with passed options
d3.select(indicatorVars[indicator].container)
.call(indicatorVars[indicator].chart);
// Reload chart data and force chart update
indicatorVars[indicator].chartData = indicatorVars[indicator].chart.data(); // get chart data
indicatorVars[indicator].chart.data(indicatorVars[indicator].chartData); // set chart data
// Highlight plot title according to selected option
let option = $("#indicatorSelect").val(); // option selected from dropdrown
d3.select(indicatorVars[option].container).select("svg text.title").classed("active", true);
});
let map = mapData.map,
minIndicators = mapData.minIndicators,
maxIndicators = mapData.maxIndicators;
......@@ -411,43 +448,10 @@ const populateMap = (mapData) => {
layerControl = L.control.layers(baseLayers, overlays).addTo(map);
makeBaseMap(); // basemap.js
});
// Define charts with reusable components
indicators.map( async (indicator, index) => {
// indicatorVars[indicator].chart gives areaChart, perimeterChart, etc.
// First, make all charts with same general options
indicatorVars[indicator].chart = makeIndicatorGraph()
.width(Math.floor($(indicatorVars[indicator].container)[0].offsetParent.offsetWidth * 0.95))
.height(Math.floor($(indicatorVars[indicator].container)[0].offsetParent.offsetHeight * 0.95))
.lineVariables([`${indicator}0`]) // d.area is used to draw stuff on y axis
.displayName("date") // d.date is used to draw stuff on x axis
.lineAxisLabel("(m)")
.id(indicator)
.xAxisFormat(d3.timeFormat("%b '%y")) // label x axis as mm 'yy
.yAxisFormat(d3.format(indicatorsxAxisFormat[index])) // yAxis label in SI or other
// Then, specify some parameters for each chart
.tooltipUnits(indicatorsUnits[index])
.tooltipFormat(d3.format(indicatorsxAxisFormat[index])) // tooltip format in SI or other
.title(indicatorsUnits[index] == "" ? indicatorsNames[index] :
`${indicatorsNames[index]} (${indicatorsUnits[index]})`);
// Finally, set chart data with async function calling stuff from DB
indicatorVars[indicator].chart.data( await getData(indicator));
// create chart with passed options
d3.select(indicatorVars[indicator].container)
.call(indicatorVars[indicator].chart);
// Reload chart data and force chart update
indicatorVars[indicator].chartData = indicatorVars[indicator].chart.data(); // get chart data
indicatorVars[indicator].chart.data(indicatorVars[indicator].chartData); // set chart data
// Highlight plot title according to selected option
let option = $("#indicatorSelect").val(); // option selected from dropdrown
d3.select(indicatorVars[option].container).select("svg text.title").classed("active", true);
});
}
const updateMap = (mapData) => {
console.log(userFiles);
//console.log(userFiles);
// clear tiles
currentTiles = {};
......@@ -500,30 +504,34 @@ const updateMap = (mapData) => {
updateCharts();
}
const updateCharts = () => {
const updateCharts = async () => {
$(".loader").css("display", "block");
// TODO: add mask while fetching async data
// if user has drawn polygons, update chart with data inside selection
if (drawnItems.toGeoJSON().features.length != 0) {
let allData = await getDataInSelection();
indicators.map( async indicator => {
//indicatorVars[indicator].chart.data( await summarizeData(await getDataInSelection(), indicator) );
indicatorVars[indicator].chart.data( await getDataInSelection(indicator) );
indicatorVars[indicator].chart.data( summarizeData(allData, indicator) );
});
} else {
// otherwise use all data
let allData = await getData();
indicators.map( async indicator => {
indicatorVars[indicator].chart.data( await getData(indicator));
indicatorVars[indicator].chart.data( allData[indicator]);
});
}
$(".loader").hide("fade", 750);
}
// define MVT layer for given month table and all indicators
const mapboxLayer = (monthYear) => {
const baseUrl = new URL(`/data`, window.location.href).href;
let pbfLayer = {
id: monthYear,
source: {
type: "vector",
tiles: [`http://localhost:8090/data/${monthYear}/mvt/{z}/{x}/{y}?geom_column=geom&columns=${indicators.join()}`],
tiles: [`${baseUrl}/${monthYear}/mvt/{z}/{x}/{y}?geom_column=geom&columns=${indicators.join()}`],
maxzoom: 14,
minzoom: 5
},
......@@ -651,7 +659,7 @@ L.TimeDimension.Layer.Tile = L.TimeDimension.Layer.extend({
});
//console.time("process");
console.log("data for", monthYear);
//console.log("data for", monthYear);
//console.log(currentTiles)
Object.keys(allTiles).forEach(layer => {
if (layer !== monthYear) { // hide all other months
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment