// Imports import * as PartyModel from "/services/model/party-model.js"; import * as AreaModel from "/services/model/area-model.js"; import * as ElectionModel from "/services/model/election-model.js"; export async function mount(parent) { const mapComponent = new MapComponent(parent); return mapComponent; } class MapComponent { constructor(parent) { this.parent = parent; this.PartyModel = PartyModel.getPartyModel(); this.AreaModel = AreaModel.getAreaModel(); this.ElectionModel = ElectionModel.getElectionModel(); } async displayMapAreas() { let election = await this.ElectionModel.getElection( this.parent.parent.round.ElectionID ); await this.initMap( election.MapAreaFile.replace("web/", ""), this.colorAreas ); } async displayMapSections() { let election = await this.ElectionModel.getElection( this.parent.parent.round.ElectionID ); await this.initMap(election.MapSectionFile.replace("web/", ""), this.colorSections); } async initMap(mapFile, colorationFunction) { // Create datasource const request = new XMLHttpRequest(); request.open("GET", mapFile, false); request.send(null); this.dataSource = JSON.parse(request.responseText); // Add parties and colors to datasource this.dataSource = await colorationFunction(this, this.dataSource); document.getElementById("map-component").innerHTML = ""; // Create a popup, but don't add it to the map yet. let popup = new mapboxgl.Popup({ closeButton: false, }); this.map = new mapboxgl.Map({ container: "map-component", // container id style: "/assets/mapbox/vector.json", // stylesheet location center: [4.9, 45.75], // starting position [lng, lat] zoom: 9.5, // starting zoom }); this.map.on("load", () => { this.map.addSource("data-source", { type: "geojson", data: this.dataSource, }); this.map.addLayer( { id: "winners-fills", type: "fill", source: "data-source", layout: {}, paint: { "fill-color": { type: "identity", property: "color" }, "fill-opacity": 0.5, "fill-outline-color": "black", }, }, "place_label_city" ); this.map.addLayer({ id: "winners-names", type: "symbol", source: "data-source", filter: ["all"], layout: { "text-field": "{partyName}", "text-font": ["titiliumweb-regular"], }, }); }); this.map.on("mousemove", "winners-fills", (e) => { // Change the cursor style as a UI indicator. this.map.getCanvas().style.cursor = "pointer"; // Single out the first found feature. const feature = e.features[0]; if (e.features.length > 0) { // Display a popup with the name of the county popup .setLngLat(e.lngLat) .setText( `${feature.properties.Name} : ${ feature.properties.partyName == undefined ? "aucun" : feature.properties.partyName }` ) .addTo(this.map); } }); this.map.on("mouseleave", "winners-fills", () => { this.map.getCanvas().style.cursor = ""; popup.remove(); }); } async colorAreas(mapHandler, dataSource) { for (let area of mapHandler.parent.parent.results.areasResults) { if (area.status == mapHandler.parent.parent.filter) { let party = await mapHandler.PartyModel.getParty( area.candidateLists[0].PartyID ); dataSource = mapHandler.colorTiles( dataSource, parseInt(area.MapID), party.Name, party.Color ); } else { dataSource = mapHandler.colorTiles(dataSource, area.MapID, "", ""); } } return dataSource; } async colorSections(mapHandler, dataSource) { mapHandler.parent.parent.results.areasResults.forEach(async (area) => { for (let section of area.Sections) { if (section.status == mapHandler.parent.parent.filter) { let party = await mapHandler.PartyModel.getParty( section.candidateLists[0].PartyID ); dataSource = mapHandler.colorTiles( dataSource, parseInt(section.MapID), party.Name, party.Color ); } else { dataSource = mapHandler.colorTiles(dataSource, section.MapID, "", ""); } } }); return dataSource; } colorTiles(dataSource, gid, partyName, color) { for (let f of dataSource.features) { if (f.properties.nomcircons) f.properties.Name = f.properties.nomcircons; if (f.properties["Nom réduit"]) f.properties.Name = f.properties["Nom réduit"]; if (f.properties.gid === gid) { f.properties.partyName = partyName; f.properties.color = color; break; } } return dataSource; } }