//import * as geoDataPointsFromApi from './data.json'; // liste des cuisines uniques let cuisineSet = ['pizza', 'italian', 'japanese', 'thai', 'thaï', 'lebanese','portugese'] // Filtre pour afficher seulement les cafés // Appliquer/retirer le filtre quand on clique sur le bouton export function toggleFilter(objectAmenity) { const filterExpression = ['==', ['get', 'amenity'], objectAmenity]; let visibility = map.getLayoutProperty('points', 'visibility') console.log('visibility', visibility) if (map.getLayoutProperty('points', 'visibility') === 'visible') { console.log('cacher les aménités', objectAmenity) map.setFilter('points', ['!=', 'amenity', objectAmenity]); map.setLayoutProperty('points', 'visibility', 'none'); } else { console.log('montrer les aménités', objectAmenity) map.setFilter('points', filterExpression); map.setLayoutProperty('points', 'visibility', 'visible'); } } const geoDataJsonMock = { 'version': 0.6, 'generator': 'Overpass API 0.7.57 93a4d346', 'osm3s': { 'timestamp_osm_base': '2021-12-05T21:05:09Z', 'copyright': 'The data included in this document is from www.openstreetmap.org. The data is made available under ODbL.', }, 'elements': [{ 'type': 'node', 'id': 598729945, 'lat': 48.6727029, 'lon': 2.0690276, 'tags': {'amenity': 'restaurant', 'cuisine': 'crepe', 'name': 'Le Chat Botté'}, }, { 'type': 'node', 'id': 963824814, 'lat': 48.6735834, 'lon': 2.1704756, 'tags': { 'addr:city': 'Saint-Jean-de-Beauregard', 'addr:housenumber': '5', 'addr:postcode': '91940', 'addr:street': 'Grande Rue', 'amenity': 'restaurant', 'cuisine': 'french', 'name': 'L\'Atelier Gourmand', 'phone': '+33 1 60 12 31 01', 'website': 'https://lateliergourmand-restaurant.fr/', }, }], }; const overrideQuery = true; const initialZoom = 14; const osmMention = '© OpenStreetMap contributors' // serveurs de tuiles: https://wiki.openstreetmap.org/wiki/Tile_servers // https://stamen-tiles.a.ssl.fastly.net/toner/{z}/{x}/{y}.png // https://a.tile.openstreetmap.fr/osmfr/{z}/{x}/{y}.png const tileServer = "https://cartodb-basemaps-{s}.global.ssl.fastly.net/light_all/{z}/{x}/{y}.png" var map = L.map('map').setView([48.6410, 2.1307], initialZoom); L.tileLayer(tileServer, { maxZoom: 19, attribution: osmMention, }).addTo(map); // if (overrideQuery) { // $('#overpass-api-controls').hide(); // } function buildOverpassApiUrl(map, overpassQuery) { var baseUrl = 'https://overpass-api.de/api/interpreter'; var bounds = map.getBounds().getSouth() + ',' + map.getBounds().getWest() + ',' + map.getBounds().getNorth() + ',' + map.getBounds().getEast(); var resultUrl, query = ''; if (overrideQuery) { query = `?data=[out:json][timeout:15];( node[shop=bakery](${bounds}); node[amenity=fast_food](${bounds}); node[amenity=restaurant](${bounds}); node[amenity=pub](${bounds}); node[amenity=drinking_water](${bounds}); node[shop=convenience](${bounds}); node[shop=supermarket](${bounds}); way[amenity=microwave](${bounds}); way[amenity=pub](${bounds}); way[amenity=bar](${bounds}); way[amenity=cafe](${bounds}); way[shop=bakery](${bounds}); way[amenity=fast_food](${bounds}); way[amenity=vending_machine](${bounds}); way[amenity=restaurant](${bounds}); );out body geom;`; let not_used_query = ` node[man_made=water_tap](${bounds}); node[man_made=drinking_fountain](${bounds}); node[amenity=vending_machine](${bounds}); node[amenity=bar](${bounds}); node[amenity=cafe](${bounds}); ` } else { var nodeQuery = 'node[' + overpassQuery + '](' + bounds + ');'; var wayQuery = 'way[' + overpassQuery + '](' + bounds + ');'; var relationQuery = 'relation[' + overpassQuery + '](' + bounds + ');'; query = '?data=[out:json][timeout:15];(' + nodeQuery + wayQuery + relationQuery + ');out body geom;'; } resultUrl = baseUrl + query; // console.log("query url", resultUrl) return resultUrl; } const UseLocalJson = false; const loadQueryPoints = () => { if (UseLocalJson) { displayPointsFromApi(geoDataJsonMock); } else { loadOverpassQuery(); } }; function loadedSuccess() { document.querySelector('#success_load').classList.add('visible') setTimeout(function () { document.querySelector('#success_load').classList.remove('visible') }, 1000) $('#spinning_icon').fadeOut(); } let counterFeatures = 0; let counterFeaturesHourMissing = 0; let counterFeaturesCuisineMissing = 0; function displayPointsFromApi(points) { var resultAsGeojson = osmtogeojson(points); var resultLayer = L.geoJson(resultAsGeojson, { style: function (feature) { return {color: '#ff0000'}; }, filter: function (feature, layer) { var isPolygon = (feature.geometry) && (feature.geometry.type !== undefined) && (feature.geometry.type === 'Polygon'); if (isPolygon) { feature.geometry.type = 'Point'; var polygonCenter = L.latLngBounds(feature.geometry.coordinates[0]).getCenter(); feature.geometry.coordinates = [polygonCenter.lat, polygonCenter.lng]; } return true; }, onEachFeature: function (feature, layer) { counterFeatures++ var popupContent = ''; popupContent = popupContent + '
@id
' + feature.properties.type + '/' + feature.properties.id + '
'; var keys = Object.keys(feature.properties.tags); keys.forEach(function (key) { popupContent = popupContent + '
' + key + '
' + feature.properties.tags[key] + '
'; }); popupContent = popupContent + ''; layer.bindPopup(popupContent); let iconSiZePx = 20; if (feature.properties.tags['amenity'] && feature.properties.tags['amenity'] === 'restaurant' || feature.properties.tags['amenity'] === 'fast_food' ) { iconSiZePx = 40; } let icon, cuisine, rest_name = ''; if (feature.properties.tags['name'] !== undefined) { rest_name = feature.properties.tags['name']; } else { rest_name = ` Nom inconnu, ${feature.properties.tags['amenity']}`; } if (typeof feature.properties.tags['cuisine'] !== typeof undefined && feature.properties.tags['cuisine'].length) { let cooklist = feature.properties.tags['cuisine'] // console.log('feature.properties.tags[\'cuisine\']', feature.properties.tags['cuisine']) if (cooklist) { cuisine = ` - cuisine: ${cooklist}`; } } if (!cuisine) { cuisine = ' '; counterFeaturesCuisineMissing++ } let isOpen = false; let opening, hours = ''; // let isOpen = getIsOpenFromOpeningHours(feature.properties.tags) if (feature.properties.tags.opening_hours) { isOpen = isLocationOpenNow(feature.properties.tags.opening_hours) } if (feature.properties.tags.opening_hours) { hours = feature.properties.tags.opening_hours } if (hours) { if (isOpen) { isOpen = 'ouvert' } else { isOpen = 'fermé' } } else { isOpen = 'horaires non renseignées' } if (isOpen) { opening = ` ${isOpen} ${hours} ` } let html = `
✏️
${cuisine}
${opening}
`; L.marker(layer._latlng, { icon: L.divIcon({ iconUrl: 'https://www.cipherbliss.com/ou-manger/img/' + getIconFromTags(feature.properties.tags), className: 'label ' + makeCssClassFromTags(feature.properties.tags), // html : html, iconSize: ['auto', 'auto'], }), }).addTo(map); var myIcon = L.icon({ iconUrl: 'https://www.cipherbliss.com/ou-manger/img/' + getIconFromTags(feature.properties.tags), iconSize: [iconSiZePx, iconSiZePx], iconAnchor: [iconSiZePx / 2, iconSiZePx / 2], popupAnchor: [iconSiZePx / 2, iconSiZePx / 2], className: makeCssClassFromTags(feature.properties.tags), }); let regular_marker = L.marker(layer._latlng, {title: rest_name, icon: myIcon}).addTo(map); regular_marker.bindPopup(html); regular_marker.on({ mouseover: function () { this.openPopup(); }, mouseout: function () { setTimeout(() => this.closePopup(), 3000); }, click: function () { this.openPopup(); }, }); /** * ajout d'icone pour chaque restaurant où il manque l'horaire */ if (!feature.properties.tags.opening_hours) { counterFeaturesHourMissing++ var missingHour = L.icon({ iconUrl: '/img/miss_hour.png', iconSize: [iconSiZePx/3, iconSiZePx/3], iconAnchor: [iconSiZePx / 2, iconSiZePx / 2], className: makeCssClassFromTags(feature.properties.tags), }); L.marker( { lat: layer._latlng.lat + 0.00002, lng: layer._latlng.lng + 0.00001 }, { title: "horaire manquante", icon: missingHour } ).addTo(map); } }, }); console.log('counterFeatures', counterFeatures) console.log('counterFeatures hour missing', counterFeaturesHourMissing) console.log('counterFeatures cuisine missing', counterFeaturesCuisineMissing) } function makeCssClassFromTags(tags) { let tagKeys = Object.keys(tags); if (!tags) { return ''; } let listOfClasses = []; tagKeys.forEach((element) => { listOfClasses.push('tag-' + element + '_' + tags[element].replace(':', '--')); }); let isOpen = getIsOpenFromOpeningHours(tags) if (tags['opening_hours']) { listOfClasses.push('tag-has-opening-hours') } else { listOfClasses.push('tag-no-opening-hours') } listOfClasses.push('is-open-today-' + isOpen) return listOfClasses.join(' '); } /** * trouver si un magasin est actuellement ouvert, ou si les infos de opening_hours sont absentes * exemple: Mo 06:30-20:00; Tu 06:30-20:00; We off; Th 06:30-20:00; * Fr 06:30-20:00; Sa 06:30-20:00; Su 06:30-13:30 * @param tags * @returns {string} */ function getIsOpenFromOpeningHours(tags) { let isOpen = 'has-no-opening-hours'; let currentDay = new Date(); let daysArray = ['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa'] let todayInLetters = daysArray[currentDay.getDay()]; let todayInHour = daysArray[currentDay.getHours()]; if (tags['opening_hours']) { let opening_hours = tags['opening_hours'].trim(); // trouver les sections séparées par des points virgule let sections = opening_hours.split(' ') // séparer les sections d'ouverture par un espace entre la plage de jour et les heures sections.map(part => { // prendre en compte les périodes de plusieurs jours Mo-Sa // prise en compte d'un seul jour à la fois if (part.indexOf(todayInLetters)) { // voir si le jour actuel est inclus dans la section // voir si les horaires de ce jour sont dans le futur // dans ce cas le restaurant est ouvert, YES! isOpen = 'is-open-this-day' let splitDay = part.split('-') if (splitDay.length) { let start = splitDay[0] let end = splitDay[1] if (start.substring(0, 2) < todayInHour) { //sera ouvert aujourd'hui } else { //était ouvert aujourd'hui } } } }) } // console.log(tags['opening_hours'], isOpen) return isOpen; } /** * Determine whether an location with given open hours is currently open or closed. * @param {string} openingHours The value of the 'opening_hours' tag. */ function isLocationOpenNow(openingHours) { if (openingHours === '24/7') { return true; } const regex = /MO(\d+)-(\d+)|TU(\d+)-(\d+)|WE(\d+)-(\d+)|TH(\d+)-(\d+)|FR(\d+)-(\d+)|SA(\d+)-(\d+)|SU(\d+)-(\d+)/g; const matches = Array.from(openingHours.matchAll(regex)).flat(); const dayOfWeek = new Date().getDay(); const startTime = parseInt(matches[(dayOfWeek - 1) * 2]); const closeTime = parseInt(matches[(dayOfWeek - 1) * 2 + 1]); const now = new Date(); const openAt = new Date(now.getFullYear(), now.getMonth(), now.getDate(), startTime); const closeAt = new Date(now.getFullYear(), now.getMonth(), now.getDate(), closeTime); if (now >= openAt && now <= closeAt) { return true; } return false; } function getIconFromTags(tags) { let iconFileName = 'icon_restaurant.png'; if (!tags['cuisine']) { return iconFileName; } let firstCuisine = tags['cuisine'].split(';')[0]; if (!firstCuisine) { firstCuisine = tags['cuisine'] } if(cuisineSet.indexOf(firstCuisine) === -1) { cuisineSet.push(firstCuisine) } if (tags['man_made']) { iconFileName = 'fountain.png'; } else if (tags['shop']) { iconFileName = 'croissant.png'; } else if (tags['amenity']) { if (tags['amenity'] === 'restaurant') { if (firstCuisine === 'pizza') { iconFileName = 'pizza.png'; } if (firstCuisine === 'italian') { iconFileName = 'pizza.png'; } if (firstCuisine === 'japanese') { iconFileName = 'asian_food.png'; } if (firstCuisine === 'thai') { iconFileName = 'pad-thai.png'; } if (firstCuisine === 'thaï') { iconFileName = 'pad-thai.png'; } if (firstCuisine === 'crepe') { iconFileName = 'crepe.png'; } if (firstCuisine === 'crepes') { iconFileName = 'crepe.png'; } if (firstCuisine === 'sushi') { iconFileName = 'asian_food.png'; } if (firstCuisine === 'asian') { iconFileName = 'asian_food.png'; } if (firstCuisine === 'chinese') { iconFileName = 'asian_food.png'; } } else if (tags['amenity'] === 'vending_machine') { iconFileName = 'vending_machine.png'; } else if (tags['amenity'] === 'drinking_water') { iconFileName = 'fountain.png'; } else if (tags['amenity'] === 'pub') { iconFileName = 'beer.jpg'; } else if (tags['amenity'] === 'bar') { iconFileName = 'beer.jpg'; } else if (tags['amenity'] === 'fast_food') { iconFileName = 'burger.png'; if (firstCuisine === 'pizza') { iconFileName = 'pizza.png'; } } } return iconFileName; } let isLoading = false; function removeOlderPoints() { // L.clearLayers() } function loadOverpassQuery() { // ne pas charger si on recherche déjà if (!isLoading) { isLoading = true; $('#spinning_icon').fadeIn(); var queryTextfieldValue = $('#query-textfield').val(); var overpassApiUrl = buildOverpassApiUrl(map, queryTextfieldValue); $.get(overpassApiUrl, function (geoDataPointsFromApi) { removeOlderPoints() displayPointsFromApi(geoDataPointsFromApi); console.log('cuisineSet', new Set(cuisineSet)) loadedSuccess(); isLoading = false; }); // end of the getting from overpass API } } console.log('loadQueryPoints', loadQueryPoints); loadQueryPoints(); $('#spinning_icon').hide(); /** * liens avec les boutons */ $('#query-button').click(function () { loadOverpassQuery(); }); $('#toggle_cafe').click(function () { toggleFilter('cafe'); }); $('#toggle_restaurant').click(function () { toggleFilter('restaurant'); }); $('#toggle_fast_food').click(function () { toggleFilter('fast_food'); });