From 7f84d26390781fa3a5d4427d1165e54cdead8231 Mon Sep 17 00:00:00 2001 From: Joaquim Nallar Date: Fri, 22 Nov 2024 20:56:32 +0100 Subject: [PATCH 1/2] feat: Add blurring observations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ce commit intègre tout les changements lié au floutage des données en fonction du niveau de sensiblité d'une observation. --- atlas/atlasRoutes.py | 8 +- atlas/configuration/settings.ini.sample | 10 + atlas/modeles/entities/vmObservations.py | 3 +- .../repositories/vmCommunesRepository.py | 20 + .../vmObservationsMaillesRepository.py | 72 +- .../repositories/vmObservationsRepository.py | 4 +- atlas/static/css/index.css | 4 +- atlas/static/css/listEspeces.css | 5 +- atlas/static/mapAreas.js | 9 +- atlas/static/mapGenerator.js | 1234 ++++++++++------- atlas/static/mapHome.js | 111 +- atlas/static/mapMailles.js | 221 +-- atlas/static/package-lock.json | 6 +- atlas/templates/home/lastObs.html | 2 +- data/atlas/11.vm_cor_area_synthese.sql | 45 + data/atlas/12.atlas.t_mailles_territoire.sql | 6 +- .../13.atlas.vm_observations_mailles.sql | 12 +- data/atlas/14.grant.sql | 3 +- data/atlas/2.atlas.vm_observations.sql | 89 +- data/atlas/7.atlas.vm_communes.sql | 2 +- data/gn2/atlas_ref_geo.sql | 83 +- data/update/update_vm_observations.sql | 2 +- docs/vues_materialisees_maj.rst | 3 +- install_db.sh | 8 +- 24 files changed, 1140 insertions(+), 822 deletions(-) create mode 100644 data/atlas/11.vm_cor_area_synthese.sql diff --git a/atlas/atlasRoutes.py b/atlas/atlasRoutes.py index 21b95163d..fb26de7f6 100644 --- a/atlas/atlasRoutes.py +++ b/atlas/atlasRoutes.py @@ -233,7 +233,10 @@ def ficheEspece(cd_nom): altitudes = vmAltitudesRepository.getAltitudesChilds(connection, cd_ref) months = vmMoisRepository.getMonthlyObservationsChilds(connection, cd_ref) synonyme = vmTaxrefRepository.getSynonymy(connection, cd_ref) - communes = vmCommunesRepository.getCommunesObservationsChilds(connection, cd_ref) + if current_app.config["AFFICHAGE_MAILLE"]: + communes = vmCommunesRepository.getCommunesObservationsChildsMailles(connection, cd_ref) + else: + communes = vmCommunesRepository.getCommunesObservationsChilds(connection, cd_ref) taxonomyHierarchy = vmTaxrefRepository.getAllTaxonomy(db_session, cd_ref) firstPhoto = vmMedias.getFirstPhoto(connection, cd_ref, current_app.config["ATTR_MAIN_PHOTO"]) photoCarousel = vmMedias.getPhotoCarousel( @@ -292,7 +295,6 @@ def ficheCommune(insee): session = db.session connection = db.engine.connect() - listTaxons = vmTaxonsRepository.getTaxonsCommunes(connection, insee) commune = vmCommunesRepository.getCommuneFromInsee(connection, insee) if current_app.config["AFFICHAGE_MAILLE"]: observations = vmObservationsMaillesRepository.lastObservationsCommuneMaille( @@ -304,7 +306,7 @@ def ficheCommune(insee): ) surroundingAreas = [] - + listTaxons = vmTaxonsRepository.getTaxonsCommunes(connection, insee) observers = vmObservationsRepository.getObserversCommunes(connection, insee) session.close() diff --git a/atlas/configuration/settings.ini.sample b/atlas/configuration/settings.ini.sample index f8eddf134..e98e351ee 100644 --- a/atlas/configuration/settings.ini.sample +++ b/atlas/configuration/settings.ini.sample @@ -108,6 +108,16 @@ metropole=true # Choisissez alors la taille de vos mailles à utiliser (en km) / Valeurs possibles 1, 5 ou 10 taillemaille=5 +# Choisissez alors la taille de vos mailles à utiliser +# Valeurs possibles M1, M5, COM, 10, COM, DEP ou REG + +sensibility0="M1" # sensibilité de niveau 0 +sensibility1="M1" # sensibilité de niveau 1 +sensibility2="COM" # sensibilité de niveau 2 +sensibility3="M10" # sensibilité de niveau 3 + +# A noter que la sensibilité de niveau 4 sera ignoré afin de ne pas afficher les observations correspondant a ces espèces. + # Si 'metropole=false', rajoutez dans le dossier /data/ref un SHP des mailles de votre territoire et renseignez son chemin chemin_custom_maille=/home/`whoami`/atlas/data/ref/custom_maille.shp diff --git a/atlas/modeles/entities/vmObservations.py b/atlas/modeles/entities/vmObservations.py index 319f3aa5a..9630f4775 100644 --- a/atlas/modeles/entities/vmObservations.py +++ b/atlas/modeles/entities/vmObservations.py @@ -16,12 +16,13 @@ class VmObservations(Base): Column("id_observation", Integer, primary_key=True, unique=True), Column("insee", String(5), index=True), Column("dateobs", Date, index=True), + Column("type_code", Integer), Column("observateurs", String(255)), Column("altitude_retenue", Integer, index=True), Column("cd_ref", Integer, index=True), Column("the_geom_point", Geometry(geometry_type="POINT", srid=4326)), Column("geojson_point", Text), - Column("diffusion_level"), + Column("sensitivity"), schema="atlas", autoload=True, autoload_with=db.engine, diff --git a/atlas/modeles/repositories/vmCommunesRepository.py b/atlas/modeles/repositories/vmCommunesRepository.py index 4c9252489..56261fc2f 100644 --- a/atlas/modeles/repositories/vmCommunesRepository.py +++ b/atlas/modeles/repositories/vmCommunesRepository.py @@ -78,3 +78,23 @@ def getCommunesObservationsChilds(connection, cd_ref): municipality = {"insee": r.insee, "commune_maj": r.commune_maj} municipalities.append(municipality) return municipalities + + +def getCommunesObservationsChildsMailles(connection, cd_ref): + sql = """ + SELECT DISTINCT (com.insee) AS insee, com.commune_maj + FROM atlas.vm_communes com + JOIN atlas.t_mailles_territoire m ON st_intersects(m.the_geom, com.the_geom) + JOIN atlas.vm_observations_mailles obs ON m.id_maille=obs.id_maille + WHERE obs.cd_ref in ( + SELECT * from atlas.find_all_taxons_childs(:thiscdref) + ) + OR obs.cd_ref = :thiscdref + ORDER BY com.commune_maj ASC + """ + req = connection.execute(text(sql), thiscdref=cd_ref) + listCommunes = list() + for r in req: + temp = {"insee": r.insee, "commune_maj": r.commune_maj} + listCommunes.append(temp) + return listCommunes diff --git a/atlas/modeles/repositories/vmObservationsMaillesRepository.py b/atlas/modeles/repositories/vmObservationsMaillesRepository.py index 3628ed93e..58b65a425 100644 --- a/atlas/modeles/repositories/vmObservationsMaillesRepository.py +++ b/atlas/modeles/repositories/vmObservationsMaillesRepository.py @@ -8,6 +8,15 @@ from atlas.modeles.utils import deleteAccent, findPath +def format_taxon_name(observation): + if observation.nom_vern: + inter = observation.nom_vern.split(",") + taxon_name_formated = inter[0] + " | " + observation.lb_nom + "" + else: + taxon_name_formated = "" + observation.lb_nom + "" + return taxon_name_formated + + def getObservationsMaillesChilds(session, cd_ref, year_min=None, year_max=None): """ Retourne les mailles et le nombre d'observation par maille pour un taxon et ses enfants @@ -23,6 +32,7 @@ def getObservationsMaillesChilds(session, cd_ref, year_min=None, year_max=None): TMaillesTerritoire.geojson_maille, func.max(VmObservationsMailles.annee).label("last_obs_year"), func.sum(VmObservationsMailles.nbr).label("obs_nbr"), + VmObservationsMailles.type_code, ) .join( TMaillesTerritoire, @@ -32,6 +42,7 @@ def getObservationsMaillesChilds(session, cd_ref, year_min=None, year_max=None): .group_by( VmObservationsMailles.id_maille, TMaillesTerritoire.geojson_maille, + VmObservationsMailles.type_code, ) ) if year_min and year_max: @@ -44,6 +55,7 @@ def getObservationsMaillesChilds(session, cd_ref, year_min=None, year_max=None): geometry=json.loads(o.geojson_maille), properties={ "id_maille": o.id_maille, + "type_code": o.type_code, "nb_observations": int(o.obs_nbr), "last_observation": o.last_obs_year, }, @@ -60,13 +72,13 @@ def lastObservationsMailles(connection, mylimit, idPhoto): tax.lb_nom, tax.nom_vern, tax.group2_inpn, o.dateobs, o.altitude_retenue, o.id_observation, medias.url, medias.chemin, medias.id_media, - m.geojson_maille + m.geojson_4326 AS geom FROM atlas.vm_observations_mailles obs JOIN atlas.vm_taxons tax ON tax.cd_ref = obs.cd_ref JOIN atlas.vm_observations o ON o.id_observation=ANY(obs.id_observations) - JOIN atlas.t_mailles_territoire m ON m.id_maille=obs.id_maille + JOIN atlas.vm_cor_area_synthese m ON m.id_synthese=o.id_observation AND m.is_blurred_geom IS TRUE LEFT JOIN atlas.vm_medias medias - ON medias.cd_ref = obs.cd_ref AND medias.id_type = :thisID + ON medias.cd_ref = obs.cd_ref AND medias.id_type = 1 WHERE o.dateobs >= (CURRENT_TIMESTAMP - INTERVAL :thislimit) ORDER BY o.dateobs DESC """ @@ -82,11 +94,12 @@ def lastObservationsMailles(connection, mylimit, idPhoto): temp = { "id_observation": o.id_observation, "id_maille": o.id_maille, + "type_code": o.type_code, "cd_ref": o.cd_ref, "dateobs": o.dateobs, "altitude_retenue": o.altitude_retenue, "taxon": taxon, - "geojson_maille": json.loads(o.geojson_maille), + "geojson_maille": json.loads(o.geom), "group2_inpn": deleteAccent(o.group2_inpn), "pathImg": findPath(o), "id_media": o.id_media, @@ -97,38 +110,33 @@ def lastObservationsMailles(connection, mylimit, idPhoto): def lastObservationsCommuneMaille(connection, obs_limit, insee_code): sql = """ - WITH last_obs AS ( SELECT - obs.id_observation, obs.cd_ref, obs.dateobs, + obs.id_observations, obs.cd_ref, obs.type_code, obs.nbr, c.insee, COALESCE(t.nom_vern || ' | ', '') || t.lb_nom AS display_name, - obs.the_geom_point AS l_geom - FROM atlas.vm_observations AS obs + m.the_geom AS l_geom, + t.nom_vern, m.the_geom as l_geom, + m.geojson_maille, obs.id_maille + FROM atlas.vm_observations_mailles obs + JOIN atlas.t_mailles_territoire m ON m.id_maille = obs.id_maille JOIN atlas.vm_communes AS c - ON ST_Intersects(obs.the_geom_point, c.the_geom) + ON ST_Intersects(m.the_geom, c.the_geom) AND NOT ST_Touches(m.the_geom, c.the_geom) JOIN atlas.vm_taxons AS t ON obs.cd_ref = t.cd_ref WHERE c.insee = :inseeCode - ORDER BY obs.dateobs DESC LIMIT :obsLimit - ) - SELECT - l.id_observation, l.cd_ref, l.display_name, m.id_maille, m.geojson_maille - FROM atlas.t_mailles_territoire AS m - JOIN last_obs AS l - ON st_intersects(m.the_geom, l.l_geom) - GROUP BY l.id_observation, l.cd_ref, l.display_name, m.id_maille, m.geojson_maille - ORDER BY l.display_name """ results = connection.execute(text(sql), inseeCode=insee_code, obsLimit=obs_limit) observations = list() for r in results: - # taxon = (r.nom_vern + " | " + r.lb_nom) if r.nom_vern else r.lb_nom infos = { "cd_ref": r.cd_ref, + "insee": r.insee, "taxon": r.display_name, "geojson_maille": json.loads(r.geojson_maille), "id_maille": r.id_maille, - "id_observation": r.id_observation, + "id_observation": r.id_observations, + "nb_observations": r.nbr, + "type_code": r.type_code, } observations.append(infos) return observations @@ -139,16 +147,19 @@ def getObservationsTaxonCommuneMaille(connection, insee, cd_ref): sql = """ SELECT o.cd_ref, - t.id_maille, - t.geojson_maille, - extract(YEAR FROM o.dateobs)::INT AS annee - FROM atlas.vm_observations AS o - JOIN atlas.vm_communes AS c - ON ST_INTERSECTS(o.the_geom_point, c.the_geom) - JOIN atlas.t_mailles_territoire AS t - ON ST_INTERSECTS(t.the_geom, o.the_geom_point) + o.id_maille, + o.type_code, + o.annee, + m.geojson_maille, + m.the_geom, + t.cd_ref, + t.nom_vern, + t.lb_nom + FROM atlas.vm_observations_mailles AS o + JOIN atlas.vm_taxons AS t ON t.cd_ref = o.cd_ref + JOIN atlas.t_mailles_territoire m ON m.id_maille = o.id_maille + JOIN atlas.vm_communes AS c ON c.insee = :thisInsee AND st_intersects(c.the_geom, m.the_geom) AND NOT st_touches(c.the_geom, m.the_geom) WHERE o.cd_ref = :thiscdref - AND c.insee = :thisInsee ORDER BY id_maille """ observations = connection.execute(text(sql), thisInsee=insee, thiscdref=cd_ref) @@ -156,6 +167,9 @@ def getObservationsTaxonCommuneMaille(connection, insee, cd_ref): for o in observations: temp = { "id_maille": o.id_maille, + "cd_ref": o.cd_ref, + "taxon": format_taxon_name(o), + "type_code": o.type_code, "nb_observations": 1, "annee": o.annee, "geojson_maille": json.loads(o.geojson_maille), diff --git a/atlas/modeles/repositories/vmObservationsRepository.py b/atlas/modeles/repositories/vmObservationsRepository.py index cf17c55ce..73a644de2 100644 --- a/atlas/modeles/repositories/vmObservationsRepository.py +++ b/atlas/modeles/repositories/vmObservationsRepository.py @@ -96,6 +96,7 @@ def lastObservations(connection, mylimit, idPhoto): temp.pop("the_geom_point", None) temp["geojson_point"] = json.loads(o.geojson_point or "{}") temp["dateobs"] = o.dateobs + temp["type_code"] = o.type_code temp["group2_inpn"] = utils.deleteAccent(o.group2_inpn) temp["pathImg"] = utils.findPath(o) obsList.append(temp) @@ -111,9 +112,8 @@ def lastObservationsCommune(connection, mylimit, insee): '' ) AS taxon FROM atlas.vm_observations o - JOIN atlas.vm_communes c ON ST_Intersects(o.the_geom_point, c.the_geom) JOIN atlas.vm_taxons tax ON o.cd_ref = tax.cd_ref - WHERE c.insee = :thisInsee + WHERE o.insee = :thisInsee ORDER BY o.dateobs DESC LIMIT 100""" observations = connection.execute(text(sql), thisInsee=insee) diff --git a/atlas/static/css/index.css b/atlas/static/css/index.css index c16a570e1..89c882e95 100644 --- a/atlas/static/css/index.css +++ b/atlas/static/css/index.css @@ -366,11 +366,11 @@ h3.title-spaced { }*/ .tabEspece:hover { - background-color: #cccccc; + background-color: rgba(var(--main-color-rgb), 0.2); } .tabEspece.current { - background-color: #e6e6e6; + background-color: rgba(var(--main-color-rgb), 0.4); font-weight: bold; } diff --git a/atlas/static/css/listEspeces.css b/atlas/static/css/listEspeces.css index 291d527f5..d143e91e2 100644 --- a/atlas/static/css/listEspeces.css +++ b/atlas/static/css/listEspeces.css @@ -146,12 +146,13 @@ ul#statHierarchy { } tbody tr:hover { + background-color: rgba(var(--main-color-rgb), 0.2) !important; /*background-color: #cccccc !important;*/ cursor: pointer; } tbody tr.current { - background-color: #e6e6e6 !important; + background-color: rgba(var(--main-color-rgb), 0.4) !important; font-weight: bold; } @@ -203,4 +204,4 @@ tbody tr.current { font-size: 0.8rem; color: deeppink; } -} \ No newline at end of file +} diff --git a/atlas/static/mapAreas.js b/atlas/static/mapAreas.js index 1baeb8a15..dced16dc6 100644 --- a/atlas/static/mapAreas.js +++ b/atlas/static/mapAreas.js @@ -17,7 +17,8 @@ var areaLayer = L.geoJson(areaInfos.areaGeoJson, { weight: 2, color: areaBorderColor, // dashArray: "3", - fillOpacity: 0.3 + fillOpacity: 0.3, + invert: true }; } }).addTo(map); @@ -93,6 +94,7 @@ function displayObsPreciseBaseUrl(areaCode, cd_ref) { $("#loaderSpinner").hide(); // $("#loadingGif").hide(); map.removeLayer(currentLayer); + clearOverlays() if (configuration.AFFICHAGE_MAILLE) { displayMailleLayerLastObs(observations); } else { @@ -129,6 +131,7 @@ function displayObsTaxon(insee, cd_ref) { }).done(function(observations) { $("#loadingGif").hide(); map.removeLayer(currentLayer); + clearOverlays() if (configuration.AFFICHAGE_MAILLE) { displayMailleLayerLastObs(observations); } else { @@ -153,7 +156,9 @@ function displayObsTaxonMaille(areaCode, cd_ref) { $("#loaderSpinner").hide(); // $("#loadingGif").hide(); map.removeLayer(currentLayer); - displayGridLayerArea(observations); + clearOverlays() + const geojsonMaille = generateGeoJsonMailleLastObs(observations); + displayMailleLayerFicheEspece(geojsonMaille); }); } diff --git a/atlas/static/mapGenerator.js b/atlas/static/mapGenerator.js index c1df79768..b48e69ff2 100644 --- a/atlas/static/mapGenerator.js +++ b/atlas/static/mapGenerator.js @@ -1,24 +1,45 @@ const mailleBorderColor = String( - getComputedStyle(document.documentElement).getPropertyValue( - "--map-maille-border-color" - ) + getComputedStyle(document.documentElement).getPropertyValue( + "--map-maille-border-color" + ) ); const mailleLastObsBorderColor = String( - getComputedStyle(document.documentElement).getPropertyValue( - "--map-maille-lastobs-border-color" - ) + getComputedStyle(document.documentElement).getPropertyValue( + "--map-maille-lastobs-border-color" + ) ); const territoryBorderColor = String( - getComputedStyle(document.documentElement).getPropertyValue( - "--map-territory-border-color" - ) + getComputedStyle(document.documentElement).getPropertyValue( + "--map-territory-border-color" + ) ); const areaBorderColor = String( - getComputedStyle(document.documentElement).getPropertyValue( - "--map-area-border-color" - ) + getComputedStyle(document.documentElement).getPropertyValue( + "--map-area-border-color" + ) ); +function clearOverlays(){ + // remove all Layer from leaflet overlays (featureGroup) + // TODO: Rendre les overlays dynamiques. + m1FeatureGroup.eachLayer( + function(l){ + m1FeatureGroup.removeLayer(l); + }); + m5FeatureGroup.eachLayer( + function(l){ + m5FeatureGroup.removeLayer(l); + }); + COMFeatureGroup.eachLayer( + function(l){ + COMFeatureGroup.removeLayer(l); + }); + m10FeatureGroup.eachLayer( + function(l){ + m10FeatureGroup.removeLayer(l); + }); +} + function formatDate(date) { const date_options = { year: 'numeric', @@ -58,155 +79,217 @@ function generateObservationPopup(feature, linkSpecies = false) { function generateMap(zoomHomeButton) { - // Map initialization - firstMapTile = L.tileLayer(configuration.MAP.FIRST_MAP.url, { - attribution: configuration.MAP.FIRST_MAP.attribution, - }); - orthoMap = L.tileLayer(configuration.MAP.SECOND_MAP.url, { - attribution: configuration.MAP.SECOND_MAP.attribution, - }); - - baseMap = {}; - baseMap[configuration.MAP.FIRST_MAP.tileName] = firstMapTile; - - var map = L.map("map", { - crs: L.CRS.EPSG3857, - center: configuration.MAP.LAT_LONG, - maxBounds: configuration.MAP.MAX_BOUNDS, - minZoom: configuration.MAP.MIN_ZOOM, - geosearch: true, - zoom: configuration.MAP.ZOOM, - layers: [firstMapTile], - fullscreenControl: true, - zoomControl: !(zoomHomeButton), - }); - - if (zoomHomeButton) { - var zoomHome = L.Control.zoomHome(); - zoomHome.addTo(map); - } + // Map initialization + firstMapTile = L.tileLayer(configuration.MAP.FIRST_MAP.url, { + attribution: configuration.MAP.FIRST_MAP.attribution, + }); + orthoMap = L.tileLayer(configuration.MAP.SECOND_MAP.url, { + attribution: configuration.MAP.SECOND_MAP.attribution, + }); + baseMap = {}; + baseMap[configuration.MAP.FIRST_MAP.tileName] = firstMapTile; + + var map = L.map("map", { + crs: L.CRS.EPSG3857, + center: configuration.MAP.LAT_LONG, + maxBounds: configuration.MAP.MAX_BOUNDS, + minZoom: configuration.MAP.MIN_ZOOM, + geosearch: true, + zoom: configuration.MAP.ZOOM, + layers: [firstMapTile], + fullscreenControl: true, + zoomControl: !(zoomHomeButton), + }); + // TODO: Rendre les overlays dynamiques. + m10FeatureGroup = L.featureGroup(); + m5FeatureGroup = L.featureGroup(); + COMFeatureGroup = L.featureGroup(); + m1FeatureGroup = L.featureGroup(); + + // "Maille 5": m5FeatureGroup, + var overlays = { + "Maille 10": m10FeatureGroup, + "Maille COM": COMFeatureGroup, + "Maille 5": m5FeatureGroup, + "Maille 1": m1FeatureGroup, + }; + // Add layers + control = L.control.layers(null, overlays); - // Style of territory on map - // Uses snogylop to generate a mask - territoryStyle = { - fill: false, - color: territoryBorderColor, - weight: configuration.MAP.BORDERS_WEIGHT, - }; + control.addTo(map); + // Activate layers - // Add limits of the territory to the map - $(document).ready(function () { - $.getJSON(url_limit_territory, function (json) { - const territoryGeoJson = L.geoJson(json, { - style: territoryStyle, - }); - territoryGeoJson.addTo(map); - // map.fitBounds(territoryGeoJson.getBounds()) + Object.values(overlays).forEach((e) => { + map.addLayer(e) }); - }); - - // 'Google-like' baseLayer controler - - var LayerControl = L.Control.extend({ - options: { - position: "bottomleft", - }, - - onAdd: function (map) { - currentTileMap = "topo"; - var container = L.DomUtil.create( - "div", - "leaflet-bar leaflet-control leaflet-control-custom" - ); - - container.style.backgroundColor = "white"; - container.style.backgroundImage = - "url(" + - configuration.URL_APPLICATION + - "/static/images/logo_earth_map.PNG)"; - container.style.width = "50px"; - container.style.height = "50px"; - container.style.border = "solid white 1px"; - container.style.cursor = "pointer"; - $(container).attr("data-placement", "right"); - $(container).attr("data-toggle", "tooltip"); - $(container).attr("data-original-title", "Photos aérienne"); - - container.onclick = function () { - if (currentTileMap == "topo") { - container.style.backgroundImage = - "url(" + - configuration.URL_APPLICATION + - "/static/images/logo_topo_map.PNG)"; - $(container).attr("data-original-title", "Plan"); - map.removeLayer(firstMapTile); - orthoMap.addTo(map); - currentTileMap = "earth"; - } else { - container.style.backgroundImage = - "url(" + - configuration.URL_APPLICATION + - "/static/images/logo_earth_map.PNG)"; - $(container).attr("data-original-title", "Photos aérienne"); - map.removeLayer(orthoMap); - firstMapTile.addTo(map); - currentTileMap = "topo"; - } - }; - return container; - }, - }); - - map.addControl(new LayerControl()); - - // add tooltip on fullScreen button - - fullScreenButton = $(".leaflet-control-fullscreen"); - fullScreenButton.attr("data-placement", "right"); - fullScreenButton.attr("data-toggle", "tooltip"); - fullScreenButton.attr("data-original-title", "Fullscreen"); - $(".leaflet-control-fullscreen-button").removeAttr("title"); - - // Add scale depending on the configuration - if (configuration.MAP.ENABLE_SCALE) { - L.control.scale( - { - imperial: false, - position: 'bottomright' - } - ).addTo(map); - } - return map; + // Keep Layers in the same order as specified by the + // overlays variable so Departement under Commune + // under 10km2 under 1km2 + map.on("overlayadd", function (e) { + Object.values(overlays).forEach((e) => e.bringToFront()); + }); + + if (zoomHomeButton) { + var zoomHome = L.Control.zoomHome(); + zoomHome.addTo(map); + } + + + + // Style of territory on map + // Uses snogylop to generate a mask + territoryStyle = { + fill: false, + color: territoryBorderColor, + weight: configuration.MAP.BORDERS_WEIGHT, + }; + + // Add limits of the territory to the map + $(document).ready(function () { + $.getJSON(url_limit_territory, function (json) { + const territoryGeoJson = L.geoJson(json, { + style: territoryStyle, + }); + territoryGeoJson.addTo(map); + }); + }); + + // 'Google-like' baseLayer controler + + var LayerControl = L.Control.extend({ + options: { + position: "bottomleft", + }, + + onAdd: function (map) { + currentTileMap = "topo"; + var container = L.DomUtil.create( + "div", + "leaflet-bar leaflet-control leaflet-control-custom" + ); + + container.style.backgroundColor = "white"; + container.style.backgroundImage = + "url(" + + configuration.URL_APPLICATION + + "/static/images/logo_earth_map.PNG)"; + container.style.width = "50px"; + container.style.height = "50px"; + container.style.border = "solid white 1px"; + container.style.cursor = "pointer"; + $(container).attr("data-placement", "right"); + $(container).attr("data-toggle", "tooltip"); + $(container).attr("data-original-title", "Photos aérienne"); + + container.onclick = function () { + if (currentTileMap == "topo") { + container.style.backgroundImage = + "url(" + + configuration.URL_APPLICATION + + "/static/images/logo_topo_map.PNG)"; + $(container).attr("data-original-title", "Plan"); + map.removeLayer(firstMapTile); + orthoMap.addTo(map); + currentTileMap = "earth"; + } else { + container.style.backgroundImage = + "url(" + + configuration.URL_APPLICATION + + "/static/images/logo_earth_map.PNG)"; + $(container).attr("data-original-title", "Photos aérienne"); + map.removeLayer(orthoMap); + firstMapTile.addTo(map); + currentTileMap = "topo"; + } + }; + return container; + }, + }); + + map.addControl(new LayerControl()); + + // add tooltip on fullScreen button + + fullScreenButton = $(".leaflet-control-fullscreen"); + fullScreenButton.attr("data-placement", "right"); + fullScreenButton.attr("data-toggle", "tooltip"); + fullScreenButton.attr("data-original-title", "Fullscreen"); + $(".leaflet-control-fullscreen-button").removeAttr("title"); + + // Add scale depending on the configuration + if (configuration.MAP.ENABLE_SCALE) { + L.control.scale( + { + imperial: false, + position: 'bottomright' + } + ).addTo(map); + } + + return map; } function observersTxt(feature) { - return configuration.DISPLAY_OBSERVERS - ? `
Observateurs(s): ${feature.properties.observateurs}` - : "" + return configuration.DISPLAY_OBSERVERS + ? `
Observateurs(s): ${feature.properties.observateurs}` + : "" } //****** Fonction fiche espècce *********** // Popup Point -function onEachFeaturePoint(feature, layer) { +function onEachFeaturePointSpecies(feature, layer) { popupContent = generateObservationPopup(feature, false); layer.bindPopup(popupContent); + filterObservations(feature, layer); } // popup Maille function onEachFeatureMaille(feature, layer) { - popupContent = - "Nombre d'observation(s): " + - feature.properties.nb_observations + - "
Dernière observation: " + - feature.properties.last_observation + - " "; - layer.bindPopup(popupContent); + popupContent = + "Nombre d'observation(s): " + + feature.properties.nb_observations + + "
Dernière observation: " + + feature.properties.last_observation + + " "; + layer.bindPopup(popupContent); + + filterObservations(feature, layer); + + zoomMaille(layer); + + var selected = false; + layer.setStyle(styleMailleAtlas(feature.properties.nb_observations)) + layer.on("click", function (layer) { + resetStyleMailles(); + this.setStyle(styleMailleClickedOrHover(layer.target)); + selected = true; + }); + layer.on("mouseover", function (layer) { + this.setStyle(styleMailleClickedOrHover(layer.target)); + selected = false; + }); + + layer.on("mouseout", function () { + if (!selected) { + this.setStyle(styleMailleAtlas(feature.properties.nb_observations)); + } + }); + + + } +function zoomMaille(layer) { + layer.on("click", function (e) { + map.fitBounds(layer.getBounds()); + }); +} + + // Style maille function getColor(d) { return d > 100 @@ -227,220 +310,221 @@ function getColor(d) { } function styleMaille(feature) { - return { - fillColor: getColor(feature.properties.nb_observations), - weight: 1, - color: mailleBorderColor, - fillOpacity: 0.8, - }; + return { + fillColor: getColor(feature.properties.nb_observations), + weight: 1, + color: mailleBorderColor, + fillOpacity: 0.8, + }; } function generateLegendMaille() { - // check if contour already exists - if (L.DomUtil.get("contour-legend")) { - return - } - legend.onAdd = function (map) { - var div = L.DomUtil.create("div", "info legend"), - grades = [0, 1, 2, 5, 10, 20, 50, 100], - labels = [" Nombre
d'observations

"]; - - // loop through our density intervals and generate a label with a colored square for each interval - for (var i = 0; i < grades.length; i++) { - grade_n1 = grades[i + 1] ? `– ${grades[i + 1] }
` : "+" - labels.push( - ` + // check if contour already exists + if (L.DomUtil.get("contour-legend")) { + return + } + legend.onAdd = function (map) { + var div = L.DomUtil.create("div", "info legend"), + grades = [0, 1, 2, 5, 10, 20, 50, 100], + labels = [" Nombre
d'observations

"]; + + // loop through our density intervals and generate a label with a colored square for each interval + for (var i = 0; i < grades.length; i++) { + grade_n1 = grades[i + 1] ? `– ${grades[i + 1] }
` : "+" + labels.push( + ` ${grades[i]}${grade_n1} ` - ); - } - // Add id to get it above - div.id = "contour-legend" - div.innerHTML = labels.join("
"); + ); + } + // Add id to get it above + div.id = "contour-legend" + div.innerHTML = labels.join("
"); - return div; - }; + return div; + }; - legend.addTo(map); + legend.addTo(map); } // Geojson Maille function generateGeojsonMaille(observations, yearMin, yearMax) { - var i = 0; - myGeoJson = { type: "FeatureCollection", features: [] }; - tabProperties = []; - while (i < observations.length) { - if (observations[i].annee >= yearMin && observations[i].annee <= yearMax) { - geometry = observations[i].geojson_maille; - idMaille = observations[i].id_maille; - properties = { - id_maille: idMaille, - nb_observations: 1, - last_observation: observations[i].annee, - tabDateobs: [new Date(observations[i].dateobs)], - }; - var j = i + 1; - while (j < observations.length && observations[j].id_maille <= idMaille) { - if ( - observations[j].annee >= yearMin && - observations[j].annee <= yearMax - ) { - properties.nb_observations += observations[j].nb_observations; - properties.tabDateobs.push(new Date(observations[i].dateobs)); - } - if (observations[j].annee >= properties.last_observation) { - properties.last_observation = observations[j].annee; + var i = 0; + myGeoJson = { type: "FeatureCollection", features: [] }; + tabProperties = []; + while (i < observations.length) { + if (observations[i].annee >= yearMin && observations[i].annee <= yearMax) { + geometry = observations[i].geojson_maille; + idMaille = observations[i].id_maille; + typeCode = observations[i].type_code; + properties = { + type_code: typeCode, + id_maille: idMaille, + nb_observations: 1, + last_observation: observations[i].annee, + tabDateobs: [new Date(observations[i].dateobs)], + }; + var j = i + 1; + while (j < observations.length && observations[j].id_maille <= idMaille) { + if ( + observations[j].annee >= yearMin && + observations[j].annee <= yearMax + ) { + properties.nb_observations += observations[j].nb_observations; + properties.tabDateobs.push(new Date(observations[i].dateobs)); + } + if (observations[j].annee >= properties.last_observation) { + properties.last_observation = observations[j].annee; + } + j = j + 1; + } + myGeoJson.features.push({ + type: "Feature", + properties: properties, + geometry: geometry, + }); + // on avance jusqu' à j + i = j; + } else { + i = i + 1; } - j = j + 1; - } - myGeoJson.features.push({ - type: "Feature", - properties: properties, - geometry: geometry, - }); - // on avance jusqu' à j - i = j; - } else { - i = i + 1; } - } - return myGeoJson; + return myGeoJson; } // Display Maille layer function displayMailleLayerFicheEspece(observationsMaille) { - myGeoJson = observationsMaille; - currentLayer = L.geoJson(myGeoJson, { - onEachFeature: onEachFeatureMaille, - style: styleMaille, - }); - currentLayer.addTo(map); - // map.fitBounds(currentLayer.getBounds()); ZOOM FUNCTION ON SPECIES SHEET MAILLE OBSERVATIONS DISPLAY + myGeoJson = observationsMaille; + currentLayer = L.geoJson(myGeoJson, { + onEachFeature: onEachFeatureMaille, + }); + currentLayer.addTo(map); + // map.fitBounds(currentLayer.getBounds()); ZOOM FUNCTION ON SPECIES SHEET MAILLE OBSERVATIONS DISPLAY - // ajout de la légende - generateLegendMaille(); + // ajout de la légende + generateLegendMaille(); } function generateGeojsonGridArea(observations) { - var i = 0; - myGeoJson = { type: "FeatureCollection", features: [] }; - tabProperties = []; - while (i < observations.length) { - geometry = observations[i].geojson_maille; - idMaille = observations[i].id_maille; - properties = { - id_maille: idMaille, - nb_observations: 1, - last_observation: observations[i].annee, - }; - var j = i + 1; - while (j < observations.length && observations[j].id_maille <= idMaille) { - properties.nb_observations += observations[j].nb_observations; - - if (observations[j].annee >= properties.last_observation) { - properties.last_observation = observations[j].annee; - } - j = j + 1; + var i = 0; + myGeoJson = { type: "FeatureCollection", features: [] }; + tabProperties = []; + while (i < observations.length) { + geometry = observations[i].geojson_maille; + idMaille = observations[i].id_maille; + properties = { + id_maille: idMaille, + nb_observations: 1, + last_observation: observations[i].annee, + }; + var j = i + 1; + while (j < observations.length && observations[j].id_maille <= idMaille) { + properties.nb_observations += observations[j].nb_observations; + + if (observations[j].annee >= properties.last_observation) { + properties.last_observation = observations[j].annee; + } + j = j + 1; + } + myGeoJson.features.push({ + type: "Feature", + properties: properties, + geometry: geometry, + }); + // on avance jusqu' à j + i = j; } - myGeoJson.features.push({ - type: "Feature", - properties: properties, - geometry: geometry, - }); - // on avance jusqu' à j - i = j; - } - return myGeoJson; + return myGeoJson; } function displayGridLayerArea(observations) { myGeoJson = generateGeojsonGridArea(observations); - currentLayer = L.geoJson(myGeoJson, { - onEachFeature: onEachFeatureMaille, - style: styleMaille, - }); - currentLayer.addTo(map); - if (currentLayer.getBounds().isValid()) { - map.fitBounds(currentLayer.getBounds()); - } + currentLayer = L.geoJson(myGeoJson, { + onEachFeature: onEachFeatureMaille, + style: styleMaille, + }); + currentLayer.addTo(map); + if (currentLayer.getBounds().isValid()) { + map.fitBounds(currentLayer.getBounds()); + } - // ajout de la légende - generateLegendMaille(); + // ajout de la légende + generateLegendMaille(); } // GeoJson Point function generateGeojsonPointFicheEspece( - geojsonPoint, - yearMin, - yearMax, - sliderTouch + geojsonPoint, + yearMin, + yearMax, + sliderTouch ) { - var filteredGeoJsonPoint = Object.assign({}, geojsonPoint); - // si on a touché le slider on filtre sinon on retourne directement le geojson - if (yearMin && yearMax && sliderTouch) { - filteredGeoJsonPoint.features = geojsonPoint.features.filter(function ( - obs - ) { - return obs.properties.year >= yearMin && obs.properties.year <= yearMax; - }); - return filteredGeoJsonPoint; - } else { - return filteredGeoJsonPoint; - } + var filteredGeoJsonPoint = Object.assign({}, geojsonPoint); + // si on a touché le slider on filtre sinon on retourne directement le geojson + if (yearMin && yearMax && sliderTouch) { + filteredGeoJsonPoint.features = geojsonPoint.features.filter(function ( + obs + ) { + return obs.properties.year >= yearMin && obs.properties.year <= yearMax; + }); + return filteredGeoJsonPoint; + } else { + return filteredGeoJsonPoint; + } } // Display marker Layer (cluster or not) function displayMarkerLayerFicheEspece( - observationsPoint, - yearMin, - yearMax, - sliderTouch -) { - // on vérifie si le slider a été touché - // sinon on met null a yearmin et yearmax pour ne pas filtrer par année a la génération du GeoJson - - // yearMin = years[0] == taxonYearMin ? null : years[0]; - // yearMax = years[1] == YEARMAX ? null : years[1]; - myGeoJson = generateGeojsonPointFicheEspece( observationsPoint, yearMin, yearMax, sliderTouch - ); +) { + // on vérifie si le slider a été touché + // sinon on met null a yearmin et yearmax pour ne pas filtrer par année a la génération du GeoJson + + // yearMin = years[0] == taxonYearMin ? null : years[0]; + // yearMax = years[1] == YEARMAX ? null : years[1]; + myGeoJson = generateGeojsonPointFicheEspece( + observationsPoint, + yearMin, + yearMax, + sliderTouch + ); - if (typeof pointDisplayOptionsFicheEspece == "undefined") { - pointDisplayOptionsFicheEspece = function (feature) { - return {}; - }; - } - currentLayer = L.geoJson(myGeoJson, { - onEachFeature: onEachFeaturePoint, - - pointToLayer: function (feature, latlng) { - return L.circleMarker(latlng, pointDisplayOptionsFicheEspece(feature)); - }, - }); - if (myGeoJson.features.length > configuration.LIMIT_CLUSTER_POINT) { - newLayer = currentLayer; - currentLayer = L.markerClusterGroup(); - currentLayer.addLayer(newLayer); - map.addLayer(currentLayer); - } else { - currentLayer.addTo(map); - } - // map.fitBounds(currentLayer.getBounds()); ZOOM FUNCTION ON SPECIES SHEET MARKER LAYER OBSERVATIONS DISPLAY + if (typeof pointDisplayOptionsFicheEspece == "undefined") { + pointDisplayOptionsFicheEspece = function (feature) { + return {}; + }; + } + currentLayer = L.geoJson(myGeoJson, { + onEachFeature: onEachFeaturePointSpecies, - if (typeof divLegendeFicheEspece !== "undefined") { - legend.onAdd = function (map) { - var div = L.DomUtil.create("div", "info legend"); - div.innerHTML = divLegendeFicheEspece; - return div; - }; - legend.addTo(map); - } + pointToLayer: function (feature, latlng) { + return L.circleMarker(latlng, pointDisplayOptionsFicheEspece(feature)); + }, + }); + if (myGeoJson.features.length > configuration.LIMIT_CLUSTER_POINT) { + newLayer = currentLayer; + currentLayer = L.markerClusterGroup(); + currentLayer.addLayer(newLayer); + map.addLayer(currentLayer); + } else { + currentLayer.addTo(map); + } + // map.fitBounds(currentLayer.getBounds()); ZOOM FUNCTION ON SPECIES SHEET MARKER LAYER OBSERVATIONS DISPLAY + + if (typeof divLegendeFicheEspece !== "undefined") { + legend.onAdd = function (map) { + var div = L.DomUtil.create("div", "info legend"); + div.innerHTML = divLegendeFicheEspece; + return div; + }; + legend.addTo(map); + } } // ***************Fonction lastObservations: mapHome et mapCommune***************** @@ -450,177 +534,265 @@ function displayMarkerLayerFicheEspece( function onEachFeaturePointLastObs(feature, layer) { popupContent = generateObservationPopup(feature, true); layer.bindPopup(popupContent); + filterObservations(feature, layer); } function onEachFeaturePointCommune(feature, layer) { popupContent = generateObservationPopup(feature, true); layer.bindPopup(popupContent); + filterObservations(feature, layer); } function generateGeojsonPointLastObs(observationsPoint) { - myGeoJson = { type: "FeatureCollection", features: [] }; - - observationsPoint.forEach(function (obs) { - properties = obs; - properties["dateobsCompare"] = new Date(obs.dateobs); - properties["dateobs"] = obs.dateobs; - properties["nb_observations"] = 1; - myGeoJson.features.push({ - type: "Feature", - properties: properties, - geometry: obs.geojson_point, + myGeoJson = { type: "FeatureCollection", features: [] }; + + observationsPoint.forEach(function (obs) { + properties = obs; + properties["dateobsCompare"] = new Date(obs.dateobs); + properties["dateobs"] = obs.dateobs; + properties["type_code"] = obs.type_code; + properties["nb_observations"] = 1; + myGeoJson.features.push({ + type: "Feature", + properties: properties, + geometry: obs.geojson_point, + }); }); - }); - return myGeoJson; + return myGeoJson; } function displayMarkerLayerPointLastObs(observationsPoint) { - myGeoJson = generateGeojsonPointLastObs(observationsPoint); - if (typeof pointDisplayOptionsFicheCommuneHome == "undefined") { - pointDisplayOptionsFicheCommuneHome = function (feature) { - return {}; - }; - } + myGeoJson = generateGeojsonPointLastObs(observationsPoint); + if (typeof pointDisplayOptionsFicheCommuneHome == "undefined") { + pointDisplayOptionsFicheCommuneHome = function (feature) { + return {}; + }; + } - currentLayer = L.geoJson(myGeoJson, { - onEachFeature: onEachFeaturePointLastObs, - pointToLayer: function (feature, latlng) { - return L.circleMarker( - latlng, - pointDisplayOptionsFicheCommuneHome(feature) - ); - }, - }); - - map.addLayer(currentLayer); - if (typeof divLegendeFicheCommuneHome !== "undefined") { - legend.onAdd = function (map) { - var div = L.DomUtil.create("div", "info legend"); - div.innerHTML = divLegendeFicheCommuneHome; - return div; - }; - legend.addTo(map); - } + currentLayer = L.geoJson(myGeoJson, { + onEachFeature: onEachFeaturePointLastObs, + pointToLayer: function (feature, latlng) { + return L.circleMarker( + latlng, + pointDisplayOptionsFicheCommuneHome(feature) + ); + }, + }); + + map.addLayer(currentLayer); + if (typeof divLegendeFicheCommuneHome !== "undefined") { + legend.onAdd = function (map) { + var div = L.DomUtil.create("div", "info legend"); + div.innerHTML = divLegendeFicheCommuneHome; + return div; + }; + legend.addTo(map); + } } function displayMarkerLayerPointCommune(observationsPoint) { - myGeoJson = generateGeojsonPointLastObs(observationsPoint); - if (typeof pointDisplayOptionsFicheCommuneHome == "undefined") { - pointDisplayOptionsFicheCommuneHome = function (feature) { - return {}; - }; - } + myGeoJson = generateGeojsonPointLastObs(observationsPoint); + if (typeof pointDisplayOptionsFicheCommuneHome == "undefined") { + pointDisplayOptionsFicheCommuneHome = function (feature) { + return {}; + }; + } - currentLayer = L.geoJson(myGeoJson, { - onEachFeature: onEachFeaturePointCommune, - pointToLayer: function (feature, latlng) { - return L.circleMarker( - latlng, - pointDisplayOptionsFicheCommuneHome(feature) - ); - }, - }); - - map.addLayer(currentLayer); - if (typeof divLegendeFicheCommuneHome !== "undefined") { - legend.onAdd = function (map) { - var div = L.DomUtil.create("div", "info legend"); - div.innerHTML = divLegendeFicheCommuneHome; - return div; - }; - legend.addTo(map); - } + currentLayer = L.geoJson(myGeoJson, { + onEachFeature: onEachFeaturePointCommune, + pointToLayer: function (feature, latlng) { + return L.circleMarker( + latlng, + pointDisplayOptionsFicheCommuneHome(feature) + ); + }, + }); + + map.addLayer(currentLayer); + if (typeof divLegendeFicheCommuneHome !== "undefined") { + legend.onAdd = function (map) { + var div = L.DomUtil.create("div", "info legend"); + div.innerHTML = divLegendeFicheCommuneHome; + return div; + }; + legend.addTo(map); + } } // ** MAILLE *** function compare(a, b) { - if (a.id_maille < b.id_maille) return -1; - if (a.id_maille > b.id_maille) return 1; - return 0; + if (a.id_maille < b.id_maille) return -1; + if (a.id_maille > b.id_maille) return 1; + return 0; } function buildSpeciesEntries(taxons) { - rows = []; - taxons.forEach(taxon => { - href = `${configuration.URL_APPLICATION}/espece/${taxon.cdRef}` - rows.push(`
  • ${taxon.name}
  • `); - }); - return rows.join('\n'); + rows = []; + taxons.forEach(taxon => { + href = `${configuration.URL_APPLICATION}/espece/${taxon.cdRef}` + rows.push(`
  • ${taxon.name}
  • `); + }); + return rows.join('\n'); } function onEachFeatureMailleLastObs(feature, layer) { - title = `${feature.properties.taxons.length} espèces observées dans la maille  : `; - rows = buildSpeciesEntries(feature.properties.taxons); - popupContent = `${title}`; + title = `${feature.properties.taxons.length} espèces observées dans la maille  : `; + rows = buildSpeciesEntries(feature.properties.taxons); + popupContent = `${title}`; + + layer.bindPopup(popupContent, { maxHeight: 300 }); + + filterObservations(feature, layer); - layer.bindPopup(popupContent, { maxHeight: 300 }); + zoomMaille(layer); + + var selected = false; + layer.setStyle(styleMailleAtlas(feature.properties.nb_observations)) + layer.on("click", function (layer) { + resetStyleMailles(); + this.setStyle(styleMailleClickedOrHover(layer.target)); + selected = true; + }); + layer.on("mouseover", function (layer) { + this.setStyle(styleMailleClickedOrHover(layer.target)); + selected = false; + }); + + layer.on("mouseout", function () { + if (!selected) { + this.setStyle(styleMailleAtlas(feature.properties.nb_observations)); + } + }); } -function styleMailleLastObs() { - return { - opacity: 1, - weight: 2, - color: mailleLastObsBorderColor, - fillOpacity: 0, - }; +function styleMailleAtlas(nb) { + return { + opacity: 0, + weight: 2, + color: getColor(nb), + fillOpacity: 0.5, + }; + // TODO: C'est une proposition afin de mieux voir les différentes + // mailles ainsi que changer le style lors d'une intéraction + // return { + // opacity: 1, + // weight: 2, + // color: mailleLastObsBorderColor, + // fillOpacity: 0, + // }; } -function generateGeoJsonMailleLastObs(observations) { - var features = []; - observations.forEach((obs) => { - findedFeature = features.find( - (feat) => feat.properties.meshId === obs.id_maille +function styleMailleClickedOrHover(layer) { + var mailleCode = layer.feature.properties.type_code; + var fillColor = getComputedStyle(document.body).getPropertyValue( + "--main-color" ); - if (!findedFeature) { - features.push({ - type: "Feature", - geometry: obs.geojson_maille, - properties: { - meshId: obs.id_maille, - list_id_observation: [obs.id_observation], - taxons: [ - { - cdRef: obs.cd_ref, - name: obs.taxon, - }, - ], - }, - }); - } else if ( - !findedFeature.properties.taxons.find( - (taxon) => taxon.cdRef === obs.cd_ref - ) - ) { - findedFeature.properties.taxons.push({ - cdRef: obs.cd_ref, - name: obs.taxon, - }); + + let fillOpacity = 0.85; + if (mailleCode === "M1") { + fillOpacity = 0.2; + } else if (mailleCode === "COM") { + fillOpacity = 0.4; + } else if (mailleCode === "M5") { + fillOpacity = 0.4; + } else if (mailleCode === "M10") { + fillOpacity = 0.6; } - }); - return { - type: "FeatureCollection", - features: features, - }; + var options = layer.options; + return { + ...options, + opacity: 1, + weight: 2, + color: fillColor, + fillOpacity: fillOpacity, + }; } -function find_id_observation_in_array(tab_id, id_observation) { - i = 0; - while (i < tab_id.length && tab_id[i] != id_observation) { - i = i + 1; - } - return i != tab_id.length; +function resetStyleMailles() { + // set style for all cells + map.eachLayer(function (layer) { + if (layer.feature && layer.feature.properties.id_type) { + layer.setStyle(styleMailleAtlas(layer.feature.properties.taxons.length)); + } + }); } -function displayMailleLayerLastObs(observations) { - var geojsonMaille = generateGeoJsonMailleLastObs(observations); - currentLayer = L.geoJson(geojsonMaille, { - onEachFeature: onEachFeatureMailleLastObs, - style: styleMailleLastObs, - }); - currentLayer.addTo(map); - //map.fitBounds(currentLayer.getBounds()); ZOOM ON LAST OBS MAILLE +function filterObservations(feature, layer) { + mailleTypeCode = feature.properties.type_code; + if (mailleTypeCode === "M10") { + m10FeatureGroup.addLayer(layer); + m10FeatureGroup.bringToBack(); + } else if (mailleTypeCode === "M5") { + m5FeatureGroup.addLayer(layer); + } else if (mailleTypeCode === "COM") { + COMFeatureGroup.addLayer(layer); + } else if (mailleTypeCode === "M1") { + m1FeatureGroup.addLayer(layer); + } +} + +function generateGeoJsonMailleLastObs(observations, isRefresh=false) { + var features = []; + if (isRefresh) { + observations = observations.features; + } + observations.forEach((obs) => { + findedFeature = features.find( + (feat) => feat.properties.meshId === obs.id_maille + ); + if (!findedFeature) { + features.push({ + type: "Feature", + geometry: obs.geojson_maille, + properties: { + type_code: obs.type_code, + insee: obs.insee, + last_observation: obs.annee, + meshId: obs.id_maille, + list_id_observation: [obs.id_observation], + nb_observations: obs.nb_observations, + taxons: [ + { + cdRef: obs.cd_ref, + name: obs.taxon, + }, + ], + }, + }); + } else if ( + !findedFeature.properties.taxons.find( + (taxon) => taxon.cdRef === obs.cd_ref + ) + ) { + findedFeature.properties.taxons.push({ + cdRef: obs.cd_ref, + name: obs.taxon, + }); + if (findedFeature.properties.last_observation < obs.annee) { + findedFeature.properties.last_observation = obs.annee + } + findedFeature.properties.nb_observations += obs.nb_observations + } + else { + findedFeature.properties.nb_observations += obs.nb_observations + } + }); + return { + type: "FeatureCollection", + features: features, + }; +} + + +function displayMailleLayerLastObs(observations, isRefresh=false) { + const geojsonMaille = generateGeoJsonMailleLastObs(observations, isRefresh); + currentLayer = L.geoJson(geojsonMaille, { + onEachFeature: onEachFeatureMailleLastObs, + }); + currentLayer.addTo(map); + generateLegendMaille() } // Legend @@ -630,103 +802,103 @@ var legendActiv = false; var div; function generateLegende(htmlLegend) { - // Legende - - var legendControl = L.Control.extend({ - options: { - position: "topleft", - //control position - allowed: 'topleft', 'topright', 'bottomleft', 'bottomright' - }, - - onAdd: function (map) { - var container = L.DomUtil.create( - "div", - "leaflet-bar leaflet-control leaflet-control-custom" - ); - - container.style.backgroundColor = "white"; - container.style.width = "25px"; - container.style.height = "25px"; - container.style.border = "solid white 1px"; - container.style.cursor = "pointer"; - $(container).html( - "Légende" - ); - $(container).attr("data-placement", "right"); - $(container).attr("data-toggle", "tooltip"); - $(container).attr("data-original-title", "Legend"); - - container.onclick = function () { - if (legendActiv == false) { - legend = L.control({ position: "topleft" }); - - legend.onAdd = function (map) { - (div = L.DomUtil.create("div", "info legend")), - $(div).addClass("generalLegend"); - - div.innerHTML = htmlLegend; + // Legende - return div; - }; - legend.addTo(map); - legendActiv = true; - } else { - legend.remove(map); - legendActiv = false; - } - }; - return container; - }, - }); + var legendControl = L.Control.extend({ + options: { + position: "topleft", + //control position - allowed: 'topleft', 'topright', 'bottomleft', 'bottomright' + }, - map.addControl(new legendControl()); + onAdd: function (map) { + var container = L.DomUtil.create( + "div", + "leaflet-bar leaflet-control leaflet-control-custom" + ); + + container.style.backgroundColor = "white"; + container.style.width = "25px"; + container.style.height = "25px"; + container.style.border = "solid white 1px"; + container.style.cursor = "pointer"; + $(container).html( + "Légende" + ); + $(container).attr("data-placement", "right"); + $(container).attr("data-toggle", "tooltip"); + $(container).attr("data-original-title", "Legend"); + + container.onclick = function () { + if (legendActiv == false) { + legend = L.control({ position: "topleft" }); + + legend.onAdd = function (map) { + (div = L.DomUtil.create("div", "info legend")), + $(div).addClass("generalLegend"); + + div.innerHTML = htmlLegend; + + return div; + }; + legend.addTo(map); + legendActiv = true; + } else { + legend.remove(map); + legendActiv = false; + } + }; + return container; + }, + }); + + map.addControl(new legendControl()); } var mySlider; function generateSliderOnMap() { - var SliderControl = L.Control.extend({ - options: { - position: "bottomleft", - //control position - allowed: 'topleft', 'topright', 'bottomleft', 'bottomright' - }, - - onAdd: function (map) { - var sliderContainer = L.DomUtil.create( - "div", - "leaflet-bar leaflet-control leaflet-slider-control" - ); - - sliderContainer.style.backgroundColor = "white"; - sliderContainer.style.width = "300px"; - sliderContainer.style.height = "70px"; - sliderContainer.style.border = "solid white 1px"; - sliderContainer.style.cursor = "pointer"; - $(sliderContainer).css("margin-bottom", "-300px"); - $(sliderContainer).css("margin-left", "200px"); - $(sliderContainer).css("text-align", "center"); - $(sliderContainer).append( - "

    " + - "

    Nombre d'observation(s): " + - nb_obs + - "

    " - ); - L.DomEvent.disableClickPropagation(sliderContainer); - return sliderContainer; - }, - }); - - map.addControl(new SliderControl()); - - mySlider = new Slider("#sliderControl", { - value: [taxonYearMin, YEARMAX], - min: taxonYearMin, - max: YEARMAX, - step: configuration.MAP.STEP, - }); - - $("#yearMax").html("    " + YEARMAX); - $("#yearMin").html(taxonYearMin + "    "); + var SliderControl = L.Control.extend({ + options: { + position: "bottomleft", + //control position - allowed: 'topleft', 'topright', 'bottomleft', 'bottomright' + }, + + onAdd: function (map) { + var sliderContainer = L.DomUtil.create( + "div", + "leaflet-bar leaflet-control leaflet-slider-control" + ); + + sliderContainer.style.backgroundColor = "white"; + sliderContainer.style.width = "300px"; + sliderContainer.style.height = "70px"; + sliderContainer.style.border = "solid white 1px"; + sliderContainer.style.cursor = "pointer"; + $(sliderContainer).css("margin-bottom", "-300px"); + $(sliderContainer).css("margin-left", "200px"); + $(sliderContainer).css("text-align", "center"); + $(sliderContainer).append( + "

    " + + "

    Nombre d'observation(s): " + + nb_obs + + "

    " + ); + L.DomEvent.disableClickPropagation(sliderContainer); + return sliderContainer; + }, + }); + + map.addControl(new SliderControl()); + + mySlider = new Slider("#sliderControl", { + value: [taxonYearMin, YEARMAX], + min: taxonYearMin, + max: YEARMAX, + step: configuration.MAP.STEP, + }); + + $("#yearMax").html("    " + YEARMAX); + $("#yearMin").html(taxonYearMin + "    "); } diff --git a/atlas/static/mapHome.js b/atlas/static/mapHome.js index 45e54b63a..b2b562040 100644 --- a/atlas/static/mapHome.js +++ b/atlas/static/mapHome.js @@ -6,7 +6,7 @@ var legend = L.control({position: 'bottomright'}); map.scrollWheelZoom.disable(); $('#map').click(function(){ - map.scrollWheelZoom.enable(); + map.scrollWheelZoom.enable(); }) @@ -15,63 +15,58 @@ $('#map').click(function(){ $(function(){ - if (configuration.AFFICHAGE_MAILLE){ - // display maille layer - displayMailleLayerLastObs(observations); - - // interaction list - map - $('.lastObslistItem').click(function(){ - $(this).siblings().removeClass('bg-light'); - $(this).addClass('bg-light'); - var id_observation = $(this).attr('idSynthese'); - p = (currentLayer._layers); - var selectLayer; - for (var key in p) { - if (find_id_observation_in_array(p[key].feature.properties.list_id_observation, id_observation) ){ - selectLayer = p[key]; - } - } - - selectLayer.openPopup(); - var bounds = L.latLngBounds(); - var layerBounds = selectLayer.getBounds(); - bounds.extend(layerBounds); - map.fitBounds(bounds, { - maxZoom : 12 + if (configuration.AFFICHAGE_MAILLE){ + // display maille layer + displayMailleLayerLastObs(observations); + + // interaction list - map + $('.lastObslistItem').click(function(elem){ + $(this).siblings().removeClass('current'); + $(this).addClass('current'); + const idMaille = Number(elem.currentTarget.getAttribute("area-code")); + p = (currentLayer._layers); + let selectLayer; + for (var key in p) { + if (p[key].feature.properties.meshId === idMaille){ + selectLayer = p[key]; + } + } + + resetStyleMailles() + selectLayer.setStyle(styleMailleClickedOrHover(selectLayer)); + selectLayer.openPopup(selectLayer._bounds.getCenter()); + var bounds = L.latLngBounds([]); + var layerBounds = selectLayer.getBounds(); + bounds.extend(layerBounds); + map.fitBounds(bounds, { + maxZoom : 12 + }); }); - }); - } - - // Display point layer - else{ - displayMarkerLayerPointLastObs(observations); - - // interaction list - map - $('.lastObslistItem').click(function(){ - $(this).siblings().removeClass('current'); - $(this).addClass('current'); - var id_observation = $(this).attr('idSynthese'); - - var p = (currentLayer._layers); - var selectLayer; - for (var key in p) { - if (p[key].feature.properties.id_observation == id_observation){ - selectLayer = p[key]; - } - } - selectLayer.openPopup(); - map.setView(selectLayer._latlng, 14); - }) - } - - -// Zoom on the popup on observation click - - currentLayer.on('click', function(e){ - if (map.getZoom()<14) { - map.setView(e.latlng, 14); } - }); + + // Display point layer + else{ + displayMarkerLayerPointLastObs(observations); + + // interaction list - map + $('.lastObslistItem').click(function(){ + $(this).siblings().removeClass('current'); + $(this).addClass('current'); + var id_observation = $(this).attr('idSynthese'); + + var p = (currentLayer._layers); + var selectLayer; + for (var key in p) { + if (p[key].feature.properties.id_observation == id_observation){ + selectLayer = p[key]; + } + } + selectLayer.openPopup(); + selectLayer.openPopup(selectLayer._latlng); + map.setView(selectLayer._latlng, 14); + }) + } + }); @@ -79,10 +74,10 @@ $(function(){ // Generate legends and check configuration to choose which to display (Maille ou Point) htmlLegendMaille = "       Maille comportant au moins une observation

    " + - "       Limite du "+configuration.STRUCTURE; + "       Limite du "+configuration.STRUCTURE; htmlLegendPoint = "       Limite du "+configuration.STRUCTURE htmlLegend = configuration.AFFICHAGE_MAILLE ? htmlLegendMaille : htmlLegendPoint; -generateLegende(htmlLegend); \ No newline at end of file +generateLegende(htmlLegend); diff --git a/atlas/static/mapMailles.js b/atlas/static/mapMailles.js index 9c1fbaf6e..599a630bb 100644 --- a/atlas/static/mapMailles.js +++ b/atlas/static/mapMailles.js @@ -3,19 +3,19 @@ var zoomHomeButton = true; var map = generateMap(zoomHomeButton); if (configuration.MAP.ENABLE_SLIDER) { - generateSliderOnMap(); + generateSliderOnMap(); } var legend = L.control({ position: "bottomright" }); // Legende htmlLegend = - "       Limite du " + - configuration.STRUCTURE; + "       Limite du " + + configuration.STRUCTURE; generateLegende(htmlLegend); // Current observation Layer: leaflet layer type @@ -27,117 +27,118 @@ var myGeoJson; var compteurLegend = 0; // compteur pour ne pas rajouter la légende à chaque fois $.ajax({ - url: configuration.URL_APPLICATION + "/api/observationsMaille/" + cd_ref, - dataType: "json", - beforeSend: function() { - // // $("#loadingGif").attr( - // "src", - // configuration.URL_APPLICATION + "/static/images/loading.svg" - // ); - } + url: configuration.URL_APPLICATION + "/api/observationsMaille/" + cd_ref, + dataType: "json", + beforeSend: function() { + // // $("#loadingGif").attr( + // "src", + // configuration.URL_APPLICATION + "/static/images/loading.svg" + // ); + } }).done(function(observations) { - $("#loaderSpinner").hide(); - - // affichage des mailles - displayMailleLayerFicheEspece(observations, taxonYearMin, YEARMAX); - - //display nb observations - $("#nbObsLateral").html( - "" + observations.length + "
    Observations" - ); - - // pointer on first and last obs - $(".pointer").css("cursor", "pointer"); - //display nb observations - nbObs = 0; - myGeoJson.features.forEach(function(l) { - nbObs += l.properties.nb_observations; - }); - $("#nbObs").html("Nombre d'observation(s): " + nbObs); - - // Slider event - - mySlider.on("slideStop", function() { - years = mySlider.getValue(); - yearMin = years[0]; - yearMax = years[1]; - map.removeLayer(currentLayer); - $.ajax({ - url: configuration.URL_APPLICATION + "/api/observationsMaille/" + cd_ref, - dataType: "json", - type: "get", - data: { - year_min: yearMin, - year_max: yearMax - }, - beforeSend: function() { - $("#loadingGif").show(); - } - }).done(function(observations) { - $("#loadingGif").hide(); - observationsMaille = observations; - - // desactivation de l'event precedent - map.off("zoomend", function() {}); - - displayMailleLayerFicheEspece(observationsMaille); - nbObs = 0; - observationsMaille.features.forEach(function(l) { - nbObs += l.properties.nb_observations; - }); + $("#loaderSpinner").hide(); - $("#nbObs").html("Nombre d'observation(s): " + nbObs); - $("#yearMin").html(yearMin + "    "); - $("#yearMax").html("    " + yearMax); - }); - }); - - // Stat - map interaction - $("#firstObs").click(function() { - var firstObsLayer; - var year = new Date("2400-01-01"); - - var layer = currentLayer._layers; - for (var key in layer) { - layer[key].feature.properties.tabDateobs.forEach(function(thisYear) { - if (thisYear <= year) { - year = thisYear; - firstObsLayer = layer[key]; - } - }); - } + // affichage des mailles + displayMailleLayerFicheEspece(observations, taxonYearMin, YEARMAX); + + //display nb observations + $("#nbObsLateral").html( + "" + observations.length + "
    Observations" + ); - var bounds = L.latLngBounds([]); - var layerBounds = firstObsLayer.getBounds(); - bounds.extend(layerBounds); - map.fitBounds(bounds, { - maxZoom: 12 + // pointer on first and last obs + $(".pointer").css("cursor", "pointer"); + //display nb observations + nbObs = 0; + myGeoJson.features.forEach(function(l) { + nbObs += l.properties.nb_observations; }); + $("#nbObs").html("Nombre d'observation(s): " + nbObs); + + // Slider event + + mySlider.on("slideStop", function() { + years = mySlider.getValue(); + yearMin = years[0]; + yearMax = years[1]; + map.removeLayer(currentLayer); + clearOverlays() + $.ajax({ + url: configuration.URL_APPLICATION + "/api/observationsMaille/" + cd_ref, + dataType: "json", + type: "get", + data: { + year_min: yearMin, + year_max: yearMax + }, + beforeSend: function() { + $("#loadingGif").show(); + } + }).done(function(observations) { + $("#loadingGif").hide(); + observationsMaille = observations; + + // desactivation de l'event precedent + map.off("zoomend", function() {}); + + displayMailleLayerFicheEspece(observationsMaille); + nbObs = 0; + observationsMaille.features.forEach(function(l) { + nbObs += l.properties.nb_observations; + }); + + $("#nbObs").html("Nombre d'observation(s): " + nbObs); + $("#yearMin").html(yearMin + "    "); + $("#yearMax").html("    " + yearMax); + }); + }); + + // Stat - map interaction + $("#firstObs").click(function() { + var firstObsLayer; + var year = new Date("2400-01-01"); + + var layer = currentLayer._layers; + for (var key in layer) { + layer[key].feature.properties.tabDateobs.forEach(function(thisYear) { + if (thisYear <= year) { + year = thisYear; + firstObsLayer = layer[key]; + } + }); + } - firstObsLayer.openPopup(); - }); + var bounds = L.latLngBounds([]); + var layerBounds = firstObsLayer.getBounds(); + bounds.extend(layerBounds); + map.fitBounds(bounds, { + maxZoom: 12 + }); - $("#lastObs").click(function() { - var firstObsLayer; - var year = new Date("1800-01-01"); + firstObsLayer.openPopup(); + }); - var layer = currentLayer._layers; - for (var key in layer) { - layer[key].feature.properties.tabDateobs.forEach(function(thisYear) { - if (thisYear >= year) { - year = thisYear; - firstObsLayer = layer[key]; + $("#lastObs").click(function() { + var firstObsLayer; + var year = new Date("1800-01-01"); + + var layer = currentLayer._layers; + for (var key in layer) { + layer[key].feature.properties.tabDateobs.forEach(function(thisYear) { + if (thisYear >= year) { + year = thisYear; + firstObsLayer = layer[key]; + } + }); } - }); - } - var bounds = L.latLngBounds([]); - var layerBounds = firstObsLayer.getBounds(); - bounds.extend(layerBounds); - map.fitBounds(bounds, { - maxZoom: 12 - }); + var bounds = L.latLngBounds([]); + var layerBounds = firstObsLayer.getBounds(); + bounds.extend(layerBounds); + map.fitBounds(bounds, { + maxZoom: 12 + }); - firstObsLayer.openPopup(); - }); + firstObsLayer.openPopup(); + }); }); diff --git a/atlas/static/package-lock.json b/atlas/static/package-lock.json index f8dfea67a..3e3499b79 100644 --- a/atlas/static/package-lock.json +++ b/atlas/static/package-lock.json @@ -1529,9 +1529,9 @@ "dev": true }, "fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", "dev": true, "optional": true }, diff --git a/atlas/templates/home/lastObs.html b/atlas/templates/home/lastObs.html index 7ce5be3ea..d927ff77e 100644 --- a/atlas/templates/home/lastObs.html +++ b/atlas/templates/home/lastObs.html @@ -17,7 +17,7 @@

      {% for obs in observations %} -
    • +
    • {% if obs.pathImg == None %} > log/install_db.log + export PGPASSWORD=$owner_atlas_pass;psql -d $db_name -U $owner_atlas -h $db_host -p $db_port \ + -v sensibility0=$sensibility0 \ + -v sensibility1=$sensibility1 \ + -v sensibility2=$sensibility2 \ + -v sensibility3=$sensibility3 \ + -f /tmp/atlas/${script} &>> log/install_db.log echo "[$(date +'%H:%M:%S')] Passed - Duration : $((($SECONDS-$time_temp)/60))m$((($SECONDS-$time_temp)%60))s" done From aa2f5efa708965526cb40b6bb6f194afad4daad4 Mon Sep 17 00:00:00 2001 From: J-E Castagnede Date: Fri, 20 Dec 2024 10:37:44 +0100 Subject: [PATCH 2/2] fix core_area_synthese reference --- data/atlas/11.vm_cor_area_synthese.sql | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/data/atlas/11.vm_cor_area_synthese.sql b/data/atlas/11.vm_cor_area_synthese.sql index 544322144..f37fd4c59 100644 --- a/data/atlas/11.vm_cor_area_synthese.sql +++ b/data/atlas/11.vm_cor_area_synthese.sql @@ -1,5 +1,5 @@ IMPORT FOREIGN SCHEMA gn_synthese - LIMIT TO (gn_synthese.tmp_cor_area_synthse) + LIMIT TO (gn_synthese.cor_area_synthese) FROM SERVER geonaturedbserver INTO synthese; CREATE MATERIALIZED VIEW atlas.vm_cor_area_synthese @@ -14,7 +14,7 @@ SELECT s.id_nomenclature_sensitivity, st_transform(a.geom, 4326) AS geom FROM synthese.synthese s - JOIN synthese.tmp_cor_area_synthse sa ON sa.id_synthese = s.id_synthese + JOIN synthese.cor_area_synthese sa ON sa.id_synthese = s.id_synthese JOIN ref_geo.l_areas a ON sa.id_area = a.id_area JOIN atlas.t_layer_territoire ON st_intersects(a.geom_4326, t_layer_territoire.geom)-- AND NOT ST_Touches(t_layer_territoire.geom, a.geom_4326) )