<template>
    <div class="map-contain">
        <div id="map" ref="root"></div>
        <img src="/image/compass.png" class="compass" ref="compass" :style="`transform: rotateZ(${compassRotationAngle}rad)`" alt="" @click="changeCompass">
        <div class="navigate-preview">
            <img src="/image/navigate.png" class="navigate" @click="changeNavigate" alt="" />
        </div>
    </div>
</template>

<script setup>
    import { markRaw, onMounted, watch, ref, computed, onBeforeUnmount, nextTick } from 'vue'
    import { useMapStore } from '@/store/MapStore.js'
    import { useVehicleStore } from '@/store/VehicleStore'
    import { storeToRefs } from 'pinia'
    import { vehicleScale } from '../js/tools'
    import L from 'leaflet'
    import 'leaflet-rotate'
    import '@/tools/Leaflet.LayerGroup.Collision'
    import * as turf from '@turf/turf'

    const safe_color = '#FFA500'
    const BASE_RAD = 1.5707963267948966
    const MAP_ZOOM = 18
    const LAYER_PROPOITY = {
        runablearea: 1,
        staticobjs: 2,
        diggingarea: 3,
        diggingworkarea: 3,
        dumparea: 4,
        barricade: 5,
        electronicFence: 6,
        wetArea: 7,
        lane: 8,
        obstacles: 9,
        stationarea: 10,
        parkspot: 11,
        lanenode: 12,
        currPathinfo: 13,
        nextPathinfo: 14,
        avoidancePath: 15,
        traj: 16,
        obstacle: 17
    }

    const vehicles = {}
    let ismousedown = false
    let ismousemove = false
    let resetTime = null
    let obstaclePolygons = []
    let dynamicPaths=[]

    const reNavigateTime = 10 * 1000

    const props = defineProps({
        isShowBasic: Boolean,
        clearSinglePointEnable: Boolean,
        reloadData: Boolean
    })

    let map = markRaw({})
    let currentPosition = markRaw([])
    const root = ref(null)
    const mapLayers = markRaw({})
    const safeObjects = markRaw({})
    const safeTrajs = markRaw({})
    const singlePaths = markRaw([])
    const navigate = ref(true)
    const currentRotation = ref(0)
    const markerLayerGroupLists = markRaw({})
    const isSinglePreview = ref(false)
    const compassRotationAngle = ref(0)
    const compass = ref(null)
    const mapStore = useMapStore()
    const mapStoreToRefs = storeToRefs(mapStore)
    const { 
        lanenode, 
        lane, 
        runablearea, 
        centerline, 
        obstacles, 
        diggingworkarea, 
        dumparea, 
        barricade, 
        stationarea,
        parkspot, 
        staticobjs,
        electronicFence,
        morepoint, // 单机循迹单路径
        morepath, // 单机循迹多路径
        nextPathinfo,
        currPathinfo,
        nextPathAvailable,
        avoidancePath, // 绕障路径
        obstacleData,
        dynamicPathinfo, // 车辆动态路权信息
    } = mapStoreToRefs
    const vehicleStore = useVehicleStore()
    const vehicleStoreToRefs = storeToRefs(vehicleStore)
    const { vehiclesPositioninfo, safeObj, trajObj, paraminfo, deleteVehicles } = vehicleStoreToRefs

    const deviceId = computed(() => {
        return paraminfo.value.deviceId
    })

    const emits = defineEmits(['handleSend'])

    onMounted(() => {
        map = L.map(root.value, {
            center: document.location.mapCenter,
            zoom: 14,
            zoomControl: false,
            minZoom: 10,
            maxZoom: 21,
            rotate: true,
            touchRotate: true
        })
        map.on('zoomend', () => {
            let zoom = map.getZoom()
        
            let { iconSize, iconAnchor } = vehicleScale(zoom)
            for (let vehicle in vehicles) {
                let icon = vehicles[vehicle].getIcon()
                let { iconUrl } = icon.options
                let newIcon = L.icon({
                    iconUrl,
                    iconSize,
                    iconAnchor
                })
                vehicles[vehicle].setIcon(newIcon)
            }
        })

        let mapDom = root.value
        mapDom.addEventListener('mousedown', () => {
            changeMouseDown()
        })

        mapDom.addEventListener('mousemove', (evt) => {
            changeMouseMove()
        })

        mapDom.addEventListener('mouseup', (evt) => {
            changeMouseUp()
        })

        emits('handleSend', {
            type: 'syncMapVersion',
            msg: {}
        })
    })

    function changeNavigate() {
        navigate.value = true
        dealMapRotate(currentRotation.value, currentPosition, map.getZoom())
    }

    // 指南针
    function changeCompass() {
        dealVehicleRotate(0)
        currentRotation.value = BASE_RAD
        if (navigate.value) {
            setTimeout(() => {
                dealVehicleRotate()
            }, 3 * 1000)
        }
    }

    function changeMouseDown() {
        ismousedown = true
    }

    function changeMouseMove() {
        if (ismousedown) {
            ismousemove = true
            if (resetTime) {
                window.clearTimeout(resetTime)
                resetTime = null
            }
        }
    }

    function changeMouseUp() {
        if (!currentPosition) return
        if (ismousedown && ismousemove) {
            navigate.value = false
            resetTime = window.setTimeout(() => {
                if (!navigate.value) {
                    navigate.value = true
                    dealVehicleRotate()
                    currentRotation.value = BASE_RAD
                }
            }, reNavigateTime)
            ismousedown = false
            ismousemove = false
        }
    }

    function dealVehicleRotate(rotate) {
        let keys = Object.keys(vehicles)
        let target = keys.find(item => item === deviceId.value)
        let currentTarget = vehicles[target]
        let vehicleHeading = BASE_RAD
        let currentOldHeading = currentTarget && currentTarget.options.vehicleHeading
        if (typeof rotate === 'number') {
            dealMapRotate(0, currentPosition, map.getZoom())
            currentTarget.setRotation(-currentOldHeading + vehicleHeading)
        } else {
            vehicleHeading = currentOldHeading
            currentRotation.value = vehicleHeading
            dealMapRotate(vehicleHeading, currentPosition, map.getZoom())
            currentTarget.setRotation(0)
        }
        for (let key in vehicles) {
            if (key !== deviceId.value) {
                let oldHeading = vehicles[key].options['vehicleHeading']
                vehicles[key].setRotation(-oldHeading + vehicleHeading)
            }
        }
    }

    function dealMapLayer(value, color, layerName) {
        if (!value || !map) return

        let result = JSON.parse(value)
        if (!result) return

        if (mapLayers[layerName]) {
            map.removeLayer(mapLayers[layerName])
            delete mapLayers[layerName]
        }

        let layer = L.geoJSON(result, {
                    style: function (feature) {
                        if(layerName === 'barricade'){
                            return {
                            color: '#0066ff',
                            opacity: 1,
                            width:5
                         }
                        }else{
                            return {
                            color: layerName === 'lane' ? '#eee' : feature.properties.color,
                            opacity: layerName === 'lane' ? .5 : 1,
                            fillColor: layerName === 'electronicFence'
                                ? feature.properties.color
                                : color ? color : feature.properties.color,
                            fillOpacity: layerName === 'runablearea' ? .5 : .7
                         }
                        }
                    },
                })
        mapLayers[layerName] = layer.addTo(map)
        let bottomLayerOne = mapLayers['diggingworkarea']
        let bottomLayerTwo = mapLayers['runablearea']
        let bottomLayerThree = mapLayers['barricade']
        bottomLayerThree && bottomLayerThree.bringToFront()
        bottomLayerOne && bottomLayerOne.bringToBack()
        bottomLayerTwo && bottomLayerTwo.bringToBack()

        mapStore.setData(layerName, null)
    }

    function dealMapPath(value, layerName, color) {
        if (mapLayers[layerName]) {
            map.removeLayer(mapLayers[layerName])
            delete mapLayers[layerName]
        }
        if (mapLayers[`${layerName}Buffer`]) {
            map.removeLayer(mapLayers[`${layerName}Buffer`])
            delete mapLayers[`${layerName}Buffer`]
        }

        if (value && value.length) {
            let data = JSON.parse(JSON.stringify(value))
            let path = L.polyline(data, {
                color: '#ffff00',
                opacity: 1,
                className: 'middle-line',
                fillColor: '#ffff00',
                fillOpacity: 1,
            }).addTo(map)
            mapLayers[layerName] = path
            let bufferLine = turf.buffer(path.toGeoJSON(), 6.5, { units: "meters" })
            mapLayers[`${layerName}Buffer`] = L.geoJSON(bufferLine, {
                style: function () { return { color, fillOpacity: .6 } },
            }).addTo(map)
            mapLayers[`${layerName}Buffer`].bringToFront()
        }
    }

    function deleteMarker(features, layerName) {
        Object.keys(markerLayerGroupLists).forEach(item => {
            if(item.includes(layerName)){
                map.removeLayer(markerLayerGroupLists[item])
            }
        })
        let marker = Object.keys(markerLayerGroupLists).filter(item => item.includes(layerName))
        for (let i = 0; i < marker.length; i++) {
            let item = marker[i]
            let isIn = features.find(f => `${layerName}${f.properties.id}` === item)
            if (isIn) continue
            if (item.includes('point')) continue
            let id = item.replace(`${layerName}`, '')
            let icon = L.divIcon({
                html: `<span class="icon-node-name"></span>`,
                className: 'icon-node',
            })
            markerLayerGroupLists[`${layerName}${id}`].setIcon(icon)
        }
    }

    function dealDivIcon(value, layerName) {
        if (!value || !map) return
        let result = JSON.parse(value)
        if (!result) return

        const { features } = result
        deleteMarker(features, layerName)
        let markerLayerGroup = L.LayerGroup.collision({ margin: 5 })

        for (let i = 0; i < features.length; i++) {
                let feature = features[i]
                let { name, id } = feature.properties
                let { coordinates } = feature.geometry
                let markerCoor = null
                if (layerName === 'lanenode') {
                    markerCoor = [coordinates[1], coordinates[0]]
                } else {
                    let center = turf.center(feature)
                    markerCoor = [center.geometry.coordinates[1], center.geometry.coordinates[0]]
                }
                let icon = L.divIcon({
                    html: `<span class="icon-node-name">${name}</span>`,
                    className: 'icon-node',
                })
                if (markerLayerGroupLists[`${layerName}${id}`]) {
                    markerLayerGroupLists[`${layerName}${id}`].setIcon(icon)
                } else {
                    let nameMarker = L.marker(markerCoor, { icon, zIndexOffset: -100 })
                    markerLayerGroup.addLayer(nameMarker)
                    markerLayerGroupLists[`${layerName}${id}`] = nameMarker
                }

                markerLayerGroupLists[`${layerName}${id}point`] = L.marker(markerCoor, {
                    icon: L.icon({
                        iconUrl: '/image/bluePoint.png',
                        iconSize: [12, 12],
                        iconAnchor: [6, 6],
                    }),
                    zIndexOffset: -100,
                }).addTo(map)
            }
            markerLayerGroup.addTo(map)

            mapStore.setData(layerName, null)
    }

    function removeLayer(obj, vehicleID) {
        if (obj[vehicleID]) {
            for (let item in obj[vehicleID]) {
                map.removeLayer(obj[vehicleID][item])
            }
        }
    }

    function adjustmentLayer() {
        mapLayers['currentPath'] && mapLayers['currentPath'].bringToFront()
        mapLayers['nextPath'] && mapLayers['nextPath'].bringToFront()

        for (let key in safeObjects) {
            let safeLayer = safeObjects[key]
            for (let lkey in safeLayer) {
                lkey && safeLayer[lkey].bringToFront()
            }
        }

        for (let key in safeTrajs) {
            safeTrajs[key] && safeTrajs[key]['pathBuffer'] && safeTrajs[key]['pathBuffer'].bringToFront()
        }
    }

    function dealSafe(vehicleID, safe) {
        if (!map) return

        const { enable, data, dealedData, vehicleType, vehicleLatitude, vehicleLongtitude } = safe
        removeLayer(safeObjects, vehicleID)
        safeObjects[vehicleID] = {}
        if (!enable) return

        let safeType = [1, 20, 21].includes(vehicleType) ? 'circle' : 'rectangle'
        let zIndex = 16
        for (let i = 0; i < dealedData.length; i++) {
            let item = JSON.parse(JSON.stringify(dealedData[i]))
            let layer = safeType === 'rectangle' ? L.polygon(item, { color: safe_color, weight: 1 }) : L.circle([vehicleLatitude, vehicleLongtitude], { radius: data[i], color: safe_color })
            safeObjects[vehicleID][i] = layer.addTo(map)
            safeObjects[vehicleID][i].bringToFront()
        }
    }

    function dealTraj(vehicleID, traj) {
        if (!traj || !map) return
        const { trajPathWid, radius, dealedData, vehicleType, vehicleLatitude, vehicleLongtitude } = traj
        removeLayer(safeTrajs, vehicleID)
        safeTrajs[vehicleID] = {}
        // if (!dealedData) return
        // if ((dealedData && !dealedData.length) || !radius)) return
        // if([1, 20, 21].includes(vehicleType && !radius)) return;

        const zIndex = LAYER_PROPOITY['traj']
        if ([1, 20, 21].includes(vehicleType) && radius) {
            let layer = L.circle([vehicleLatitude, vehicleLongtitude], { radius, color: '#FFA500' })
            safeTrajs[vehicleID]['circle'] = layer.addTo(map)
            safeTrajs[vehicleID]['circle'].bringToFront()
        } else {
            if(dealedData && !dealedData.length) return;
            let path = L.polyline(JSON.parse(JSON.stringify(dealedData)), {})
            safeTrajs[vehicleID]['path'] = path
            let bufferLine = turf.buffer(path.toGeoJSON(), trajPathWid / 2, { units: "meters" })
            let layer = L.geoJSON(bufferLine, {
                style: function () {
                    return {
                        color: safe_color,
                        fillOpacity: .4
                    }
                },
            })
            safeTrajs[vehicleID]['pathBuffer'] = layer.addTo(map)
            safeTrajs[vehicleID]['pathBuffer'].bringToFront()
        }
    }

    function rotateVehicles(vehicleHeading) {
        for (let key in vehicles) {
            if (key !== deviceId.value) {
                let oldHeading = vehicles[key].options['vehicleHeading']
                vehicles[key].setRotation(-oldHeading + vehicleHeading)
            }
        }
    }

    function dealMapRotate(rotationAngle, center, zoom) {
        let rotate = 0
        if (rotationAngle) {
            rotate = turf.radiansToDegrees(rotationAngle - BASE_RAD)
        }
        if (compass.value) {
            compassRotationAngle.value = rotationAngle
            map.setBearing(rotate)
        }
        center && center.length && map.flyTo(center, zoom, {animate: false})
    }

    function dealVehiclePosition(value) {
        if (!map || !value.length) return

        let zoom = map.getZoom()
        let { iconSize, iconAnchor } = vehicleScale(zoom)
        for (let i = 0; i < value.length; i++) {
            const item = value[i]
            const { vehicleLatitude, vehicleLongtitude, vehicleHeading, vehicleID, image } = item
            let vehiclePosition = [vehicleLatitude, vehicleLongtitude]
            if (vehicles[vehicleID]) {
                let beforeIconUrl = vehicles[vehicleID].getIcon().options 
                                    ? vehicles[vehicleID].getIcon().options.iconUrl 
                                    : vehicles[vehicleID].getIcon().iconUrl
                if (!beforeIconUrl.includes(image)) {
                    let newIcon = L.icon({
                        iconUrl: `/image/${image}.png`,
                        iconSize,
                        iconAnchor
                    })
                    vehicles[vehicleID].setIcon(newIcon)
                }
                vehicles[vehicleID].setLatLng(vehiclePosition)
            } else {
                let icon = L.icon({
                    iconUrl: `/image/${image}.png`,
                    iconSize,
                    iconAnchor,
                })
                vehicles[vehicleID] = L.marker(vehiclePosition, {
                    icon: icon,
                    draggable: false,
                    rotationOrigin: 'center',
                    rotationAngle: 0,
                    zIndexOffset: 999
                }).addTo(map)
                vehicles[vehicleID].bindTooltip(`${vehicleID}`, {
                    permanent: true,
                    direction: 'center',
                }).openTooltip()
            }
            vehicles[vehicleID].options = Object.assign({}, vehicles[vehicleID].options, {
                vehicleHeading,
                vehicleLongtitude,
                vehicleLatitude
            })
            if (vehicleID === deviceId.value) {
                currentPosition = vehiclePosition
                if (navigate.value) {
                    if (vehicleHeading !== currentRotation.value) {
                        rotateVehicles(vehicleHeading)
                    }
                    currentRotation.value = vehicleHeading
                    dealMapRotate(vehicleHeading, vehiclePosition, zoom <= MAP_ZOOM ? MAP_ZOOM : zoom)
                    vehicles[vehicleID].setRotation(0)
                } else {
                    // 再不旋转地图的情况下，需要旋转车辆本身(弧度)
                    vehicles[vehicleID].setRotation(-vehicleHeading + currentRotation.value)
                }
            } else {
                // 非本车
                vehicles[vehicleID].setRotation(-vehicleHeading + currentRotation.value)
            }
        }
    }

    function dealSingleDatas(datas) {
        const { color, coor } = datas
        let path = L.polyline(coor, {
            color,
        }).addTo(map)
        singlePaths.push(path)
    }

    function dealObtacleData(value) {
        if (obstaclePolygons.length) {
            obstaclePolygons.forEach(item => map.removeLayer(item))
            obstaclePolygons = []
        }
        if (value && value.length) {
            for (let i = 0; i < value.length; i++) {
                let obstacle = value[i]
                let { typeColor, coordinate, centerLon, centerLat, centerRadius, centerColor } = obstacle
                let obstaclePolygon = L.polygon(JSON.parse(JSON.stringify(coordinate)), { color: typeColor }).addTo(map)
                let point = turf.point([centerLon, centerLat])
                let obstacleBuffer = turf.buffer(point, centerRadius, { units: "meters" })
                let obstacleCircle = L.geoJSON(obstacleBuffer, {
                    style: () => {
                        return {
                            color: centerColor,
                            fillOpacity: .5
                        }
                    }
                }).addTo(map)
                obstaclePolygons.push(obstacleCircle)
                obstaclePolygons.push(obstaclePolygon)
            }
        }
    }

    function dealDynamicDatas(datas) {
        let name='dynamicLine';
        if (mapLayers[name]) {
            map.removeLayer(mapLayers[name])
            delete mapLayers[name]
        }
        // if (dynamicPaths.length) {
        //     dynamicPaths.forEach(item => map.removeLayer(item))
        //     dynamicPaths = []
        // }
        const { color, path } = datas
        let pathNew = L.polyline(path, {
            color,
            opacity:0.3,
            weight:30,
        }).addTo(map)
        mapLayers[name] = pathNew
        mapLayers[name].bringToFront()
        // dynamicPaths.push(pathNew)
    }

    // 直接监听props.isShowBasic 不会触发
    watch(() => props.isShowBasic, () => {
        nextTick(() => {
            map.invalidateSize(true)
        })
    })

    watch(lanenode, (value) => {
        dealDivIcon(value, 'lanenode', '#ff0000')
    }, {immediate: true, deep: true})

    watch(lane, (value) => {
        dealMapLayer(value, '#fff', 'lane')
    }, {immediate: true, deep: true})

    watch(runablearea, (value) => {
        dealMapLayer(value, '#98a0a0', 'runablearea')
    }, {immediate: true, deep: true})

    watch(centerline, (value) => {
        dealMapLayer(value, '#eee', 'centerline')
    }, {immediate: true, deep: true})

    watch(obstacles, (value) => {
        dealDivIcon(value, 'obstacles')
        dealMapLayer(value, '#6f9bdd', 'obstacles')
    }, {immediate: true, deep: true})

    watch(diggingworkarea, (value) => {
        dealDivIcon(value, 'diggingworkarea')
        dealMapLayer(value, '#886e26', 'diggingworkarea')
    }, {immediate: true, deep: true})

    watch(dumparea, (value) => {
        dealDivIcon(value, 'dumparea')
        dealMapLayer(value, '#886e26', 'dumparea')
    }, {immediate: true, deep: true})

    watch(barricade, (value) => {
        dealMapLayer(value, '#0000ff', 'barricade')
    }, {immediate: true, deep: true})

    watch(stationarea, (value) => {
        dealDivIcon(value, 'stationarea')
        dealMapLayer(value, '#90ee90', 'stationarea')
    }, {immediate: true, deep: true})

    watch(parkspot, (value) => {
        dealDivIcon(value, 'parkspot')
        dealMapLayer(value, '#7e8185', 'parkspot')
    }, {immediate: true, deep: true})

    watch(staticobjs, (value) => {
        dealMapLayer(value, '#98a0a0', 'staticobjs')
    }, {immediate: true, deep: true})

    watch(electronicFence, (value) => {
        dealDivIcon(value, 'electronicFence')
        dealMapLayer(value, '#d51d20', 'electronicFence')
    }, {immediate: true, deep: true})

    watch(nextPathinfo, (value) => {
        dealMapPath(value, 'nextPath', nextPathAvailable.value === 1 ? '#19ae19' : '#8B4513')
        adjustmentLayer()
    }, {immediate: true, deep: true})

    watch(currPathinfo, (value) => {
        dealMapPath(value, 'currentPath', '#19ae19')
        adjustmentLayer()
    }, {immediate: true, deep: true})

    watch(avoidancePath, (value) => {
        dealMapPath(value, 'avoidancePath', 'blue')
    }, {immediate: true, deep: true})

    watch(vehiclesPositioninfo, (value) => {
        dealVehiclePosition(value)
    }, {
        immediate: true,
        deep: true
    })

    watch(safeObj, (value) => {
        Object.keys(value).forEach(item => {
            dealSafe(item, value[item])
        })
    }, {
        immediate: true,
        deep: true
    })

    watch(trajObj, (value) => {
        Object.keys(value).forEach(item => {
            dealTraj(item, value[item])
        })
    }, {
        immediate: true,
        deep: true
    })

    watch(obstacleData, (value) => {
        dealObtacleData(value)
    }, {immediate: true, deep: true})

    watch(deleteVehicles, (data) => {
        if (!map) return
        if (data && data.length) {
            data.forEach(item => {
                map.removeLayer(vehicles[item])
                removeLayer(safeTrajs, item)
                removeLayer(safeObjects, item)
                delete vehicles[item]
            })
        }
    }, {
        immediate: true
    })

    watch(() => props.clearSinglePointEnable, (enable) => {
        if (!enable) return
        isSinglePreview.value = true
        singlePaths.forEach(item => map.removeLayer(item))
    }, {deep: true})

    watch([morepoint, morepath], (pointData, pathData) => {
        if (isSinglePreview.value && (pointData || pathData)) {
            let datas = pointData.concat(pathData)
            for (let i = 0; i < datas.length; i++) {
                dealSingleDatas(datas[i])
            }
        }
    }, {deep: true})

    watch(dynamicPathinfo, (pathData) => {
        if (pathData.length>0) {
            for(let i=0;i<pathData.length;i++) {
                dealDynamicDatas(pathData[i])
            } 
        }
    }, {deep: true})

    watch(deviceId, (value) => {
        if (value && map) {
            dealMapRotate(currentRotation.value, currentPosition, map.getZoom())
        }
    }, {deep: true})

    function doUnmount() {
        Object.keys(mapLayers).map(layer => map.removeLayer(mapLayers[layer]))
        let mapDom = root.value
        mapDom.removeEventListener('mousedown', changeMouseDown)
        mapDom.removeEventListener('mousemove', changeMouseMove)
        mapDom.removeEventListener('mouseup', changeMouseUp)

        map.remove()
        map = null
    }

    watch(() => props.reloadData, (value) => {
        if (value) {
            doUnmount()
        }
    })

    onBeforeUnmount(() => {
        doUnmount()
    })
</script>

<style lang="less" scope>
.map-contain {
    height: 100%;
    overflow: hidden;
}
#map {
    width: 200%;
    height: 200%;
    top: -50%;
    left: -50%;
    background: #171A23;
    position: relative;
}

.navigate-preview {
    background: #4A75A9;
    box-shadow: 0px 0px 10px 0px rgba(0, 0, 0, 0.25);
    border-radius: 10px;
    opacity: 1;
    display: flex;
    align-items: center;
    justify-content: center;
}

.compass,
.navigate-preview {
    position: absolute;
    width: 4vw;
    height: 4vw;
    z-index: 999;
}

.compass {
    bottom: 88px;
    max-width: 60px;
    max-height: 60px;
}

.navigate-preview {
    bottom: 24px;
    max-width: 60px;
    max-height: 60px;
}
</style>
<style lang="less">
.icon-node {
    width: 120px !important;
    white-space: nowrap;
    color: #676565;
    // padding-left: -2em !important;
    z-index: 1;
    font-size: 12px !important;
    font-family: "Open Sans Regular", "Arial Unicode MS Regular", sans-serif;
    text-transform: uppercase;
    text-align: center;
    -webkit-text-stroke-display: block;
    -webkit-text-stroke-width: 1px;
    -webkit-text-stroke-color: rgba(33, 33, 33, 0.8);
}

@media screen and (min-width: 1700px) {
    .icon-node {
        font-size: 18px !important;
    }
}

.icon-node-name {
    display: inline-block;
    transform: scale(.6);
    padding-left: -20px !important;
}

.hide {
    display: none !important;
}

.middle-line {
    // 为svg设置虚线,数字越大,虚线段越长,
    // 设置2个参数,参数1: 虚线的长度  参数2: 虚线和虚线之间的间隔, 如果只设置一个参数,说明两个值一样大小
    stroke-dasharray: 15 20;
    z-index: 999;
}

.leaflet-tooltip {
    color: #fff !important;
    background-color: rgba(255, 255, 255, 0) !important;
    border: 0 !important;
    box-shadow: rgba(0, 0, 0, 0);
    font-size: 12px !important;
}

.leaflet-control-attribution {
    display: none !important;
}</style>