npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

maptalks-spider

v1.0.7

Published

A spider expansion manager for maptalks - handles overlapping markers with spiral expansion

Readme

maptalks-spider

处理地图上同坐标重叠点的展开/收起动画。当多个标记落在同一位置时,显示一个堆叠标记;点击后螺旋散开显示全部,并绘制中心点到展开点的连线。

安装

npm install maptalks maptalks-spider

如需使用 PointLayer(配合 maptalks-gl),需额外安装:

npm install maptalks-gl

快速开始

浏览器引入

<div id="map" style="width: 100%; height: 100vh;"></div>

<script src="https://unpkg.com/maptalks/dist/maptalks.min.js"></script>
<script src="https://unpkg.com/maptalks-spider/dist/maptalks-spider.js"></script>
<script>
  const map = new maptalks.Map('map', {
    center: [121.507, 31.247],
    zoom: 16
  });

  const layer = new maptalks.VectorLayer('markers').addTo(map);

  const spider = new maptalks.SpiderManager(layer, {
    spiderRadius: 40,
    spiderLineColor: '#4a8af4',
    spiderMode: 'circle',
    spiderSpread: 1.2,
    stackSymbol: {
      markerType: 'ellipse',
      markerWidth: 36,
      markerHeight: 36,
      markerFill: '#FF5722',
      markerLineColor: '#fff',
      markerLineWidth: 2
    },
    onSpiderMarkerClick(item, marker) {
      marker.setInfoWindow({
        content: `<b>${item.name}</b><br>${item.desc || ''}`,
        autoOpenOn: false
      });
      marker.openInfoWindow();
    }
  });

  spider.setData([
    { coord: [121.507, 31.247], id: 1, name: '星巴克', desc: '咖啡' },
    { coord: [121.507, 31.247], id: 2, name: '瑞幸', desc: '咖啡' },
    { coord: [121.507, 31.247], id: 3, name: '喜茶', desc: '茶饮' }
  ]);
</script>

模块化引入

import * as maptalks from 'maptalks';
import { SpiderManager } from 'maptalks-spider';

const map = new maptalks.Map('map', {
  center: [121.507, 31.247],
  zoom: 16
});

const layer = new maptalks.VectorLayer('markers').addTo(map);

const spider = new SpiderManager(layer, {
  spiderRadius: 40,
  spiderLineColor: '#4a8af4',
  spiderMode: 'grid',
  spiderSpread: 1.5,
  onSpiderMarkerClick(item, marker) {
    console.log('点击了:', item.name);
  }
});

spider.setData([
  { coord: [121.507, 31.247], id: 1, name: 'Point A' },
  { coord: [121.507, 31.247], id: 2, name: 'Point B' }
]);

PointLayer 支持

PointLayer 只能存储点类型,展开后的连线是 LineString,SpiderManager 会自动创建内部 VectorLayer Overlay 来承载。

const pointLayer = new maptalks.PointLayer('markers').addTo(map);

const spider = new SpiderManager(pointLayer, {
  spiderRadius: 40,
  spiderLineColor: '#2196F3'
});

spider.setData([...]);

// 访问内部 overlay(如需自定义样式)
spider.spiderOverlay;

数据格式

{
  coord: [121.507, 31.247],   // 必须:坐标 [经度, 纬度]
  id: 'store_001',            // 推荐:唯一标识,用于查询和删除
  name: '店铺名称',           // 业务字段,会保留在 item 中
  symbol: {                   // 可选:展开后单个标记的样式
    markerType: 'ellipse',
    markerWidth: 24,
    markerHeight: 24,
    markerFill: '#4CAF50'
  }
}

| 字段 | 类型 | 必填 | 说明 | |------|------|------|------| | coord | [number, number] | 是 | [经度, 纬度] | | id | string \| number | 推荐 | 唯一标识,用于 API 调用 | | symbol | object | 否 | 展开后标记的样式,覆盖全局默认 | | 其他 | any | 否 | 业务数据会保留在 item 对象中 |

配置项

const spider = new SpiderManager(layer, {
  spiderRadius: 60,           // 展开半径(像素)
  spiderLineColor: '#DE3333', // 连线颜色
  spiderLineWidth: 2,        // 连线宽度
  spiderLineOpacity: 0.6,    // 连线透明度
  spiderMode: 'spiral',      // 散开方式
  spiderSpread: 1,           // 散开间距倍数
  animationDuration: 400,    // 动画时长(毫秒)
  markerSymbol: null,        // 展开后标记的默认样式
  stackSymbol: null,         // 堆叠状态标记的样式
  onSpiderMarkerClick: null  // 点击展开标记的回调
});

| 配置 | 默认值 | 说明 | |------|--------|------| | spiderRadius | 60 | 螺旋展开半径 | | spiderLineColor | #DE3333 | 中心点到标记的连线颜色 | | spiderLineWidth | 2 | 连线宽度 | | spiderLineOpacity | 0.6 | 连线透明度 | | spiderMode | spiral | 散开方式,见下方模式列表 | | spiderSpread | 1 | 散开间距倍数,值越大点之间越稀疏 | | animationDuration | 400 | 展开/收起动画时长(毫秒) | | markerSymbol | null | 展开后标记的默认 symbol | | stackSymbol | null | 堆叠状态标记的 symbol | | onSpiderMarkerClick | null | 点击展开标记时触发 (item, marker, event) => {} |

散开方式 (spiderMode)

| 模式 | 说明 | |------|------| | spiral | 黄金角度螺旋散开(默认) | | circle | 圆形排列,所有标记均匀分布在圆周上 | | grid | 网格排列,近似正方形网格布局 | | line | 水平直线排列,从中心向两侧扩散 | | fan | 扇形展开,120度范围内均匀分布 | | diamond | 菱形环绕,从内向外层层扩散 |

// 构造函数设置默认模式
const spider = new SpiderManager(layer, {
  spiderMode: 'circle',
  spiderSpread: 1.5,
  animationDuration: 600
});

// 单独展开时指定
spider.spiderfy([lng, lat], { spiderMode: 'fan', spread: 2, animationDuration: 800 });

// 动态修改
spider.setOptions({ spiderMode: 'grid', spiderSpread: 1.2, animationDuration: 500 });

API

增删数据

// 添加单个
spider.addMarker([lng, lat], { id: 1, name: 'A' });

// 批量设置(清空之前的数据)
spider.setData([
  { coord: [lng, lat], id: 1, name: 'A' },
  { coord: [lng, lat], id: 2, name: 'B' }
]);

// 删除单个
spider.removeMarker(id);

// 清空全部
spider.clear();

// 销毁(清空并移除内部 overlay)
spider.dispose();

展开/收起

// 展开指定坐标
spider.spiderfy([121.507, 31.247]);
spider.spiderfy([121.507, 31.247], { animation: false }); // 无动画

// 收起当前展开
spider.unspiderfy();
spider.unspiderfy({ animation: false }); // 无动画

状态查询

spider.getActiveCoord();      // 返回当前展开的坐标,无则返回 null
spider.getGroupCount([lng, lat]); // 返回该坐标下的标记数量
spider.isStacked([lng, lat]);    // 是否存在多个重叠
spider.isExpanded();              // 是否有任何展开
spider.isExpanded([lng, lat]);    // 指定坐标是否展开

标记查询

// 根据 id 获取原始数据
const item = spider.getMarkerById('store_001');

// 根据 id 获取可见的 marker 几何体
// 展开时返回展开后的 marker,未展开时返回堆叠 marker
const marker = spider.getGeometryById('store_001');

配置更新

spider.setOptions({ spiderRadius: 80 });
const opts = spider.getOptions();

示例

本地调试示例:

npm install
npm run build-dev
# 启动静态服务器后访问 debug/ 目录
  • debug/spider-marker.html — VectorLayer 基础示例
  • debug/spider-pointlayer.html — PointLayer + maptalks-gl 示例

常见问题

Q: 报 LineString can't be added to PointLayer 错误

PointLayer 只能存点,展开后的连线是 LineString。请确保使用的是支持 PointLayer 的 SpiderManager 版本,并正确引入了 maptalks-spider。

Q: 修改源码后 demo 没变化

debug 页面加载的是 dist/maptalks-spider.js,修改源码后需重新构建:

npm run build-dev

Q: 坐标精度如何处理

坐标按 lng.toFixed(6) + ',' + lat.toFixed(6) 分组。如需调整精度,需在传入前自行处理坐标。

License

MIT