Commit 4643d048 authored by Rodrigo Tapia-McClung's avatar Rodrigo Tapia-McClung

Clean up unused inherited grijalva code

parent 75c892cf
/* /*
* Copyright 2019 - All rights reserved. * Copyright 2021 - All rights reserved.
* Rodrigo Tapia-McClung * Rodrigo Tapia-McClung
* *
* August-September 2019 * January 2021
*/ */
/* global Promise, omnivore, JSZip, map, layerControl, updateCharts */ /* global Promise, omnivore, JSZip, map, layerControl */
/* exported makeBaseMap, baseLayerPromises, drawnItems */ /* exported makeBaseMap, baseLayerPromises, drawnItems */
/* Lines related to displaying loading bar are commented */ /* Lines related to displaying loading bar are commented */
...@@ -55,13 +55,7 @@ const createPane = (layerPane, zIndex) => { ...@@ -55,13 +55,7 @@ const createPane = (layerPane, zIndex) => {
map.getPane(layerPane).style["mix-blend-mode"] = "normal"; map.getPane(layerPane).style["mix-blend-mode"] = "normal";
} }
const getSchoolColor = s => { let descargas, presas, tuxtlaVH, zms, anps;
return s == "Básico" ? "#409400" :
s == "Medio superior" ? "#df6400" :
"#c0d1e5";
}
let escuelas, hospitales, hoteles, puentes, puntoFronterizo, descargas, presas, subcuencas, tuxtlaVH, zms, anps;
// *** WMS INEGI *** // *** WMS INEGI ***
// NOMBRES DE CUERPOS DE AGUA // NOMBRES DE CUERPOS DE AGUA
...@@ -286,42 +280,6 @@ let layer_ANPs = new L.geoJson(null, { ...@@ -286,42 +280,6 @@ let layer_ANPs = new L.geoJson(null, {
style: style_ANPs style: style_ANPs
}); });
const styleDrawnItems = () => {
let currentId = 0;
drawnItems.eachLayer( l => {
l.feature.properties.id = currentId;
l.feature.properties.color = d3.schemeCategory10[currentId];
l.setStyle({
fillColor: d3.schemeCategory10[currentId],
opacity: 0.5,
fillOpacity: 0.2,
color: d3.schemeCategory10[currentId],
weight: 4
});
currentId++;
});
}
const toggleButtons = () => {
let buttons = [];
buttons.push(document.getElementsByClassName("leaflet-draw-draw-polyline")[0]);
buttons.push(document.getElementsByClassName("leaflet-draw-draw-polygon")[0]);
buttons.push(document.getElementsByClassName("leaflet-draw-draw-rectangle")[0]);
buttons.forEach( b => {
// disable buttons if there are 10 drawn items
if (drawnItems.getLayers().length >= 10) {
b.onClick = "preventEventDefault(); return false";
b.classList.add("draw-control-disabled");
// enable buttons if there are less than 10 drawn items
} else if (drawnItems.getLayers().length < 10) {
b.onClick = null;
b.classList.remove("draw-control-disabled");
}
})
}
const makeBaseMap = () => { const makeBaseMap = () => {
createPane("pane_ANPs", 400); createPane("pane_ANPs", 400);
createPane("pane_munis", 402); createPane("pane_munis", 402);
...@@ -353,206 +311,4 @@ const makeBaseMap = () => { ...@@ -353,206 +311,4 @@ const makeBaseMap = () => {
zip2Lyr("../grijalva/data/anps.zip", anps, layer_ANPs); zip2Lyr("../grijalva/data/anps.zip", anps, layer_ANPs);
//map.addLayer(layer_ANPs); //map.addLayer(layer_ANPs);
layerControl.addOverlay(layer_ANPs, "&nbsp; <svg height=\"15\" width=\"15\"><path d=\"M0 0 L15 0 L15 10 L0 10 Z \" x=\"5\" y=\"5\" fill=\"rgba(0,255,0,.3)\" stroke=\"rgba(128,152,72,1.0)\" stroke-dasharray=\"0.5,1\" stroke-dashoffset=\"0.5\"></rect></svg> Áreas Naturales Protegidas 2018"); layerControl.addOverlay(layer_ANPs, "&nbsp; <svg height=\"15\" width=\"15\"><path d=\"M0 0 L15 0 L15 10 L0 10 Z \" x=\"5\" y=\"5\" fill=\"rgba(0,255,0,.3)\" stroke=\"rgba(128,152,72,1.0)\" stroke-dasharray=\"0.5,1\" stroke-dashoffset=\"0.5\"></rect></svg> Áreas Naturales Protegidas 2018");
// Localize Leaflet.Draw texts
L.drawLocal = {
draw: {
toolbar: {
actions: {
title: "Cancelar dibujo",
text: "Cancelar"
},
finish: {
title: "Terminar dibujo",
text: "Terminar"
},
undo: {
title: "Eliminar último punto dibujado",
text: "Eliminar último punto"
},
buttons: {
polyline: "Dibujar una polilínea",
polygon: "Dibujar un polígono",
rectangle: "Dibujar un rectángulo",
circle: "Dibujar un círculo",
marker: "Dibujar un marcador",
circlemarker: "Dibujar un marcador circular"
}
},
handlers: {
circle: {
tooltip: {
start: "Haz click y arrastra para dibujar un círculo"
},
radius: "Radio"
},
circlemarker: {
tooltip: {
start: "Haz click en el mapa para ubicar el marcador circular"
}
},
marker: {
tooltip: {
start: "Haz click en el mapa para ubicar el marcador"
}
},
polygon: {
error: "<strong>Error:</strong>",
tooltip: {
start: "Haz click para empezar a dibujar la figura",
cont: "Haz click para continuar dibujando la figura",
end: "Haz click en el primer punto para cerrar la figura"
}
},
polyline: {
error: "<strong>Error:</strong> las líneas no deben cruzarse",
tooltip: {
start: "Haz click para empezar a dibujar la línea",
cont: "Haz click para continuar dibujando la línea",
end: "Haz click en el último punto para terminar la línea"
}
},
rectangle: {
tooltip: {
start: "Haz click y arrastra para dibujar un rectángulo"
}
},
simpleshape: {
tooltip: {
end: "Suelta el ratón para terminar de dibujar"
}
}
}
},
edit: {
toolbar: {
actions: {
save: {
title: "Guardar los cambios",
text: "Guardar"
},
cancel: {
title: "Cancelar la edición, descarta todos los cambios",
text: "Cancelar"
},
clearAll: {
title: "Limpiar todas las capas",
text: "Limpiar todo"
}
},
buttons: {
edit: "Editar capas",
editDisabled: "No hay capas que editar",
remove: "Eliminar capas",
removeDisabled: "No hay capas que eliminar"
}
},
handlers: {
edit: {
tooltip: {
text: "Arrastra el marcador para editar la figura",
subtext: "Haz click en cancelar para deshacer los cambios"
}
},
remove: {
tooltip: {
text: "Haz click en una figura para eliminarla"
}
}
}
}
}
// leaflet draw control
drawnItems = L.featureGroup().addTo(map);
let drawControl = new L.Control.Draw({
draw: {
polygon: {
showArea: true,
//allowIntersection: false, // Restricts shapes to simple polygons
//drawError: {
//color: "#f9a800",
//message: "<strong>you can't draw that!" // Message that will show when intersect
//},
shapeOptions: {
color: "#42ffc3"
}
},
// disable toolbar item by setting it to false
polyline: {
//allowIntersection:false,
shapeOptions: {
color: "#42ffc3"
}
},
rectangle: {
shapeOptions: {
color: "#42ffc3"
}
},
marker: false,
circlemarker: false,
circle: false // Turns off this drawing tool
},
edit: {
featureGroup: drawnItems,
//remove: false
}
});
map.addControl(drawControl);
// set z-index of panes so actions can be done on drawnItems when editing/deleting
map.on(L.Draw.Event.CREATED, event => {
$("#mexmap .leaflet-pane.leaflet-overlay-pane").css("z-index", "400");
let layer = event.layer,
feature = layer.feature = layer.feature || {}; // Initialize feature
feature.type = feature.type || "Feature"; // Initialize feature.type
feature.properties = feature.properties || {}; // Initialize feature.properties
drawnItems.addLayer(layer); // whatever you want to do with the created layer
// give each drawn item an id and color from an array
styleDrawnItems();
// disable buttons if there are 10 drawn items
toggleButtons();
// after drawing shape, update chart with data for polygons contained inside it
//updateCharts();
});
map.on(L.Draw.Event.DELETESTART, () => {
// before deleting shape, bring pane up
$("#mexmap .leaflet-pane.leaflet-overlay-pane").css("z-index", "451");
});
map.on(L.Draw.Event.DELETED, () => {
// after deleting a drawn item, refresh the list of ids and colors
styleDrawnItems();
// enable buttons if there are less than 10 drawn items
toggleButtons();
// after deleting shape, send pane down
$("#mexmap .leaflet-pane.leaflet-overlay-pane").css("z-index", "400");
// and update chart with data:
// if there are drawnItems, use them. If not, use original data
//updateCharts();
});
map.on(L.Draw.Event.EDITSTART, () => {
$("#mexmap .leaflet-pane.leaflet-overlay-pane").css("z-index", "451");
// before editing shape, bring pane up
});
map.on(L.Draw.Event.EDITSTOP, () => {
$("#mexmap .leaflet-pane.leaflet-overlay-pane").css("z-index", "400");
// before editing shape, bring pane up
});
map.on(L.Draw.Event.EDITED, () => {
// before editing shape, send pane down
$("#mexmap .leaflet-pane.leaflet-overlay-pane").css("z-index", "400");
// after editing shape, update chart with data for polygons contained inside it
//updateCharts();
});
} }
\ No newline at end of file
...@@ -5,639 +5,7 @@ ...@@ -5,639 +5,7 @@
* January 2021 * January 2021
*/ */
/* globals map, userFiles, userDates, indicators, indicatorVars, indicatorsNames, updateBarChart, barChartData, am4charts, am4core */ /* globals updateBarChart, barChartData, am4charts, am4core, am4themes_animated */
/* exported makeIndicatorGraph, getData, updateData, getDataInSelection */
let mainTextColor = getComputedStyle(document.body).getPropertyValue('--main-text-color');
let minDate, maxDate, xLine, yLine;
const sortByDateAscending = (a, b) => {
// Dates will be cast to numbers automagically:
return a.date - b.date;
}
//TODO: scale data to appropriate units? m2-> ha? m -> km?
const getData = async() => {
let queryColumns = ["sum(areacpo) as area", "sum(perimcpo) as perimeter", "avg(dlccpo) as costa", "avg(dimfrcpo) as df"],
timeParse = d3.timeParse("cuerpos_%B_%Y"),
data = {};
indicators.map(indicator => {
data[indicator] = [];
data[indicator].push({ name: `${indicator}0`, values: [] });
});
const baseUrl = new URL(`/data`, window.location.href).href;
const userFilePromises = userFiles.map(async monthYear => {
let queryDB = `${baseUrl}/query/${monthYear}?columns=${queryColumns.join(",")}`;
const dbData = await d3.json(queryDB);
return { date: timeParse(monthYear), value: dbData[0] };
});
const chartData = await Promise.all(userFilePromises);
chartData.map(monthData => {
indicators.map(indicator => {
data[indicator][0].values.push({
"date": monthData.date,
"value": +monthData.value[indicator]
});
// order data[i].values.date
data[indicator].forEach(d => d.values.sort(sortByDateAscending));
});
});
return data;
}
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] = [];
});
const baseUrl = new URL(`/data`, window.location.href).href;
// Convert drawn items to GeoJSON and check what's inside each one of them
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: []}]...}
let filter = `ST_Intersects(geom, (SELECT ST_Multi(ST_GeomFromGeoJSON('${JSON.stringify(geojson.features[i].geometry)}') ) ) )`
const userFilePromises = userFiles.map(async monthYear => {
let queryData = `${baseUrl}/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(userFilePromises);
selectionData.map(itemData => {
indicators.map(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 = (allData, indicator) => {
let dataFull = allData;
let data = dataFull[indicator];
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 makeIndicatorGraph = () => {
let data = [],
width = 450,
height = 400,
padding = 30,
margin = { top: 5, right: 10, bottom: 100, left: 35 },
id, // variable in data to use as identifier
lineVariables = null, // list of variables to display as lines
displayName, // variable in data to use as x axis labels
transitionTime = 500,
//lineColor = "#17678E",
//pointColor = "#17678E",
defaultLineColor = "CadetBlue",
defaultPointColor = "CadetBlue",
lineColors = d3.scaleOrdinal(d3.schemeCategory10),
pointColors = d3.scaleOrdinal(d3.schemeCategory10),
lineAxisLabel = "",
xAxisFormat = d3.timeFormat("%b '%y"), // mm 'yy
yAxisFormat = d3.format(".2s"), // SI format with 2 significant numbers
//rightAxisFormat = ".0%", // rounded percentage
legend = false,
title = "",
tooltipUnits = "",
tooltipFormat = "",
//legend = {title: "title", translateX: 100, translateY: 0, items:["item1","item2"]}
legendContainer = "legendZone",
updateData;
const chart = selection => {
// get data ranges using values from displayName
minDate = d3.min(data[0].values, d => {
return d[displayName];
});
minDate = d3.timeDay.offset(minDate, -15) // get previous month to get correct x-axis alignment
maxDate = d3.max(data[0], d => {
return d[displayName];
});
maxDate = d3.timeDay.offset(maxDate, 15) // get next month to get correct x-axis alignment
selection.each(() => {
// add graph svg to selected container on webpage
let areaSVG = selection
.append("svg")
// don't set height/width but use viewBox so charts get resized
// if they are within a container that can be resized (also scales text)
.attr("viewBox", `0 0 ${width} ${height}`)
//.attr("preserveAspectRatio", "xMinYMin meet"),
.attr("preserveAspectRatio", "xMidYMid meet"),
g = areaSVG.append("g")
.attr("class", "lineChart")
.attr("transform", `translate(${margin.left}, ${margin.top})`);
// add x axis
g.append("g")
.attr("class", "x axis")
.attr("transform", `translate(30, ${height - margin.left})`);
// add x axis for ticks
g.append("g")
.attr("class", "x axis-ticks")
.attr("transform", `translate(30, ${height - margin.left})`);
// add x axis for month labels
g.append("g")
.attr("class", "x axis-month-labels")
.attr("transform", `translate(30, ${height - margin.left})`);
// add x axis for year labels
g.append("g")
.attr("class", "x axis-year-labels")
.attr("transform", `translate(30, ${height - margin.left + 12})`);
//add left y axis
g.append("g")
.attr("class", "y axis")
.attr("transform", "translate(30,0)");
//label y axes
areaSVG.append("text")
.attr("class", "label")
.attr("text-anchor", "middle") // this makes it easy to centre the text as the transform is applied to the anchor
.attr("transform", `translate(${padding / 3}, ${height / 2}) rotate(-90)`) // text is drawn off the screen top left, move down and out and rotate
.attr("fill", "#b2b2b2");
//.text("Superficie inundada");
// append line container
g.append("g")
.attr("class", "lines")
.attr("transform", "translate(30, 0)");
// append circle container
g.append("g")
.attr("class", "circles")
.attr("transform", "translate(30, 0)");
// add chart title container
areaSVG.append("text")
.attr("class", "title label")
.attr("text-anchor", "middle") // this makes it easy to centre the text as the transform is applied to the anchor
.attr("transform", `translate(${width / 2}, ${margin.top * 4})`); // text is drawn off the screen top left, move down and out and rotate
// add the tooltip area to the webpage
let tooltip;
if (d3.select("div.tooltip").empty()) { // check if no tooltip div exists and add if necessary
tooltip = d3.select("body").append("div")
.attr("class", "tooltip")
.style("opacity", 0);
}
// define axes with ranges
xLine = d3.scaleTime().range([0, width - margin.left - margin.right - 30]).clamp(true);
yLine = d3.scaleLinear().range([height - margin.left - margin.right, 0 + 35])
// scale data range
xLine.domain([minDate, maxDate]).nice();
//yLine.domain(d3.extent(data, function(d) { return d[lineVariables[0]]; })).nice();
//yLine.domain([0, d3.max(data, function(d) { return d[lineVariables[0]]; })]).nice();
// Calculate min and max values of data to define chart y-axis domain
//let minDomain = d3.min(data.map(d => d.values).flat().map(d => d.value));
//console.log("data: ", data.map(d => d.values));
let maxDomain = d3.max(data.map(d => d.values).flat().map(d => d.value));
yLine.domain([0, maxDomain]).nice();
//yLine.domain([0, d3.max(data[0].values, d => d.value)]).nice();
// add axes
let xaxis = g.select(".x.axis");
xaxis.call(
d3.axisBottom(xLine)
// .ticks(d3.timeMonth.every(1))
// .tickFormat(d3.timeFormat("%b '%y"))
)
.selectAll("text")
//.attr("y", 0)
//.attr("x", 9)
.attr("y", 15)
.attr("x", 0)
.attr("dy", ".35em")
.attr("font-size", "12px")
//.attr("transform", "rotate(90)")
//.style("text-anchor", "start");
.style("text-anchor", "middle")
.style("fill", "#b2b2b2");
// format x-axis lines for minor and major ticks
//TODO: check this line to separate years starting in Jan. Maybe it is not needed
xaxis.selectAll("g.tick line")
.attr("y2", d => { // d is the tick value
if (d3.timeFormat("%m")(d) == "01") //if it is Jan
return -height - 6;
else
return 6;
})
.attr("transform", d => { // d is the tick value
if (d3.timeFormat("%m")(d) == "01") //if it is Jan
return "translate(0,6)";
})
.attr("class", d => { // d is the tick value
if (d3.timeFormat("%m")(d) == "01") //if it is Jan
return "yearTick";
});
let yaxis = g.select(".y.axis");
yaxis.transition()
.duration(500)
.call(d3.axisLeft(yLine)
/*.tickFormat(d3.format(".2s"))*/
);
// color axis labels
g.selectAll(".y.axis g.tick text")
.style("fill", "#b2b2b2"); // function (d,i) {return (i%2)?"red":"blue";})
let title = selection.select(".title.label");
title.text(chart.title())
.style("fill", "#b2b2b2");
selection.select(".title.label")
.append("tspan")
.attr("class", "far")
.html(" \uf059")
//.style("color", "#b2b2b2")
.style("cursor", "pointer")
.on("click", () => { // when clicking ? display modal with information about indicator
$("#explainIndicatorModal").on("show.bs.modal", () => {
let indicatorName = indicatorsNames[indicators.indexOf(id)]
$("#explainIndicatorModal").find("#explainIndicatorModalTitle").text(indicatorName);
$("#explainIndicatorModal").find(".modal-body").html(indicatorVars[id].explanation);
});
$("#explainIndicatorModal").modal();
});
// update chart
updateData = () => {
let time = map.timeDimension.getCurrentTime();
// update data ranges using values from displayName and lineVariables
minDate = d3.min(data[0].values, d => {
return d[displayName];
});
minDate = d3.timeDay.offset(minDate, -15) // get previous month to get correct x-axis alignment
maxDate = d3.max(data[0].values, d => {
return d[displayName];
});
maxDate = d3.timeDay.offset(maxDate, 15) // get next month to get correct x-axis alignment
// update axes' domain
xLine.domain([minDate, maxDate])
//.nice()
//.nice(d3.timeMonth)
.range([0, width - margin.left - margin.right - 30])
.clamp(true);
//yLine.domain(d3.extent(data, function(d) { return d[lineVariables[0]]; }))
//yLine.domain([0, d3.max(data, function(d) { return d[lineVariables[0]]; })]).nice()
// Calculate min and max values of data to define chart y-axis domain
//let minDomain = d3.min(data.map(d => d.values).flat().map(d => d.value));
let maxDomain = d3.max(data.map(d => d.values).flat().map(d => d.value));
yLine.domain([0, maxDomain])
//yLine.domain([0, d3.max(data[0].values, d => d.value)]).nice()
.range([height - margin.left - margin.right, 0 + 35])
.nice();
// filter data to only use the ones needed for current time
let filteredData = [];
data.forEach((d, i) => {
filteredData.push({
name: d.name,
values: []
});
d.values.filter(v => {
if (v.date <= new Date(time)) {
filteredData[i].values.push(v);
}
});
});
// update axes
let g = selection.select(".lineChart");
// update axis line with no ticks
let xaxis = g.select(".x.axis");
xaxis.transition()
.duration(500)
.call(
d3.axisBottom(xLine)
.ticks(0)
.tickSize(0)
);
// update axis ticks - one for each month
let xaxisTicks = g.select(".x.axis-ticks");
let monthsInGraph = [];
userDates.forEach(d => {
monthsInGraph.push(new Date(d));
});
xaxisTicks.transition()
.duration(500)
.call(
d3.axisBottom(xLine)
.tickValues(monthsInGraph)
.tickFormat("")
);
// update axis month labels depending on how many months there are
let xaxisLabels = g.select(".x.axis-month-labels");
// FIXME: check how this displays ticks when there are many months/years
// this fix gives up to 10 ticks
// maybe need to set up more conditions
let numberOfTicks = monthsInGraph.length < 6 ? d3.timeMonth.every(1) : 6;
xaxisLabels.transition().duration(500)
.call(
d3.axisBottom(xLine)
.ticks(numberOfTicks)
.tickFormat(d3.timeFormat("%b"))
)
.selectAll("text")
.style("fill", "#b2b2b2")
.attr("font-size", "12px");
// update axis year labels depending on how many months there are
let xaxisYearLabels = g.select(".x.axis-year-labels");
xaxisYearLabels.transition().duration(500)
.call(
d3.axisBottom(xLine)
.ticks(numberOfTicks)
.tickFormat(d3.timeFormat("'%y"))
)
.selectAll("text")
.style("fill", "#b2b2b2")
.attr("font-size", "12px");
// format x-axis lines for minor and major ticks
//TODO: check this line to separate years starting in Jan. Maybe it is not needed
xaxis.selectAll("g.tick line")
.attr("y2", d => { // d is the tick value
if (d3.timeFormat("%m")(d) == "01") //if it is Jan
return -height - 6;
else
return 6;
})
.attr("transform", d => { // d is the tick value
if (d3.timeFormat("%m")(d) == "01") //if it is Jan
return "translate(0,6)";
})
.attr("class", d => { // d is the tick value
if (d3.timeFormat("%m")(d) == "01") //if it is Jan
return "yearTick";
});
let yaxis = g.select(".y.axis");
yaxis.transition()
.duration(500)
.call(d3.axisLeft(yLine)
.tickFormat(yAxisFormat));
// color axis labels
g.selectAll(".y.axis g.tick text")
.style("fill", "#b2b2b2");
// define line
let line = d3.line()
.defined(d => d)
.curve(d3.curveMonotoneX)
.x(d => xLine(d.date))
.y(d => yLine(d.value));
// get lines
let lines = g.select(".lines");
lines.selectAll("path.line")
.data(filteredData)
.join("path") // handle enter, update, and exit automagically
.attr("stroke", (d, i) => {
return i == 0 ? defaultLineColor : lineColors(i - 1);
})
.attr("class", "line")
.attr("fill", "none")
.attr("stroke-linejoin", "round")
.attr("stroke-linecap", "round")
.attr("stroke-width", 1.5)
.attr("d", d => line(d.values))
// get circles
let circles = g.select(".circles"),
tooltip = d3.select(".tooltip");
//tooltipFormat = d3.timeFormat("%b "%y"),
//tooltipFormat = d3.format(",.2f")
//tooltipFormat = d3.format(",.3s");
circles.selectAll("g") // using nested data, so need to make a g to contain stuff
.data(filteredData)
.join( // handle enter, update, and exit separately for overall g circle containers
enter => enter
.append("g")
.attr("class", d => d.name)
.attr("stroke", (d, i) => {
return i == 0 ? defaultPointColor : pointColors(i - 1);
})
.attr("fill", (d, i) => {
return i == 0 ? defaultPointColor : pointColors(i - 1);
}),
update => update
.attr("class", d => d.name)
.attr("stroke", (d, i) => {
return i == 0 ? defaultPointColor : pointColors(i - 1);
})
.attr("fill", (d, i) => {
return i == 0 ? defaultPointColor : pointColors(i - 1);
}),
exit => exit.remove()
)
// nested join
.selectAll("circle").data(d => d.values) // access internal values array for circles here
.join( // handle enter, update, and exit separately for circles
enter => enter
.append("circle")
.attr("class", "circle")
.attr("r", 2.5)
.attr("cx", d => xLine(d.date))
.attr("cy", d => yLine(d.value))
.on("mouseover", d => {
tooltip.html(`${tooltipFormat(d.value)} ${tooltipUnits}`);
let tpWidth = tooltip.node().offsetWidth; // to center tooltip
tooltip.style("left", `${d3.event.pageX - tpWidth / 2}px`)
.style("top", `${d3.event.pageY - 23}px`)
.style("font-family", "Consolas, courier")
.style("font-size", "10pt")
.transition()
.duration(200)
.style("opacity", .9);
})
.on("mouseout", () => {
tooltip.transition()
.duration(500)
.style("opacity", 0);
}),
update => update
.attr("cx", d => xLine(d.date))
.attr("cy", d => yLine(d.value)),
exit => exit.remove()
);
}
});
}
chart.width = function(value) {
if (!arguments.length) return width;
width = value;
return chart;
};
chart.height = function(value) {
if (!arguments.length) return height;
height = value;
return chart;
};
chart.margin = function(value) {
if (!arguments.length) return margin;
margin = value;
return chart;
};
chart.id = function(value) {
if (!arguments.length) return id;
id = value;
return chart;
};
chart.lineVariables = function(value) {
if (!arguments.length) return lineVariables;
lineVariables = value;
return chart;
};
chart.displayName = function(value) {
if (!arguments.length) return displayName;
displayName = value;
return chart;
};
chart.transitionTime = function(value) {
if (!arguments.length) return transitionTime;
transitionTime = value;
return chart;
};
chart.legend = function(value) {
if (!arguments.length) return legend;
legend = value;
return chart;
};
chart.legendContainer = function(value) {
if (!arguments.length) return legendContainer;
legendContainer = value;
return chart;
};
chart.data = function(value) {
if (!arguments.length) return data;
data = value;
if (typeof updateData === "function") updateData();
return chart;
};
chart.lineColors = function(value) {
if (!arguments.length) return lineColors;
lineColors = value;
return chart;
};
chart.pointColors = function(value) {
if (!arguments.length) return pointColors;
pointColors = value;
return chart;
};
chart.xAxisFormat = function(value) {
if (!arguments.length) return xAxisFormat;
xAxisFormat = value;
return chart;
};
chart.yAxisFormat = function(value) {
if (!arguments.length) return yAxisFormat;
yAxisFormat = value;
return chart;
};
chart.transitionTime = function(value) {
if (!arguments.length) return transitionTime;
transitionTime = value;
return chart;
};
chart.lineAxisLabel = function(value) {
if (!arguments.length) return lineAxisLabel;
lineAxisLabel = value;
return chart;
};
chart.title = function(value) {
if (!arguments.length) return title;
title = value;
return chart;
};
chart.tooltipUnits = function(value) {
if (!arguments.length) return tooltipUnits;
tooltipUnits = value;
return chart;
};
chart.tooltipFormat = function(value) {
if (!arguments.length) return tooltipFormat;
tooltipFormat = value;
return chart;
};
return chart;
}
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
function grijalva_theme(target) { function grijalva_theme(target) {
...@@ -856,16 +224,14 @@ am4core.ready(function() { ...@@ -856,16 +224,14 @@ am4core.ready(function() {
radialChart.legend.fontSize = 9; radialChart.legend.fontSize = 9;
radialChart.legend.labels.template.fill = am4core.color(mainTextColor); radialChart.legend.labels.template.fill = am4core.color(mainTextColor);
let legend2 = [] var legenddata = [{ name: "Estiaje", fill: am4core.color("#595952") },
var legenddata2 = [{ name: "Estiaje", fill: am4core.color("#595952") },
{ name: "Tropical", fill: am4core.color("#838278") }, { name: "Tropical", fill: am4core.color("#838278") },
{ name: "Tropical-Invernal", fill: am4core.color("#B1AE9F") }, { name: "Tropical-Invernal", fill: am4core.color("#B1AE9F") },
{ name: "Invernal", fill: am4core.color("#E1DBC8") } { name: "Invernal", fill: am4core.color("#E1DBC8") }
]; ];
//chart.legend.data = legenddata; radialChart.legend.data = legenddata;
radialChart.legend.data = legenddata2;
radialChart.legend.fontSize = 10; radialChart.legend.fontSize = 10;
radialChart.legend.labels.template.fill = am4core.color(mainTextColor); radialChart.legend.labels.template.fill = am4core.color(mainTextColor);
var markerTemplate = radialChart.legend.markers.template; var markerTemplate = radialChart.legend.markers.template;
...@@ -914,43 +280,6 @@ am4core.ready(function() { ...@@ -914,43 +280,6 @@ am4core.ready(function() {
lineSeries.tensionX = 0.8; lineSeries.tensionX = 0.8;
lineSeries.showOnInit = true; lineSeries.showOnInit = true;
//var interfaceColors = new am4core.InterfaceColorSet();
/* switch (bullet) {
case "triangle":
var bullet = series.bullets.push(new am4charts.Bullet());
bullet.width = 12;
bullet.height = 12;
bullet.horizontalCenter = "middle";
bullet.verticalCenter = "middle";
var triangle = bullet.createChild(am4core.Triangle);
triangle.stroke = interfaceColors.getFor("background");
triangle.strokeWidth = 2;
triangle.direction = "top";
triangle.width = 12;
triangle.height = 12;
break;
case "rectangle":
var bullet = series.bullets.push(new am4charts.Bullet());
bullet.width = 10;
bullet.height = 10;
bullet.horizontalCenter = "middle";
bullet.verticalCenter = "middle";
var rectangle = bullet.createChild(am4core.Rectangle);
rectangle.stroke = interfaceColors.getFor("background");
rectangle.strokeWidth = 2;
rectangle.width = 10;
rectangle.height = 10;
break;
default:
var bullet = series.bullets.push(new am4charts.CircleBullet());
bullet.circle.stroke = interfaceColors.getFor("background");
bullet.circle.strokeWidth = 2;
break;
}*/
lineValueAxis.renderer.line.strokeOpacity = 1; lineValueAxis.renderer.line.strokeOpacity = 1;
lineValueAxis.renderer.line.strokeWidth = 2; lineValueAxis.renderer.line.strokeWidth = 2;
lineValueAxis.renderer.line.stroke = lineSeries.stroke; lineValueAxis.renderer.line.stroke = lineSeries.stroke;
...@@ -962,15 +291,6 @@ am4core.ready(function() { ...@@ -962,15 +291,6 @@ am4core.ready(function() {
createAxisAndSeries("temporal", "Áreas temporalmente inundadas", true, "triangle"); createAxisAndSeries("temporal", "Áreas temporalmente inundadas", true, "triangle");
createAxisAndSeries("vegetacion", "Suelos húmedos-vegetación acuática", true, "rectangle"); createAxisAndSeries("vegetacion", "Suelos húmedos-vegetación acuática", true, "rectangle");
// Add legend
/*
chart.legend = new am4charts.Legend();
//chart.legend.labels.template.fill = am4core.color("#ffff");
chart.legend.fontSize = 8;
chart.legend.labels.template.fill = am4core.color(mainTextColor);
chart.legend.maxHeight = 100;
*/
// Add cursor // Add cursor
lineChart.cursor = new am4charts.XYCursor(); lineChart.cursor = new am4charts.XYCursor();
lineChart.scrollbarX = new am4core.Scrollbar(); lineChart.scrollbarX = new am4core.Scrollbar();
...@@ -987,28 +307,6 @@ am4core.ready(function() { ...@@ -987,28 +307,6 @@ am4core.ready(function() {
firstDate.setDate(firstDate.getDate() - 100); firstDate.setDate(firstDate.getDate() - 100);
firstDate.setHours(0, 0, 0, 0); firstDate.setHours(0, 0, 0, 0);
var permanente = 1600;
var temporal = 2900;
var vegetacion = 8700;
/* for (var i = 0; i < 15; i++) {
// we create date objects here. In your data, you can have date strings
// and then set format of your dates using chart.dataDateFormat property,
// however when possible, use date objects, as this will speed up chart rendering.
var newDate = new Date(firstDate);
newDate.setDate(newDate.getDate() + i);
permanente += Math.round((Math.random() < 0.5 ? 1 : -1) * Math.random() * 10);
temporal += Math.round((Math.random() < 0.5 ? 1 : -1) * Math.random() * 10);
vegetacion += Math.round((Math.random() < 0.5 ? 1 : -1) * Math.random() * 10);
chartData.push({
date: newDate,
permanente: permanente,
temporal: temporal,
vegetacion: vegetacion
});
}*/
return chartData; return chartData;
} }
...@@ -1283,25 +581,6 @@ am4core.ready(function() { ...@@ -1283,25 +581,6 @@ am4core.ready(function() {
} }
}) })
/* popChart.cursor = new am4charts.XYCursor();
popChart.snapToSeries = popSeriesFemale;
popChart.cursor.events.on("cursorpositionchanged", function(ev) {
currentYear = popXAxis.positionToDate(popXAxis.toAxisPosition(ev.target.xPosition)).getFullYear().toString();
updateData();
});*/
/* range.label.text = "Fines for speeding increased";
range.label.inside = true;
range.label.rotation = 90;
range.label.horizontalCenter = "right";
range.label.verticalCenter = "bottom";*/
/* range2.label.text = "Motorcycle fee introduced";
range2.label.inside = true;
range2.label.rotation = 90;
range2.label.horizontalCenter = "right";
range2.label.verticalCenter = "bottom";*/
// bar chart // bar chart
var barChart = am4core.create("dimfrcpo-graph", am4charts.XYChart); var barChart = am4core.create("dimfrcpo-graph", am4charts.XYChart);
...@@ -1325,16 +604,6 @@ popChart.cursor.events.on("cursorpositionchanged", function(ev) { ...@@ -1325,16 +604,6 @@ popChart.cursor.events.on("cursorpositionchanged", function(ev) {
barCategoryAxis.title.text = "Superficie (Ha)"; barCategoryAxis.title.text = "Superficie (Ha)";
barCategoryAxis.title.fill = am4core.color(mainTextColor); barCategoryAxis.title.fill = am4core.color(mainTextColor);
/*var barDateAxis = barChart.yAxes.push(new am4charts.DateAxis());
barDateAxis.dataFields.date = "date"; //"year";
//barDateAxis.numberFormatter.numberFormat = "#";
barDateAxis.renderer.inversed = true;
barDateAxis.renderer.grid.template.location = 0;
barDateAxis.renderer.cellStartLocation = 0.1;
barDateAxis.renderer.cellEndLocation = 0.9;
barDateAxis.fontSize = 10;
barDateAxis.renderer.labels.template.fill = am4core.color(mainTextColor);*/
//var barValueAxis = barChart.xAxes.push(new am4charts.ValueAxis()); //var barValueAxis = barChart.xAxes.push(new am4charts.ValueAxis());
var barValueAxis = barChart.yAxes.push(new am4charts.ValueAxis()); var barValueAxis = barChart.yAxes.push(new am4charts.ValueAxis());
//barValueAxis.renderer.opposite = true; //barValueAxis.renderer.opposite = true;
...@@ -1374,27 +643,12 @@ popChart.cursor.events.on("cursorpositionchanged", function(ev) { ...@@ -1374,27 +643,12 @@ popChart.cursor.events.on("cursorpositionchanged", function(ev) {
//barValueLabel.label.fill = am4core.color(mainTextColor); //barValueLabel.label.fill = am4core.color(mainTextColor);
barValueLabel.label.fill = am4core.color("#fff"); barValueLabel.label.fill = am4core.color("#fff");
/* var barCategoryLabel = barSeries.bullets.push(new am4charts.LabelBullet());
barCategoryLabel.label.text = "{name}";
barCategoryLabel.label.horizontalCenter = "right";
barCategoryLabel.label.dx = -10;
//barCategoryLabel.label.fill = am4core.color("#fff");
barCategoryLabel.label.hideOversized = false;
barCategoryLabel.label.truncate = false;
barCategoryLabel.fontSize = 12;*/
} }
createSeries("ap", "Agua permanente"); createSeries("ap", "Agua permanente");
createSeries("at", "Áreas temporalmente inundadas"); createSeries("at", "Áreas temporalmente inundadas");
createSeries("av", "Suelos húmedos-vegetación acuática"); createSeries("av", "Suelos húmedos-vegetación acuática");
// Add a legend
/*
barChart.legend = new am4charts.Legend();
// barChart.legend.position = "top";
barChart.legend.fontSize = 10;
barChart.legend.labels.template.fill = am4core.color(mainTextColor);*/
}); // end am4core.ready() }); // end am4core.ready()
//-------------------------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------------------------
\ No newline at end of file
/* /*
* Copyright 2019 - All rights reserved. * Copyright 2021 - All rights reserved.
* Rodrigo Tapia-McClung * Rodrigo Tapia-McClung
* *
* December 2020 * January 2021
*/ */
/* globals omnivore, Promise, chroma, makeBaseMap, makeIndicatorGraph, getData, getDataInSelection */ /* globals omnivore, Promise, makeBaseMap, am4core */
/* exported indicators. userFiles, userDates, timeParse, layerControl, updateCharts */ /* exported. userFiles, userDates, timeParse, layerControl */
let timeParse, let timeParse,
timeFormat, timeFormat,
...@@ -24,18 +24,8 @@ let timeParse, ...@@ -24,18 +24,8 @@ let timeParse,
glmap, glmap,
osmLayer, cartoLightLayer, cartoDarkLayer, osmLayer, cartoLightLayer, cartoDarkLayer,
timeLayer, timeLayer,
layerControl, layerControl;
scale;
// define empty objects and indicators
let maxIndicators = {},
minIndicators = {},
indicators = ["areacpo", "perimcpo", "dlccpo", "dimfrcpo"],
indicatorsNames = ["Área", "Perímetro", "Desarrollo de la línea de costa", "Dimensión fractal"],
indicatorsUnits = ["m\u00B2", "m", "", ""],
indicatorsxAxisFormat = [".2s", ".2s", ".2f", ".2f"],
indicatorVars = {},
cols = [];
let colors = { let colors = {
"Agua permanente": { "Agua permanente": {
...@@ -52,43 +42,6 @@ let colors = { ...@@ -52,43 +42,6 @@ let colors = {
} }
} }
// Add options to combo box, and set their chart variables
// chart containers must already exist in index.php
indicators.forEach((indicator, index) => {
// colnames for queries
cols.push(`min(${indicator}) as min${indicator}`);
cols.push(`max(${indicator}) as max${indicator}`);
// initialize min and max objects to hold values for each indicator and add select options
maxIndicators[indicator] = 0;
minIndicators[indicator] = 1e30;
$("#indicatorSelect").append(`<option value="${indicator}"> ${indicatorsNames[index]}</option>`);
// chart variables
indicatorVars[indicator] = {
"chart": `${indicator}Chart`,
"chartaData": `${indicator}Data`,
"container": `#${indicator}-graph`
};
});
indicatorVars.areacpo.explanation = "Muestra la suma del &aacute;rea contenida en los pol&iacute;gonos dentro de la selecci&oacute;n o en toda la regi&oacute;n de estudio.";
indicatorVars.perimcpo.explanation = "Muestra la suma del per&iacute;metro de los pol&iacute;gonos dentro de la selecci&oacute;n o en toda la regi&oacute;n de estudio.";
indicatorVars.dlccpo.explanation = "Relaciona el per&iacute;metro de un cuerpo de agua o longitud de l&iacute;nea de costa con el per&iacute;metro de un c&iacute;rculo de igual \
&aacute;rea (A) que el cuerpo. El valor m&iacute;nimo es 1, el cual corresponde a un c&iacute;rculo perfecto, mientras que el valor m&aacute;ximo no tiene l&iacute;mite. \
En varios estudios se han obtenido valores mayores de 20, como en algunos lagos en Finlandia. Los valores cercanos a 1 son indicativos de formas circulares, mientras que \
los valores mayores de 3 son referencia de cuerpos de agua con contornos de formas alargadas. \
<br/><br/> \
Se calcula como \
<p class=\"equation\">DI = <span class=\"frac\"><sup>P</sup><span>&frasl;</span><sub>2&radic;<span style=\"text-decoration: overline;\">&pi; A</span></sub></span>,</p> \
donde P es el per&iacute;metro y A es el &aacute;rea.";
indicatorVars.dimfrcpo.explanation = "La geometr&iacute;a fractal se usa para hacer referencia a objetos demasiado irregulares y que tienen la propiedad de ser invariantes ante \
cambios de escala. En el caso de la hidrolog&iacute;a, este &iacute;ndice nos refiere la sinuosidad del contorno de un cuerpo de agua. La dimensi&oacute;n presenta valores \
reales no negativos entre 1 y 2. Los valores de este &iacute;ndice aumentan conforme el contorno del cuerpo de agua es más sinuoso. El an&aacute;lisis fractal se ha utilizado \
con &eacute;xito para medir y caracterizar rasgos lineales irregulares como las costas. \
<br/></br> \
Se calcula como \
<p class=\"equation\">DF = <span class=\"frac\"><sup>2 ln(P/4)</sup><span>&frasl;</span><sub>ln(A)</sub></span>,</p> \
donde P es el per&iacute;metro y A es el &aacute;rea.";
let currentTiles = {}, let currentTiles = {},
allTiles = {}; allTiles = {};
...@@ -215,6 +168,7 @@ const populateDates = (dates) => { // fill out date pickers with available dates ...@@ -215,6 +168,7 @@ const populateDates = (dates) => { // fill out date pickers with available dates
// hide initial screen and show map // hide initial screen and show map
$("#startHeader").remove(); $("#startHeader").remove();
$("#initial-backdrop").remove(); $("#initial-backdrop").remove();
$("#indicatorSelect").parent().remove();
$("#mainContainer")[0].style.setProperty("display", "flex", "important") $("#mainContainer")[0].style.setProperty("display", "flex", "important")
$("#mexmap").show(); $("#mexmap").show();
...@@ -324,38 +278,7 @@ const setupMap = (dates) => { ...@@ -324,38 +278,7 @@ const setupMap = (dates) => {
} }
map.sync(overlay, { offsetFn: offsetGlobal }); map.sync(overlay, { offsetFn: offsetGlobal });
resolve({ "map": map });
//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 => {
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 });
});
});
}
const flatten = arrays => {
return [].concat(arrays);
}
const queryFiles = () => {
return Promise.all(userFiles.map(getMinMax))
// the result is an array of arrays, so we'll flatten them here
.then(flatten);
}
const getMinMax = table => {
return new Promise(resolve => {
const baseUrl = new URL(`/data`, window.location.href).href;
let minmaxQuery = `${baseUrl}/query/${table}?columns=${cols.join(", ")}`;
d3.json(minmaxQuery).then(minmax => {
resolve(minmax[0]);
});
}); });
} }
...@@ -375,8 +298,6 @@ const populateMap = async(mapData) => { ...@@ -375,8 +298,6 @@ const populateMap = async(mapData) => {
let query = `${baseUrl}/query/${mes}?columns=sum(areacpo)/10000 value1`; let query = `${baseUrl}/query/${mes}?columns=sum(areacpo)/10000 value1`;
const queryData = await d3.json(query); const queryData = await d3.json(query);
let date = new Date(dateArray[i]); let date = new Date(dateArray[i]);
// console.log(date);
// date.setFullYear(2016)
queryData[0].date = date; queryData[0].date = date;
data.push(queryData[0]); data.push(queryData[0]);
}); });
...@@ -407,17 +328,10 @@ const populateMap = async(mapData) => { ...@@ -407,17 +328,10 @@ const populateMap = async(mapData) => {
let cc; let cc;
for (cc = 0; cc < data_1.length; cc++) { for (cc = 0; cc < data_1.length; cc++) {
//data_1[cc].mm = (data_1[cc].date).getMonth();
data_1[cc].mm = month[(data_1[cc].date).getMonth()]; data_1[cc].mm = month[(data_1[cc].date).getMonth()];
//data_1[cc].yy = (data_1[cc].date).getYear();
data_1[cc].yy = year[(data_1[cc].date).getYear()]; data_1[cc].yy = year[(data_1[cc].date).getYear()];
} }
/* var element = {},cart = [];
element.id = id;
element.quantity = quantity;
cart.push(element);*/
// TODO: check this for loop to use selected months and years // TODO: check this for loop to use selected months and years
var element = {}, var element = {},
...@@ -431,13 +345,8 @@ const populateMap = async(mapData) => { ...@@ -431,13 +345,8 @@ const populateMap = async(mapData) => {
element.value2 = (data_1.filter(function(d) { return d.mm == month[cntr] && d.yy == 2017 }))[0].value1; element.value2 = (data_1.filter(function(d) { return d.mm == month[cntr] && d.yy == 2017 }))[0].value1;
element.value3 = (data_1.filter(function(d) { return d.mm == month[cntr] && d.yy == 2018 }))[0].value1; element.value3 = (data_1.filter(function(d) { return d.mm == month[cntr] && d.yy == 2018 }))[0].value1;
cart.push(element); cart.push(element);
//console.log(cart);
} }
//radialChart.data = data_1;
//console.log(data_1);
//console.log(cart);
radialChart.data = cart; radialChart.data = cart;
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ LINE CHART //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ LINE CHART
...@@ -469,8 +378,6 @@ const populateMap = async(mapData) => { ...@@ -469,8 +378,6 @@ const populateMap = async(mapData) => {
let i; let i;
for (i = 0; i < aguaPermanente.length; i++) { for (i = 0; i < aguaPermanente.length; i++) {
// aguaPermanente[i].temporal = aguaTemporal[i].temporal;
// aguaPermanente[i].vegetacion = aguaVegetacion[i].vegetacion;
aguaPermanente[i].permanente = aguaPermanente[i].area; aguaPermanente[i].permanente = aguaPermanente[i].area;
aguaPermanente[i].temporal = aguaTemporal[i].area; aguaPermanente[i].temporal = aguaTemporal[i].area;
aguaPermanente[i].vegetacion = aguaVegetacion[i].area; aguaPermanente[i].vegetacion = aguaVegetacion[i].area;
...@@ -480,9 +387,7 @@ const populateMap = async(mapData) => { ...@@ -480,9 +387,7 @@ const populateMap = async(mapData) => {
} }
let grijalva_bodies = aguaPermanente; let grijalva_bodies = aguaPermanente;
grijalva_bodies.sort((a, b) => (a.date > b.date) ? 1 : -1) grijalva_bodies.sort((a, b) => (a.date > b.date) ? 1 : -1);
//let data_ls = aguaPermanente;
//console.log("grijalva bodies", grijalva_bodies);
linesChart.data = grijalva_bodies; linesChart.data = grijalva_bodies;
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ STACKED AREAS CHART //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ STACKED AREAS CHART
let data_sa = []; let data_sa = [];
...@@ -522,17 +427,13 @@ const populateMap = async(mapData) => { ...@@ -522,17 +427,13 @@ const populateMap = async(mapData) => {
let grijalva_bodies_1 = aguaPermanente_1; let grijalva_bodies_1 = aguaPermanente_1;
grijalva_bodies_1.sort((a, b) => (a.date > b.date) ? 1 : -1) grijalva_bodies_1.sort((a, b) => (a.date > b.date) ? 1 : -1)
//let data_ls = aguaPermanente;
// console.log("grijalva_bodies_1", grijalva_bodies_1);
stackedAreaChart.data = grijalva_bodies_1; stackedAreaChart.data = grijalva_bodies_1;
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ POPULATION BARS
//let data_pb = []; // populate bars
// async queries for each date that has been loaded // async queries for each date that has been loaded
const queries_pb = userFiles.map(async(mes, i) => { const queries_pb = userFiles.map(async(mes, i) => {
let query_pb = `${baseUrl}/query/${mes}?columns=descrip, areacpo`; let query_pb = `${baseUrl}/query/${mes}?columns=descrip, areacpo`;
//let query_pb = `${baseUrl}/query/${mes}?columns=areacpo/10000 area, descrip`;
//let query_pb = `${baseUrl}/query/${mes}?columns=count(descrip)::int cuenta, descrip&group=descrip`;
const queryData = await d3.json(query_pb); const queryData = await d3.json(query_pb);
let date = new Date(dateArray[i]); let date = new Date(dateArray[i]);
for (let k = 0; k < queryData.length; k++) { for (let k = 0; k < queryData.length; k++) {
...@@ -542,66 +443,23 @@ const populateMap = async(mapData) => { ...@@ -542,66 +443,23 @@ const populateMap = async(mapData) => {
if (Math.log(queryData[k].areacpo) <= 1) { queryData[k].grupo = 1 } else if (Math.log(queryData[k].areacpo) <= 2) { queryData[k].grupo = 2 } else if (Math.log(queryData[k].areacpo) <= 3) { queryData[k].grupo = 3 } else if (Math.log(queryData[k].areacpo) <= 4) { queryData[k].grupo = 4 } else if (Math.log(queryData[k].areacpo) <= 5) { queryData[k].grupo = 5 } else if (Math.log(queryData[k].areacpo) <= 6) { queryData[k].grupo = 6 } else if (Math.log(queryData[k].areacpo) <= 7) { queryData[k].grupo = 7 } else if (Math.log(queryData[k].areacpo) <= 8) { queryData[k].grupo = 8 } else if (Math.log(queryData[k].areacpo) <= 9) { queryData[k].grupo = 9 } else if (Math.log(queryData[k].areacpo) <= 10) { queryData[k].grupo = 10 } else if (Math.log(queryData[k].areacpo) <= 11) { queryData[k].grupo = 11 } else if (Math.log(queryData[k].areacpo) <= 12) { queryData[k].grupo = 12 } else if (Math.log(queryData[k].areacpo) <= 13) { queryData[k].grupo = 13 } else if (Math.log(queryData[k].areacpo) <= 14) { queryData[k].grupo = 14 } else if (Math.log(queryData[k].areacpo) <= 15) { queryData[k].grupo = 15 } else if (Math.log(queryData[k].areacpo) <= 16) { queryData[k].grupo = 16 } else if (Math.log(queryData[k].areacpo) <= 17) { queryData[k].grupo = 17 } else if (Math.log(queryData[k].areacpo) <= 18) { queryData[k].grupo = 18 } else if (Math.log(queryData[k].areacpo) <= 19) { queryData[k].grupo = 19 } else if (Math.log(queryData[k].areacpo) <= 20) { queryData[k].grupo = 20 } else { queryData[k].grupo = 20.0301186564 } if (Math.log(queryData[k].areacpo) <= 1) { queryData[k].grupo = 1 } else if (Math.log(queryData[k].areacpo) <= 2) { queryData[k].grupo = 2 } else if (Math.log(queryData[k].areacpo) <= 3) { queryData[k].grupo = 3 } else if (Math.log(queryData[k].areacpo) <= 4) { queryData[k].grupo = 4 } else if (Math.log(queryData[k].areacpo) <= 5) { queryData[k].grupo = 5 } else if (Math.log(queryData[k].areacpo) <= 6) { queryData[k].grupo = 6 } else if (Math.log(queryData[k].areacpo) <= 7) { queryData[k].grupo = 7 } else if (Math.log(queryData[k].areacpo) <= 8) { queryData[k].grupo = 8 } else if (Math.log(queryData[k].areacpo) <= 9) { queryData[k].grupo = 9 } else if (Math.log(queryData[k].areacpo) <= 10) { queryData[k].grupo = 10 } else if (Math.log(queryData[k].areacpo) <= 11) { queryData[k].grupo = 11 } else if (Math.log(queryData[k].areacpo) <= 12) { queryData[k].grupo = 12 } else if (Math.log(queryData[k].areacpo) <= 13) { queryData[k].grupo = 13 } else if (Math.log(queryData[k].areacpo) <= 14) { queryData[k].grupo = 14 } else if (Math.log(queryData[k].areacpo) <= 15) { queryData[k].grupo = 15 } else if (Math.log(queryData[k].areacpo) <= 16) { queryData[k].grupo = 16 } else if (Math.log(queryData[k].areacpo) <= 17) { queryData[k].grupo = 17 } else if (Math.log(queryData[k].areacpo) <= 18) { queryData[k].grupo = 18 } else if (Math.log(queryData[k].areacpo) <= 19) { queryData[k].grupo = 19 } else if (Math.log(queryData[k].areacpo) <= 20) { queryData[k].grupo = 20 } else { queryData[k].grupo = 20.0301186564 }
//if (k <= 20 && Math.log(queryData[k].areacpo) <= k + 1) { queryData[k].grupo = k + 1 } else { queryData[k].grupo = 20.0301186564 } //if (k <= 20 && Math.log(queryData[k].areacpo) <= k + 1) { queryData[k].grupo = k + 1 } else { queryData[k].grupo = 20.0301186564 }
} }
//data_pb.push(queryData);
//console.log(queryData)
return new Promise(resolve => { return new Promise(resolve => {
resolve(queryData); resolve(queryData);
}); });
}); });
//console.log(data_pb)
// wait for all queries to complete and set barChartData to its response // wait for all queries to complete and set barChartData to its response
Promise.all(queries_pb).then((d) => { Promise.all(queries_pb).then((d) => {
//console.log(d) barChartData = [].concat.apply([], d);
barChartData = d;
// and then set chart data
//lineStackedChart.data = data_ls;
//console.log("data_pb", data_pb);
//var merged_2 = [].concat.apply([], data_pb);
//var merged_2 = [].concat.apply([], barChartData);
barChartData = [].concat.apply([], barChartData);
//console.log("merged_2", merged_2);
//console.log(barChartData)
// set initial date to january 2016 // set initial date to january 2016
let filterDate = new Date(dateArray[0]); let filterDate = new Date(dateArray[0]);
updateBarChart(filterDate, barChartData); updateBarChart(filterDate, barChartData);
//let startDate = new Date("2015-12-31");
//let endDate = new Date("2016-02-01");
//let areclass = merged_2.filter(function(d) { return d.date >= startDate && d.date <= endDate });
/*
let areclass = merged_2.filter(d => d.date.valueOf() == filterDate.valueOf());
var elementpb = {},
cart_pb = [];
//cntr;
for (cntr = 0; cntr < 22; cntr++) {
//console.log(month[cntr]);
elementpb = {};
elementpb.grupo = Math.exp(cntr) / 10000;
elementpb.ap = (areclass.filter(function(d) { return d.descrip == "Agua permanente" && d.grupo == cntr })).length;
elementpb.at = (areclass.filter(function(d) { return d.descrip == "Áreas temporalmente inundadas" && d.grupo == cntr })).length;
elementpb.av = (areclass.filter(function(d) { return d.descrip == "Suelos húmedos-vegetación acuática" && d.grupo == cntr })).length;
//elementpb.ha = Math.exp(areclass[k].grupo) / 10000;
cart_pb.push(elementpb);
//console.log(elementpb);
}
let cart_pb1 = cart_pb.filter(function(d) { return d.ap > 0 || d.at > 0 || d.av > 0 });
cart_pb1.sort((a, b) => (a < b ? 1 : -1));
console.log("cart_pb1", cart_pb1);
popBarsChart.data = cart_pb1;*/
}); });
// end bars
//------------------------------------------------------------------------------------------------------------------------------------ let map = mapData.map;
let map = mapData.map,
minIndicators = mapData.minIndicators,
maxIndicators = mapData.maxIndicators;
let cuencaLayer = L.geoJson(null, { let cuencaLayer = L.geoJson(null, {
style: { style: {
...@@ -618,7 +476,7 @@ const populateMap = async(mapData) => { ...@@ -618,7 +476,7 @@ const populateMap = async(mapData) => {
// create mvt layers // create mvt layers
userFiles.forEach(f => { userFiles.forEach(f => {
f = mapboxLayer(f); mapboxLayer(f);
}); });
glmap = L.mapboxGL({ glmap = L.mapboxGL({
...@@ -636,7 +494,8 @@ const populateMap = async(mapData) => { ...@@ -636,7 +494,8 @@ const populateMap = async(mapData) => {
const baseUrl = new URL(`/data`, window.location.href).href; const baseUrl = new URL(`/data`, window.location.href).href;
glmap.getMapboxMap().addSource("basecuerposagua", { glmap.getMapboxMap().addSource("basecuerposagua", {
type: "vector", type: "vector",
tiles: [`${baseUrl}/basecuerposagua/mvt/{z}/{x}/{y}?geom_column=geom&columns=${indicators.join()},descrip`], //tiles: [`${baseUrl}/basecuerposagua/mvt/{z}/{x}/{y}?geom_column=geom&columns=${indicators.join()},descrip`],
tiles: [`${baseUrl}/basecuerposagua/mvt/{z}/{x}/{y}?geom_column=geom&columns=descrip`],
maxzoom: 14, maxzoom: 14,
minzoom: 7 minzoom: 7
}); });
...@@ -673,14 +532,6 @@ const populateMap = async(mapData) => { ...@@ -673,14 +532,6 @@ const populateMap = async(mapData) => {
} }
}); });
/*map.on('click', function (e) {
var features = glmap.getMapboxMap().queryRenderedFeatures(e.point, {layers: ["cuerpos_enero_2016"]});
console.log(e, features)
features.forEach(f => {
// console.log(f.properties)
})
});*/
userFiles.forEach(monthYear => { userFiles.forEach(monthYear => {
glmap.getMapboxMap().addLayer(currentTiles[monthYear]); glmap.getMapboxMap().addLayer(currentTiles[monthYear]);
}); });
...@@ -700,11 +551,6 @@ const populateMap = async(mapData) => { ...@@ -700,11 +551,6 @@ const populateMap = async(mapData) => {
duration: "P1M" duration: "P1M"
}); });
timeLayer.addTo(map); timeLayer.addTo(map);
// style currentTiles
let option = $("#indicatorSelect").val(); // option selected from dropdrown
//styleTiles(option, minIndicators, maxIndicators)
//.then(legend.addTo(map)); // add legend control -> it updates
legend.addTo(map); legend.addTo(map);
let baseLayers = { let baseLayers = {
...@@ -720,7 +566,7 @@ const populateMap = async(mapData) => { ...@@ -720,7 +566,7 @@ const populateMap = async(mapData) => {
makeBaseMap(); // basemap.js makeBaseMap(); // basemap.js
// fix for leaflet-mapbox-gl v. 0.0.11 that adds map's to tile pane: // fix for leaflet-mapbox-gl v. 0.0.11 that adds map's to tile pane:
// get children of map tile pane, create array from it and iterate // get children of map tile pane, create array from it and iterate
// setting their z-index // setting their z-index
let glmapChildren = map.getPanes().tilePane.children, let glmapChildren = map.getPanes().tilePane.children,
children = Array.from(glmapChildren); children = Array.from(glmapChildren);
...@@ -729,7 +575,6 @@ const populateMap = async(mapData) => { ...@@ -729,7 +575,6 @@ const populateMap = async(mapData) => {
} }
const updateMap = (mapData) => { const updateMap = (mapData) => {
//console.log(userFiles);
// clear tiles // clear tiles
currentTiles = {}; currentTiles = {};
...@@ -751,55 +596,6 @@ const updateMap = (mapData) => { ...@@ -751,55 +596,6 @@ const updateMap = (mapData) => {
// update timeDimension times // update timeDimension times
timeLayer._timeDimension.setAvailableTimes(userDates, "replace"); timeLayer._timeDimension.setAvailableTimes(userDates, "replace");
timeLayer._timeDimension.setCurrentTime(mapData.min); 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 = 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(summarizeData(allData, indicator));
});
} else {
// otherwise use all data
let allData = await getData();
indicators.map(async indicator => {
indicatorVars[indicator].chart.data(allData[indicator]);
});
}
$(".loader").hide("fade", 750);
} }
// define MVT layer for given month table and all indicators // define MVT layer for given month table and all indicators
...@@ -809,7 +605,8 @@ const mapboxLayer = (monthYear) => { ...@@ -809,7 +605,8 @@ const mapboxLayer = (monthYear) => {
id: monthYear, id: monthYear,
source: { source: {
type: "vector", type: "vector",
tiles: [`${baseUrl}/${monthYear}/mvt/{z}/{x}/{y}?geom_column=geom&columns=${indicators.join()},descrip`], //tiles: [`${baseUrl}/${monthYear}/mvt/{z}/{x}/{y}?geom_column=geom&columns=${indicators.join()},descrip`],
tiles: [`${baseUrl}/${monthYear}/mvt/{z}/{x}/{y}?geom_column=geom&columns=descrip`],
maxzoom: 14, maxzoom: 14,
minzoom: 7 minzoom: 7
}, },
...@@ -920,15 +717,6 @@ L.TimeDimension.Layer.Tile = L.TimeDimension.Layer.extend({ ...@@ -920,15 +717,6 @@ L.TimeDimension.Layer.Tile = L.TimeDimension.Layer.extend({
let title = $("#title"); let title = $("#title");
title.html(`<h2>Cobertura de agua en la cuenca del r&iacute;o Grijalva en ${month} de ${year}</h2>`); title.html(`<h2>Cobertura de agua en la cuenca del r&iacute;o Grijalva en ${month} de ${year}</h2>`);
// Update graphs only on timeload event
/*indicators.forEach( indicator => {
indicatorVars[indicator].chartData = indicatorVars[indicator].chart.data(); // get chart data
indicatorVars[indicator].chart.data(indicatorVars[indicator].chartData); // set chart data
});*/
//console.time("process");
//console.log("data for", monthYear);
//console.log(currentTiles)
Object.keys(allTiles).forEach(layer => { Object.keys(allTiles).forEach(layer => {
if (layer.split("cuerpos_")[1] !== monthYear) { // hide all other months if (layer.split("cuerpos_")[1] !== monthYear) { // hide all other months
glmap.getMapboxMap().setPaintProperty(layer, "fill-opacity", 0); glmap.getMapboxMap().setPaintProperty(layer, "fill-opacity", 0);
...@@ -936,7 +724,6 @@ L.TimeDimension.Layer.Tile = L.TimeDimension.Layer.extend({ ...@@ -936,7 +724,6 @@ L.TimeDimension.Layer.Tile = L.TimeDimension.Layer.extend({
glmap.getMapboxMap().setPaintProperty(layer, "fill-opacity", 0.5); glmap.getMapboxMap().setPaintProperty(layer, "fill-opacity", 0.5);
} }
}); });
//console.timeEnd("process");
} }
}); });
...@@ -944,55 +731,14 @@ L.timeDimension.layer.Tile = (layer, options) => { ...@@ -944,55 +731,14 @@ L.timeDimension.layer.Tile = (layer, options) => {
return new L.TimeDimension.Layer.Tile(layer, options); return new L.TimeDimension.Layer.Tile(layer, options);
}; };
// When selecting indicator from dropdown, style tiles.
$("#indicatorSelect").on("change", function() {
// style currentTiles
let option = this.value; // option selected from dropdrown
//styleTiles(option, minIndicators, maxIndicators)
//.then(legend.addTo(map)); // add legend control -> it updates
// FIXME: re-adding control updates its contents... why?
// Highlight plot title according to selected option
indicators.forEach(indicator => {
d3.select(indicatorVars[indicator].container).select("svg text.title").classed("active", indicator === option ? true : false);
});
});
const styleTiles = (option, minIndicators, maxIndicators) => {
// define color scale domain based on min-max values for selected indicator
let domain = [minIndicators[option], maxIndicators[option]];
//console.log(domain)
scale = chroma.scale("PuBu").padding([0.5, 0]).domain(domain).classes(5);
Object.keys(currentTiles).forEach(layer => {
/*let color = [
"interpolate",
["linear"],
["get", option],
minIndicators[option], scale(minIndicators[option]).hex(),
maxIndicators[option], scale(maxIndicators[option]).hex()
];*/
let color = ["case", ["==", ["get", "descrip"], "Agua permanente"], "#00c5ff", ["==", ["get", "descrip"], "Áreas temporalmente inundadas"], "#ff5500", ["==", ["get", "descrip"], "Suelos húmedos-vegetación acuática"], "#98e600",
'#ff0000'
];
glmap.getMapboxMap().setPaintProperty(layer, "fill-color", color);
});
return Promise.resolve(scale);
}
let legend = L.control({ let legend = L.control({
position: "bottomright" position: "bottomright"
}); });
legend.onAdd = () => { legend.onAdd = () => {
let div = L.DomUtil.create("div", "info legend leaflet-bar"); let div = L.DomUtil.create("div", "info legend leaflet-bar");
/*let option = $("#indicatorSelect").val();
let optionIndex = indicators.indexOf(option);
let legendText = indicatorsUnits[optionIndex] == "" ? indicatorsNames[optionIndex] :
`${indicatorsNames[optionIndex]} (${indicatorsUnits[optionIndex]})`;
var html = `<h6>${legendText}</h6><ul>`;
let classes = scale.classes();*/
var html = "<h6>Cuerpos de agua</h6><ul>"; var html = "<h6>Cuerpos de agua</h6><ul>";
Object.keys(colors).forEach((c, idx, array) => { Object.keys(colors).forEach( c => {
html += `<li><i style="background: ${colors[c].fill}"></i>${c}</li>`; html += `<li><i style="background: ${colors[c].fill}"></i>${c}</li>`;
}); });
html += "</ul>"; html += "</ul>";
...@@ -1008,7 +754,7 @@ const updateBarChart = (filterDate, data) => { ...@@ -1008,7 +754,7 @@ const updateBarChart = (filterDate, data) => {
cart_pb = []; cart_pb = [];
// TODO: prepare all these group data sets instead of recalculating when calling the function // TODO: prepare all these group data sets instead of recalculating when calling the function
for (cntr = 0; cntr < 22; cntr++) { for (let cntr = 0; cntr < 22; cntr++) {
elementpb = {}; elementpb = {};
elementpb.grupo = Math.exp(cntr) / 10000; elementpb.grupo = Math.exp(cntr) / 10000;
elementpb.ap = (areclass.filter(function(d) { return d.descrip == "Agua permanente" && d.grupo == cntr })).length; elementpb.ap = (areclass.filter(function(d) { return d.descrip == "Agua permanente" && d.grupo == cntr })).length;
......
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