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 🙏

© 2025 – Pkg Stats / Ryan Hefner

cc-arcgis-map

v1.0.13

Published

Vue 3 component for ArcGIS 3.x maps with full configuration support

Downloads

1,440

Readme

cc-arcgis-map

Vue 3 组件,用于 ArcGIS 3.x 地图的快速集成。支持完整的配置系统、MapUtil工具类以及灵活的扩展机制。

🏢 核心优势

🏢 企业级内网支持 - 开箱即用的内网ArcGIS配置,无需额外设置即可使用 📍 武汉2000坐标系 - 专门优化的本地坐标支持,默认可视范围已配置 🗺️ 50+预配置图层 - 涵盖电子地图、影像、专题图等所有常用图层 🛠️ 43个实用工具方法 - 涵盖绘制、查询、测量等所有地图操作场景

✨ 特性

  • 🗺️ 完整的ArcGIS 3.x支持 - 基于esri-loader,完整支持ArcGIS 3.x API
  • 🎨 零配置使用 - 开箱即用,包含完整的默认配置(50+图层、内网地址等)
  • ⚙️ 灵活的全局配置 - 通过Vue插件一次性配置,所有组件自动使用
  • 🛠️ 强大的MapUtil工具类 - 保留所有原有方法,支持扩展
  • 📦 TypeScript支持 - 完整的类型定义和智能提示
  • 🔧 Composable API - 提供useMap、useMapLayer等组合式API
  • 🚀 性能优化 - 图层缓存、懒加载队列等优化机制

📦 安装

当前版本: v1.0.12

npm install [email protected] esri-loader
# 或
yarn add [email protected] esri-loader

注意: 本组件库专为内网环境优化,默认已配置内网ArcGIS服务地址。如需外网使用,请参考下方配置章节。

🚀 快速开始

1. 全局注册(推荐)

在应用入口文件中注册插件:

// main.ts
import { createApp } from 'vue'
import VueArcgisMap from 'cc-arcgis-map'
import 'cc-arcgis-map/style.css'
import App from './App.vue'

const app = createApp(App)

// 方式1: 直接使用默认配置(包含所有预配置图层和内网设置)
app.use(VueArcgisMap)

// 方式2: 覆盖部分配置
app.use(VueArcgisMap, {
  esriconfig: {
    url: 'http://192.168.8.74:8085/arcgis_js_api/init.js'
  },
  mapExtent: {
    xMin: 725836,
    yMin: 355421,
    xMax: 876728,
    yMax: 423604
  }
})

app.mount('#app')

2. 在组件中使用

<template>
  <!-- 基础使用 -->
  <ArcgisMap
    @map-ready="onMapReady"
    @map-click="onMapClick"
  />

  <!-- 带参数使用 -->
  <ArcgisMap
    :center="[114.3055, 30.5996]"
    :zoom="13"
    :base-layer="'暗黑版电子地图'"
    @map-ready="onMapReady"
  />
</template>

<script setup lang="ts">
import type { MapReadyEvent, MapClickEvent } from 'cc-arcgis-map'

const onMapReady = (event: MapReadyEvent) => {
  const { map, mapUtil } = event

  // 使用MapUtil添加图形
  mapUtil.addPointMark(map, 114.3, 30.5, '/icon.png', { id: '1', name: '标注点' })
  mapUtil.addPolygonGraphic(map, [[
    [114.3, 30.5],
    [114.4, 30.5],
    [114.4, 30.6],
    [114.3, 30.6]
  ]], { id: '2', name: '地块' })
}

const onMapClick = (event: MapClickEvent) => {
  console.log('点击坐标:', event.mapPoint)
}
</script>

🔧 内网环境配置

默认内网配置

本组件库已内置内网环境的 ArcGIS 配置:

// 默认内网配置
{
  esriconfig: {
    url: 'http://192.168.8.74:8085/arcgis_js_api/init.js'
  }
}

修改内网地址

如需修改为其他内网地址:

app.use(VueArcgisMap, {
  esriconfig: {
    url: 'http://your-server:port/arcgis_js_api/init.js'
  }
})

外网环境配置

如需在外网环境使用,配置官方 ArcGIS API:

app.use(VueArcgisMap, {
  esriconfig: {
    url: 'https://js.arcgis.com/3.41/init.js'
  }
})

最佳实践

  1. 内网环境:使用默认配置即可,所有图层已配置内网地址
  2. 图层URL:所有预配置图层默认使用内网地址前缀
  3. 性能优化:内网环境下建议启用本地缓存以提升加载速度

📍 武汉2000坐标系

坐标系范围

默认配置了武汉2000坐标系的可视范围:

// 武汉2000坐标系默认范围
{
  xMin: 725836,
  yMin: 355421,
  xMax: 876728,
  yMax: 423604
}

自定义范围

// 修改可视范围
app.use(VueArcgisMap, {
  mapExtent: {
    xMin: 700000,
    yMin: 350000,
    xMax: 900000,
    yMax: 450000
  }
})

坐标转换示例

// 地理坐标(WGS84)转武汉2000
const wgs84Point = [114.3055, 30.5996]
const wh2000Point = coordinateTransform(wgs84Point, 'WGS84', 'WH2000')

// 在地图上添加点
mapUtil.addPointMark(map, wh2000Point[0], wh2000Point[1], icon, attrs)

🗺️ 预配置图层列表

本组件库内置了50+个常用图层,按类型分为:

电子地图类

  • 暗黑版电子地图 - 适合夜间使用
  • 标准版电子地图 - 日常使用标准样式
  • 影像版电子地图 - 卫星影像底图
  • 注记版电子地图 - 带地名标注

专题地图类

  • 行政区划 - 省、市、县级行政边界
  • 地名地址 - 兴趣点、街道名称
  • 水系分布 - 河流、湖泊、水库
  • 道路网络 - 高速、国道、省道

业务图层类

可根据业务需求动态添加:

// 添加业务图层
addLayerConfig({
  label: '业务图层',
  mapUrl: 'http://your-server/arcgis/rest/services/ServiceName/MapServer',
  mapType: 'dynamic',
  visible: true
})

📖 API文档

组件 Props

| 属性 | 类型 | 默认值 | 说明 | |------|------|--------|------| | center | [number, number] | [114.3055, 30.5996] | 地图中心点 | | zoom | number | 13 | 缩放级别 | | extent | MapExtent | - | 地图范围 | | baseLayer | string \| LayerConfig \| false | '暗黑版电子地图' | 底图配置 | | layers | LayerConfig[] | [] | 额外图层 | | showLoading | boolean | true | 是否显示加载状态 | | esriConfig | Partial<EsriConfig> | - | 自定义ArcGIS配置 |

组件 Events

| 事件名 | 参数 | 说明 | |--------|------|------| | map-ready | { map, geometryEngine, mapUtil } | 地图加载完成 | | map-click | MapClickEvent | 地图点击事件 | | zoom-change | ZoomChangeEvent | 缩放级别变化 | | center-change | CenterChangeEvent | 中心点变化 | | extent-change | ExtentChangeEvent | 范围变化 |

组件方法

通过 ref 可以调用组件的公共方法:

<template>
  <ArcgisMap ref="mapRef" />
</template>

<script setup lang="ts">
const mapRef = ref<InstanceType<typeof ArcgisMap>>()

const clearMap = () => {
  mapRef.value?.clearGraphics()
}

const zoomToExtent = () => {
  mapRef.value?.setExtent({
    xMin: 725836,
    yMin: 355421,
    xMax: 876728,
    yMax: 423604
  })
}
</script>

| 方法 | 说明 | |------|------| | getMap() | 获取地图实例 | | getGeometryEngine() | 获取几何引擎 | | getMapUtil() | 获取MapUtil实例 | | clearGraphics() | 清除所有图形 | | setExtent(extent, fit?) | 设置地图范围 | | zoomToGraphics(graphics, expand?) | 缩放到图形 |

🛠️ MapUtil工具类

MapUtil 提供了43个实用的地图操作方法,完全向后兼容原有代码。

📍 图形绘制类(13个)

点标记

// 添加图片标记
mapUtil.addPointMark(map, x, y, imgPath, attributes)
// 添加圆形标记
mapUtil.addPointRound(map, x, y, rgba, radius, attributes)
// 添加文字标记
mapUtil.addPointFont(map, x, y, text, attributes)
// 添加文本标注
mapUtil.addPointText(map, x, y, text, textColor, attributes)

线图形

// 添加线图形
mapUtil.addLineGraphic(map, paths, attributes)
// 添加渐变线
mapUtil.addLineRound(map, paths, attributes)
// 添加动态线(带流向)
mapUtil.addLineDynamic(map, paths, attributes)

面图形

// 添加面图形
mapUtil.addPolygonGraphic(map, rings, attributes)
// 添加渐变面
mapUtil.addPolygonGradient(map, rings, attributes)
// 添加动态面
mapUtil.addPolygonDynamic(map, rings, attributes)

其他图形

// 添加圆
mapUtil.addCircleGraphic(map, center, radius, attributes)
// 添加环形
mapUtil.addDonutGraphic(map, rings, attributes)
// 添加图片
mapUtil.addImageGraphic(map, extent, imageUrl, attributes)

🗂️ 图层管理类(8个)

// 控制图层显隐
mapUtil.controlLayer(map, layerConfig, visible)
// 添加图层到列表
mapUtil.addMenuLayer(map, url, type, id, alpha)
// 添加WFS图层
mapUtil.addWFSLayer(map, url, layerName)
// 移除WFS图层
mapUtil.removeWFSLayer(map, layerName)
// 创建矢量图层
mapUtil.createVectorLayer(map, layerId)
// 根据名称获取图层
mapUtil.getLayerByName(map, layerName)
// 根据标题获取图层
mapUtil.getLayerByTitle(map, title)
// 获取所有图层信息
mapUtil.getAllLayerInfos(map)

🔍 空间查询类(8个)

// 通用查询
mapUtil.query(url, where, outFields, callback)
// 条件查询
mapUtil.queryByWhere(url, where, outFields, callback)
// 几何查询
mapUtil.queryByGeometry(url, geometry, spatialRelationship, callback)
// 要素查找
mapUtil.findTask(url, searchFields, searchText, callback)
// 要素识别
mapUtil.identinate(url, geometry, tolerance, callback)
// 空间关系查询
mapUtil.spatialQuery(url, geometry, spatialRelationship, callback)
// 获取图层字段
mapUtil.getLayerFields(url, callback)
// 统计分析
mapUtil.getStatistics(url, field, statisticType, callback)

📐 几何操作类(7个)

// 获取几何中心
mapUtil.getGeometryCenter(geometry)
// 获取总范围
mapUtil.getTotalExtent(geometryList, spatialReference)
// 缓冲区分析
mapUtil.geometryBuffer(geometry, distance)
// 相交分析
mapUtil.intersect(geometry1, geometry2)
// 合并分析
mapUtil.union(geometryList)
// 计算面积
mapUtil.getArea(geometry)
// 计算长度
mapUtil.getLength(geometry)

🛠️ 实用工具类(7个)

// 清除所有图形
mapUtil.clearAllGraphic(map)
// 清除指定图形
mapUtil.clearTargetGraphics(map, attributeName, attributeValue)
// 图形闪烁
mapUtil.geometryFlick(map, geometry, attributes, isLoop)
// 开始绘制
mapUtil.startDraw(map, drawType, callback)
// 停止绘制
mapUtil.stopDraw(map)
// 距离测量
mapUtil.measureDistance(map, callback)
// 面积测量
mapUtil.measureArea(map, callback)

扩展方法

// 注册单方法
mapUtil.extend('addHeatMap', function(data, options) {
  // this 指向 mapUtil 实例
  const map = this.getMap()
  // 实现热力图逻辑...
})

// 批量注册
mapUtil.use({
  addCluster(points) {
    // 聚合图实现
  },
  addTrack(coordinates) {
    // 轨迹图实现
  }
})

// 使用扩展方法
mapUtil.addHeatMap(data, options)

🎨 Composables API

useMap - 地图基础操作

import { useMap } from 'cc-arcgis-map'

const { map, setExtent, setCenter, setZoom } = useMap()

setExtent({ xMin: 1, yMin: 2, xMax: 3, yMax: 4 })
setCenter([114, 30], 13)

useMapLayer - 图层管理

import { useMapLayer } from 'cc-arcgis-map'

const { addLayer, removeLayer, toggleLayer } = useMapLayer(map)

addLayer({
  label: '自定义图层',
  mapUrl: 'http://example.com/map',
  mapType: 'dynamic'
})

useMapGraphics - 图形操作

import { useMapGraphics } from 'cc-arcgis-map'

const { addPointMark, addPolygon, clearAll } = useMapGraphics(map)

addPointMark(114, 30, '/icon.png', { id: '1' })
addPolygon([[[114, 30], [115, 30], [115, 31], [114, 31]]], { id: '2' })

useMapQuery - 空间查询

import { useMapQuery } from 'cc-arcgis-map'

const { queryByWhere, spatialQuery } = useMapQuery(map)

queryByWhere(
  'http://example.com/map/MapServer/0',
  "NAME = '武汉'",
  ['*'],
  true,
  (result) => {
    console.log('查询结果:', result)
  }
)

⚙️ 配置系统

默认配置

包内置了完整的默认配置:

  • esriconfig: 内网ArcGIS地址
  • mapExtent: 武汉2000坐标系范围
  • layerConfig: 50+个完整图层配置
  • defaultBaseLayer: '暗黑版电子地图'

覆盖配置

app.use(VueArcgisMap, {
  esriconfig: {
    url: 'http://192.168.8.74:8085/arcgis_js_api/init.js'
  },
  mapExtent: {
    xMin: 725836,
    yMin: 355421,
    xMax: 876728,
    yMax: 423604
  },
  layerConfig: [
    ...getDefaultLayerConfig(), // 保留所有默认图层
    { label: '新图层', mapUrl: '...', mapType: 'dynamic' }
  ]
})

运行时配置

import { addLayerConfig, updateLayerConfig } from 'cc-arcgis-map'

// 添加新图层
addLayerConfig({
  label: '运行时添加的图层',
  mapUrl: 'http://example.com/map',
  mapType: 'dynamic'
})

// 更新现有图层
updateLayerConfig('电子地图', {
  mapUrl: 'http://new-server.com/map'
})

🔄 从现有项目迁移

现有代码

// 旧代码
import { mapUtil } from '@/utils/MapUtil'

// 使用
mapUtil.addPointMark(map, x, y, icon, attrs)

迁移后

// 新代码(完全兼容)
import { mapUtil } from 'cc-arcgis-map'

// mapUtil方法调用完全不变
mapUtil.addPointMark(map, x, y, icon, attrs)

获取配置

如果之前使用了 sysConfig,现在可以用 getGlobalConfig 获取:

import { getGlobalConfig } from 'cc-arcgis-map'

// 获取所有配置
const config = getGlobalConfig()
console.log(config.layerConfig) // 所有图层配置
console.log(config.esriconfig)  // ArcGIS配置

💡 实战示例

基础使用示例

最简单的地图初始化

<template>
  <div class="map-container">
    <ArcgisMap
      @map-ready="onMapReady"
      style="width: 100%; height: 500px;"
    />
  </div>
</template>

<script setup lang="ts">
import { ArcgisMap } from 'cc-arcgis-map'

const onMapReady = (event: MapReadyEvent) => {
  console.log('地图加载完成', event.map)
}
</script>

添加点标记和响应点击

<template>
  <ArcgisMap
    :center="[114.3055, 30.5996]"
    :zoom="13"
    @map-ready="onMapReady"
    @map-click="onMapClick"
  />
</template>

<script setup lang="ts">
import { ref } from 'vue'
import type { MapReadyEvent, MapClickEvent } from 'cc-arcgis-map'

const mapInstance = ref<any>()

const onMapReady = (event: MapReadyEvent) => {
  const { map, mapUtil } = event
  mapInstance.value = map

  // 添加一个标记点
  mapUtil.addPointMark(
    map,
    114.3055,
    30.5996,
    '/location-pin.png',
    { id: 'hq', name: '总部', type: 'important' }
  )
}

const onMapClick = (event: MapClickEvent) => {
  console.log('点击位置:', event.mapPoint)

  // 在点击位置添加临时标记
  if (mapInstance.value) {
    mapUtil.addPointRound(
      mapInstance.value,
      event.mapPoint.x,
      event.mapPoint.y,
      'rgba(255, 0, 0, 0.8)',
      8,
      { temp: true }
    )
  }
}
</script>

高级功能示例

复杂空间查询

<template>
  <div>
    <ArcgisMap ref="mapRef" @map-ready="onMapReady" />
    <div class="toolbar">
      <button @click="queryNearby">查询周边1公里</button>
      <button @click="queryByGeometry">查询选中区域</button>
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref } from 'vue'
import { useMapQuery } from 'cc-arcgis-map'

const mapRef = ref()
const mapInstance = ref()
const { queryByWhere, spatialQuery } = useMapQuery(mapInstance)

const onMapReady = (event: MapReadyEvent) => {
  mapInstance.value = event.map
}

// 查询周边1公里的POI
const queryNearby = () => {
  const center = [114.3055, 30.5996] // 武汉市中心
  const radius = 1000 // 1公里

  // 创建缓冲区
  const buffer = mapUtil.geometryBuffer(
    { x: center[0], y: center[1] },
    radius
  )

  spatialQuery(
    'http://your-server/arcgis/rest/services/POI/MapServer/0',
    buffer,
    'INTERSECT',
    ['*'],
    (result) => {
      console.log('找到', result.features.length, '个POI')

      // 在地图上显示结果
      result.features.forEach(feature => {
        mapUtil.addPointMark(
          mapInstance.value,
          feature.geometry.x,
          feature.geometry.y,
          '/poi-icon.png',
          feature.attributes
        )
      })
    }
  )
}

// 查询用户绘制的区域
const queryByGeometry = () => {
  // 开始绘制多边形
  mapUtil.startDraw(mapInstance.value, 'POLYGON', (geometry) => {
    queryByWhere(
      'http://your-server/arcgis/rest/services/LandUse/MapServer/0',
      `LAND_TYPE = '商业用地'`,
      ['*'],
      true,
      (result) => {
        console.log('商业用地查询结果:', result)
      }
    )
  })
}
</script>

图层动态切换和透明度控制

<template>
  <div>
    <ArcgisMap :base-layer="currentBaseLayer" @map-ready="onMapReady" />
    <div class="layer-control">
      <h3>底图切换</h3>
      <button
        v-for="layer in baseLayers"
        :key="layer.label"
        @click="switchBaseLayer(layer)"
        :class="{ active: currentBaseLayer === layer.label }"
      >
        {{ layer.label }}
      </button>

      <h3>图层控制</h3>
      <div v-for="layer in overlayLayers" :key="layer.id">
        <label>
          <input
            type="checkbox"
            v-model="layer.visible"
            @change="toggleLayer(layer)"
          />
          {{ layer.label }}
        </label>
        <input
          type="range"
          min="0"
          max="100"
          v-model="layer.opacity"
          @input="setLayerOpacity(layer)"
        />
      </div>
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref, reactive } from 'vue'
import { useMapLayer, getGlobalConfig } from 'cc-arcgis-map'

const mapInstance = ref()
const { addLayer, removeLayer, toggleLayer, setOpacity } = useMapLayer(mapInstance)
const config = getGlobalConfig()

const currentBaseLayer = ref('暗黑版电子地图')

const baseLayers = config.layerConfig.filter(layer =>
  layer.label.includes('电子地图') || layer.label.includes('影像')
)

const overlayLayers = reactive([
  {
    id: 'road',
    label: '道路网络',
    visible: true,
    opacity: 100,
    config: config.layerConfig.find(l => l.label === '道路网络')
  },
  {
    id: 'poi',
    label: '兴趣点',
    visible: false,
    opacity: 80,
    config: config.layerConfig.find(l => l.label === '地名地址')
  }
])

const onMapReady = (event: MapReadyEvent) => {
  mapInstance.value = event.map

  // 添加叠加图层
  overlayLayers.forEach(layer => {
    if (layer.visible && layer.config) {
      addLayer(layer.config)
    }
  })
}

const switchBaseLayer = (layer: any) => {
  currentBaseLayer.value = layer.label
  // 组件会自动响应 base-layer prop 的变化
}

const toggleLayer = (layer: any) => {
  if (layer.config) {
    if (layer.visible) {
      addLayer(layer.config)
    } else {
      removeLayer(layer.config)
    }
  }
}

const setLayerOpacity = (layer: any) => {
  if (layer.config) {
    setOpacity(layer.config, layer.opacity / 100)
  }
}
</script>

<style scoped>
.layer-control {
  position: absolute;
  top: 10px;
  right: 10px;
  background: white;
  padding: 15px;
  border-radius: 5px;
  box-shadow: 0 2px 5px rgba(0,0,0,0.2);
}

.active {
  background-color: #007cff;
  color: white;
}
</style>

完整项目示例

综合地图应用(包含工具栏、图层控制、查询、测量)

<template>
  <div class="map-app">
    <!-- 顶部工具栏 -->
    <div class="toolbar">
      <button @click="zoomIn">放大</button>
      <button @click="zoomOut">缩小</button>
      <button @click="toggleMeasure">
        {{ measuring ? '停止测量' : '距离测量' }}
      </button>
      <button @click="clearAll">清除所有</button>
      <button @click="toggleLayerPanel">
        {{ showLayerPanel ? '隐藏图层' : '显示图层' }}
      </button>
    </div>

    <!-- 地图容器 -->
    <div class="map-wrapper">
      <ArcgisMap
        ref="mapRef"
        :center="center"
        :zoom="zoom"
        @map-ready="onMapReady"
        @map-click="onMapClick"
      />

      <!-- 图层面板 -->
      <div v-if="showLayerPanel" class="layer-panel">
        <h3>图层控制</h3>
        <div class="layer-group" v-for="group in layerGroups" :key="group.name">
          <h4>{{ group.name }}</h4>
          <label v-for="layer in group.layers" :key="layer.id">
            <input
              type="checkbox"
              :checked="layer.visible"
              @change="toggleLayerVisibility(layer)"
            />
            {{ layer.label }}
          </label>
        </div>
      </div>

      <!-- 查询结果面板 -->
      <div v-if="queryResults.length > 0" class="result-panel">
        <h3>查询结果 ({{ queryResults.length }})</h3>
        <ul>
          <li v-for="item in queryResults" :key="item.id">
            {{ item.name }} - {{ item.address }}
            <button @click="locateFeature(item)">定位</button>
          </li>
        </ul>
      </div>

      <!-- 坐标显示 -->
      <div class="coord-display">
        坐标: {{ coords.x.toFixed(6) }}, {{ coords.y.toFixed(6) }}
      </div>
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref, reactive, onMounted } from 'vue'
import {
  ArcgisMap,
  useMap,
  useMapLayer,
  useMapGraphics,
  useMapQuery,
  mapUtil,
  getGlobalConfig
} from 'cc-arcgis-map'
import type { MapReadyEvent, MapClickEvent } from 'cc-arcgis-map'

// 响应式数据
const mapRef = ref()
const mapInstance = ref()
const measuring = ref(false)
const showLayerPanel = ref(false)
const queryResults = ref([])
const coords = reactive({ x: 0, y: 0 })
const center = ref([114.3055, 30.5996])
const zoom = ref(13)

// 获取配置
const config = getGlobalConfig()
const { setZoom, zoomToGraphics } = useMap(mapInstance)
const { addLayer, removeLayer, toggleLayer } = useMapLayer(mapInstance)
const { addPointMark, addPolygon, clearAllGraphics } = useMapGraphics(mapInstance)
const { queryByWhere, spatialQuery } = useMapQuery(mapInstance)

// 图层分组
const layerGroups = [
  {
    name: '基础地图',
    layers: [
      { id: 'base-dark', label: '暗黑版', type: 'base', visible: true },
      { id: 'base-standard', label: '标准版', type: 'base', visible: false },
      { id: 'base-image', label: '影像版', type: 'base', visible: false }
    ]
  },
  {
    name: '业务图层',
    layers: [
      { id: 'boundary', label: '行政区划', type: 'overlay', visible: true },
      { id: 'poi', label: '兴趣点', type: 'overlay', visible: false },
      { id: 'traffic', label: '交通路网', type: 'overlay', visible: true }
    ]
  }
]

// 地图就绪
const onMapReady = (event: MapReadyEvent) => {
  mapInstance.value = event.map

  // 添加默认图层
  layerGroups.forEach(group => {
    group.layers.forEach(layer => {
      if (layer.visible) {
        const layerConfig = config.layerConfig.find(l =>
          l.label.includes(layer.label)
        )
        if (layerConfig) {
          addLayer(layerConfig)
        }
      }
    })
  })

  // 添加欢迎标记
  mapUtil.addPointMark(
    event.map,
    center.value[0],
    center.value[1],
    '/welcome.png',
    { name: '欢迎使用cc-arcgis-map', type: 'welcome' }
  )
}

// 地图点击
const onMapClick = (event: MapClickEvent) => {
  coords.x = event.mapPoint.x
  coords.y = event.mapPoint.y

  if (measuring.value) {
    // 测量模式:添加测量点
    mapUtil.addPointRound(
      event.map,
      event.mapPoint.x,
      event.mapPoint.y,
      'rgba(255, 0, 0, 0.8)',
      5,
      { measure: true }
    )
  }
}

// 工具栏功能
const zoomIn = () => {
  setZoom(zoom.value + 1)
}

const zoomOut = () => {
  setZoom(zoom.value - 1)
}

const toggleMeasure = () => {
  measuring.value = !measuring.value
  if (measuring.value) {
    mapUtil.measureDistance(mapInstance.value, (result) => {
      console.log('测量结果:', result.distance, '米')
    })
  } else {
    mapUtil.stopDraw(mapInstance.value)
  }
}

const clearAll = () => {
  clearAllGraphics()
  queryResults.value = []
}

const toggleLayerPanel = () => {
  showLayerPanel.value = !showLayerPanel.value
}

// 图层控制
const toggleLayerVisibility = (layer: any) => {
  layer.visible = !layer.visible
  const layerConfig = config.layerConfig.find(l =>
    l.label.includes(layer.label)
  )
  if (layerConfig) {
    if (layer.visible) {
      addLayer(layerConfig)
    } else {
      removeLayer(layerConfig)
    }
  }
}

// 查询功能示例
const searchPOI = (keyword: string) => {
  queryByWhere(
    'http://your-server/arcgis/rest/services/POI/MapServer/0',
    `NAME LIKE '%${keyword}%'`,
    ['*'],
    true,
    (result) => {
      queryResults.value = result.features.map(feature => ({
        id: feature.attributes.OBJECTID,
        name: feature.attributes.NAME,
        address: feature.attributes.ADDRESS,
        geometry: feature.geometry
      }))

      // 在地图上显示结果
      result.features.forEach(feature => {
        addPointMark(
          feature.geometry.x,
          feature.geometry.y,
          '/search-result.png',
          feature.attributes
        )
      })
    }
  )
}

// 定位要素
const locateFeature = (item: any) => {
  // 缩放到要素
  zoomToGraphics([{
    geometry: { x: item.x, y: item.y }
  }])

  // 添加闪烁效果
  mapUtil.geometryFlick(
    mapInstance.value,
    { x: item.x, y: item.y },
    { name: item.name },
    false
  )
}

// 初始化
onMounted(() => {
  // 可以在这里添加初始化逻辑
})
</script>

<style scoped>
.map-app {
  width: 100%;
  height: 100vh;
  display: flex;
  flex-direction: column;
}

.toolbar {
  height: 50px;
  background: #333;
  display: flex;
  align-items: center;
  padding: 0 20px;
  gap: 10px;
}

.toolbar button {
  padding: 8px 16px;
  background: #007cff;
  color: white;
  border: none;
  border-radius: 4px;
  cursor: pointer;
}

.toolbar button:hover {
  background: #0056b3;
}

.map-wrapper {
  flex: 1;
  position: relative;
}

.layer-panel, .result-panel {
  position: absolute;
  top: 10px;
  right: 10px;
  background: white;
  padding: 15px;
  border-radius: 5px;
  box-shadow: 0 2px 5px rgba(0,0,0,0.2);
  max-height: 400px;
  overflow-y: auto;
  z-index: 1000;
}

.result-panel {
  top: auto;
  bottom: 10px;
  max-height: 200px;
}

.layer-group {
  margin-bottom: 15px;
}

.coord-display {
  position: absolute;
  bottom: 10px;
  left: 10px;
  background: rgba(0, 0, 0, 0.7);
  color: white;
  padding: 5px 10px;
  border-radius: 3px;
  font-size: 12px;
}
</style>

📝 TypeScript支持

完整支持TypeScript类型定义:

import type {
  ArcgisMapProps,
  ArcgisMapEmits,
  MapReadyEvent,
  MapClickEvent,
  LayerConfig,
  EsriConfig
} from 'cc-arcgis-map'

const props = defineProps<ArcgisMapProps>()
const emit = defineEmits<ArcgisMapEmits>()

const onReady = (event: MapReadyEvent) => {
  const { map, mapUtil } = event
}

🤝 贡献

欢迎提交 Issue 和 Pull Request!

📄 许可证

MIT

🙏 致谢

  • 基于 Vue 3 Composition API
  • 使用 esri-loader 加载 ArcGIS API
  • 参考 ArcGIS JavaScript API 3.x