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 {
/*text-transform: capitalize;*/
}
.legendItem {
top: -25%;
position: relative;
padding-left: 10px;
}
/* Footer */
img.grayscale {
filter: gray; /* IE6-9 */
......
......@@ -5,7 +5,7 @@
* 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 */
/* Lines related to displaying loading bar are commented */
......@@ -19,7 +19,7 @@ let baseLayerPromises = [];
currentBaseLayer = 1;*/
let drawnItems;
let od, flowMapLayer;
let od, flowMapsArray = [];
/*Object.keys(baseFileSize).forEach((name) => {
if (name.split(".")[1] == "zip") {
......@@ -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 = () => {
//return new Promise( resolve=> {
createPane("pane_munis", 402);
createPane("pane_munis_contexto", 402);
createPane("pane_ZMs", 403);
......@@ -981,393 +1093,224 @@ const makeBaseMap = () => {
od = data;
});
let canvasPointRenderer = L.canvas({ pane: 'pane_flujos' });
$.getJSON("data/viajes_ocupados_desde.geojson", data => {
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: [{
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
// create one flow, then another, then another...
// and finally set reset control funcionality
createFlowLayer("data/viajes_ocupados_desde.geojson", "ocupadosDesde", true)
.then( () => createFlowLayer("data/viajes_ocupados_hacia.geojson", "ocupadosHacia") )
.then( layers => {
// reset to all flows displayed
$("#resetFlows").on("click", () => {
layers.forEach( layer => {
if (map.hasLayer(layer)) {
layer.selectFeaturesForPathDisplay(layer.originAndDestinationGeoJsonPoints.features, "SELECTION_NEW");
$("#tblViajesDesde tbody").html("");
}
}, {
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);
// 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("");
//resolve(layers);
});
});
/* // 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"
//});
/* // 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"
}
},
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"
}
}
}
},
handlers: {
circle: {
tooltip: {
start: "Haz click y arrastra para dibujar un círculo"
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"
}
},
radius: "Radio"
},
circlemarker: {
tooltip: {
start: "Haz click en el mapa para ubicar el marcador circular"
buttons: {
edit: "Editar capas",
editDisabled: "No hay capas que editar",
remove: "Eliminar capas",
removeDisabled: "No hay capas que eliminar"
}
},
marker: {
tooltip: {
start: "Haz click en el mapa para ubicar el marcador"
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: {
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"
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: {
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"
//allowIntersection:false,
shapeOptions: {
color: "#42ffc3"
}
},
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"
shapeOptions: {
color: "#42ffc3"
}
},
buttons: {
edit: "Editar capas",
editDisabled: "No hay capas que editar",
remove: "Eliminar capas",
removeDisabled: "No hay capas que eliminar"
}
marker: false,
circlemarker: false,
circle: false // Turns off this drawing tool
},
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"
}
}
edit: {
featureGroup: drawnItems,
//remove: false
}
}
}
// 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);
});
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
// 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
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
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();
// 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();
});
// 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.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.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();
map.on(L.Draw.Event.EDITSTART, () => {
$("#mexmap .leaflet-pane.leaflet-overlay-pane").css("z-index", "451");
// before editing shape, bring pane up
});
// 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.EDITSTOP, () => {
$("#mexmap .leaflet-pane.leaflet-overlay-pane").css("z-index", "400");
// before editing shape, bring pane up
});
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.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();
});
*/
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
......@@ -6,7 +6,7 @@
*/
/* 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,
timeFormat,
......@@ -30,9 +30,15 @@ let timeParse,
// define empty objects and indicators
let maxIndicators = {},
minIndicators = {},
indicators = ["area", "perimeter", "costa", "df"],
indicatorsNames = ["Área", "Perímetro", "Desarrollo de la línea de costa", "Dimensión fractal"],
indicatorsUnits = ["m\u00B2", "m", "", ""],
//indicators = ["area", "perimeter", "costa", "df"],
indicators = ["ocupadosDesde", "ocupadosHacia", "poicDesde", "poicHacia", "ocupadosEntre", "poicEntre"],
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"],
indicatorVars = {},
cols = [];
......@@ -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.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 \
......@@ -73,6 +97,7 @@ indicatorVars.df.explanation = "La geometr&iacute;a fractal se usa para hacer re
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 = {},
allTiles = {};
......@@ -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) => {
// FIX: comment out to avoid DB calls
......@@ -462,7 +516,9 @@ const populateMap = async(mapData) => {
};
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:
// get children of map tile pane, create array from it and iterate
......@@ -705,6 +761,23 @@ L.timeDimension.layer.Tile = (layer, options) => {
$("#indicatorSelect").on("change", function() {
// style currentTiles
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)
.then(legend.addTo(map)); // add legend control -> it updates
// FIXME: re-adding control updates its contents... why?
......@@ -726,7 +799,7 @@ const styleTiles = (option, minIndicators, maxIndicators) => {
minIndicators[option], scale(minIndicators[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);
}
......@@ -735,20 +808,70 @@ let legend = L.control({
position: "bottomright"
});
legend.onAdd = () => {
legend.onAdd = function() {
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();
classes.forEach((c, idx, array) => {
//let legendText = indicatorsUnits[optionIndex] == "" ? indicatorsNames[optionIndex] :
// `${indicatorsNames[optionIndex]} (${indicatorsUnits[optionIndex]})`;
//title
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) {
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;
};
\ 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