Skip to content

Instantly share code, notes, and snippets.

@simonw
Last active September 28, 2024 21:43
Show Gist options
  • Save simonw/da2b20711b96f745873ccb44a3347ce9 to your computer and use it in GitHub Desktop.
Save simonw/da2b20711b96f745873ccb44a3347ce9 to your computer and use it in GitHub Desktop.

Adding 1000 Random Markers to a Map

human (Sep 28, 2024, 10:52 AM)

const map = new maplibregl.Map({
    style: 'https://tiles.openfreemap.org/styles/liberty',
    center: [13.388, 52.517],
    zoom: 9.5,
    container: 'map',
  })

Expand this example to add 1000 markers randomly placed roughly within San Francisco and zoom the map to the point where it can see all those markers

assistant (Sep 28, 2024, 10:52 AM)

Certainly! I'll expand the example to add 1000 markers randomly placed within the San Francisco area and adjust the map view to show all the markers. Here's the updated code:

MapLibre GL JS map with 1000 random markers in San Francisco

// Function to generate random coordinates within a bounding box
function getRandomCoordinate(minLng, maxLng, minLat, maxLat) {
  const lng = Math.random() * (maxLng - minLng) + minLng;
  const lat = Math.random() * (maxLat - minLat) + minLat;
  return [lng, lat];
}

// San Francisco bounding box (approximate)
const sfBounds = {
  minLng: -122.5155,
  maxLng: -122.3247,
  minLat: 37.7038,
  maxLat: 37.8324
};

// Create the map
const map = new maplibregl.Map({
  style: 'https://tiles.openfreemap.org/styles/liberty',
  center: [-122.4194, 37.7749], // San Francisco coordinates
  zoom: 11,
  container: 'map',
});

// Array to store all marker coordinates
const markerCoordinates = [];

// Generate 1000 random markers
for (let i = 0; i < 1000; i++) {
  const [lng, lat] = getRandomCoordinate(
    sfBounds.minLng,
    sfBounds.maxLng,
    sfBounds.minLat,
    sfBounds.maxLat
  );
  markerCoordinates.push([lng, lat]);
}

// Add markers to the map
markerCoordinates.forEach(coord => {
  new maplibregl.Marker()
    .setLngLat(coord)
    .addTo(map);
});

// Fit the map to the extent of all markers
map.on('load', () => {
  const bounds = markerCoordinates.reduce((bounds, coord) => {
    return bounds.extend(coord);
  }, new maplibregl.LngLatBounds(markerCoordinates[0], markerCoordinates[0]));

  map.fitBounds(bounds, {
    padding: 50 // Add some padding around the markers
  });
});

This code does the following:

  1. Defines a function getRandomCoordinate to generate random coordinates within a given bounding box.
  2. Sets up a bounding box for San Francisco.
  3. Creates the map centered on San Francisco.
  4. Generates 1000 random coordinates within the San Francisco bounding box.
  5. Adds a marker for each of these coordinates.
  6. Uses the fitBounds method to adjust the map view to show all markers when the map loads.

The map will now display 1000 randomly placed markers within the San Francisco area and automatically zoom to a level where all markers are visible.

Would you like me to explain any part of this code in more detail?

human (Sep 28, 2024, 10:53 AM)

Options for making those markers a bit smaller

assistant (Sep 28, 2024, 10:53 AM)

Certainly! There are a few ways to make the markers smaller in MapLibre GL JS. I'll show you some options:

MapLibre GL JS map with 1000 smaller random markers in San Francisco

// ... (previous code for map setup and random coordinate generation)

// Option 1: Use built-in scaling
function addScaledMarkers() {
  markerCoordinates.forEach(coord => {
    new maplibregl.Marker({ scale: 0.5 }) // Scale down to 50%
      .setLngLat(coord)
      .addTo(map);
  });
}

// Option 2: Custom HTML element
function addCustomMarkers() {
  markerCoordinates.forEach(coord => {
    const el = document.createElement('div');
    el.className = 'custom-marker';
    el.style.width = '10px';
    el.style.height = '10px';
    el.style.borderRadius = '50%';
    el.style.backgroundColor = 'red';

    new maplibregl.Marker(el)
      .setLngLat(coord)
      .addTo(map);
  });
}

// Option 3: Use circle layer instead of markers
function addCircleLayer() {
  map.on('load', () => {
    map.addSource('markers', {
      type: 'geojson',
      data: {
        type: 'FeatureCollection',
        features: markerCoordinates.map(coord => ({
          type: 'Feature',
          geometry: {
            type: 'Point',
            coordinates: coord
          }
        }))
      }
    });

    map.addLayer({
      id: 'markers',
      type: 'circle',
      source: 'markers',
      paint: {
        'circle-radius': 3,
        'circle-color': 'red'
      }
    });
  });
}

// Choose one of these options:
// addScaledMarkers();
// addCustomMarkers();
addCircleLayer();

// ... (previous code for fitting bounds)

I've provided three options for creating smaller markers:

  1. Scaled Markers: This uses the built-in scale option of maplibregl.Marker. By setting scale: 0.5, we reduce the marker size to 50% of its original size.

  2. Custom HTML Markers: This creates a small, circular div element for each marker. You can easily adjust the size, color, and shape.

  3. Circle Layer: Instead of using individual markers, this option adds all points as a single circle layer. This is more efficient for rendering many points and allows easy customization of size and appearance.

To use one of these options, uncomment the corresponding function call at the bottom of the script.

The circle layer option (Option 3) is generally the most efficient for rendering a large number of points, as it uses a single layer for all markers instead of creating 1000 separate DOM elements.

Would you like me to explain any of these options in more detail or show you how to further customize them?

human (Sep 28, 2024, 10:54 AM)

give me the full javascript

assistant (Sep 28, 2024, 10:54 AM)

Certainly! I'll provide the full JavaScript code that includes all the options we've discussed for creating smaller markers in San Francisco.

MapLibre GL JS map with 1000 smaller random markers in San Francisco - Full Code

// Function to generate random coordinates within a bounding box
function getRandomCoordinate(minLng, maxLng, minLat, maxLat) {
  const lng = Math.random() * (maxLng - minLng) + minLng;
  const lat = Math.random() * (maxLat - minLat) + minLat;
  return [lng, lat];
}

// San Francisco bounding box (approximate)
const sfBounds = {
  minLng: -122.5155,
  maxLng: -122.3247,
  minLat: 37.7038,
  maxLat: 37.8324
};

// Create the map
const map = new maplibregl.Map({
  style: 'https://tiles.openfreemap.org/styles/liberty',
  center: [-122.4194, 37.7749], // San Francisco coordinates
  zoom: 11,
  container: 'map',
});

// Array to store all marker coordinates
const markerCoordinates = [];

// Generate 1000 random markers
for (let i = 0; i < 1000; i++) {
  const [lng, lat] = getRandomCoordinate(
    sfBounds.minLng,
    sfBounds.maxLng,
    sfBounds.minLat,
    sfBounds.maxLat
  );
  markerCoordinates.push([lng, lat]);
}

// Option 1: Use built-in scaling
function addScaledMarkers() {
  markerCoordinates.forEach(coord => {
    new maplibregl.Marker({ scale: 0.5 }) // Scale down to 50%
      .setLngLat(coord)
      .addTo(map);
  });
}

// Option 2: Custom HTML element
function addCustomMarkers() {
  markerCoordinates.forEach(coord => {
    const el = document.createElement('div');
    el.className = 'custom-marker';
    el.style.width = '10px';
    el.style.height = '10px';
    el.style.borderRadius = '50%';
    el.style.backgroundColor = 'red';

    new maplibregl.Marker(el)
      .setLngLat(coord)
      .addTo(map);
  });
}

// Option 3: Use circle layer instead of markers
function addCircleLayer() {
  map.on('load', () => {
    map.addSource('markers', {
      type: 'geojson',
      data: {
        type: 'FeatureCollection',
        features: markerCoordinates.map(coord => ({
          type: 'Feature',
          geometry: {
            type: 'Point',
            coordinates: coord
          }
        }))
      }
    });

    map.addLayer({
      id: 'markers',
      type: 'circle',
      source: 'markers',
      paint: {
        'circle-radius': 3,
        'circle-color': 'red'
      }
    });
  });
}

// Choose one of these options:
// addScaledMarkers();
// addCustomMarkers();
addCircleLayer();

// Fit the map to the extent of all markers
map.on('load', () => {
  const bounds = markerCoordinates.reduce((bounds, coord) => {
    return bounds.extend(coord);
  }, new maplibregl.LngLatBounds(markerCoordinates[0], markerCoordinates[0]));

  map.fitBounds(bounds, {
    padding: 50 // Add some padding around the markers
  });
});

This full JavaScript code includes:

  1. The function to generate random coordinates within the San Francisco bounding box.
  2. Map initialization with MapLibre GL JS.
  3. Generation of 1000 random coordinates within San Francisco.
  4. Three options for adding smaller markers:
    • Option 1: Scaled markers using the built-in scale property.
    • Option 2: Custom HTML markers created as small, circular div elements.
    • Option 3: A circle layer that renders all points as a single layer (most efficient for large numbers of points).
  5. Code to fit the map bounds to show all markers.

By default, the code uses Option 3 (circle layer) as it's the most efficient for rendering 1000 points. To use one of the other options, you can comment out addCircleLayer(); and uncomment either addScaledMarkers(); or addCustomMarkers();.

To use this code:

  1. Make sure you have the MapLibre GL JS library included in your HTML file.
  2. Create a div element with id="map" in your HTML where the map will be rendered.
  3. Copy this JavaScript into a script tag or a separate .js file that's included in your HTML.

You can further customize the appearance of the markers by adjusting the size, color, or other properties in the respective functions.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment