npm package: @gis_victory/gismap
Description: GISMap 是一个基于适配器模式设计的通用地图组件库，支持多种地图引擎（如 Mapbox GL、MapLibre 等），提供统一的 API 接口和丰富的功能模块。
Latest version: 2.0.12

# GISMap - 通用地图组件库

GISMap 是一个基于适配器模式设计的通用地图组件库，支持多种地图引擎（如 Mapbox GL、MapLibre 等），提供统一的 API 接口和丰富的功能模块。

## 特性

- **多引擎支持**：通过适配器模式，支持不同的地图引擎
- **丰富的管理器**：提供图层、标记、雷达、地形、绘制、测量等多种管理器
- **响应式设计**：基于 Vue 3 的 Composition API，提供响应式的地图状态管理
- **模块化架构**：清晰的代码结构，易于扩展和维护
- **TypeScript 支持**：完整的类型定义，提供良好的开发体验

## 安装

```bash
# 使用 npm
npm install gismap

# 使用 yarn
yarn add gismap

# 使用 pnpm
pnpm add gismap
```

## 基本使用

### 1. 基础地图组件

```vue
<template>
  <div style="width: 100vw; height: 100vh;">
    <GisMapContainer
      :center="[120, 30]"
      :zoom="10"
      :access-token="'your-mapbox-access-token'"
      :init-icons="initIcons"
    >
      <!-- 可以在这里添加地图控件 -->
    </GisMapContainer>
  </div>
</template>

<script setup lang="ts">
import { GisMapContainer } from 'gismap';

// 初始化图标配置
const initIcons = [
  {
    name: 'marker-icon',
    url: 'https://example.com/marker.png'
  },
  {
    name: 'icon-2',
    url: 'https://example.com/icon2.png'
  }
];
</script>
```

### 2. 使用组合式函数

```vue
<template>
  <div style="width: 100vw; height: 100vh;">
    <GisMapContainer @ready="handleMapReady">
      <button @click="addMarker" style="position: absolute; top: 10px; left: 10px; z-index: 1000;">
        添加标记
      </button>
    </GisMapContainer>
  </div>
</template>

<script setup lang="ts">
import { GisMapContainer } from 'gismap';
import { useMap, useMarker, useLayer } from 'gismap';

const { map, layers, markers } = useMap();

const handleMapReady = () => {
  console.log('地图就绪');
};

const addMarker = () => {
  // 添加标记
  markers.value.add({
    id: `marker-${Date.now()}`,
    position: [120, 30],
    options: {
      draggable: true
    }
  });
};
</script>
```

### 3. 使用 MapSwitch 组件

```vue
<template>
  <div style="width: 100vw; height: 100vh; position: relative;">
    <!-- 地图容器 -->
    <GisMapContainer
      :center="[120, 30]"
      :zoom="10"
      :access-token="'your-mapbox-access-token'"
    >
      <!-- 地图切换组件 -->
      <template #top-right>
        <GisMapSwitch :data="mapSwitchData" />
      </template>
    </GisMapContainer>
  </div>
</template>

<script setup lang="ts">
import { ref } from 'vue';
import { GisMapContainer, GisMapSwitch } from 'gismap';

// 地图切换数据
const mapSwitchData = ref({
  // 底图图层
  layers: [
    {
      name: 'tdt-vec',
      label: '矢量底图',
      checked: true,
      iconName: 'Picture'
    },
    {
      name: 'tdt-img',
      label: '影像底图',
      checked: false,
      iconName: 'Camera'
    },
    {
      name: 'custom-layer',
      label: '自定义底图',
      checked: false,
      iconName: 'Map'
    }
  ],
  // 叠加图层
  extensions: [
    {
      name: 'tdt-cia',
      label: '天地图注记',
      checked: true
    },
    {
      name: 'terrain',
      label: '地形',
      checked: false
    },
    {
      name: 'custom-extension',
      label: '自定义叠加层',
      checked: false
    }
  ]
});
</script>
```

## 核心功能

### 1. 图层管理

```typescript
import { useLayers } from 'gismap';

const { addLayer, removeLayer, layers } = useLayers();

// 添加 GeoJSON 图层
const layer = addLayer({
  id: 'points',
  type: 'circle',
  source: {
    type: 'geojson',
    data: {
      type: 'FeatureCollection',
      features: [
        {
          type: 'Feature',
          geometry: {
            type: 'Point',
            coordinates: [120, 30]
          }
        }
      ]
    }
  },
  paint: {
    'circle-radius': 10,
    'circle-color': '#ff0000'
  }
});

// 移除图层
removeLayer(layer.id);
```

### 2. 标记管理

```typescript
import { useMarkers } from 'gismap';

const { add, remove, getAll } = useMarkers();

// 添加标记
const marker = add({
  id: 'marker-1',
  position: [120, 30],
  options: {
    draggable: true,
    anchor: 'bottom'
  }
});

// 移除标记
remove('marker-1');

// 获取所有标记
const allMarkers = getAll();
```

### 3. 绘制功能

```typescript
import { useDraw } from 'gismap';

const { startDraw, stopDraw, isDrawing, selected } = useDraw();

// 开始绘制多边形
startDraw('polygon', (type, geoJson, wkt, feature) => {
  console.log('绘制完成:', type, geoJson, wkt);
});

// 停止绘制
stopDraw();
```

### 4. 测量功能

```typescript
import { useMeasure } from 'gismap';

const { startMeasure, stopMeasure, isMeasuring, results } = useMeasure();

// 开始测量距离
startMeasure('line', (result) => {
  console.log('测量结果:', result.value, result.unit);
});

// 停止测量
stopMeasure();
```

### 5. 雷达图层

```typescript
import { useMap } from 'gismap';

const { radarManager } = useMap();

// 添加雷达
radarManager.value?.add({
  center: [120, 30],
  radius: 500,
  sectorVisible: true,
  sectorAngle: 45
});

// 开始扫描
radarManager.value?.startScan();

// 停止扫描
radarManager.value?.stopScan();

// 移除雷达
radarManager.value?.remove();
```

### 6. 地形管理

```typescript
import { useMap } from 'gismap';

const { terrainManager } = useMap();

// 添加地形
terrainManager.value?.add({
  source: {
    tiles: ['https://example.com/terrain/{z}/{x}/{y}.png'],
    minzoom: 0,
    maxzoom: 14
  },
  layer: {
    exaggeration: 1.5
  }
});

// 添加山体阴影
terrainManager.value?.addHillshade();

// 移除地形
terrainManager.value?.remove();
```

### 7. 图标管理

#### 最佳实践：在地图初始化完成后立即加载图标

为了确保地图能够正确读取图标，应该在地图初始化完成后立即加载图标。推荐使用 `useMapReady` 组合式函数来监听地图就绪事件：

```typescript
import { useMapReady } from 'gismap';

// 在地图就绪后立即加载图标
useMapReady(async (context) => {
  try {
    // 批量加载图标
    await context.iconManager?.load([
      {
        name: 'marker-icon',
        url: 'https://example.com/marker.png'
      },
      {
        name: 'icon-2',
        url: 'https://example.com/icon2.png'
      }
    ], {
      batchSize: 5, // 每批加载5个图标
      batchInterval: 100, // 每批间隔100毫秒
      onProgress: (loaded, total) => {
        console.log(`加载进度: ${loaded}/${total}`);
      }
    });
    
    console.log('图标加载完成');
    
    // 图标加载完成后，再添加使用图标的图层
    addIconLayer(context);
  } catch (error) {
    console.error('图标加载失败:', error);
  }
});

// 添加使用图标的图层
function addIconLayer(context) {
  if (context?.layerManager) {
    context.layerManager.addLayer({
      id: 'icon-layer',
      type: 'symbol',
      source: {
        type: 'geojson',
        data: {
          type: 'FeatureCollection',
          features: [
            {
              type: 'Feature',
              geometry: {
                type: 'Point',
                coordinates: [120, 30]
              }
            }
          ]
        }
      },
      layout: {
        'icon-image': 'marker-icon', // 使用已加载的图标
        'icon-size': 1.5
      }
    });
  }
}
```

#### 其他用法

```typescript
import { useMap } from 'gismap';

const { iconManager } = useMap();

// 批量加载图标（基本用法）
iconManager.value?.load([
  {
    name: 'marker-icon',
    url: 'https://example.com/marker.png'
  },
  {
    name: 'icon-2',
    url: 'https://example.com/icon2.png'
  }
]).then(() => {
  console.log('图标加载完成');
});

// 加载单个图标
iconManager.value?.loadOne({
  name: 'single-icon',
  url: 'https://example.com/single.png'
}).then(() => {
  console.log('单个图标加载完成');
});

// 检查图标是否已加载
if (iconManager.value?.hasIcon('marker-icon')) {
  console.log('图标已加载');
}

// 移除图标
iconManager.value?.removeIcon('marker-icon');

// 清除所有图标记录
iconManager.value?.clear();
```

## 高级功能

### 1. 自定义适配器

您可以通过实现 `MapAdapter` 或 `VectorTileAdapter` 接口来创建自定义适配器，支持其他地图引擎。

```typescript
import type { MapAdapter, MapInitOptions, MapViewState } from 'gismap';

export class MyCustomAdapter implements MapAdapter {
  private map: any = null;

  async initialize(container: HTMLElement, options: MapInitOptions): Promise<void> {
    // 初始化您的地图引擎
    // this.map = new MyMapEngine(container, options);
  }

  dispose(): void {
    // 清理资源
  }

  getMap(): any {
    return this.map;
  }

  // 实现其他必要的方法...
}

// 使用自定义适配器
<GisMapContainer :adapter="new MyCustomAdapter()" />
```

### 2. 扩展管理器

您可以通过继承现有管理器或创建新的管理器来扩展功能。

```typescript
import { VectorTileAdapter } from 'gismap';

export class CustomManager {
  private adapter: VectorTileAdapter;

  constructor(adapter: VectorTileAdapter) {
    this.adapter = adapter;
  }

  // 实现您的自定义功能
  doSomething() {
    // 使用 this.adapter 操作地图
  }
}
```

### 3. 事件系统

GISMap 提供了完善的事件系统，您可以监听各种地图事件。

```typescript
import { useMapEvent } from 'gismap';

// 监听地图点击事件
useMapEvent('click', (event) => {
  console.log('地图点击:', event.coordinates);
});

// 监听视图变化事件
useMapEvent('viewChange', (view) => {
  console.log('视图变化:', view);
});
```

## 项目结构

```
src/
├── adapters/          # 地图适配器
│   ├── mapbox/        # Mapbox GL 适配器
│   ├── types.ts       # 适配器类型定义
│   └── index.ts       # 适配器统一导出
├── components/        # Vue 组件
│   ├── MapContainer/  # 地图容器组件
│   └── ...
├── composables/       # 组合式函数
│   ├── useMap.ts      # 地图核心组合式函数
│   ├── useLayer.ts    # 图层组合式函数
│   └── ...
├── core/              # 核心功能
│   ├── event.ts       # 事件系统
│   ├── StateStore.ts  # 状态管理
│   └── ...
├── domain/            # 领域服务
│   ├── LayerService.ts    # 图层服务
│   ├── MarkerService.ts   # 标记服务
│   └── ...
├── manager/           # 管理器
│   ├── mapbox/        # Mapbox 专用管理器
│   ├── layer/         # 图层相关
│   ├── LayerManager.ts    # 图层管理器
│   ├── RadarManager.ts    # 雷达管理器
│   └── ...
├── services/          # 服务
│   ├── MapContext.ts  # 地图上下文
│   └── ...
└── index.ts           # 主入口
```

## 浏览器兼容性

- Chrome/Edge >= 88
- Firefox >= 85
- Safari >= 14

## 许可证

MIT

## 贡献

欢迎提交 Issue 和 Pull Request！

## 联系方式

- 项目地址：https://github.com/your-username/gismap
- 问题反馈：https://github.com/your-username/gismap/issues