# game-map
**Repository Path**: xkpro/game-map
## Basic Information
- **Project Name**: game-map
- **Description**: 游戏地图
- **Primary Language**: Unknown
- **License**: Not specified
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 0
- **Created**: 2026-05-02
- **Last Updated**: 2026-05-08
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# GameMap 互动地图通用工具
GameMap 是一个基于 Leaflet 的互动地图通用工具库,支持瓦片地图和单图模式,提供标注管理、区域绘制、分类筛选、搜索定位等完整功能。
## 项目结构
```txt
map/
├── gamemap.js # 打包后的独立库文件(直接引入即可)
├── src/ # 模块化源码(开发用)
│ ├── index.js # 主入口,GameMap 类
│ ├── config.js # 默认配置与合并工具
│ ├── constants.js # 调色板、图标映射、缩放级别
│ ├── data-builder.js # 数据转换模块
│ ├── map-core.js # 地图核心初始化
│ ├── markers.js # 标注管理模块
│ ├── regions.js # 区域管理模块
│ ├── sidebar.js # 侧边栏 UI 模块
│ ├── edit-mode.js # 编辑模式模块
│ └── utils.js # 工具函数
├── data/ # 数据文件目录
│ ├── point-series.js # 分类系列数据
│ ├── points.js # 标注点数据
│ └── senses.js # 区域数据
├── tiles/ # 瓦片图片目录
├── index.html # 使用示例
├── style.css # 样式文件
├── app.js # 旧版单文件(已弃用)
└── data.js # 旧版示例数据(已弃用)
```
---
## 快速开始
### 1. 引入依赖
在 HTML 中引入 Leaflet、Font Awesome 和 GameMap:
```html
```
### 2. 准备 HTML 容器
```html
```
### 3. 创建地图实例
```javascript
var map = GameMap.create('map', {
mode: 'tiles',
mapWidth: 8192,
mapHeight: 8192,
tiles: {
url: './tiles/{z}/{x}/{y}.png',
tileSize: 256,
maxZoom: 6,
paddedWidth: 8192,
paddedHeight: 8192,
},
}, {
series: mySeriesData,
points: myPointsData,
senses: mySensesData,
});
```
---
## 配置参数
### 完整配置项
```javascript
{
mode: 'tiles', // 'tiles' 瓦片模式 | 'image' 单图模式
mapWidth: 8192, // 地图宽度(像素)
mapHeight: 8192, // 地图高度(像素)
image: { // image 模式配置
url: './map.jpg', // 底图文件路径
},
tiles: { // tiles 模式配置
url: './tiles/{z}/{x}/{y}.png', // 瓦片路径模板
tileSize: 256, // 瓦片尺寸
maxZoom: 6, // 最大缩放级别
paddedWidth: 8192, // 填充后宽度
paddedHeight: 8192, // 填充后高度
},
view: { // 视图配置
minZoom: 3, // 最小缩放
maxZoom: 6, // 最大缩放
defaultZoom: 1, // 默认缩放
zoomSnap: 0.25, // 缩放步进
zoomDelta: 0.5, // 缩放增量
wheelPxPerZoomLevel: 50, // 鼠标滚轮灵敏度
maxBoundsViscosity: 1.0, // 边界弹性
},
marker: { // 标注配置
flyToZoom: 4, // 飞行定位缩放级别
flyToDuration: 1.0, // 飞行动画时长(秒)
popupDelay: 600, // 弹窗延迟(毫秒)
},
sidebar: { // 侧边栏配置
position: 'right', // 'left' | 'right'
},
title: '互动游戏地图', // 地图标题
}
```
### image 模式
适用于小尺寸地图,直接加载单张图片:
```javascript
GameMap.create('map', {
mode: 'image',
mapWidth: 5824,
mapHeight: 3264,
image: { url: './map.jpg' },
view: { minZoom: -1, maxZoom: 4, defaultZoom: 0 },
}, userData);
```
### tiles 模式
适用于大尺寸地图,使用瓦片金字塔加载:
```javascript
GameMap.create('map', {
mode: 'tiles',
mapWidth: 8192,
mapHeight: 8192,
tiles: {
url: './tiles/{z}/{x}/{y}.png',
tileSize: 256,
maxZoom: 5,
paddedWidth: 8192,
paddedHeight: 8192,
},
}, userData);
```
**关键约束**:`paddedWidth` 必须等于 `tileSize × 2^maxZoom`
### 切割瓦片
```bash
python tile_cutter.py map.png --pad-power2 --max-zoom 5 --output ./tiles
```
---
## 数据格式
GameMap 支持两种数据传入方式:
### 方式一:原始数据格式(自动转换)
传入 `series`、`points`、`senses` 原始数据,GameMap 会自动转换为内部格式:
```javascript
GameMap.create('map', config, {
series: [
{
seriesId: '1',
seriesName: '传送点',
defaultShow: true,
children: [
{ seriesId: '2', seriesName: '界碑', defaultShow: true },
{ seriesId: '30', seriesName: '天涯客', defaultShow: false },
],
},
],
points: [
{
pointId: '20101',
name: '竹隐居',
x: -2388.72,
y: -2779.33,
series: ['2'],
layer: '0',
},
],
senses: [
{
name: '清河',
x: -1297.01,
y: -2989.88,
children: [
{ name: '百草野', x: -1918.72, y: -2808.29, children: [...] },
],
},
],
});
```
#### series 数据结构
| 字段 | 类型 | 说明 |
| -- | -- | -- |
| seriesId | string | 分类组 ID |
| seriesName | string | 分类组名称 |
| defaultShow | boolean | 是否默认显示 |
| children | array | 子分类列表 |
| children[].seriesId | string | 子分类 ID |
| children[].seriesName | string | 子分类名称 |
| children[].posterUrl | string | 海报图片 URL(可选) |
| children[].defaultShow | boolean | 子分类是否默认显示 |
#### points 数据结构
| 字段 | 类型 | 说明 |
| -- | -- | -- |
| pointId | string | 点位唯一 ID |
| name | string | 点位名称 |
| x | number | X 坐标 |
| y | number | Y 坐标 |
| series | array | 所属分类 ID 列表 |
| layer | string | 层级('0' 为默认层) |
| icon | string | 自定义图标 URL(可选) |
#### senses 数据结构
区域数据为树形结构,每个有 children 的节点会自动生成椭圆区域:
| 字段 | 类型 | 说明 |
| -- | -- | -- |
| name | string | 区域名称 |
| x | number | 中心 X 坐标 |
| y | number | 中心 Y 坐标 |
| children | array | 子区域列表 |
### 方式二:直接传入内部格式
跳过自动转换,直接传入处理好的数据:
```javascript
GameMap.create('map', config, {
categoryGroups: [
{
id: 'landmark',
label: '地标',
icon: 'fa-landmark',
children: ['city', 'village'],
defaultShow: true,
},
],
categories: {
city: {
label: '城镇',
icon: 'fa-city',
color: '#3b82f6',
bgColor: 'rgba(59, 130, 246, 0.15)',
group: 'landmark',
},
},
locations: [
{ id: 1, name: '星辰王都', type: 'city', x: 2900, y: 1630, description: '王都描述' },
],
regions: [
{ name: '清河', coords: [[lat1, lng1], [lat2, lng2], ...], color: '#3b82f6' },
],
});
```
#### categoryGroups 结构
| 字段 | 类型 | 说明 |
| -- | -- | -- |
| id | string | 分组 ID |
| label | string | 分组显示名 |
| icon | string | Font Awesome 图标类名 |
| children | array | 子分类 ID 列表 |
| defaultShow | boolean | 是否默认显示 |
#### categories 结构
| 字段 | 类型 | 说明 |
| -- | -- | -- |
| label | string | 分类显示名 |
| icon | string | Font Awesome 图标类名 |
| color | string | 主题色(HEX) |
| bgColor | string | 背景色(RGBA) |
| group | string | 所属分组 ID |
| defaultShow | boolean | 是否默认显示 |
#### locations 结构
| 字段 | 类型 | 说明 |
| -- | -- | -- |
| id | number | 唯一 ID |
| name | string | 地点名称 |
| type | string | 分类 ID |
| x | number | X 坐标 |
| y | number | Y 坐标 |
| description | string | 描述(可选) |
| stats | object | 统计信息(可选) |
| zoom | number | 自定义缩放级别(可选) |
#### regions 结构
| 字段 | 类型 | 说明 |
| -- | -- | -- |
| name | string | 区域名称 |
| coords | array | 多边形坐标 [[lat, lng], ...] |
| color | string | 区域颜色 |
---
## API 接口
### 创建实例
```javascript
var map = new GameMap(containerId, config, data);
var map = GameMap.create(containerId, config, data); // 等价
```
| 参数 | 类型 | 说明 |
| -- | -- | -- |
| containerId | string | 地图容器 DOM ID(通常为 'map') |
| config | object | 配置参数(与默认配置合并) |
| data | object | 地图数据 |
### 数据获取
| 方法 | 返回值 | 说明 |
| -- | -- | -- |
| `getMap()` | L.Map | Leaflet 地图实例 |
| `getConfig()` | object | 当前配置 |
| `getCategories()` | object | 分类定义 |
| `getCategoryGroups()` | array | 分类组列表 |
| `getLocations()` | array | 原始标注列表 |
| `getRegions()` | array | 区域列表 |
| `getCustomMarkers()` | array | 用户自定义标注 |
| `getCustomRegions()` | array | 用户自定义区域 |
### 导航与交互
```javascript
map.flyTo(locationId); // 飞行定位到指定地点
map.search('关键词'); // 搜索地点
map.filterByType('city', true); // 按类型筛选(true=显示,false=隐藏)
map.showAll(); // 显示所有分类
map.hideAll(); // 隐藏所有分类
```
### 编辑模式
```javascript
map.enterEditMode(); // 进入编辑模式
map.exitEditMode(); // 退出编辑模式
```
编辑模式下:
- **点击地图**:添加标注点(弹出编辑表单)
- **绘制区域**:点击工具栏"区域"按钮,依次点击添加顶点,双击完成
- **撤销顶点**:Ctrl+Z 撤销最后一个顶点
- **取消绘制**:按 Esc 取消当前绘制
### 编程式添加数据
```javascript
map.addLocation({
name: '新标注',
x: 1000,
y: 2000,
type: 'city',
description: '描述文字',
});
map.addRegion({
name: '新区域',
coords: [[lat1, lng1], [lat2, lng2], [lat3, lng3]],
color: '#3b82f6',
});
map.clearCustomData(); // 清除所有自定义数据
```
### 销毁实例
```javascript
map.destroy(); // 销毁地图,释放资源
```
---
## 图标映射
GameMap 内置了常用分类的 Font Awesome 图标映射(`SERIES_ICONS`),未映射的分类默认使用 `fa-location-dot`。
自定义图标映射可在创建实例后通过修改 `categories` 实现:
```javascript
var map = GameMap.create('map', config, {
categories: {
myType: {
label: '自定义类型',
icon: 'fa-star', // Font Awesome 图标
color: '#f59e0b',
bgColor: 'rgba(245, 158, 11, 0.15)',
group: 'custom',
},
},
locations: [
{ id: 1, name: '测试点', type: 'myType', x: 1000, y: 1000 },
],
});
```
---
## 缩放级别映射
不同类型的标注在飞行定位时会自动使用不同的缩放级别,由 `TYPE_ZOOM_TILES` 和 `TYPE_ZOOM_IMAGE` 控制。
也可为单个标注指定自定义缩放级别:
```javascript
{ id: 1, name: '大城堡', type: 'city', x: 2900, y: 1630, zoom: 3 }
```
---
## 自定义数据持久化
用户在编辑模式下添加的标注和区域会自动保存到 `localStorage`(键名 `map_custom_data`),刷新页面后自动恢复。
---
## 模块化开发
如需二次开发或扩展功能,可使用 `src/` 目录下的 ES 模块源码:
```javascript
import { GameMap } from './src/index.js';
const map = new GameMap('map', config, data);
```
**注意**:ES 模块需要通过 HTTP 服务器访问,不能直接用 `file://` 协议打开。可使用以下方式启动本地服务器:
```bash
# Python
python -m http.server 8080
# Node.js
npx serve .
```
### 模块说明
| 模块 | 说明 |
|------|------|
| `config.js` | 默认配置定义与深度合并工具函数 |
| `constants.js` | 调色板、图标映射表、缩放级别映射表 |
| `utils.js` | 工具函数(颜色转换、Toast 通知、HTML 生成、样式注入) |
| `data-builder.js` | 将 series/points/senses 原始数据转换为内部格式 |
| `map-core.js` | Leaflet 地图初始化、CRS 构建、图层配置 |
| `markers.js` | 标注管理器(空间索引、创建、可见性、弹窗) |
| `regions.js` | 区域管理器(多边形添加、样式、交互) |
| `sidebar.js` | 侧边栏管理器(搜索、筛选、列表渲染、导航) |
| `edit-mode.js` | 编辑模式管理器(添加标注、绘制区域、自定义数据持久化) |
| `index.js` | 主入口,GameMap 类,组合所有模块 |
---
## 完整示例
### 瓦片地图 + 原始数据
```html
我的游戏地图
```
### 单图模式 + 直接数据
```html
```
### 编程式操作
```javascript
var map = GameMap.create('map', config, data);
map.flyTo(1); // 飞行到 ID 为 1 的地点
map.search('王都'); // 搜索"王都"
map.filterByType('city', false); // 隐藏城镇类型
map.showAll(); // 显示全部
map.enterEditMode(); // 进入编辑模式
map.addLocation({ // 编程式添加标注
name: '秘密洞穴',
x: 1500,
y: 800,
type: 'dungeon',
description: '隐藏的宝藏',
});
map.exitEditMode(); // 退出编辑模式
var leafletMap = map.getMap(); // 获取 Leaflet 实例进行高级操作
```
---
## 版本历史
- **v2.0.0** - 模块化重构,支持两种数据格式,完善 API 接口
- **v1.0.0** - 初始版本,单文件架构