什么是GeoScene Maps
GeoScene Maps是一套功能強大的Web地圖開發平臺,它基于現代Web技術構建,為開發者提供了豐富的地圖服務和開發工具。與其他地圖API相比,GeoScene Maps具有以下特點:
核心優勢
- 全面的地圖服務:支持2D/3D地圖、多種底圖類型
- 高性能渲染:基于WebGL的高效渲染引擎
- 豐富的API:完整的地圖操作、空間分析功能
- 跨平臺支持:支持桌面端和移動端
- 靈活的樣式:可自定義地圖樣式和符號
適用場景
- 位置服務應用
- 物流追蹤系統
- 智慧城市平臺
- 地理信息系統(GIS)
- 實時監控系統
環境準備與安裝
1. 前置要求
在開始之前,確保您的開發環境滿足以下要求:
# Node.js版本要求
Node.js >= 14.0.0
npm >= 6.0.0# 或者使用yarn
yarn >= 1.22.0
2. 創建Vue項目
# 使用Vue CLI創建項目
npm install -g @vue/cli
vue create geoscene-map-demo# 或使用Vite創建項目(推薦)
npm create vue@latest geoscene-map-demo
cd geoscene-map-demo
npm install
3. 安裝GeoScene Maps SDK
# 安裝GeoScene Maps核心包
npm install @geoscene/core# 如果需要額外的功能模塊
npm install @geoscene/map-components
npm install @geoscene/calcite-components
創建第一個地圖
1. 基礎地圖組件
首先,讓我們創建一個基礎的地圖組件:
<!-- src/components/MapContainer.vue -->
<template><div class="map-container"><div ref="mapDiv" class="map-view"id="map-view"></div></div>
</template><script setup>
import { ref, onMounted, onUnmounted } from 'vue'
import Map from '@geoscene/core/Map.js'
import MapView from '@geoscene/core/views/MapView.js'
import TileLayer from '@geoscene/core/layers/TileLayer.js'// 模板引用
const mapDiv = ref(null)// 地圖實例
let map = null
let view = null// 初始化地圖
const initializeMap = async () => {try {// 創建地圖實例map = new Map({basemap: 'streets-navigation-vector' // 使用內置底圖})// 創建地圖視圖view = new MapView({container: mapDiv.value,map: map,center: [116.397, 39.909], // 北京天安門坐標zoom: 13})// 等待視圖加載完成await view.when()console.log('地圖初始化完成')} catch (error) {console.error('地圖初始化失敗:', error)}
}// 組件掛載時初始化地圖
onMounted(() => {initializeMap()
})// 組件卸載時清理資源
onUnmounted(() => {if (view) {view.destroy()view = null}map = null
})// 暴露地圖實例供父組件使用
defineExpose({getMap: () => map,getView: () => view
})
</script><style scoped>
.map-container {width: 100%;height: 100%;position: relative;
}.map-view {width: 100%;height: 100%;
}
</style>
2. 使用自定義底圖
如果需要使用天地圖等國內地圖服務
// src/utils/mapConfig.js
export const TIANDITU_CONFIG = {key: '您的天地圖API密鑰', // 需要到天地圖官網申請baseUrl: 'https://t{subDomain}.tianditu.gov.cn'
}export const MAP_TYPES = {SATELLITE: 'satellite', // 衛星圖VECTOR: 'vector', // 矢量圖TERRAIN: 'terrain' // 地形圖
}
// 創建天地圖底圖的函數
import WebTileLayer from '@geoscene/core/layers/WebTileLayer.js'
import Basemap from '@geoscene/core/Basemap.js'
import { TIANDITU_CONFIG } from '@/utils/mapConfig.js'const createTiandituBasemap = (mapType = 'vector') => {let layerType = ''let annotationType = ''switch (mapType) {case 'satellite':layerType = 'img_w'annotationType = 'cia_w'breakcase 'terrain':layerType = 'ter_w'annotationType = 'cta_w'breakdefault: // vectorlayerType = 'vec_w'annotationType = 'cva_w'}return new Basemap({baseLayers: [// 底圖層new WebTileLayer({urlTemplate: `${TIANDITU_CONFIG.baseUrl}/${layerType}/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=${layerType.split('_')[0]}&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILEMATRIX={level}&TILEROW={row}&TILECOL={col}&tk=${TIANDITU_CONFIG.key}`,subDomains: ['0', '1', '2', '3'],copyright: '? 天地圖'}),// 標注層new WebTileLayer({urlTemplate: `${TIANDITU_CONFIG.baseUrl}/${annotationType}/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=${annotationType.split('_')[0]}&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILEMATRIX={level}&TILEROW={row}&TILECOL={col}&tk=${TIANDITU_CONFIG.key}`,subDomains: ['0', '1', '2', '3'],copyright: '? 天地圖'})]})
}
地圖基礎操作
1. 地圖導航控制
// 添加地圖導航控件
import Home from '@geoscene/core/widgets/Home.js'
import Zoom from '@geoscene/core/widgets/Zoom.js'
import Compass from '@geoscene/core/widgets/Compass.js'const addMapControls = (view) => {// 添加縮放控件const zoomWidget = new Zoom({view: view})view.ui.add(zoomWidget, 'top-left')// 添加指南針控件const compassWidget = new Compass({view: view})view.ui.add(compassWidget, 'top-left')// 添加主頁按鈕const homeWidget = new Home({view: view})view.ui.add(homeWidget, 'top-left')
}
2. 地圖視圖操作
// 地圖操作工具函數
export const mapOperations = {// 跳轉到指定位置goTo: async (view, target, options = {}) => {try {await view.goTo(target, {duration: options.duration || 1000,easing: options.easing || 'ease-in-out'})} catch (error) {console.error('地圖跳轉失敗:', error)}},// 設置地圖中心點setCenter: (view, longitude, latitude, zoom = null) => {view.center = [longitude, latitude]if (zoom !== null) {view.zoom = zoom}},// 獲取當前地圖范圍getExtent: (view) => {return view.extent},// 設置地圖范圍setExtent: async (view, extent) => {try {await view.goTo(extent)} catch (error) {console.error('設置地圖范圍失敗:', error)}}
}
3. 地圖事件處理
// 地圖事件監聽
const setupMapEvents = (view) => {// 點擊事件view.on('click', (event) => {console.log('地圖被點擊:', event.mapPoint)const { longitude, latitude } = event.mapPointconsole.log(`坐標: ${longitude}, ${latitude}`)})// 雙擊事件view.on('double-click', (event) => {console.log('地圖被雙擊:', event.mapPoint)// 阻止默認的縮放行為event.stopPropagation()})// 鼠標移動事件view.on('pointer-move', (event) => {// 獲取鼠標位置的地理坐標const point = view.toMap(event)if (point) {// 可以在這里更新坐標顯示updateCoordinateDisplay(point.longitude, point.latitude)}})// 地圖范圍變化事件view.watch('extent', (newExtent) => {console.log('地圖范圍發生變化:', newExtent)})// 縮放級別變化事件view.watch('zoom', (newZoom) => {console.log('縮放級別變化:', newZoom)})
}
添加圖層和數據
1. 添加圖形圖層
import GraphicsLayer from '@geoscene/core/layers/GraphicsLayer.js'
import Graphic from '@geoscene/core/Graphic.js'
import Point from '@geoscene/core/geometry/Point.js'
import SimpleMarkerSymbol from '@geoscene/core/symbols/SimpleMarkerSymbol.js'// 創建圖形圖層
const createGraphicsLayer = () => {return new GraphicsLayer({id: 'graphics-layer',title: '標記圖層'})
}// 添加點標記
const addPointMarker = (layer, longitude, latitude, attributes = {}) => {// 創建點幾何const point = new Point({longitude: longitude,latitude: latitude})// 創建點符號const symbol = new SimpleMarkerSymbol({color: [226, 119, 40], // 橙色outline: {color: [255, 255, 255], // 白色邊框width: 2},size: 12})// 創建圖形const graphic = new Graphic({geometry: point,symbol: symbol,attributes: attributes})// 添加到圖層layer.add(graphic)return graphic
}
2. 添加自定義圖標
import PictureMarkerSymbol from '@geoscene/core/symbols/PictureMarkerSymbol.js'// 創建自定義圖標標記
const addCustomIconMarker = (layer, longitude, latitude, iconUrl, attributes = {}) => {const point = new Point({longitude: longitude,latitude: latitude})// 使用圖片符號const symbol = new PictureMarkerSymbol({url: iconUrl,width: 32,height: 32})const graphic = new Graphic({geometry: point,symbol: symbol,attributes: attributes})layer.add(graphic)return graphic
}// 批量添加標記點
const addMultipleMarkers = (layer, markersData) => {const graphics = markersData.map(marker => {return addCustomIconMarker(layer,marker.longitude,marker.latitude,marker.iconUrl,marker.attributes)})return graphics
}
3. 添加線和面
import Polyline from '@geoscene/core/geometry/Polyline.js'
import Polygon from '@geoscene/core/geometry/Polygon.js'
import SimpleLineSymbol from '@geoscene/core/symbols/SimpleLineSymbol.js'
import SimpleFillSymbol from '@geoscene/core/symbols/SimpleFillSymbol.js'// 添加線要素
const addPolyline = (layer, paths, attributes = {}) => {const polyline = new Polyline({paths: paths})const symbol = new SimpleLineSymbol({color: [226, 119, 40],width: 4})const graphic = new Graphic({geometry: polyline,symbol: symbol,attributes: attributes})layer.add(graphic)return graphic
}// 添加面要素
const addPolygon = (layer, rings, attributes = {}) => {const polygon = new Polygon({rings: rings})const symbol = new SimpleFillSymbol({color: [227, 139, 79, 0.8], // 半透明填充outline: {color: [255, 255, 255],width: 1}})const graphic = new Graphic({geometry: polygon,symbol: symbol,attributes: attributes})layer.add(graphic)return graphic
}
交互功能實現
1.?彈窗功能
import PopupTemplate from '@geoscene/core/PopupTemplate.js'// 創建彈窗模板
const createPopupTemplate = (title, content) => {return new PopupTemplate({title: title,content: content,// 自定義彈窗操作actions: [{title: '詳細信息',id: 'show-details',className: 'geoscene-icon-description'},{title: '導航到此',id: 'navigate-to',className: 'geoscene-icon-navigation'}]})
}// 為圖形添加彈窗
const addPopupToGraphic = (graphic, popupTemplate) => {graphic.popupTemplate = popupTemplate
}// 處理彈窗操作
const handlePopupActions = (view) => {view.popup.on('trigger-action', (event) => {const action = event.actionswitch (action.id) {case 'show-details':console.log('顯示詳細信息')// 實現詳細信息邏輯breakcase 'navigate-to':console.log('導航到此位置')// 實現導航邏輯break}})
}
2. 繪制工具
import SketchViewModel from '@geoscene/core/widgets/Sketch/SketchViewModel.js'// 創建繪制工具
const createSketchViewModel = (view, layer) => {return new SketchViewModel({view: view,layer: layer,// 繪制符號樣式pointSymbol: new SimpleMarkerSymbol({color: [255, 0, 0],size: 10}),polylineSymbol: new SimpleLineSymbol({color: [0, 255, 0],width: 3}),polygonSymbol: new SimpleFillSymbol({color: [0, 0, 255, 0.3],outline: {color: [0, 0, 255],width: 2}})})
}// 繪制操作
const drawingOperations = {// 開始繪制點drawPoint: (sketchViewModel) => {sketchViewModel.create('point')},// 開始繪制線drawPolyline: (sketchViewModel) => {sketchViewModel.create('polyline')},// 開始繪制面drawPolygon: (sketchViewModel) => {sketchViewModel.create('polygon')},// 取消繪制cancel: (sketchViewModel) => {sketchViewModel.cancel()}
}// 監聽繪制事件
const setupDrawingEvents = (sketchViewModel) => {// 繪制完成事件sketchViewModel.on('create', (event) => {if (event.state === 'complete') {console.log('繪制完成:', event.graphic)// 處理繪制完成的圖形handleDrawingComplete(event.graphic)}})// 更新事件sketchViewModel.on('update', (event) => {if (event.state === 'complete') {console.log('更新完成:', event.graphics)}})// 刪除事件sketchViewModel.on('delete', (event) => {console.log('刪除圖形:', event.graphics)})
}
3. 測量工具
import DistanceMeasurement2D from '@geoscene/core/widgets/DistanceMeasurement2D.js'
import AreaMeasurement2D from '@geoscene/core/widgets/AreaMeasurement2D.js'// 創建距離測量工具
const createDistanceMeasurement = (view) => {const distanceMeasurement = new DistanceMeasurement2D({view: view})return distanceMeasurement
}// 創建面積測量工具
const createAreaMeasurement = (view) => {const areaMeasurement = new AreaMeasurement2D({view: view})return areaMeasurement
}// 測量工具管理
const measurementTools = {distanceTool: null,areaTool: null,// 開始距離測量startDistanceMeasurement: (view) => {// 清除其他測量工具measurementTools.clearAll()measurementTools.distanceTool = createDistanceMeasurement(view)view.ui.add(measurementTools.distanceTool, 'top-right')},// 開始面積測量startAreaMeasurement: (view) => {// 清除其他測量工具measurementTools.clearAll()measurementTools.areaTool = createAreaMeasurement(view)view.ui.add(measurementTools.areaTool, 'top-right')},// 清除所有測量工具clearAll: () => {if (measurementTools.distanceTool) {measurementTools.distanceTool.destroy()measurementTools.distanceTool = null}if (measurementTools.areaTool) {measurementTools.areaTool.destroy()measurementTools.areaTool = null}}
}
高級功能應用
1.?聚合顯示
import FeatureLayer from '@geoscene/core/layers/FeatureLayer.js'// 創建聚合圖層
const createClusterLayer = (data) => {// 創建要素圖層const featureLayer = new FeatureLayer({source: data.map(item => ({geometry: {type: 'point',longitude: item.longitude,latitude: item.latitude},attributes: item.attributes})),objectIdField: 'ObjectID',geometryType: 'point',spatialReference: { wkid: 4326 },fields: [{name: 'ObjectID',alias: 'ObjectID',type: 'oid'},{name: 'name',alias: '名稱',type: 'string'}],// 啟用聚合featureReduction: {type: 'cluster',clusterRadius: '100px',popupTemplate: {title: '聚合點',content: '此處有 {cluster_count} 個點'},symbol: {type: 'simple-marker',color: '#69dcff',outline: {color: 'rgba(0, 139, 174, 0.5)',width: 15},size: 15},labelingInfo: [{deconflictionStrategy: 'none',labelExpressionInfo: {expression: '$feature.cluster_count_label'},symbol: {type: 'text',color: '#004a5d',font: {weight: 'bold',family: 'Noto Sans',size: 10}},labelPlacement: 'center-center'}]}})return featureLayer
}
2. 熱力圖
// 創建熱力圖圖層
const createHeatmapLayer = (data) => {const featureLayer = new FeatureLayer({source: data,objectIdField: 'ObjectID',fields: [{name: 'ObjectID',alias: 'ObjectID',type: 'oid'},{name: 'intensity',alias: '強度',type: 'double'}],// 使用熱力圖渲染器renderer: {type: 'heatmap',field: 'intensity',colorStops: [{ color: 'rgba(63, 40, 102, 0)', ratio: 0 },{ color: '#472d7b', ratio: 0.083 },{ color: '#4e2d87', ratio: 0.166 },{ color: '#563086', ratio: 0.249 },{ color: '#5d3280', ratio: 0.332 },{ color: '#65337c', ratio: 0.415 },{ color: '#6e3375', ratio: 0.498 },{ color: '#76336e', ratio: 0.581 },{ color: '#7f3465', ratio: 0.664 },{ color: '#88355f', ratio: 0.747 },{ color: '#903658', ratio: 0.83 },{ color: '#99374f', ratio: 0.913 },{ color: '#a23847', ratio: 1 }],maxPixelIntensity: 25,minPixelIntensity: 1}})return featureLayer
}