Commit 23d86a41 authored by Rodrigo Tapia-McClung's avatar Rodrigo Tapia-McClung

Add legend. Functions to create flows and handle funcionality

parent 0869d678
{
"type": "FeatureCollection",
"name": "viajes_ocupados_hacia",
"crs": { "type": "name", "properties": { "name": "urn:ogc:def:crs:OGC:1.3:CRS84" } },
"features": [
{ "type": "Feature", "properties": { "id_origen": 24035, "muni_origen": "Soledad de Graciano Sánchez", "xo": -100.940833, "yo": 22.183056, "ocupados": "Secundario", "viajes": 53298, "id_destino": 24028, "muni_destino": "San Luis Potosí", "xd": -100.975, "yd": 22.149722, "personas": 53298 }, "geometry": { "type": "Point", "coordinates": [ -100.940833, 22.183056 ] } },
{ "type": "Feature", "properties": { "id_origen": 22006, "muni_origen": "Corregidora", "xo": -100.442, "yo": 20.531, "ocupados": "Primario", "viajes": 32663, "id_destino": 22014, "muni_destino": "Querétaro", "xd": -100.391, "yd": 20.591, "personas": 32663 }, "geometry": { "type": "Point", "coordinates": [ -100.442, 20.531 ] } },
{ "type": "Feature", "properties": { "id_origen": 22011, "muni_origen": "El Marqués", "xo": -100.275248, "yo": 20.687706, "ocupados": "Primario", "viajes": 20108, "id_destino": 22014, "muni_destino": "Querétaro", "xd": -100.391, "yd": 20.591, "personas": 20108 }, "geometry": { "type": "Point", "coordinates": [ -100.275248, 20.687706 ] } },
{ "type": "Feature", "properties": { "id_origen": 1005, "muni_origen": "Jesús María", "xo": -102.343333, "yo": 21.961111, "ocupados": "Secundario", "viajes": 16934, "id_destino": 1001, "muni_destino": "Aguascalientes", "xd": -102.296111, "yd": 21.880833, "personas": 16934 }, "geometry": { "type": "Point", "coordinates": [ -102.343333, 21.961111 ] } },
{ "type": "Feature", "properties": { "id_origen": 11004, "muni_origen": "Apaseo el Alto", "xo": -100.621667, "yo": 20.455556, "ocupados": "Primario", "viajes": 5586, "id_destino": 22014, "muni_destino": "Querétaro", "xd": -100.391, "yd": 20.591, "personas": 5586 }, "geometry": { "type": "Point", "coordinates": [ -100.621667, 20.455556 ] } },
{ "type": "Feature", "properties": { "id_origen": 11037, "muni_origen": "Silao", "xo": -101.426667, "yo": 20.943611, "ocupados": "Primario", "viajes": 4993, "id_destino": 11020, "muni_destino": "León", "xd": -101.680556, "yd": 21.119722, "personas": 4993 }, "geometry": { "type": "Point", "coordinates": [ -101.426667, 20.943611 ] } },
{ "type": "Feature", "properties": { "id_origen": 11009, "muni_origen": "Comonfort", "xo": -100.791667, "yo": 20.716667, "ocupados": "Terciario", "viajes": 4755, "id_destino": 11007, "muni_destino": "Celaya", "xd": -100.815, "yd": 20.528889, "personas": 4755 }, "geometry": { "type": "Point", "coordinates": [ -100.791667, 20.716667 ] } },
{ "type": "Feature", "properties": { "id_origen": 1011, "muni_origen": "San Francisco de los Romo", "xo": -102.270278, "yo": 22.0725, "ocupados": "Secundario", "viajes": 4375, "id_destino": 1001, "muni_destino": "Aguascalientes", "xd": -102.296111, "yd": 21.880833, "personas": 4375 }, "geometry": { "type": "Point", "coordinates": [ -102.270278, 22.0725 ] } },
{ "type": "Feature", "properties": { "id_origen": 22008, "muni_origen": "Huimilpan", "xo": -100.283333, "yo": 20.366667, "ocupados": "Primario", "viajes": 3934, "id_destino": 22014, "muni_destino": "Querétaro", "xd": -100.391, "yd": 20.591, "personas": 3934 }, "geometry": { "type": "Point", "coordinates": [ -100.283333, 20.366667 ] } },
{ "type": "Feature", "properties": { "id_origen": 11044, "muni_origen": "Villagrán", "xo": -100.996389, "yo": 20.511111, "ocupados": "Terciario", "viajes": 3916, "id_destino": 11007, "muni_destino": "Celaya", "xd": -100.815, "yd": 20.528889, "personas": 3916 }, "geometry": { "type": "Point", "coordinates": [ -100.996389, 20.511111 ] } },
{ "type": "Feature", "properties": { "id_origen": 24055, "muni_origen": "Zaragoza", "xo": -100.729722, "yo": 22.039722, "ocupados": "Secundario", "viajes": 3823, "id_destino": 24028, "muni_destino": "San Luis Potosí", "xd": -100.975, "yd": 22.149722, "personas": 3823 }, "geometry": { "type": "Point", "coordinates": [ -100.729722, 22.039722 ] } },
{ "type": "Feature", "properties": { "id_origen": 11031, "muni_origen": "San Francisco del Rincón", "xo": -101.857778, "yo": 21.018333, "ocupados": "Primario", "viajes": 1981, "id_destino": 11020, "muni_destino": "León", "xd": -101.680556, "yd": 21.119722, "personas": 1981 }, "geometry": { "type": "Point", "coordinates": [ -101.857778, 21.018333 ] } },
{ "type": "Feature", "properties": { "id_origen": 11027, "muni_origen": "Salamanca", "xo": -101.195717, "yo": 20.573931, "ocupados": "Terciario", "viajes": 1670, "id_destino": 11017, "muni_destino": "Irapuato", "xd": -101.3475, "yd": 20.674167, "personas": 1670 }, "geometry": { "type": "Point", "coordinates": [ -101.195717, 20.573931 ] } },
{ "type": "Feature", "properties": { "id_origen": 22016, "muni_origen": "San Juan del Río", "xo": -99.996389, "yo": 20.388889, "ocupados": "Primario", "viajes": 1636, "id_destino": 22014, "muni_destino": "Querétaro", "xd": -100.391, "yd": 20.591, "personas": 1636 }, "geometry": { "type": "Point", "coordinates": [ -99.996389, 20.388889 ] } },
{ "type": "Feature", "properties": { "id_origen": 11007, "muni_origen": "Celaya", "xo": -100.815, "yo": 20.528889, "ocupados": "Primario", "viajes": 1301, "id_destino": 22014, "muni_destino": "Querétaro", "xd": -100.391, "yd": 20.591, "personas": 1301 }, "geometry": { "type": "Point", "coordinates": [ -100.815, 20.528889 ] } },
{ "type": "Feature", "properties": { "id_origen": 11011, "muni_origen": "Cortazar", "xo": -100.941667, "yo": 20.433333, "ocupados": "Terciario", "viajes": 751, "id_destino": 11007, "muni_destino": "Celaya", "xd": -100.815, "yd": 20.528889, "personas": 751 }, "geometry": { "type": "Point", "coordinates": [ -100.941667, 20.433333 ] } },
{ "type": "Feature", "properties": { "id_origen": 11017, "muni_origen": "Irapuato", "xo": -101.3475, "yo": 20.674167, "ocupados": "Primario", "viajes": 729, "id_destino": 11020, "muni_destino": "León", "xd": -101.680556, "yd": 21.119722, "personas": 729 }, "geometry": { "type": "Point", "coordinates": [ -101.3475, 20.674167 ] } },
{ "type": "Feature", "properties": { "id_origen": 11009, "muni_origen": "Comonfort", "xo": -100.791667, "yo": 20.716667, "ocupados": "Primario", "viajes": 686, "id_destino": 22014, "muni_destino": "Querétaro", "xd": -100.391, "yd": 20.591, "personas": 686 }, "geometry": { "type": "Point", "coordinates": [ -100.791667, 20.716667 ] } },
{ "type": "Feature", "properties": { "id_origen": 11020, "muni_origen": "León", "xo": -101.680556, "yo": 21.119722, "ocupados": "Terciario", "viajes": 643, "id_destino": 11017, "muni_destino": "Irapuato", "xd": -101.3475, "yd": 20.674167, "personas": 643 }, "geometry": { "type": "Point", "coordinates": [ -101.680556, 21.119722 ] } },
{ "type": "Feature", "properties": { "id_origen": 11003, "muni_origen": "San Miguel de Allende", "xo": -100.743889, "yo": 20.915278, "ocupados": "Primario", "viajes": 622, "id_destino": 22014, "muni_destino": "Querétaro", "xd": -100.391, "yd": 20.591, "personas": 622 }, "geometry": { "type": "Point", "coordinates": [ -100.743889, 20.915278 ] } },
{ "type": "Feature", "properties": { "id_origen": 11025, "muni_origen": "Purísima del Rincón", "xo": -101.879167, "yo": 21.030556, "ocupados": "Primario", "viajes": 506, "id_destino": 11020, "muni_destino": "León", "xd": -101.680556, "yd": 21.119722, "personas": 506 }, "geometry": { "type": "Point", "coordinates": [ -101.879167, 21.030556 ] } }
]
}
...@@ -194,6 +194,12 @@ body { ...@@ -194,6 +194,12 @@ body {
/*text-transform: capitalize;*/ /*text-transform: capitalize;*/
} }
.legendItem {
top: -25%;
position: relative;
padding-left: 10px;
}
/* Footer */ /* Footer */
img.grayscale { img.grayscale {
filter: gray; /* IE6-9 */ filter: gray; /* IE6-9 */
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
* August-September 2019 * August-September 2019
*/ */
/* global baseFileSize, formatBytes, Promise, omnivore, JSZip, map, layerControl, updateCharts */ /* global baseFileSize, formatBytes, Promise, omnivore, JSZip, map, layerControl, intervals, updateCharts, odClick*/
/* exported makeBaseMap, baseLayerPromises, drawnItems */ /* exported makeBaseMap, baseLayerPromises, drawnItems */
/* Lines related to displaying loading bar are commented */ /* Lines related to displaying loading bar are commented */
...@@ -19,7 +19,7 @@ let baseLayerPromises = []; ...@@ -19,7 +19,7 @@ let baseLayerPromises = [];
currentBaseLayer = 1;*/ currentBaseLayer = 1;*/
let drawnItems; let drawnItems;
let od, flowMapLayer; let od, flowMapsArray = [];
/*Object.keys(baseFileSize).forEach((name) => { /*Object.keys(baseFileSize).forEach((name) => {
if (name.split(".")[1] == "zip") { if (name.split(".")[1] == "zip") {
...@@ -888,7 +888,119 @@ const toggleButtons = () => { ...@@ -888,7 +888,119 @@ const toggleButtons = () => {
}) })
}*/ }*/
let canvasPointRenderer = L.canvas({ pane: 'pane_flujos' });
const createFlowLayer = (geojson, type, addOnCreate) => {
return new Promise(resolve => {
let canvasBezierStyle = [],
animatedCanvasBezierStyle = [];
// define styles based on properties and values
intervals[type].values.forEach( (val, idx) => {
canvasBezierStyle.push({
classMinValue: idx == 0 ? 0 : intervals[type].values[idx-1] + 1,
classMaxValue: val,
symbol: {
strokeStyle: intervals[type].colors[idx],
lineWidth: intervals[type].thickness[idx],
lineCap: "round",
shadowColor: intervals[type].colors[idx],
shadowBlur: 1.5
}
});
animatedCanvasBezierStyle.push({
classMinValue: idx == 0 ? 0 : intervals[type].values[idx-1] + 1,
classMaxValue: val,
symbol: {
strokeStyle: intervals[type].colors[idx],
lineWidth: intervals[type].animThickness[idx],
lineDashOffsetSize: 4,
lineCap: "round",
shadowColor: intervals[type].colors[idx],
shadowBlur: 1.5
}
})
});
$.getJSON(geojson, data => {
let flowMapLayer = L.canvasFlowmapLayer(data, {
// Define origins and destination from json values
originAndDestinationFieldIds: {
originUniqueIdField: "id_origen",
originGeometry: {
x: "xo",
y: "yo"
},
destinationUniqueIdField: "id_destino",
destinationGeometry: {
x: "xd",
y: "yd"
}
},
// Line styles
canvasBezierStyle: {
type: "classBreaks",
field: "viajes",
classBreakInfos: canvasBezierStyle
},
// Animated line styles
animatedCanvasBezierStyle: {
type: "classBreaks",
field: "viajes",
classBreakInfos: animatedCanvasBezierStyle
},
// dot styles
style: function (geoJsonFeature) {
if (geoJsonFeature.properties.isOrigin) {
return {
renderer: canvasPointRenderer,
radius: 5,
weight: 1,
color: 'rgb(195, 255, 62)',
fillColor: 'rgba(195, 255, 62, 0.6)',
fillOpacity: 0.6
};
} else {
return {
renderer: canvasPointRenderer,
radius: 2.5,
weight: 0.25,
color: 'rgb(17, 142, 170)',
fillColor: 'rgb(17, 142, 170)',
fillOpacity: 0.7
};
}
},
// some custom options
pathDisplayMode: "all",
animationStarted: true,
//animationEasingFamily: "Cubic",
//animationEasingType: "In",
animationEasingFamily: "Linear",
animationEasingType: "None",
animationDuration: 2000,
customLayerId: type,
pane: "pane_flujos"
}).bindTooltip( layer => { // what to display on hover
let coords = layer.getLatLng();
let label = od.features.filter( f => f.properties.lng == coords.lng && f.properties.lat == coords.lat);
return label[0].properties.nombre;
})
// if layer is to be added to on creation, add click funcionality
if (addOnCreate) {
flowMapLayer.addTo(map).on('click', odClick);
}
flowMapsArray.push(flowMapLayer);
resolve(flowMapsArray);
});
});
}
const makeBaseMap = () => { const makeBaseMap = () => {
//return new Promise( resolve=> {
createPane("pane_munis", 402); createPane("pane_munis", 402);
createPane("pane_munis_contexto", 402); createPane("pane_munis_contexto", 402);
createPane("pane_ZMs", 403); createPane("pane_ZMs", 403);
...@@ -981,393 +1093,224 @@ const makeBaseMap = () => { ...@@ -981,393 +1093,224 @@ const makeBaseMap = () => {
od = data; od = data;
}); });
let canvasPointRenderer = L.canvas({ pane: 'pane_flujos' }); // create one flow, then another, then another...
// and finally set reset control funcionality
$.getJSON("data/viajes_ocupados_desde.geojson", data => { createFlowLayer("data/viajes_ocupados_desde.geojson", "ocupadosDesde", true)
flowMapLayer = L.canvasFlowmapLayer(data, { .then( () => createFlowLayer("data/viajes_ocupados_hacia.geojson", "ocupadosHacia") )
// Define origins and destination from json values .then( layers => {
originAndDestinationFieldIds: { // reset to all flows displayed
originUniqueIdField: "id_origen", $("#resetFlows").on("click", () => {
originGeometry: { layers.forEach( layer => {
x: "xo", if (map.hasLayer(layer)) {
y: "yo" layer.selectFeaturesForPathDisplay(layer.originAndDestinationGeoJsonPoints.features, "SELECTION_NEW");
}, $("#tblViajesDesde tbody").html("");
destinationUniqueIdField: "id_destino",
destinationGeometry: {
x: "xd",
y: "yd"
}
},
// Line styles
canvasBezierStyle: {
type: "classBreaks",
field: "viajes",
classBreakInfos: [{
classMinValue: 0,
classMaxValue: 1000,
symbol: {
strokeStyle: "#00c5ff",
lineWidth: 0.5,
lineCap: "round",
shadowColor: "#00c5ff",
shadowBlur: 1.5
}
}, {
classMinValue: 1001,
classMaxValue: 2000,
symbol: {
strokeStyle: "#008fdc",
lineWidth: 1.5,
lineCap: "round",
shadowColor: "#008fdc",
shadowBlur: 1.5
}
}, {
classMinValue: 2001,
classMaxValue: 6000,
symbol: {
strokeStyle: "#005ce6",
lineWidth: 2,
lineCap: "round",
shadowColor: "#005ce6",
shadowBlur: 1.5
}
}, {
classMinValue: 6001,
classMaxValue: 7200,
symbol: {
strokeStyle: "#4c0073",
lineWidth: 10,
lineCap: "round",
shadowColor: "#4c0073",
shadowBlur: 1.5
}
}]
},
// Animated line styles
animatedCanvasBezierStyle: {
type: "classBreaks",
field: "viajes",
classBreakInfos: [{
classMinValue: 0,
classMaxValue: 1000,
symbol: {
strokeStyle: "#00c5ff",
lineWidth: 0.5,
lineDashOffsetSize: 4,
lineCap: "round",
shadowColor: "#00c5ff",
shadowBlur: 1.5
} }
}, { });
classMinValue: 1001,
classMaxValue: 2000,
symbol: {
strokeStyle: "#008fdc",
lineWidth: 1.5,
lineDashOffsetSize: 4,
lineCap: "round",
shadowColor: "#008fdc",
shadowBlur: 1.5
}
}, {
classMinValue: 2001,
classMaxValue: 6000,
symbol: {
strokeStyle: "#005ce6",
lineWidth: 4,
lineDashOffsetSize: 4,
lineCap: "round",
shadowColor: "#005ce6",
shadowBlur: 1.5
}
}, {
classMinValue: 6001,
classMaxValue: 7200,
symbol: {
strokeStyle: "#4c0073",
lineWidth: 15,
lineDashOffsetSize: 4,
lineCap: "round",
shadowColor: "#4c0073",
shadowBlur: 1.5
}
}]
},
// dot styles
style: function (geoJsonFeature) {
if (geoJsonFeature.properties.isOrigin) {
return {
renderer: canvasPointRenderer,
radius: 5,
weight: 1,
color: 'rgb(195, 255, 62)',
fillColor: 'rgba(195, 255, 62, 0.6)',
fillOpacity: 0.6
};
} else {
return {
renderer: canvasPointRenderer,
radius: 2.5,
weight: 0.25,
color: 'rgb(17, 142, 170)',
fillColor: 'rgb(17, 142, 170)',
fillOpacity: 0.7
};
}
},
// some custom options
pathDisplayMode: "all",
animationStarted: true,
//animationEasingFamily: "Cubic",
//animationEasingType: "In",
animationEasingFamily: "Linear",
animationEasingType: "None",
animationDuration: 2000,
pane: "pane_flujos"
}).bindTooltip( layer => { // what to display on hover
let coords = layer.getLatLng();
let label = od.features.filter( f => f.properties.lng == coords.lng && f.properties.lat == coords.lat);
return label[0].properties.nombre;
});
flowMapLayer.addTo(map);
// hack to get origins and destinations in desired map pane
//$(".leaflet-pane.leaflet-overlay-pane canvas").detach().appendTo($(".leaflet-pane_flujos-pane"));
// Define what happens when user clicks dots
flowMapLayer.on("click", e => {
// clear paths
flowMapLayer.clearAllPathSelections();
let origins = "";
// select and draw flows from origins
if (e.sharedOriginFeatures.length) {
flowMapLayer.selectFeaturesForPathDisplay(e.sharedOriginFeatures, "SELECTION_NEW");
/*e.sharedOriginFeatures.forEach( origin => {
origins += `${origin.properties.muni_origen} &rarr; ${origin.properties.muni_destino}: ${origin.properties.viajes} viajes <br>`;
});*/
}
// select and add flows toward those origins, i.e., for dots that are both origins and destinations
let dests = flowMapLayer.originAndDestinationGeoJsonPoints.features.filter( f => f.geometry.coordinates[0] === e.latlng.lng && f.geometry.coordinates[1] === e.latlng.lat);
flowMapLayer.selectFeaturesForPathDisplay(dests, "SELECTION_ADD");
dests.forEach( dest => {
//origins += `${dest.properties.muni_origen} &rarr; ${dest.properties.muni_destino}: ${dest.properties.viajes} viajes <br>`;
origins += `<tr><td>${dest.properties.muni_origen}</td><td>${dest.properties.muni_destino}</td><td>${dest.properties.viajes}</td></tr>`;
}); });
$("#tblViajesDesde tbody").html(origins); //resolve(layers);
// if dots are only destinations, add paths when clicked on
/*if (e.sharedDestinationFeatures.length) {
flowMapLayer.selectFeaturesForPathDisplay(e.sharedDestinationFeatures, "SELECTION_NEW");
}*/
});
// reset to all flows displayed
$("#resetFlows").on("click", () => {
flowMapLayer.selectFeaturesForPathDisplay(flowMapLayer.originAndDestinationGeoJsonPoints.features, "SELECTION_NEW");
$("#tblViajesDesde tbody").html("");
}); });
}); //});
/* // Localize Leaflet.Draw texts /* // Localize Leaflet.Draw texts
L.drawLocal = { L.drawLocal = {
draw: { draw: {
toolbar: { toolbar: {
actions: { actions: {
title: "Cancelar dibujo", title: "Cancelar dibujo",
text: "Cancelar" text: "Cancelar"
}, },
finish: { finish: {
title: "Terminar dibujo", title: "Terminar dibujo",
text: "Terminar" text: "Terminar"
}, },
undo: { undo: {
title: "Eliminar último punto dibujado", title: "Eliminar último punto dibujado",
text: "Eliminar último punto" 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"
}
}, },
buttons: { handlers: {
polyline: "Dibujar una polilínea", circle: {
polygon: "Dibujar un polígono", tooltip: {
rectangle: "Dibujar un rectángulo", start: "Haz click y arrastra para dibujar un círculo"
circle: "Dibujar un círculo", },
marker: "Dibujar un marcador", radius: "Radio"
circlemarker: "Dibujar un marcador circular" },
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"
}
}
} }
}, },
handlers: { edit: {
circle: { toolbar: {
tooltip: { actions: {
start: "Haz click y arrastra para dibujar un círculo" 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"
}
}, },
radius: "Radio" buttons: {
}, edit: "Editar capas",
circlemarker: { editDisabled: "No hay capas que editar",
tooltip: { remove: "Eliminar capas",
start: "Haz click en el mapa para ubicar el marcador circular" removeDisabled: "No hay capas que eliminar"
} }
}, },
marker: { handlers: {
tooltip: { edit: {
start: "Haz click en el mapa para ubicar el marcador" 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: { polygon: {
error: "<strong>Error:</strong>", showArea: true,
tooltip: { //allowIntersection: false, // Restricts shapes to simple polygons
start: "Haz click para empezar a dibujar la figura", //drawError: {
cont: "Haz click para continuar dibujando la figura", //color: "#f9a800",
end: "Haz click en el primer punto para cerrar la figura" //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: { polyline: {
error: "<strong>Error:</strong> las líneas no deben cruzarse", //allowIntersection:false,
tooltip: { shapeOptions: {
start: "Haz click para empezar a dibujar la línea", color: "#42ffc3"
cont: "Haz click para continuar dibujando la línea",
end: "Haz click en el último punto para terminar la línea"
} }
}, },
rectangle: { rectangle: {
tooltip: { shapeOptions: {
start: "Haz click y arrastra para dibujar un rectángulo" color: "#42ffc3"
}
},
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: { marker: false,
edit: "Editar capas", circlemarker: false,
editDisabled: "No hay capas que editar", circle: false // Turns off this drawing tool
remove: "Eliminar capas",
removeDisabled: "No hay capas que eliminar"
}
}, },
handlers: { edit: {
edit: { featureGroup: drawnItems,
tooltip: { //remove: false
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"
}
}
} }
} });
} map.addControl(drawControl);
// 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 // set z-index of panes so actions can be done on drawnItems when editing/deleting
map.on(L.Draw.Event.CREATED, event => { map.on(L.Draw.Event.CREATED, event => {
$("#mexmap .leaflet-pane.leaflet-overlay-pane").css("z-index", "400"); $("#mexmap .leaflet-pane.leaflet-overlay-pane").css("z-index", "400");
let layer = event.layer, let layer = event.layer,
feature = layer.feature = layer.feature || {}; // Initialize feature feature = layer.feature = layer.feature || {}; // Initialize feature
feature.type = feature.type || "Feature"; // Initialize feature.type feature.type = feature.type || "Feature"; // Initialize feature.type
feature.properties = feature.properties || {}; // Initialize feature.properties feature.properties = feature.properties || {}; // Initialize feature.properties
drawnItems.addLayer(layer); // whatever you want to do with the created layer drawnItems.addLayer(layer); // whatever you want to do with the created layer
// give each drawn item an id and color from an array // give each drawn item an id and color from an array
styleDrawnItems(); styleDrawnItems();
// disable buttons if there are 10 drawn items // disable buttons if there are 10 drawn items
toggleButtons(); toggleButtons();
// after drawing shape, update chart with data for polygons contained inside it // after drawing shape, update chart with data for polygons contained inside it
updateCharts(); updateCharts();
}); });
map.on(L.Draw.Event.DELETESTART, () => { map.on(L.Draw.Event.DELETESTART, () => {
// before deleting shape, bring pane up // before deleting shape, bring pane up
$("#mexmap .leaflet-pane.leaflet-overlay-pane").css("z-index", "451"); $("#mexmap .leaflet-pane.leaflet-overlay-pane").css("z-index", "451");
}); });
map.on(L.Draw.Event.DELETED, () => { map.on(L.Draw.Event.DELETED, () => {
// after deleting a drawn item, refresh the list of ids and colors // after deleting a drawn item, refresh the list of ids and colors
styleDrawnItems(); styleDrawnItems();
// enable buttons if there are less than 10 drawn items // enable buttons if there are less than 10 drawn items
toggleButtons(); 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, () => { // after deleting shape, send pane down
$("#mexmap .leaflet-pane.leaflet-overlay-pane").css("z-index", "451"); $("#mexmap .leaflet-pane.leaflet-overlay-pane").css("z-index", "400");
// before editing shape, bring pane up // and update chart with data:
}); // if there are drawnItems, use them. If not, use original data
updateCharts();
});
map.on(L.Draw.Event.EDITSTOP, () => { map.on(L.Draw.Event.EDITSTART, () => {
$("#mexmap .leaflet-pane.leaflet-overlay-pane").css("z-index", "400"); $("#mexmap .leaflet-pane.leaflet-overlay-pane").css("z-index", "451");
// before editing shape, bring pane up // before editing shape, bring pane up
}); });
map.on(L.Draw.Event.EDITED, () => { map.on(L.Draw.Event.EDITSTOP, () => {
// before editing shape, send pane down $("#mexmap .leaflet-pane.leaflet-overlay-pane").css("z-index", "400");
$("#mexmap .leaflet-pane.leaflet-overlay-pane").css("z-index", "400"); // before editing shape, bring pane up
// after editing shape, update chart with data for polygons contained inside it });
updateCharts();
}); 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
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
*/ */
/* globals omnivore, Promise, chroma, makeBaseMap, makeIndicatorGraph, getData, getDataInSelection */ /* globals omnivore, Promise, chroma, makeBaseMap, makeIndicatorGraph, getData, getDataInSelection */
/* exported indicators. userFiles, userDates, timeParse, layerControl, updateCharts */ /* exported indicators. userFiles, userDates, timeParse, layerControl, updateCharts, intervals */
let timeParse, let timeParse,
timeFormat, timeFormat,
...@@ -30,9 +30,15 @@ let timeParse, ...@@ -30,9 +30,15 @@ let timeParse,
// define empty objects and indicators // define empty objects and indicators
let maxIndicators = {}, let maxIndicators = {},
minIndicators = {}, minIndicators = {},
indicators = ["area", "perimeter", "costa", "df"], //indicators = ["area", "perimeter", "costa", "df"],
indicatorsNames = ["Área", "Perímetro", "Desarrollo de la línea de costa", "Dimensión fractal"], indicators = ["ocupadosDesde", "ocupadosHacia", "poicDesde", "poicHacia", "ocupadosEntre", "poicEntre"],
indicatorsUnits = ["m\u00B2", "m", "", ""], indicatorsNames = ["Viajes de ocupados desde centros de mercado", "Viajes de ocupados hacia centros de mercado",
"Viajes de personas en OIC desde centros de mercado", "Viajes de personas en OIC hacia centros de mercado",
"Viajes de ocupados entre zonas", "Viajes de personas en OIC entre zonas"],
indicatorsShortNames = ["Ocupados desde <br/> centros de mercado", "Ocupados hacia <br/> centros de mercado",
"OIC desde centros <br/> de mercado", "OIC hacia centros <br/> de mercado",
"Ocupados entre zonas", "OIC entre zonas"],
//indicatorsUnits = ["m\u00B2", "m", "", ""],
indicatorsxAxisFormat = [".2s", ".2s", ".2f", ".2f"], indicatorsxAxisFormat = [".2s", ".2s", ".2f", ".2f"],
indicatorVars = {}, indicatorVars = {},
cols = []; cols = [];
...@@ -55,6 +61,24 @@ indicators.forEach((indicator, index) => { ...@@ -55,6 +61,24 @@ indicators.forEach((indicator, index) => {
}; };
}); });
let intervals = {
"ocupadosDesde": {
"classes": ["Menos de 1,000", "1,001 - 2,000", "2,001 - 6,000", "6,001 - 7,200"],
"values" : [1000, 2000, 6000, 7200],
"colors": ["#00c5ff", "#008fdc", "#005ce6", "#4c0073"],
"thickness": [0.5, 1.5, 2, 10],
"animThickness": [0.5, 1.5, 4, 15]
},
"ocupadosHacia": {
"classes": ["Menos de 1,000", "1,001 - 2,000", "2,001 - 6,000", "6,001 - 32,000", "32,001 - 53,300"],
"values" : [1000, 2000, 6000, 32000, 533000],
"colors": ["#ffbee8", "#ff73df", "#ff00c5", "#ad027d", "#80006b"],
"thickness": [0.5, 1.5, 2, 4, 10],
"animThickness": [0.5, 1.5, 4, 10, 15]
}
}
/*
indicatorVars.area.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.area.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.perimeter.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.perimeter.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.costa.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 \ indicatorVars.costa.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 \
...@@ -73,6 +97,7 @@ indicatorVars.df.explanation = "La geometr&iacute;a fractal se usa para hacer re ...@@ -73,6 +97,7 @@ indicatorVars.df.explanation = "La geometr&iacute;a fractal se usa para hacer re
Se calcula como \ 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> \ <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."; donde P es el per&iacute;metro y A es el &aacute;rea.";
*/
let currentTiles = {}, let currentTiles = {},
allTiles = {}; allTiles = {};
...@@ -355,6 +380,35 @@ const getMinMax = table => { ...@@ -355,6 +380,35 @@ const getMinMax = table => {
}); });
} }
const odClick = (e) => {
e.target.clearAllPathSelections();
let origins = "";
// select and draw flows from origins
if (e.sharedOriginFeatures.length) {
e.target.selectFeaturesForPathDisplay(e.sharedOriginFeatures, "SELECTION_NEW");
/*e.sharedOriginFeatures.forEach( origin => {
/ origins += `${origin.properties.muni_origen} &rarr; ${origin.properties.muni_destino}: ${origin.properties.viajes} viajes <br>`;
});*/
}
// select and add flows toward those origins, i.e., for dots that are both origins and destinations
let dests = e.target.originAndDestinationGeoJsonPoints.features.filter( f => f.geometry.coordinates[0] === e.latlng.lng && f.geometry.coordinates[1] === e.latlng.lat);
e.target.selectFeaturesForPathDisplay(dests, "SELECTION_ADD");
dests.forEach( dest => {
//origins += `${dest.properties.muni_origen} &rarr; ${dest.properties.muni_destino}: ${dest.properties.viajes} viajes <br>`;
origins += `<tr><td>${dest.properties.muni_origen}</td><td>${dest.properties.muni_destino}</td><td>${dest.properties.viajes}</td></tr>`;
});
$("#tblViajesDesde tbody").html(origins);
if (e.sharedDestinationFeatures.length) {
e.target.selectFeaturesForPathDisplay(e.sharedDestinationFeatures, "SELECTION_ADD");
}
// if dots are only destinations, add paths when clicked on
/*if (e.sharedDestinationFeatures.length) {
e.target.selectFeaturesForPathDisplay(e.sharedDestinationFeatures, "SELECTION_NEW");
}*/
}
const populateMap = async(mapData) => { const populateMap = async(mapData) => {
// FIX: comment out to avoid DB calls // FIX: comment out to avoid DB calls
...@@ -462,7 +516,9 @@ const populateMap = async(mapData) => { ...@@ -462,7 +516,9 @@ const populateMap = async(mapData) => {
}; };
layerControl = L.control.layers(baseLayers, overlays).addTo(map); layerControl = L.control.layers(baseLayers, overlays).addTo(map);
makeBaseMap(); // basemap.js makeBaseMap() // basemap.js
//.then( flowLayers => { });
legend.addTo(map);
// 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
...@@ -705,6 +761,23 @@ L.timeDimension.layer.Tile = (layer, options) => { ...@@ -705,6 +761,23 @@ L.timeDimension.layer.Tile = (layer, options) => {
$("#indicatorSelect").on("change", function() { $("#indicatorSelect").on("change", function() {
// style currentTiles // style currentTiles
let option = this.value; // option selected from dropdrown let option = this.value; // option selected from dropdrown
flowMapsArray.forEach( layer => {
if (layer.options.customLayerId === option) {
map.addLayer(layer);
layer.on('click', odClick);
/*layer.getLayers().forEach(l => {
console.log(l.feature.properties._isSelectedForPathDisplay)
});*/
// TODO: Recover each layer state and populate table according to that
// layer._layers[i].feature.properties._isSelectedforPathDisplay
} else {
layer.off("click", odClick);
map.removeLayer(layer);
}
});
styleTiles(option, minIndicators, maxIndicators) styleTiles(option, minIndicators, maxIndicators)
.then(legend.addTo(map)); // add legend control -> it updates .then(legend.addTo(map)); // add legend control -> it updates
// FIXME: re-adding control updates its contents... why? // FIXME: re-adding control updates its contents... why?
...@@ -726,7 +799,7 @@ const styleTiles = (option, minIndicators, maxIndicators) => { ...@@ -726,7 +799,7 @@ const styleTiles = (option, minIndicators, maxIndicators) => {
minIndicators[option], scale(minIndicators[option]).hex(), minIndicators[option], scale(minIndicators[option]).hex(),
maxIndicators[option], scale(maxIndicators[option]).hex() maxIndicators[option], scale(maxIndicators[option]).hex()
]; ];
glmap.getMapboxMap().setPaintProperty(layer, "fill-color", color); //glmap.getMapboxMap().setPaintProperty(layer, "fill-color", color);
}); });
return Promise.resolve(scale); return Promise.resolve(scale);
} }
...@@ -735,20 +808,70 @@ let legend = L.control({ ...@@ -735,20 +808,70 @@ let legend = L.control({
position: "bottomright" position: "bottomright"
}); });
legend.onAdd = () => { legend.onAdd = function() {
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 option = $("#indicatorSelect").val();
let optionIndex = indicators.indexOf(option); let optionIndex = indicators.indexOf(option);
let legendText = indicatorsUnits[optionIndex] == "" ? indicatorsNames[optionIndex] : //let legendText = indicatorsUnits[optionIndex] == "" ? indicatorsNames[optionIndex] :
`${indicatorsNames[optionIndex]} (${indicatorsUnits[optionIndex]})`; // `${indicatorsNames[optionIndex]} (${indicatorsUnits[optionIndex]})`;
var html = `<h6>${legendText}</h6><ul>`;
let classes = scale.classes(); //title
classes.forEach((c, idx, array) => { let title = L.DomUtil.create("h6", "");
title.innerHTML = `${indicatorsShortNames[optionIndex]}`;
div.appendChild(title);
// list
let list = L.DomUtil.create("ul", "");
div.appendChild(list);
//var html = `<h6>${indicatorsShortNames[optionIndex]}</h6><ul>`;
//let domain =
//scale = chroma.scale("PuBu").padding([0.5, 0]).domain(domain).classes(5);
// data
let classes = intervals[option].classes;
//let classes = scale.classes();
/*classes.forEach((c, idx, array) => {
if (idx != array.length - 1) { if (idx != array.length - 1) {
html += `<li><i style="background: ${scale(c).hex()}"></i>${d3.format(",.4~s")(classes[idx])} - ${d3.format(",.4~s")(classes[idx+1])}</li>`; html += `<li><i style="background: ${scale(c).hex()}"></i>${d3.format(",.4~s")(classes[idx])} - ${d3.format(",.4~s")(classes[idx+1])}</li>`;
} }
});*/
// create stuff for each type of flow
classes.forEach( (c, idx) => {
// create list element
let item = L.DomUtil.create('li');
// create canvas element with arc of appropriate thickness ad color
let canvas = L.DomUtil.create('canvas');
let originProp = L.DomUtil.testProp(['transformOrigin', 'WebkitTransformOrigin', 'msTransformOrigin']);
canvas.style[originProp] = '50% 50%';
canvas.width = 18;
canvas.height = 18;
var ctx = canvas.getContext("2d");
ctx.beginPath();
ctx.arc(18, 18, 15, 1.5 * Math.PI, Math.PI, true);
ctx.lineWidth = intervals[option].thickness[idx];
ctx.lineCap = 'round';
// line color
ctx.strokeStyle = intervals[option].colors[idx];;
ctx.stroke();
// append canvas to list element
item.appendChild(canvas);
// create legend item text
let span = L.DomUtil.create("span", "legendItem");
span.innerText = c;
// append text to list item
item.appendChild(span)
// lastly, append item to list
list.appendChild(item);
}); });
html += "</ul>";
div.innerHTML = html;
return div; return div;
}; };
\ 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