Commit b7fd1371 authored by Rodrigo Tapia-McClung's avatar Rodrigo Tapia-McClung

Charts work with timeDimension and date change.

parent fe147516
...@@ -5,8 +5,8 @@ ...@@ -5,8 +5,8 @@
* August 2019 * August 2019
*/ */
/* globals flatten, map, userFiles, userDates, indicators, indicatorVars, indicatorsNames */ /* globals map, userFiles, userDates, indicators, indicatorVars, indicatorsNames */
/* exported makeIndicatorGraph, getData, queryIndicators */ /* exported makeIndicatorGraph, getData */
let minDate, maxDate, xLine, yLine; let minDate, maxDate, xLine, yLine;
...@@ -15,69 +15,31 @@ const sortByDateAscending = (a, b) => { ...@@ -15,69 +15,31 @@ const sortByDateAscending = (a, b) => {
return a.date - b.date; return a.date - b.date;
} }
const queryIndicators = () => {
return Promise.all(indicators.map(queryMonths))
// the result is an array of arrays, so we'll flatten them here
.then(flatten);
}
const queryMonths = (indicator) => {
return Promise.all(userFiles.map( monthYear => {
return getData(monthYear, indicator);
}));
}
//queryIndicators(queryMonths).then( results => {...} )
const getData = (monthYear, indicator) => {
return new Promise( resolve => {
//let data = [{name: `${indicator}0`, values: []}];
let timeParse = d3.timeParse("%B_%Y");
//timeFormat = d3.timeFormat("%B %Y");
// 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}`;
d3.json(queryDB).then( result => {
/*data[0].values.push({
"date": timeParse(monthYear),
"value": +result[0][indicator]
});
data.forEach(d => d.values.sort(sortByDateAscending));
resolve(data[0])*/
resolve({date: timeParse(monthYear), value: result[0][indicator]})
});
});
}
//TODO: scale data to appropriate units? m2-> ha? m -> km? //TODO: scale data to appropriate units? m2-> ha? m -> km?
const getData2 = async (indicator) => { const getData = async (indicator) => {
let data = [{name: `${indicator}0`, values: []}]; //let data = [{name: `${indicator}0`, values: []}];
let timeParse = d3.timeParse("%B_%Y"); let timeParse = d3.timeParse("%B_%Y");
//timeFormat = d3.timeFormat("%B %Y"); //timeFormat = d3.timeFormat("%B %Y");
userFiles.map( async monthYear => { const promises = userFiles.map( async monthYear => {
// get sum of area/perimeter or average of coast/fractal dimension // get sum of area/perimeter or average of coast/fractal dimension
let queryDB = indicator == "costa" || indicator == "df" ? 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=avg(${indicator})%20as%20${indicator}` :
`http://localhost:8090/data/query/${monthYear}?columns=sum(${indicator})%20as%20${indicator}`; `http://localhost:8090/data/query/${monthYear}?columns=sum(${indicator})%20as%20${indicator}`;
/*d3.json(queryDB).then( result => { const dbData = await d3.json(queryDB);
data[0].values.push({ return {date: timeParse(monthYear), value: dbData[0]};
"date": timeParse(monthYear), });
"value": +result[0][indicator]
}); const chartData = await Promise.all(promises);
data.forEach(d => d.values.sort(sortByDateAscending)); let data = [{name: `${indicator}0`, values: []}];
});*/ chartData.map( monthYear => {
let dbData = await d3.json(queryDB);
data[0].values.push({ data[0].values.push({
"date": timeParse(monthYear), "date": monthYear.date,
"value": await +dbData[0][indicator] "value": +monthYear.value[indicator]
}); });
data.forEach(d => d.values.sort(sortByDateAscending));
}) })
data.forEach(d => d.values.sort(sortByDateAscending));
return data; return data;
} }
...@@ -112,7 +74,6 @@ function makeIndicatorGraph() { ...@@ -112,7 +74,6 @@ function makeIndicatorGraph() {
function chart(selection) { function chart(selection) {
console.log("data values: ", data[0].values) // FIXME: get async data here...
// get data ranges using values from displayName // get data ranges using values from displayName
minDate = d3.min(data[0].values, d => { minDate = d3.min(data[0].values, d => {
return d[displayName]; return d[displayName];
...@@ -122,7 +83,7 @@ function makeIndicatorGraph() { ...@@ -122,7 +83,7 @@ function makeIndicatorGraph() {
return d[displayName]; return d[displayName];
}); });
maxDate = d3.timeDay.offset(maxDate, 15) // get next month to get correct x-axis alignment maxDate = d3.timeDay.offset(maxDate, 15) // get next month to get correct x-axis alignment
console.log("minDate: ", minDate)
selection.each(function () { selection.each(function () {
// add graph svg to selected container on webpage // add graph svg to selected container on webpage
...@@ -282,7 +243,7 @@ function makeIndicatorGraph() { ...@@ -282,7 +243,7 @@ function makeIndicatorGraph() {
minDate = d3.min(data[0].values, d => { minDate = d3.min(data[0].values, d => {
return d[displayName]; return d[displayName];
}); });
console.log("update data: ", data[0].values.length)
minDate = d3.timeDay.offset(minDate, -15) // get previous month to get correct x-axis alignment minDate = d3.timeDay.offset(minDate, -15) // get previous month to get correct x-axis alignment
maxDate = d3.max(data[0].values, d => { maxDate = d3.max(data[0].values, d => {
return d[displayName]; return d[displayName];
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
*/ */
/* globals omnivore, Promise, chroma, makeBaseMap, makeIndicatorGraph, getData */ /* globals omnivore, Promise, chroma, makeBaseMap, makeIndicatorGraph, getData */
/* exported userFiles, userDates, layerControl, queryFiles, flatten */ /* exported userFiles, userDates, layerControl */
let timeParse, let timeParse,
timeFormat, timeFormat,
...@@ -338,61 +338,6 @@ const getMinMax = table => { ...@@ -338,61 +338,6 @@ const getMinMax = table => {
}); });
} }
const updateMap = (mapData) => {
//console.log(mapData);
console.log(userFiles);
// ckear tiles
currentTiles = {};
//retrieve or create tiles for current dates
userFiles.forEach( monthYear => {
if (Object.keys(allTiles).includes(monthYear)) {
currentTiles[monthYear] = allTiles[monthYear]; // recover tile if it has already been created
//currentJSONs[monthYear] = allJSONs[monthYear]; // recover json if it has already been created
return; // if file has already been processed, exit
} else { // if file cannot be found in allTiles, then add 1 to the number of files to process
let newTile = mapboxLayer(monthYear);
glmap._glMap.addLayer(newTile);
if (monthYear == userFiles[0]) {
glmap._glMap.setPaintProperty(monthYear, "fill-opacity", 0.7)
}
}
});
// update timeDimension times
timeLayer._timeDimension.setAvailableTimes(userDates, "replace");
//timeLayer._timeDimension.setCurrentTime(mapData.min);
// clear minmax indicators objects
maxIndicators = {},
minIndicators = {};
indicators.forEach( (indicator) => {
maxIndicators[indicator] = 0;
minIndicators[indicator] = 1e30;
});
// query db for new minmax values then style tiles
new Promise( resolve => {
queryFiles().then( minmax => {
minmax.map( minmaxMonth => {
indicators.forEach( (indicator) => {
minIndicators[indicator] = Math.min(minIndicators[indicator], minmaxMonth[`min${indicator}`]);
maxIndicators[indicator] = Math.max(maxIndicators[indicator], minmaxMonth[`max${indicator}`]);
});
});
resolve({"map": map, "minIndicators": minIndicators, "maxIndicators": maxIndicators});
})
}).then( values => { // once we have new minmax values, style all tiles
let option = $("#indicatorSelect").val(), // option selected from dropdrown
min = values.minIndicators,
max = values.maxIndicators;
styleTiles(option, min, max)
.then(legend.addTo(map)); // add legend control -> it updates
//TODO: update charts
});
}
const populateMap = (mapData) => { const populateMap = (mapData) => {
let map = mapData.map, let map = mapData.map,
minIndicators = mapData.minIndicators, minIndicators = mapData.minIndicators,
...@@ -467,7 +412,7 @@ const populateMap = (mapData) => { ...@@ -467,7 +412,7 @@ const populateMap = (mapData) => {
}); });
// Define charts with reusable components // Define charts with reusable components
indicators.forEach( async (indicator, index) => { indicators.map( async (indicator, index) => {
// indicatorVars[indicator].chart gives areaChart, perimeterChart, etc. // indicatorVars[indicator].chart gives areaChart, perimeterChart, etc.
// First, make all charts with same general options // First, make all charts with same general options
indicatorVars[indicator].chart = makeIndicatorGraph() indicatorVars[indicator].chart = makeIndicatorGraph()
...@@ -485,22 +430,83 @@ const populateMap = (mapData) => { ...@@ -485,22 +430,83 @@ const populateMap = (mapData) => {
.title(indicatorsUnits[index] == "" ? indicatorsNames[index] : .title(indicatorsUnits[index] == "" ? indicatorsNames[index] :
`${indicatorsNames[index]} (${indicatorsUnits[index]})`); `${indicatorsNames[index]} (${indicatorsUnits[index]})`);
let data = await getData2(indicator); // Finally, set chart data with async function calling stuff from DB
await indicatorVars[indicator].chart.data(data); indicatorVars[indicator].chart.data( await getData(indicator));
console.log(data, data[0]) // data has stuff, but data[0] has empty values // create chart with passed options
d3.select(indicatorVars[indicator].container) d3.select(indicatorVars[indicator].container)
.call(await indicatorVars[indicator].chart); .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 // Highlight plot title according to selected option
let option = $("#indicatorSelect").val(); // option selected from dropdrown let option = $("#indicatorSelect").val(); // option selected from dropdrown
d3.select(indicatorVars[option].container).select("svg text.title").classed("active", true); d3.select(indicatorVars[option].container).select("svg text.title").classed("active", true);
});
// TODO: basemap // TODO: basemap
//makeBaseMap(); // basemap.js //makeBaseMap(); // basemap.js
} }
const updateMap = (mapData) => {
console.log(userFiles);
// clear tiles
currentTiles = {};
//retrieve or create tiles for current dates
userFiles.forEach( monthYear => {
if (Object.keys(allTiles).includes(monthYear)) {
currentTiles[monthYear] = allTiles[monthYear]; // recover tile if it has already been created
//currentJSONs[monthYear] = allJSONs[monthYear]; // recover json if it has already been created
return; // if file has already been processed, exit
} else { // if file cannot be found in allTiles, then add 1 to the number of files to process
let newTile = mapboxLayer(monthYear);
glmap._glMap.addLayer(newTile);
if (monthYear == userFiles[0]) {
glmap._glMap.setPaintProperty(monthYear, "fill-opacity", 0.7)
}
}
});
// update timeDimension times
timeLayer._timeDimension.setAvailableTimes(userDates, "replace");
//timeLayer._timeDimension.setCurrentTime(mapData.min);
// clear minmax indicators objects
maxIndicators = {},
minIndicators = {};
indicators.forEach( (indicator) => {
maxIndicators[indicator] = 0;
minIndicators[indicator] = 1e30;
});
// query db for new minmax values then style tiles
new Promise( resolve => {
queryFiles().then( minmax => {
minmax.map( minmaxMonth => {
indicators.forEach( (indicator) => {
minIndicators[indicator] = Math.min(minIndicators[indicator], minmaxMonth[`min${indicator}`]);
maxIndicators[indicator] = Math.max(maxIndicators[indicator], minmaxMonth[`max${indicator}`]);
});
});
resolve({"map": map, "minIndicators": minIndicators, "maxIndicators": maxIndicators});
})
}).then( values => { // once we have new minmax values, style all tiles
let option = $("#indicatorSelect").val(), // option selected from dropdrown
min = values.minIndicators,
max = values.maxIndicators;
styleTiles(option, min, max)
.then(legend.addTo(map)); // add legend control -> it updates
});
// Update charts
updateCharts();
}
const updateCharts = () => {
indicators.map( async (indicator) => {
indicatorVars[indicator].chart.data( await getData(indicator));
});
}
// define MVT layer for given month table and all indicators // define MVT layer for given month table and all indicators
const mapboxLayer = (monthYear) => { const mapboxLayer = (monthYear) => {
...@@ -538,7 +544,6 @@ const mapboxLayer = (monthYear) => { ...@@ -538,7 +544,6 @@ const mapboxLayer = (monthYear) => {
return pbfLayer; return pbfLayer;
} }
const setupTimeDimensionControl = () => { const setupTimeDimensionControl = () => {
L.Control.TimeDimensionCustom = L.Control.TimeDimension.extend({ L.Control.TimeDimensionCustom = L.Control.TimeDimension.extend({
_getDisplayDateFormat: date => { _getDisplayDateFormat: date => {
...@@ -706,6 +711,4 @@ legend.onAdd = () => { ...@@ -706,6 +711,4 @@ legend.onAdd = () => {
html += "</ul>"; html += "</ul>";
div.innerHTML = html; div.innerHTML = html;
return div; return div;
}; };
\ No newline at end of file
// TODO: add charts
\ No newline at end of file
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