mcpField
P
preview-leaflet

preview-leaflet

github.com/veelenga数据与数据库972 次安装2 周前更新
代码仓库

关于 preview-leaflet

用于将 JavaScript 代码或地图文件生成 Leaflet 交互式地图预览的技能,适合制作地理可视化的 Agent。运行脚本会生成 HTML,并可自动在浏览器中打开。

主要功能

  1. 01预览 Leaflet 交互式地图
  2. 02显示标记、路线和形状
  3. 03支持多种地图图层
  4. 04提供弹出框和悬停提示
  5. 05生成 HTML 并在浏览器打开

适用场景

  1. 01在地图上标注地点
  2. 02可视化点位之间的路线
  3. 03展示服务范围或区域

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/veelenga/preview-skills --skill preview-leaflet

安装后在 Claude Code 中输入/preview-leaflet确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

config.sh
run.sh
lib/
browser-utils.sh
content-utils.sh
html-generator.sh
templates/
user-code-template.html
templates/scripts/
common-ui.js
leaflet-renderer.js
utils.js
templates/styles/
common.css
layout.css
leaflet.css

详细介绍

预览 Leaflet 技能

使用 Leaflet 库交互式查看地理数据、标记、路线和自定义叠加层。

Agent 用法

当用户要求创建地图可视化时,编写 Leaflet 代码并将其通过管道传递给脚本。使用 Bash 工具执行此技能的 run.sh 脚本:

# Pipe Leaflet code
cat route.js | ./run.sh

# Or from a file
./run.sh city-map.leaflet

脚本会处理所有 HTML 生成工作,并自动在浏览器中打开结果。请勿手动打开文件,以免产生重复标签页。

用法

# Preview a Leaflet map file
/preview-leaflet city-map.leaflet

# Or use .map extension
/preview-leaflet route.map

# Pipe Leaflet code (preferred for temporary content)
cat route.js | /preview-leaflet
echo "const map = L.map('map').setView([51.505, -0.09], 13);" | /preview-leaflet

最佳实践: 对于临时或生成的地图,优先使用管道传递,而不是创建临时文件。这样可以避免文件系统杂乱,并且内容会自动清理。

选项

脚本使用合理的默认设置,同时支持以下标志以提高灵活性:

  • -o, --output PATH - 自定义输出路径
  • --no-browser - 跳过浏览器,仅输出文件路径

功能

  • 交互式地图,支持平移和缩放
  • 位置标记和弹出窗口
  • 使用折线绘制路线和路径
  • 使用多边形和圆形绘制形状和区域
  • 多个瓦片图层(OpenStreetMap、CartoDB 等)
  • 悬停时显示工具提示
  • 适配边界,显示所有点
  • 重置视图按钮
  • 代码查看器切换
  • 响应式设计,可适应窗口大小

何时使用此技能

当用户希望进行以下操作时,请使用此技能:

  • 在地图上可视化地理数据
  • 使用标记标注位置
  • 绘制点之间的路线
  • 显示服务区域或地域
  • 创建交互式位置可视化

Leaflet 代码要求

代码应:

  1. 使用 L.map('map').setView([lat, lng], zoom) 初始化地图
  2. 添加瓦片图层(提供地图图像)
  3. 添加标记、路径或其他要素

执行环境

代码运行时具备:

  • 可用作 L 的 Leaflet v1.9.4
  • 尺寸已设置且在 DOM 中就绪的地图容器 #map

完整示例 - 带标记的简单地图

// Initialize map centered on London
const map = L.map('map').setView([51.505, -0.09], 13);

// Add OpenStreetMap tiles (REQUIRED - map is blank without this)
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
  attribution: '© OpenStreetMap contributors',
  maxZoom: 18,
}).addTo(map);

// Add a marker
L.marker([51.505, -0.09]).addTo(map).bindPopup('Hello World!').openPopup();

完整示例 - 包含多个点的路线

// Initialize map
const map = L.map('map').setView([40.7128, -74.006], 12);

// Add tiles (REQUIRED)
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
  attribution: '© OpenStreetMap contributors',
  maxZoom: 18,
}).addTo(map);

// Define route points
const route = [
  [40.7128, -74.006], // New York
  [40.758, -73.9855], // Times Square
  [40.7614, -73.9776], // Central Park
];

// Draw route
L.polyline(route, {
  color: 'red',
  weight: 3,
}).addTo(map);

// Add markers
route.forEach((point, i) => {
  L.marker(point)
    .addTo(map)
    .bindPopup(`Stop ${i + 1}`);
});

// Fit map to show all points
map.fitBounds(L.latLngBounds(route), { padding: [50, 50] });

常见模式

标记
// Simple marker
L.marker([51.5, -0.09]).addTo(map);

// With popup
L.marker([51.5, -0.09]).addTo(map).bindPopup('Location name');

// Circle marker (fixed pixel size)
L.circleMarker([51.5, -0.09], {
  radius: 8,
  fillColor: '#3498db',
  color: 'white',
  weight: 2,
  fillOpacity: 0.9,
}).addTo(map);
线条和形状
// Polyline (route/path)
L.polyline(
  [
    [51.5, -0.09],
    [51.51, -0.08],
    [51.52, -0.07],
  ],
  {
    color: 'red',
    weight: 3,
  }
).addTo(map);

// Polygon (area)
L.polygon(
  [
    [51.5, -0.09],
    [51.51, -0.08],
    [51.52, -0.09],
  ],
  {
    color: 'blue',
    fillOpacity: 0.5,
  }
).addTo(map);

// Circle (fixed radius in meters)
L.circle([51.5, -0.09], {
  radius: 500, // meters
  color: 'red',
  fillOpacity: 0.5,
}).addTo(map);
弹出窗口和工具提示
// HTML in popup
marker.bindPopup(`
  <div>
    <h3>Location Name</h3>
    <p>Description here</p>
  </div>
`);

// Tooltip (shows on hover)
marker.bindTooltip('Tooltip text', {
  permanent: false,
  direction: 'top',
});

// Permanent tooltip (always visible)
marker.bindTooltip('Always visible', {
  permanent: true,
  direction: 'right',
});
视图控制
// Set view (instant)
map.setView([51.5, -0.09], 13);

// Fly to (animated)
map.flyTo([51.5, -0.09], 13, {
  duration: 2, // seconds
});

// Fit bounds to show all features
const bounds = L.latLngBounds([
  [51.49, -0.1],
  [51.51, -0.08],
]);
map.fitBounds(bounds, {
  padding: [50, 50],
});

瓦片图层(地图样式)

OpenStreetMap(免费,默认)
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
  attribution: '© OpenStreetMap contributors',
  maxZoom: 18,
}).addTo(map);
CartoDB Light(简洁、极简)
L.tileLayer('https://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}.png', {
  attribution: '© OpenStreetMap, © CartoDB',
  maxZoom: 18,
}).addTo(map);
CartoDB Dark
L.tileLayer('https://{s}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}.png', {
  attribution: '© OpenStreetMap, © CartoDB',
  maxZoom: 18,
}).addTo(map);

完整示例 - 多个位置

// Initialize map
const map = L.map('map').setView([37.7749, -122.4194], 10);

// Add tiles
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
  attribution: '© OpenStreetMap contributors',
}).addTo(map);

// Locations data
const locations = [
  { name: 'San Francisco', coords: [37.7749, -122.4194], type: 'city' },
  { name: 'Oakland', coords: [37.8044, -122.2712], type: 'city' },
  { name: 'Berkeley', coords: [37.8715, -122.273], type: 'city' },
];

// Add markers
locations.forEach((loc) => {
  const color = loc.type === 'city' ? 'blue' : 'red';

  L.circleMarker(loc.coords, {
    radius: 8,
    fillColor: color,
    color: 'white',
    weight: 2,
    fillOpacity: 0.8,
  })
    .addTo(map)
    .bindPopup(`<strong>${loc.name}</strong><br/>Type: ${loc.type}`);
});

// Fit map to show all locations
const allCoords = locations.map((loc) => loc.coords);
map.fitBounds(L.latLngBounds(allCoords), { padding: [50, 50] });

坐标格式

Leaflet 使用 [latitude, longitude] 格式:

  • 纬度:-90 到 90(从南到北)
  • 经度:-180 到 180(从西到东)

示例:

  • 纽约:[40.7128, -74.0060]
  • 伦敦:[51.5074, -0.1278]
  • 东京:[35.6762, 139.6503]
  • 悉尼:[-33.8688, 151.2093]

常见错误: 将坐标顺序颠倒为 [lng, lat]——始终使用 `[lat, lng]!

内置功能

  • 平移/缩放 - 单击并拖动以平移,滚动以缩放
  • 缩放按钮 - 左上角的 +/- 控件
  • 重置视图 - 恢复初始视图的按钮
  • 代码查看器 - 切换显示/隐藏源代码
  • 响应式 - 随窗口自动调整大小

缩放级别

  • 1:世界视图
  • 5:大陆
  • 10:城市
  • 15:街道
  • 18:建筑物

最佳实践

  1. 始终添加瓦片图层 - 否则地图将为空白
  2. 使用合适的缩放级别 - 1(世界)到 18(街道级别)
  3. 多点地图使用 fitBounds() - 显示所有要素
  4. 将数据嵌入代码 - 直接包含坐标
  5. 确认坐标顺序 - 使用 [lat, lng],而不是 [lng, lat]

故障排除

地图显示为空白/灰色
  • 确认已使用 .addTo(map) 添加瓦片图层
  • 检查坐标是否有效([lat, lng] 格式)
  • 确认网络连接正常(瓦片从 CDN 加载)
  • 检查浏览器控制台中是否有瓦片 404 错误
标记未显示
  • 检查坐标格式:[latitude, longitude]
  • 确认已对标记调用 .addTo(map)
  • 确认坐标位于当前视图范围内
  • 尝试使用 fitBounds() 查看所有标记
瓦片无法加载
  • 检查互联网连接
  • 确认瓦片 URL 正确
  • 查看浏览器控制台中是否有 404 错误
  • 尝试使用其他瓦片提供方
显示的位置不正确
  • 确认坐标正确
  • 检查坐标顺序(先纬度,后经度)
  • 确保缩放级别合适

技术细节

文件要求
  • 文件扩展名:.leaflet
  • 最大大小:10MB(可配置)
  • 有效的 JavaScript 代码
  • 自包含(不含外部数据文件)
浏览器兼容性
  • 现代浏览器(Chrome、Firefox、Safari、Edge)
  • 需要启用 JavaScript
  • 加载瓦片需要互联网连接
  • 依赖 CDN:Leaflet v1.9.4

输出

该技能会生成一个独立的 HTML 文件,路径为:

.preview-skills/leaflet/{filename}.html

开发

该技能可独立运行,并包含所有依赖项:

  • 共享库打包在 lib/ 中
  • 模板打包在 templates/ 中
  • 外部 CDN 依赖项:Leaflet v1.9.4

修改该技能:

  1. 编辑 config.sh 进行配置
  2. 编辑 templates/scripts/leaflet-renderer.js 调整行为
  3. 编辑 templates/styles/leaflet.css 调整样式
  4. 运行 run.sh 测试更改

了解更多

评论

支持 Markdown