Skip to content
This repository was archived by the owner on Sep 10, 2024. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14,323 changes: 8,770 additions & 5,553 deletions basic/package-lock.json

Large diffs are not rendered by default.

5 changes: 3 additions & 2 deletions basic/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,14 @@
"name": "basic",
"version": "0.1.0",
"dependencies": {
"mapbox-gl": "^1.11.1",
"bootstrap": "^5.3.0-alpha3",
"mapbox-gl": "^1.13.3",
"react": "^16.13.1",
"react-dom": "^16.13.1",
"react-scripts": "^3.4.3"
},
"scripts": {
"start": "react-scripts start",
"start": "react-scripts --openssl-legacy-provider start",
"build": "react-scripts build"
},
"browserslist": {
Expand Down
12 changes: 12 additions & 0 deletions basic/public/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,19 @@
<meta charset="utf-8" />
<link href='https://api.mapbox.com/mapbox-assembly/mbx/v0.18.0/assembly.min.css' rel='stylesheet'>
<link href='https://api.tiles.mapbox.com/mapbox-gl-js/v1.11.1/mapbox-gl.css' rel='stylesheet' />
<script src="https://api.mapbox.com/mapbox-gl-js/v2.13.0/mapbox-gl.js"></script>
<script src='https://api.tiles.mapbox.com/mapbox-gl-js/v2.13.0/mapbox-gl.js'></script>
<link href='https://api.tiles.mapbox.com/mapbox-gl-js/v2.13.0/mapbox-gl.css' rel='stylesheet' />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<style>
body { margin: 0; padding: 0; }
</style>
<style>
.mapboxgl-popup {
max-width: 400px;
font: 12px/20px 'Helvetica Neue', Arial, Helvetica, sans-serif;
}
</style>
<title>Basic</title>
</head>
<body>
Expand Down
4 changes: 1 addition & 3 deletions basic/src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,7 @@ import Map from './Map';

function App() {
return (
<div>
<Map />
</div>
<Map />
);
}

Expand Down
130 changes: 118 additions & 12 deletions basic/src/Map.css
Original file line number Diff line number Diff line change
@@ -1,20 +1,126 @@
.map-container {
@import url('https://fonts.googleapis.com/css2?family=Montserrat:wght@400;500;600;800&display=swap');

* {
box-sizing: border-box;
margin: 0;
padding: 0;
}

body {
color: #404040;
font: 400 15px/22px 'Source Sans Pro', 'Helvetica Neue', sans-serif;
-webkit-font-smoothing: antialiased;
}

a {
color: #404040;
text-decoration: none;
}

a:hover {
color: #101010;
}

/* The page is split between map and sidebar - the sidebar gets 1/3, map
gets 2/3 of the page. You can adjust this to your personal liking. */
Sidebar {
position: absolute;
width: 33.3333%;
height: 100%;
top: 0;
bottom: 0;
left: 0;
right: 0;
overflow: hidden;
border-right: 1px solid rgba(0, 0, 0, 0.25);
}

.sidebarStyle {
display: inline-block;
#map {
position: absolute;
left: 33.3333%;
width: 66.6666%;
top: 0;
left: 0;
margin: 12px;
background-color: #404040;
color: #ffffff;
z-index: 1 !important;
padding: 6px;
font-weight: bold;
bottom: 0;
}

.heading {
background: #fff;
border-bottom: 1px solid #eee;
height: 60px;
line-height: 60px;
}

.mapboxgl-popup-content {
font-size: 1rem;
border-radius: 10px;
padding: 10px;
}

.mapboxgl-popup-content h3 {
font-family: 'Montserrat', sans-serif;
font-weight: 700;
border-radius: 10px;
text-align: center;
color: #fff;
user-select: none;
padding: 5px;
transition-property: transform, box-shadow;
transition-duration: .2s;
}

.mapboxgl-popup-content h3:hover {
cursor: pointer;
opacity: .6;
}

.mapboxgl-popup-content h3:active {
cursor: pointer;
transform: scale(.95);
box-shadow: 0 3px 14px -2px;
}

.mapboxgl-popup-content-wrapper {
padding: 1%;
}

.real-container {
height: fit-content;
text-align: center;
}

.real-kitchens {
margin: 0;
}

.real-kitchen {
width: 100%;
}

.real-kitchen:hover {
background-color: 'red';
}

.ghost-container {
margin-top: 5px;
padding: 0;
}

.ghost-kitchens {
font-size: .75rem;
font-family: 'Montserrat';
display: flex;
flex-wrap: wrap;
gap: 3px;
}

.ghost-kitchen {
display: flex;
align-items: center;
justify-content: center;
margin: 2px;
}

.ghost-kitchens>* {
flex: 1 1 10em;
}
.ghost-kitchen:hover {
background-color: #91c949;
}
191 changes: 162 additions & 29 deletions basic/src/Map.js
Original file line number Diff line number Diff line change
@@ -1,48 +1,181 @@
import React, { useRef, useEffect, useState } from 'react';
import mapboxgl from 'mapbox-gl';
import './Map.css';
import geoJson from "./features.geojson"

mapboxgl.accessToken =
'pk.eyJ1IjoibWFwYm94IiwiYSI6ImNpejY4M29iazA2Z2gycXA4N2pmbDZmangifQ.-g_vE53SD2WrJ6tFX7QHmA';
'pk.eyJ1IjoiY2FzdHRoZWNhbG1pbmdhcHBsZSIsImEiOiJjbGZzZzFxNGcwNWpnM3RwanQ2bjlubGgzIn0.0WiHmOMaGvSo5Ms2TNd4Qw';


const Map = () => {
const mapContainerRef = useRef(null);

const [lng, setLng] = useState(5);
const [lat, setLat] = useState(34);
const [zoom, setZoom] = useState(1.5);


// Initialize map when component mounts
useEffect(() => {
const map = new mapboxgl.Map({
container: mapContainerRef.current,
style: 'mapbox://styles/mapbox/streets-v11',
center: [lng, lat],
zoom: zoom
});

// Add navigation control (the +/- zoom buttons)
map.addControl(new mapboxgl.NavigationControl(), 'top-right');
container: 'map',
// Choose from Mapbox's core styles, or make your own style with Mapbox Studio
style: 'mapbox://styles/mapbox/light-v11',
center: [-73.09800754761238, 40.853489556812974],
zoom: 12,
maxZoom: 17.5
});
map.on('load', () => {
// Add a new source from our GeoJSON data and
// set the 'cluster' option to true. GL-JS will
// add the point_count property to your source data.
map.addSource('kitchens', {
type: 'geojson',
data: geoJson,
cluster: true,
clusterMaxZoom: 19, // Max zoom to cluster points on
clusterRadius: 15 // Radius of each cluster when clustering points (defaults to 50)
});

map.on('move', () => {
setLng(map.getCenter().lng.toFixed(4));
setLat(map.getCenter().lat.toFixed(4));
setZoom(map.getZoom().toFixed(2));
});
map.addLayer({
id: 'clusters',
type: 'circle',
source: 'kitchens',
filter: ['has', 'point_count'],
paint: {
'circle-color': '#bafc03',
"circle-radius": [
"interpolate", ["linear"], ["zoom"],
// zoom is 5 (or less) -> circle radius will be 1px
8, 15,
// zoom is 10 (or greater) -> circle radius will be 5px
20, 10
],
'circle-stroke-width': 3,
'circle-stroke-color': '#000'
}
});



map.addLayer({
id: 'cluster-count',
type: 'symbol',
source: 'kitchens',
filter: ['has', 'point_count'],
layout: {
'text-field': ['get', 'point_count_abbreviated'],
'text-font': ['DIN Offc Pro Medium', 'Arial Unicode MS Bold']
}
});

// inspect a cluster on click
map.on('click', 'clusters', (e) => {
const features =
map.queryRenderedFeatures(e.point, {
layers: ['clusters']
});
const clusterId =
features[0].properties.cluster_id;
map.getSource('kitchens').getClusterExpansionZoom(
clusterId,
(err, zoom) => {
if (err) return;

map.easeTo({
center:
features[0].geometry.coordinates,
zoom: zoom * 1.25
});
}
);
const point_count = features[0].properties.point_count
const coordinates = e.features[0].geometry.coordinates.slice()

// Clean up on unmount
return () => map.remove();
}, []); // eslint-disable-line react-hooks/exhaustive-deps
// Get all points under a cluster
map.getSource('kitchens').getClusterLeaves(clusterId, point_count, 0, function (err, aFeatures) {
let popupReal = "";
let popupGhost = ""
let childrenCount = Object.keys(aFeatures).length
const isReal = aFeatures.filter(kitchen => kitchen.properties.is_real === '1')
const isGhost = aFeatures.filter(kitchen => kitchen.properties.is_real === '0')
const orderedArray = (isReal.length === 1 ? isReal.concat(isGhost) : [])
orderedArray.map(kitchen => {
console.log(kitchen.properties.is_real, kitchen.properties.name)
if(kitchen.properties.is_real === '1'){
popupReal += `
<h3 class="real-kitchen" style="background-color:#91c949">${kitchen.properties.name}</h3>
`
}
if(kitchen.properties.is_real === '0'){
popupGhost += `
<h3 class="ghost-kitchen" style="background-color:red">${kitchen.properties.name}</h3>
`
}
})

return (
<div>
<div className='sidebarStyle'>
<div>
Longitude: {lng} | Latitude: {lat} | Zoom: {zoom}
let popupGhostContainer = `
<div class="ghost-container">
<div class="ghost-kitchens">
${popupGhost}
</div>
</div>
`
let popupRealContainer = `
<div class="real-container">
<div class="real-kitchens">
${popupReal}
</div>
</div>
<div className='map-container' ref={mapContainerRef} />
</div>
`
const popupHtml = `${popupRealContainer}${popupGhostContainer}`
orderedArray.length > 1 && new mapboxgl.Popup({
closeButton: false,
maxWidth: "auto"
})
.setLngLat(coordinates)
.setHTML(popupHtml)
.addTo(map);
})
})

// When a click event occurs on a feature in
// the unclustered-point layer, open a popup at
// the location of the feature, with
// description HTML from its properties.
map.on('click', 'unclustered-point', (e) => {
const coordinates = e.features[0].geometry.coordinates.slice();
const name = e.features[0].properties.name;

// Ensure that if the map is zoomed out such that
// multiple copies of the feature are visible, the
// popup appears over the copy being pointed to.
while (Math.abs(e.lngLat.lng - coordinates[0]) > 180) {
coordinates[0] += e.lngLat.lng > coordinates[0] ? 360 : -360;
}

new mapboxgl.Popup()
.setLngLat(coordinates)
.setHTML(
`Name: ${name}`
)
.addTo(map);
});

map.on('mouseenter', 'clusters', () => {
map.getCanvas().style.cursor = 'pointer';
});
map.on('mouseleave', 'clusters', () => {
map.getCanvas().style.cursor = '';
});
map.on('mouseenter', 'unclustered-point', () => {
map.getCanvas().style.cursor = 'pointer';
});
map.on('mouseleave', 'unclustered-point', () => {
map.getCanvas().style.cursor = '';
});
})
})

return (
<>
<div id="map" className='map-container' ref={mapContainerRef}></div>
</>
);
};

Expand Down
Loading