封装天地图API
tiandituApiLoader.js
JavaScript
export const DEFAULT_CONFIG = {
v: '4.0',
tk: '',
plugins: []
}
export const PLUGINS_URL = {
D3: [
'https://cdn.bootcss.com/d3/3.5.17/d3.min.js',
'http://lbs.tianditu.gov.cn/api/js4.0/opensource/openlibrary/D3SvgOverlay.min.js'
],
CarTrack: [
'https://cdn.bootcss.com/d3/3.5.17/d3.min.js',
'http://lbs.tianditu.gov.cn/api/js4.0/opensource/openlibrary/D3SvgOverlay.min.js',
'http://lbs.tianditu.gov.cn/api/js4.0/opensource/openlibrary/CarTrack.min.js'
],
HeatmapOverlay: ['http://lbs.tianditu.gov.cn/api/js4.0/opensource/openlibrary/HeatmapOverlay.min.js'],
BufferTool: [
'https://cdn.bootcss.com/Turf.js/3.0.14/turf.js',
'http://lbs.tianditu.gov.cn/api/js4.0/opensource/openlibrary/BufferTool.min.js'
],
ImageOverLayer: ['http://lbs.tianditu.gov.cn/api/js4.0/opensource/openlibrary/ImageOverlay.min.js']
}
let isLoading = false
export async function useApiLoader (config = {}) {
if (isLoading) {
return new Promise(resolve => {
setTimeout(() => resolve(useApiLoader(config)))
})
} else if (globalThis.T) {
return
} else {
isLoading = true
const { v, tk, plugins } = { ...DEFAULT_CONFIG, ...config }
await loadScript(`https://api.tianditu.gov.cn/api?v=${v}&tk=${tk}`)
await Promise.all(
plugins
.map(name => PLUGINS_URL[name])
.flat()
.map(url => loadScript(url))
)
isLoading = false
}
}
function loadScript (url) {
return new Promise((resolve, reject) => {
const script = globalThis.document?.createElement('script')
if (!script) resolve()
script.src = url
script.type = 'text/javascript'
script.async = true
script.defer = true
script.onload = () => resolve()
script.onerror = e => resolve()
globalThis.document?.body.appendChild(script)
})
}export const DEFAULT_CONFIG = {
v: '4.0',
tk: '',
plugins: []
}
export const PLUGINS_URL = {
D3: [
'https://cdn.bootcss.com/d3/3.5.17/d3.min.js',
'http://lbs.tianditu.gov.cn/api/js4.0/opensource/openlibrary/D3SvgOverlay.min.js'
],
CarTrack: [
'https://cdn.bootcss.com/d3/3.5.17/d3.min.js',
'http://lbs.tianditu.gov.cn/api/js4.0/opensource/openlibrary/D3SvgOverlay.min.js',
'http://lbs.tianditu.gov.cn/api/js4.0/opensource/openlibrary/CarTrack.min.js'
],
HeatmapOverlay: ['http://lbs.tianditu.gov.cn/api/js4.0/opensource/openlibrary/HeatmapOverlay.min.js'],
BufferTool: [
'https://cdn.bootcss.com/Turf.js/3.0.14/turf.js',
'http://lbs.tianditu.gov.cn/api/js4.0/opensource/openlibrary/BufferTool.min.js'
],
ImageOverLayer: ['http://lbs.tianditu.gov.cn/api/js4.0/opensource/openlibrary/ImageOverlay.min.js']
}
let isLoading = false
export async function useApiLoader (config = {}) {
if (isLoading) {
return new Promise(resolve => {
setTimeout(() => resolve(useApiLoader(config)))
})
} else if (globalThis.T) {
return
} else {
isLoading = true
const { v, tk, plugins } = { ...DEFAULT_CONFIG, ...config }
await loadScript(`https://api.tianditu.gov.cn/api?v=${v}&tk=${tk}`)
await Promise.all(
plugins
.map(name => PLUGINS_URL[name])
.flat()
.map(url => loadScript(url))
)
isLoading = false
}
}
function loadScript (url) {
return new Promise((resolve, reject) => {
const script = globalThis.document?.createElement('script')
if (!script) resolve()
script.src = url
script.type = 'text/javascript'
script.async = true
script.defer = true
script.onload = () => resolve()
script.onerror = e => resolve()
globalThis.document?.body.appendChild(script)
})
}使用
Vue
<template>
<div class="base-layout">
<div style="width: 100%;height: 100%;" id="mapContainer"></div>
</div>
</template>
<script setup>
import { useApiLoader } from '@/utils/tiandituApiLoader.js'
import { onMounted, ref } from 'vue'
const map = ref(null)
const initMap = () =>{
useApiLoader({
v: '4.0',
tk: '941b19fcfcc02366cb81f938200e6496',
plugins: ['D3', 'CarTrack', 'HeatmapOverlay', 'BufferTool', 'ImageOverLayer']
}).then(() => {
map.value = new T.Map('mapContainer')
// 设置地图显示中心及级别
map.value.centerAndZoom(new T.LngLat(113.280637, 23.125178), 12)
// 允许鼠标双击放大地图
map.value.enableScrollWheelZoom()
// 创建标注对象
const marker = new T.Marker(new T.LngLat(113.280637, 23.125178))
// 向地图上添加标注
map.value.addOverLay(marker)
addwindowclick(marker)
})
}
const addwindowclick = marker =>{
marker.addEventListener('click', e=> {
console.log('----hhh')
})
}
onMounted(()=>{
initMap()
})
</script>
<style lang="scss" scoped>
.base-layout {
width: 100%;
height: 100%;
}
</style><template>
<div class="base-layout">
<div style="width: 100%;height: 100%;" id="mapContainer"></div>
</div>
</template>
<script setup>
import { useApiLoader } from '@/utils/tiandituApiLoader.js'
import { onMounted, ref } from 'vue'
const map = ref(null)
const initMap = () =>{
useApiLoader({
v: '4.0',
tk: '941b19fcfcc02366cb81f938200e6496',
plugins: ['D3', 'CarTrack', 'HeatmapOverlay', 'BufferTool', 'ImageOverLayer']
}).then(() => {
map.value = new T.Map('mapContainer')
// 设置地图显示中心及级别
map.value.centerAndZoom(new T.LngLat(113.280637, 23.125178), 12)
// 允许鼠标双击放大地图
map.value.enableScrollWheelZoom()
// 创建标注对象
const marker = new T.Marker(new T.LngLat(113.280637, 23.125178))
// 向地图上添加标注
map.value.addOverLay(marker)
addwindowclick(marker)
})
}
const addwindowclick = marker =>{
marker.addEventListener('click', e=> {
console.log('----hhh')
})
}
onMounted(()=>{
initMap()
})
</script>
<style lang="scss" scoped>
.base-layout {
width: 100%;
height: 100%;
}
</style>Vue
<template>
<div class="base-layout">
<div style="width: 100%;height: 100%;" id="mapContainer"></div>
</div>
</template>
<script setup>
import { useApiLoader } from '@/utils/tiandituApiLoader.js'
import { ref, nextTick } from 'vue'
import deviceIconOn from '@/assets/img/statisticalView/qualitySafetyManage/smartHelmetl/deviceIconOn.svg'
import deviceIconOff from '@/assets/img/statisticalView/qualitySafetyManage/smartHelmetl/deviceIconOff.svg'
const emit = defineEmits(['open-dialog'])
const map = ref(null)
const initMap = async (deviceList, mapInfo) =>{
await nextTick()
useApiLoader({
v: mapInfo.v,
tk: mapInfo.token,
plugins: ['D3', 'CarTrack', 'HeatmapOverlay', 'BufferTool', 'ImageOverLayer']
}).then(() => {
map.value = new T.Map('mapContainer')
// 设置地图显示中心及级别
const ponitList = deviceList.map(item=>{
return [item.latitudeChannel, item.longitudeChannel]
})
const { centerLon, centerLat } = getCenterFromDegrees(ponitList)
map.value.centerAndZoom(new T.LngLat(centerLon, centerLat), 18)
// 允许鼠标双击放大地图
map.value.enableScrollWheelZoom()
// 创建图片对象
const iconOn = new T.Icon({
iconUrl: deviceIconOn,
iconSize: new T.Point(35, 35),
iconAnchor: new T.Point(10, 25)
})
const iconOff = new T.Icon({
iconUrl: deviceIconOff,
iconSize: new T.Point(35, 35),
iconAnchor: new T.Point(10, 25)
})
// 创建标注对象
deviceList.forEach(item=>{
const icon = item.status === 1 ? iconOn : iconOff
const marker = new T.Marker(new T.LngLat(item.longitudeChannel, item.latitudeChannel), { icon: icon })
// 向地图上添加标注
map.value.addOverLay(marker)
addwindowclick(marker, item)
})
})
}
const Tlabel = ref(null)
const addwindowclick = (marker, item) =>{
marker.addEventListener('click', e=> {
emit('open-dialog', item)
})
marker.addEventListener('mousemove', e=>{
if(!Tlabel.value) {
Tlabel.value = new T.Label({
text: item.channelname,
position: marker.getLngLat(),
offset: new T.Point(0, -40)
})
map.value.addOverLay(Tlabel.value)
}
marker.addEventListener('mouseout', e=>{
if(Tlabel.value) {
map.value.removeOverLay(Tlabel.value)
}
Tlabel.value = null
})
})
}
const getCenterFromDegrees = coords=> {
if (!(coords && coords.length)) return null
let numCoords = coords.length
let X = 0.0
let Y = 0.0
let Z = 0.0
for (let i = 0; i < numCoords; i++) {
let lat = coords[i][0] * Math.PI / 180
let lon = coords[i][1] * Math.PI / 180
let a = Math.cos(lat) * Math.cos(lon)
let b = Math.cos(lat) * Math.sin(lon)
let c = Math.sin(lat)
X += a
Y += b
Z += c
}
X /= numCoords
Y /= numCoords
Z /= numCoords
let lon = Math.atan2(Y, X)
let hyp = Math.sqrt(X * X + Y * Y)
let lat = Math.atan2(Z, hyp)
let centerLat = lat * 180 / Math.PI
let centerLon = lon * 180 / Math.PI
return {
centerLon,
centerLat
}
}
defineExpose({
initMap
})
</script>
<style lang="scss" scoped>
.base-layout {
width: 100%;
height: 100%;
}
</style><template>
<div class="base-layout">
<div style="width: 100%;height: 100%;" id="mapContainer"></div>
</div>
</template>
<script setup>
import { useApiLoader } from '@/utils/tiandituApiLoader.js'
import { ref, nextTick } from 'vue'
import deviceIconOn from '@/assets/img/statisticalView/qualitySafetyManage/smartHelmetl/deviceIconOn.svg'
import deviceIconOff from '@/assets/img/statisticalView/qualitySafetyManage/smartHelmetl/deviceIconOff.svg'
const emit = defineEmits(['open-dialog'])
const map = ref(null)
const initMap = async (deviceList, mapInfo) =>{
await nextTick()
useApiLoader({
v: mapInfo.v,
tk: mapInfo.token,
plugins: ['D3', 'CarTrack', 'HeatmapOverlay', 'BufferTool', 'ImageOverLayer']
}).then(() => {
map.value = new T.Map('mapContainer')
// 设置地图显示中心及级别
const ponitList = deviceList.map(item=>{
return [item.latitudeChannel, item.longitudeChannel]
})
const { centerLon, centerLat } = getCenterFromDegrees(ponitList)
map.value.centerAndZoom(new T.LngLat(centerLon, centerLat), 18)
// 允许鼠标双击放大地图
map.value.enableScrollWheelZoom()
// 创建图片对象
const iconOn = new T.Icon({
iconUrl: deviceIconOn,
iconSize: new T.Point(35, 35),
iconAnchor: new T.Point(10, 25)
})
const iconOff = new T.Icon({
iconUrl: deviceIconOff,
iconSize: new T.Point(35, 35),
iconAnchor: new T.Point(10, 25)
})
// 创建标注对象
deviceList.forEach(item=>{
const icon = item.status === 1 ? iconOn : iconOff
const marker = new T.Marker(new T.LngLat(item.longitudeChannel, item.latitudeChannel), { icon: icon })
// 向地图上添加标注
map.value.addOverLay(marker)
addwindowclick(marker, item)
})
})
}
const Tlabel = ref(null)
const addwindowclick = (marker, item) =>{
marker.addEventListener('click', e=> {
emit('open-dialog', item)
})
marker.addEventListener('mousemove', e=>{
if(!Tlabel.value) {
Tlabel.value = new T.Label({
text: item.channelname,
position: marker.getLngLat(),
offset: new T.Point(0, -40)
})
map.value.addOverLay(Tlabel.value)
}
marker.addEventListener('mouseout', e=>{
if(Tlabel.value) {
map.value.removeOverLay(Tlabel.value)
}
Tlabel.value = null
})
})
}
const getCenterFromDegrees = coords=> {
if (!(coords && coords.length)) return null
let numCoords = coords.length
let X = 0.0
let Y = 0.0
let Z = 0.0
for (let i = 0; i < numCoords; i++) {
let lat = coords[i][0] * Math.PI / 180
let lon = coords[i][1] * Math.PI / 180
let a = Math.cos(lat) * Math.cos(lon)
let b = Math.cos(lat) * Math.sin(lon)
let c = Math.sin(lat)
X += a
Y += b
Z += c
}
X /= numCoords
Y /= numCoords
Z /= numCoords
let lon = Math.atan2(Y, X)
let hyp = Math.sqrt(X * X + Y * Y)
let lat = Math.atan2(Z, hyp)
let centerLat = lat * 180 / Math.PI
let centerLon = lon * 180 / Math.PI
return {
centerLon,
centerLat
}
}
defineExpose({
initMap
})
</script>
<style lang="scss" scoped>
.base-layout {
width: 100%;
height: 100%;
}
</style>天地图示例官网

