Skip to content

封装天地图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>

天地图示例官网

天地图API

AI助手