← 返回 Skills 市场
🔌

Mapbox Store Locator Patterns

作者 Mapbox · GitHub ↗ · v1.0.0 · MIT-0
cross-platform ✓ 安全检测通过
105
总下载
0
收藏
0
当前安装
1
版本数
在 OpenClaw 中安装
/install mapbox-store-locator-patterns
功能描述
Common patterns for building store locators, restaurant finders, and location-based search applications with Mapbox. Covers marker display, filtering, distan...
使用说明 (SKILL.md)

Store Locator Patterns Skill

Comprehensive patterns for building store locators, restaurant finders, and location-based search applications with Mapbox GL JS. Covers marker display, filtering, distance calculation, interactive lists, and directions integration.

When to Use This Skill

Use this skill when building applications that:

  • Display multiple locations on a map (stores, restaurants, offices, etc.)
  • Allow users to filter or search locations
  • Calculate distances from user location
  • Provide interactive lists synced with map markers
  • Show location details in popups or side panels
  • Integrate directions to selected locations

Dependencies

Required:

  • Mapbox GL JS v3.x
  • @turf/turf - For spatial calculations (distance, area, etc.)

Installation:

npm install mapbox-gl @turf/turf

Core Architecture

Pattern Overview

A typical store locator consists of:

  1. Map Display - Shows all locations as markers
  2. Location Data - GeoJSON with store/location information
  3. Interactive List - Side panel listing all locations
  4. Filtering - Search, category filters, distance filters
  5. Detail View - Popup or panel with location details
  6. User Location - Geolocation for distance calculation. For the blue dot location indicator, use the built-in mapboxgl.GeolocateControl — simpler than custom markers.
  7. Directions - Route to selected location (optional)

Data Structure

GeoJSON format for locations:

{
  "type": "FeatureCollection",
  "features": [
    {
      "type": "Feature",
      "geometry": {
        "type": "Point",
        "coordinates": [-77.034084, 38.909671]
      },
      "properties": {
        "id": "store-001",
        "name": "Downtown Store",
        "address": "123 Main St, Washington, DC 20001",
        "phone": "(202) 555-0123",
        "hours": "Mon-Sat: 9am-9pm, Sun: 10am-6pm",
        "category": "retail",
        "website": "https://example.com/downtown"
      }
    }
  ]
}

Key properties:

  • id - Unique identifier for each location
  • name - Display name
  • address - Full address for display and geocoding
  • coordinates - [longitude, latitude] format
  • category - For filtering (retail, restaurant, office, etc.)
  • Custom properties as needed (hours, phone, website, etc.)

Basic Store Locator Implementation

Step 1: Initialize Map and Data

import mapboxgl from 'mapbox-gl';
import 'mapbox-gl/dist/mapbox-gl.css';

mapboxgl.accessToken = 'YOUR_MAPBOX_ACCESS_TOKEN';

// Store locations data
const stores = {
  type: 'FeatureCollection',
  features: [
    {
      type: 'Feature',
      geometry: {
        type: 'Point',
        coordinates: [-77.034084, 38.909671]
      },
      properties: {
        id: 'store-001',
        name: 'Downtown Store',
        address: '123 Main St, Washington, DC 20001',
        phone: '(202) 555-0123',
        category: 'retail'
      }
    }
    // ... more stores
  ]
};

const map = new mapboxgl.Map({
  container: 'map',
  style: 'mapbox://styles/mapbox/standard',
  center: [-77.034084, 38.909671],
  zoom: 11
});

Step 2: Add Markers to Map

Marker strategy by location count:

Count Strategy Reason
Fewer than 100 HTML Markers Full DOM/CSS control; DOM node count is manageable
100–1,000 Symbol Layer (default) Renders on the GPU via WebGL — one \x3Ccanvas>, zero per-point DOM elements
More than 1,000 Clustering Reduces visual clutter at large scale

HTML Markers create one DOM element per point. Beyond ~100 locations the browser spends too much time on layout/paint. Symbol layers bypass the DOM entirely — the GPU draws all points in a single WebGL draw call.

Symbol Layer implementation (best for 100–1,000 locations). For HTML Markers (fewer than 100) or Clustering (more than 1,000), see references/markers.md.

map.on('load', () => {
  // Add store data as source
  map.addSource('stores', {
    type: 'geojson',
    data: stores
  });

  // Add custom marker image
  map.loadImage('/marker-icon.png', (error, image) => {
    if (error) throw error;
    map.addImage('custom-marker', image);

    // Add symbol layer
    map.addLayer({
      id: 'stores-layer',
      type: 'symbol',
      source: 'stores',
      layout: {
        'icon-image': 'custom-marker',
        'icon-size': 0.8,
        'icon-allow-overlap': true,
        'text-field': ['get', 'name'],
        'text-font': ['Open Sans Bold', 'Arial Unicode MS Bold'],
        'text-offset': [0, 1.5],
        'text-anchor': 'top',
        'text-size': 12
      }
    });
  });

  // Handle marker clicks using Interactions API (recommended)
  map.addInteraction('store-click', {
    type: 'click',
    target: { layerId: 'stores-layer' },
    handler: (e) => {
      const store = e.feature;
      flyToStore(store);
      createPopup(store);
    }
  });

  // Or using traditional event listener:
  // map.on('click', 'stores-layer', (e) => {
  //   const store = e.features[0];
  //   flyToStore(store);
  //   createPopup(store);
  // });

  // Change cursor on hover
  map.on('mouseenter', 'stores-layer', () => {
    map.getCanvas().style.cursor = 'pointer';
  });

  map.on('mouseleave', 'stores-layer', () => {
    map.getCanvas().style.cursor = '';
  });
});

Step 3: Build Interactive Location List

function buildLocationList(stores) {
  const listingContainer = document.getElementById('listings');

  stores.features.forEach((store, index) => {
    const listing = listingContainer.appendChild(document.createElement('div'));
    listing.id = `listing-${store.properties.id}`;
    listing.className = 'listing';

    const link = listing.appendChild(document.createElement('a'));
    link.href = '#';
    link.className = 'title';
    link.id = `link-${store.properties.id}`;
    link.innerHTML = store.properties.name;

    const details = listing.appendChild(document.createElement('div'));
    details.innerHTML = `
      \x3Cp>${store.properties.address}\x3C/p>
      \x3Cp>${store.properties.phone || ''}\x3C/p>
    `;

    // Handle listing click
    link.addEventListener('click', (e) => {
      e.preventDefault();
      flyToStore(store);
      createPopup(store);
      highlightListing(store.properties.id);
    });
  });
}

function flyToStore(store) {
  map.flyTo({
    center: store.geometry.coordinates,
    zoom: 15,
    duration: 1000
  });
}

function createPopup(store) {
  const popups = document.getElementsByClassName('mapboxgl-popup');
  // Remove existing popups
  if (popups[0]) popups[0].remove();

  new mapboxgl.Popup({ closeOnClick: true })
    .setLngLat(store.geometry.coordinates)
    .setHTML(
      `\x3Ch3>${store.properties.name}\x3C/h3>
       \x3Cp>${store.properties.address}\x3C/p>
       \x3Cp>${store.properties.phone}\x3C/p>
       ${store.properties.website ? `\x3Ca href="${store.properties.website}" target="_blank">Visit Website\x3C/a>` : ''}`
    )
    .addTo(map);
}

// IMPORTANT: highlightListing MUST include scrollIntoView — without it,
// selecting a marker on the map won't scroll the sidebar to the listing.
function highlightListing(id) {
  // Remove existing highlights
  const activeItem = document.getElementsByClassName('active');
  if (activeItem[0]) {
    activeItem[0].classList.remove('active');
  }

  // Add highlight to selected listing
  const listing = document.getElementById(`listing-${id}`);
  listing.classList.add('active');

  // Scroll the selected listing into view (critical UX requirement)
  listing.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
}

// Build the list on load
map.on('load', () => {
  buildLocationList(stores);
});

Reference Files

Load these references for additional patterns as needed:

Reference File Contents
HTML Markers & Clustering references/markers.md HTML Markers (\x3C 100 locations), Clustering (> 1000 locations)
Search & Filter references/search-filter.md Text search, category filter
Geolocation & Directions references/geolocation-directions.md User location, distance calculation, route directions
Styling & Layout references/styling-layout.md Full HTML/CSS layout, custom marker CSS
Performance & A11y references/optimization-a11y.md Debounced search, data management, error handling, accessibility
Variations & React references/variations-react.md Mobile-first, fullscreen, map-only, React implementation

Resources

安全使用建议
This skill is a coherent recipe for building Mapbox-based store locators. Before using it: (1) obtain a Mapbox access token and avoid embedding it in public client bundles—prefer a server-side proxy for sensitive requests or token-scoped usage; (2) note the examples use navigator.geolocation, which requires explicit user permission and has privacy implications—only request location when needed and explain why; (3) examples fetch directions using the Mapbox Directions API with the access token in the URL—consider server-side calls to avoid exposing the token and to manage rate limits/billing; (4) the SKILL.md recommends npm packages (mapbox-gl, @turf/turf) which you should vet and install yourself; and (5) if any example endpoints (e.g., /api/stores) are present in your app, ensure they are trusted and properly secured. If you need the skill to store or use secrets automatically, ask the author to declare required env vars and a secure install mechanism.
功能分析
Type: OpenClaw Skill Name: mapbox-store-locator-patterns Version: 1.0.0 The skill bundle provides legitimate architectural patterns and code samples for building Mapbox-based store locators. It correctly identifies performance thresholds for different marker strategies and utilizes standard browser APIs (navigator.geolocation) and official Mapbox endpoints for its features. No evidence of malicious intent, data exfiltration, or harmful prompt injection was found across the documentation or reference files.
能力评估
Purpose & Capability
The name/description match the actual content: maps, markers, filtering, distance, geolocation, and directions. Required libraries mentioned (@turf/turf, mapbox-gl) are appropriate for these tasks and nothing unrelated is requested.
Instruction Scope
The SKILL.md stays within the stated purpose (map display, filtering, distance, directions). It instructs use of navigator.geolocation (user device location) and Mapbox APIs (requiring an access token) which are expected for a store-locator but are sensitive: the skill shows examples that would access the user's location and call Mapbox Directions API from client code. There are no instructions to read unrelated system files or exfiltrate data, but consumers should be aware of the privacy implications of using navigator.geolocation and embedding API tokens in client-side code.
Install Mechanism
This is instruction-only with no install spec or downloaded code. The SKILL.md recommends installing mapbox-gl and @turf/turf via npm — that is standard and proportional. Nothing is downloaded from arbitrary URLs or written to disk by the skill itself.
Credentials
The skill examples require a Mapbox access token (mapboxgl.accessToken) and use client-side geolocation, but the skill metadata declares no required environment variables. This is not harmful but is a minor mismatch: users must still supply a Mapbox token and be careful not to expose it in public client builds. No unrelated credentials or config paths are requested.
Persistence & Privilege
always:false and no install spec mean the skill does not request permanent presence or elevated privileges. It does not attempt to modify other skills or system settings.
如何使用
  1. 确保已安装 OpenClaw(本地或 Docker 部署)
  2. 在对话框中输入安装命令:/install mapbox-store-locator-patterns
  3. 安装完成后,直接呼叫该 Skill 的名称或使用 /mapbox-store-locator-patterns 触发
  4. 根据 Skill 的参数说明提供必要输入,即可获得结构化输出
版本历史
v1.0.0
Initial release of mapbox-store-locator-patterns. - Provides comprehensive patterns and examples for building store locators and location-based search apps using Mapbox GL JS. - Covers marker strategies, filtering, distance calculation, and interactive lists. - Includes code snippets for adding maps, markers (HTML, symbol layers, clustering), and interactive location panels. - Recommends using `@turf/turf` for spatial calculations. - Details GeoJSON structure and best practices for data handling and UI interactions.
元数据
Slug mapbox-store-locator-patterns
版本 1.0.0
许可证 MIT-0
累计安装 0
当前安装数 0
历史版本数 1
常见问题

Mapbox Store Locator Patterns 是什么?

Common patterns for building store locators, restaurant finders, and location-based search applications with Mapbox. Covers marker display, filtering, distan... 它是一个面向 Claude Code / OpenClaw 的 AI Agent Skill 插件,目前累计下载 105 次。

如何安装 Mapbox Store Locator Patterns?

在 OpenClaw 或 Claude Code 对话框中运行命令「/install mapbox-store-locator-patterns」即可一键安装,无需额外配置。

Mapbox Store Locator Patterns 是免费的吗?

是的,Mapbox Store Locator Patterns 完全免费,采用 MIT-0 许可证,可自由下载、安装和使用。

Mapbox Store Locator Patterns 支持哪些平台?

Mapbox Store Locator Patterns 跨平台运行,可在任意部署了 OpenClaw / Claude Code 的环境中使用(cross-platform)。

谁开发了 Mapbox Store Locator Patterns?

由 Mapbox(@mapbox)开发并维护,当前版本 v1.0.0。

💬 留言讨论