【天地图】使用天地图api绘制GeoJson数据

重要说明:本意为解析GeoJson数据并配合个人封装的天地图hooks,仅个人记录笔记,仅供参考!天地图API需要对点/线/面单独渲染,因此最终处理格式为以下geoJsonMapFormat格式。

GeoJson格式数据入门说明参考地址:https://zhuanlan.zhihu.com/p/539689986

个人封装天地图hooks参考地址:https://blog.csdn.net/YueMiaoL/article/details/134154384?spm=1001.2014.3001.5502

封装geoJson方法的hooks

useGeoJsonData.js

/**
 * 处理geoJson格式数据并能回显至天地图上
 **/

export const useGeoJsonData = () => {
	let geoJsonData = null // 定义geoJsonData保存geoJson格式数据
	// geoJson数据处理为天地图可展示的图形结构,点/线/面分别渲染
	const geoJsonMapFormat = {
		point: [], // 点数据
		line: [], // 线数据
		polygon: [] // 面数据
	}
	// 处理geoJson方法合集
	const geoJsonFunList = {
		GeometryCollection: {
			fun: handleGeometryCollection, // 对应类型处理方法
			paramName: 'geometries' // 方法传参
		},
		MultiPoint: {
			fun: handleMultiPoint,
			paramName: 'coordinates'
		},
		Point: {
			fun: handlePoint,
			paramName: 'coordinates'
		},
		FeatureCollection: {
			fun: handleFeatureCollection,
			paramName: 'features'
		},
		Feature: {
			fun: handleFeature,
			paramName: undefined
		},
		MultiLineString: {
			fun: handleMultiLineString,
			paramName: 'coordinates'
		},
		LineString: {
			fun: handleLineString,
			paramName: 'coordinates'
		},
		MultiPolygon: {
			fun: handleMultiPolygon,
			paramName: 'coordinates'
		},
		Polygon: {
			fun: handlePolygon,
			paramName: 'coordinates'
		}
	}
	// 位置信息
	const geoJsonSiteInfo = {
		minLng: undefined, // 最小经度
		maxLng: undefined, // 最大经度
		minLat: undefined, // 最小纬度
		maxLat: undefined // 最大纬度
	}
	// 自定义获取赋予geoJson数据
	async function customGetGeoJsonData(data) {
		geoJsonData = JSON.parse(JSON.stringify(data))
		await handleGeoJsonData(geoJsonData)
		return Promise.resolve()
	}
	// 处理geoJson数据
	function handleGeoJsonData(data) {
		let typeName = data.type
		geoJsonFunList[typeName] && (geoJsonFunList[typeName].paramName ? geoJsonFunList[typeName].fun(data[geoJsonFunList[typeName].paramName]) : geoJsonFunList[typeName].fun(data))
	}
	// 处理GeometryCollection类型数据
	function handleGeometryCollection(data) {
		data?.forEach((item) => {
			handleGeoJsonData(item)
		})
	}
	// 处理Point类型数据
	function handlePoint(data) {
		handleSiteInfo(data)
		const coordinate = data.join()
		geoJsonMapFormat.point.push(coordinate)
	}
	// 处理FeatureCollection类型数据
	function handleFeatureCollection(data) {
		data?.forEach((item) => {
			handleGeoJsonData(item)
		})
	}
	// 处理MultiPoint类型数据
	function handleMultiPoint(data) {
		data?.forEach((item) => {
			handlePoint(item)
		})
	}
	// 处理Feature类型数据
	function handleFeature(data) {
		handleGeoJsonData(data.geometry)
	}
	// 处理MultiLineString类型数据
	function handleMultiLineString(data) {
		data?.forEach((item) => handleLineString(item))
	}
	// 处理LineString类型数据
	function handleLineString(data) {
		// 处理数据格式
		const coordinateList = data?.map((item) => {
			handleSiteInfo(item)
			return {
				lng: item[0],
				lat: item[1]
			}
		})
		// 添加线
		geoJsonMapFormat.line.push(coordinateList)
	}
	// 处理MultiPolygon类型数据
	function handleMultiPolygon(data) {
		data?.forEach((item) => {
			handlePolygon(item)
		})
	}
	// 处理Polygon类型数据
	function handlePolygon(data) {
		// 处理数据格式
		const coordinateList = data.map((item) => {
			return item.map((pointItem) => {
				handleSiteInfo(pointItem)
				return {
					lng: pointItem[0],
					lat: pointItem[1]
				}
			})
		})
		geoJsonMapFormat.polygon.push(coordinateList)
	}
	// 处理经纬度最大值及最小值
	function handleSiteInfo(site) {
		geoJsonSiteInfo.minLng =
			geoJsonSiteInfo.minLng != undefined && geoJsonSiteInfo.minLng < site[0] ? geoJsonSiteInfo.minLng : site[0]
		geoJsonSiteInfo.maxLng =
			geoJsonSiteInfo.maxLng != undefined && geoJsonSiteInfo.maxLng > site[0] ? geoJsonSiteInfo.maxLng : site[0]
		geoJsonSiteInfo.minLat =
			geoJsonSiteInfo.minLat != undefined && geoJsonSiteInfo.minLat < site[1] ? geoJsonSiteInfo.minLat : site[1]
		geoJsonSiteInfo.maxLat =
			geoJsonSiteInfo.maxLat != undefined && geoJsonSiteInfo.maxLat > site[1] ? geoJsonSiteInfo.maxLat : site[1]
	}
	// 图形回显天地图自适应视角算法
	function geoJsonToMapAdaptiveAlgorithm() {
		return new Promise((resolve, reject) => {
			if (
				![geoJsonSiteInfo.minLng, geoJsonSiteInfo.maxLng, geoJsonSiteInfo.minLat, geoJsonSiteInfo.maxLat].includes(
					undefined
				)
			) {
				// 处理可视化范围及层级
				let coordinate = `${(geoJsonSiteInfo.minLng + geoJsonSiteInfo.maxLng) / 2},${(geoJsonSiteInfo.minLat + geoJsonSiteInfo.maxLat) / 2}` // 中心点
				const diffArr = [180, 90, 45, 22, 11, 5.5, 2.75, 1.37, 0.68, 0.34, 0.17, 0.08, 0.04]
				const diffLng = geoJsonSiteInfo.maxLng - geoJsonSiteInfo.minLng // 经度差
				const diffLat = geoJsonSiteInfo.maxLat - geoJsonSiteInfo.minLat // 纬度差
				const standardValue =
					diffLng < diffLat * 2.1 ? parseInt(10000 * diffLat * 2.1) / 10000 : parseInt(10000 * diffLng) / 10000 // 设立标准值
				let index = diffArr.findIndex((item) => {
					return standardValue - item >= 0
				})
				let zoom = index != -1 ? index + 3 : 14 // 获得缩放级别
				resolve({
					coordinate,
					zoom
				})
			}
			reject(false)
		})
	}
	// 重置数据
	function resetGeoJsonData() {
		geoJsonData = null
		for (let key in geoJsonSiteInfo) {
			geoJsonSiteInfo[key] = undefined
		}
		for (let key in geoJsonMapFormat) {
			geoJsonMapFormat[key] = []
		}
	}

	return {
		geoJsonMapFormat,
		customGetGeoJsonData,
		geoJsonToMapAdaptiveAlgorithm,
		resetGeoJsonData
	}
}

需要引入天地图hooks配合使用,使用简单示例:

<template>
    <div id="mapId"></div>
</template>

<script setup>
    import { useTdtMap } from '@/hooks/useTdtMap'
    import { useGeoJsonData } from '@/hooks/useGeoJsonData'
    import mockGeoJsonData from '@/mock/data' // 模拟geojson数据

    // 地图
    const { mapInit, setMapScale, addMapMarker, addMapLine, addMapPolygon } = useTdtMap('mapId')
    // geoJson
    const { geoJsonMapFormat, customGetGeoJsonData, geoJsonToMapAdaptiveAlgorithm, resetGeoJsonData } = useGeoJsonData()

    nextTick(() => {
        // 初始化地图
        mapInit().then(() => {
            // 解析geoJson数据格式
            customGetGeoJsonData(mockGeoJsonData).then((res) => {
                if(res) {
                    // 天地图回显该数据
                    // 点
				    geoJsonMapFormat.point?.forEach((pointCoordinate) => {
    				    addMapMarker(pointCoordinate)
       				})
                    // 线
	    			geoJsonMapFormat.line?.forEach((lineCoordinate) => {
    				    addMapLine(lineCoordinate)
			    	})
                    // 面
				    geoJsonMapFormat.polygon?.forEach((polygonCoordinate) => {
				        addMapPolygon(polygonCoordinate)
	    			})
		    		// 调整自适应地图视角
			    	geoJsonToMapAdaptiveAlgorithm().then((res) => {
				        let { coordinate, zoom } = res
	    				setMapScale(coordinate, zoom)
		    		})
                }
            })
        })
    })
    onUnmounted(() => { 
        // 重置geoJson数据,如果需要其它geoJson数据的自适应地图视角,你则需要重置清空useGeoJsonData里的geoJson数据,否则可能会导致视角不准确
        resetGeoJsonData()
    })
</script>

图形回显天地图自适应视角算法(geoJsonToMapAdaptiveAlgorithm)说明,该部分可单独拎出去使用,这部分老早之前有参考过其它博主的文章但我找不到来源了,实在愧疚,如果能找到原主,请务必私信我再编辑放链接跳转的!!!

其中本质上是获取geoJson复杂图形中最大/最小经纬度确定图形展示范围和中心点,利用经纬度差值2.1倍进行估算地图展示级别,如果显示不准则根据自行分辨率和情况修“let zoom = index != -1 ? index + 3 : 14”中的3和14关键代码如下所示:

// 位置信息
const geoJsonSiteInfo = {
	minLng: undefined, // 最小经度
	maxLng: undefined, // 最大经度
	minLat: undefined, // 最小纬度
	maxLat: undefined // 最大纬度
}
// 图形回显天地图自适应视角算法
function geoJsonToMapAdaptiveAlgorithm() {
	return new Promise((resolve, reject) => {
		if (
			![geoJsonSiteInfo.minLng, geoJsonSiteInfo.maxLng, geoJsonSiteInfo.minLat, geoJsonSiteInfo.maxLat].includes(undefined)
		) {
			// 处理可视化范围及层级
			let coordinate = `${(geoJsonSiteInfo.minLng + geoJsonSiteInfo.maxLng) / 2},${(geoJsonSiteInfo.minLat + geoJsonSiteInfo.maxLat) / 2}` // 中心点
			const diffArr = [180, 90, 45, 22, 11, 5.5, 2.75, 1.37, 0.68, 0.34, 0.17, 0.08, 0.04]
			const diffLng = geoJsonSiteInfo.maxLng - geoJsonSiteInfo.minLng // 经度差
			const diffLat = geoJsonSiteInfo.maxLat - geoJsonSiteInfo.minLat // 纬度差
			const standardValue =
				diffLng < diffLat * 2.1 ? parseInt(10000 * diffLat * 2.1) / 10000 : parseInt(10000 * diffLng) / 10000 // 设立标准值
			let index = diffArr.findIndex((item) => {
				return standardValue - item >= 0
			})
			let zoom = index != -1 ? index + 3 : 14 // 获得缩放级别
			resolve({
				coordinate,
				zoom
			})
		}
		reject(false)
	})
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值