qiuxiang / react-native-amap3d

react-native 高德地图组件,使用最新 3D SDK,支持 Android + iOS
https://qiuxiang.github.io/react-native-amap3d/api/
MIT License
1.28k stars 327 forks source link

有没有什么方法能在可视范围内显示所有覆盖物 #770

Open ShaoGongBra opened 1 year ago

ShaoGongBra commented 1 year ago

就是能计算是一个缩放级别能把所有的覆盖物显示出来

Dwyaneluo commented 1 year ago

同求展示所有标记点

ShaoGongBra commented 1 year ago

后面我找了个方法,可以计算出合适的缩放级别和中心点

Dwyaneluo commented 1 year ago

什么方法,可以参考下吗?

ShaoGongBra commented 1 year ago

这是个显示轨迹的页面

import { useEffect, useState, useMemo, useCallback, useRef } from 'react'
import { View, Text, Image } from '@tarojs/components'
import { useRouter } from '@tarojs/taro'
import { TopView, Header, Icon, Map, Calendar, Layout } from '@/components'
import { dateToStr, request, useDevice, loading, gcjEncrypt, toast, distance } from '@/utils'
import pointBlue from './images/point-blue.png'
import pointGreen from './images/point-green.png'
import pointOrange from './images/point-orange.png'
import './track.scss'

export default function Fence() {

  const { params } = useRouter()

  const deviceInfo = useDevice(params.id)

  const [dateMore, setDateMore] = useState(false)

  const [day, setDay] = useState(dateToStr('yyyy-MM-dd'))

  const [polyline, setPolyline] = useState([])

  const [startEnd, setStartEnd] = useState([])

  const [playIndex, setPlayIndex] = useState(-1)

  const [center, setCenter] = useState(null)

  const [zoom, setZoom] = useState(18)

  useEffect(() => {
    // 请求路径数据
    request({
      url: 'device/watchData/gps',
      loading,
      toast: true,
      data: {
        family_id: deviceInfo.familyId,
        id: deviceInfo.id,
        date: day
      }
    }).then(res => {
      if (timer.current) {
        clearInterval(timer.current)
        timer.current = null
        setPlayIndex(-1)
      }
      const range = {
        maxLng: 0,
        minLng: 200,
        maxLat: 0,
        minLat: 90,
      } // 最小纬度 最大纬度 最小经度 最大经度
      const _list = res.filter(v => v.lat && v.lng).map(item => {
        const { lat, lon } = gcjEncrypt(item.lat, item.lng)
        if (lat > range.maxLat) {
          range.maxLat = lat
        }
        if (lat < range.minLat) {
          range.minLat = lat
        }
        if (lon > range.maxLng) {
          range.maxLng = lon
        }
        if (lon < range.minLng) {
          range.minLng = lon
        }
        return { lat, lng: lon, time: item.time.substr(11, 5) }
      })

      if (_list.length > 1) {
        setTimeout(() => {
          // 计算两点之间的距离
          const rangeDistance = distance(range.minLat, range.minLng, range.maxLat, range.maxLng)
          // 求出地图容器的对角线长度
          const nowDivLine = Math.sqrt(mapLayout.current.width * mapLayout.current.width + mapLayout.current.height * mapLayout.current.height)
          // 求出覆盖物范围和地图容器的比例
          const nowScale = rangeDistance / nowDivLine
          // 求出可以显示出所有覆盖物的级别
          const nowNum = 16 - Math.ceil(Math.log(nowScale) / Math.log(2))
          setZoom(nowNum)
          setCenter([(range.minLng + range.maxLng) / 2, (range.minLat + range.maxLat) / 2])
        }, 500)
        setStartEnd([_list[0], _list[_list.length - 1]])
      } else if (_list.length) {
        setCenter([_list[0].lng, _list[0].lat])
      }
      setPolyline(_list)
      polylineData.current = _list
    })
  }, [day, deviceInfo.familyId, deviceInfo.id])

  const polylines = useMemo(() => {
    return polyline.length ? [{
      colors: ['#4caf50'],
      points: polyline
    }] : []
  }, [polyline])

  const timer = useRef(null)

  const polylineData = useRef([])

  const markers = useMemo(() => {
    if(~playIndex) {
      const item = polylineData.current[playIndex]
      return [{
        ...item,
        children: <View className='track-point'>
          <View className='track-point__time'>{item.time}</View>
          <View className='track-point__icon'>
            <Image className='track-point__image' src={pointOrange} />
            <Text className='track-point__text'>此</Text>
          </View>
        </View>
      }]
    } else if (startEnd.length) {
      return startEnd.map((item, index) => {
        return {
          ...item,
          children: <View className='track-point'>
            <View className='track-point__time'>{item.time}</View>
            <View className='track-point__icon'>
              <Image className='track-point__image' src={index ? pointBlue : pointGreen} />
              <Text className='track-point__text'>{index ? '终' : '起'}</Text>
            </View>
          </View>
        }
      })
    }
    return []
  }, [playIndex, startEnd])

  useEffect(() => {
    const _timer = timer
    return () => {
      if (_timer.current) {
        clearInterval(_timer.current)
      }
    }
  }, [])

  const mapLayout = useRef({})
  const layout = useCallback(e => {
    mapLayout.current = e
  }, [])

  const play = useCallback(() => {
    if (timer.current) {
      return
    }
    if (polylineData.current?.length < 2) {
      return toast('轨迹过少 无法播放')
    }
    let i = 0
    const item = polylineData.current[0]
    setPlayIndex(i)
    // setCenter([item.lng, item.lat])
    setPolyline([item])
    timer.current = setInterval(() => {
      i++
      const _item = polylineData.current[i]
      if (!_item) {
        clearInterval(timer.current)
        setPlayIndex(-1)
        timer.current = null
        return toast('播放完毕')
      }
      // setCenter([_item.lng, _item.lat])
      setPolyline(old => [...old, _item])
      setPlayIndex(i)
    }, 1500)
  }, [])

  return <TopView>
    <Header title='历史轨迹' rightRender={<Text onClick={play}>播放</Text>} />
    <View className='track-date'>
      <Calendar onlyCurrentWeek={!dateMore} value={day} onChange={setDay} />
      <View className='track-date__more' onClick={() => setDateMore(!dateMore)}>
        <Text className='track-date__more__text'>{dateMore ? '收起' : '展开'}</Text>
        <Icon name={dateMore ? 'shang3' : 'xia1'} />
      </View>
    </View>
    <Layout className='track-map' onLayout={layout}>
      <Map
        center={center}
        polylines={polylines}
        markers={markers}
        zoom={zoom}
      />
    </Layout>
  </TopView>
}
Dwyaneluo commented 1 year ago

谢谢,我明白你的计算思路了。