index.vue 4.64 KB
<template>
  <div class="chart-amap" ref="vChartRef"></div>
</template>

<script setup lang="ts">
import { ref, PropType, toRefs, watch } from 'vue'
import AMapLoader from '@amap/amap-jsapi-loader'
import { CreateComponentType } from '@/packages/index.d'
import { useChartDataFetch } from '@/hooks'
import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
import { ThemeEnum, mapOption } from './config'

const props = defineProps({
  chartConfig: {
    type: Object as PropType<CreateComponentType>,
    required: true
  }
})

const {
  amapKey,
  amapStyleKey,
  amapLon,
  amapLat,
  amapZindex,
  lang,
  amapStyleKeyCustom,
  features,
  viewMode,
  pitch,
  skyColor,
  lineColor,
  lineWidth,
  iconMarker,
  lineOpacity,
  lineShowDir
} = toRefs(props.chartConfig.option.mapOptions)

//官方没有高德地图api的ts,所以关于官方api,类型全用的any
let mapIns: any = null

let AMapIns: any = null

let marker: any = null

let polyLine: any = null
//

const vChartRef = ref<HTMLElement>()

const viewControlPaths = ref<number[][]>([])

const initAMap = (newData: mapOption) => {
  // 地图初始化
  AMapLoader.load({
    key: amapKey.value, //api服务key--另外需要在public中使用安全密钥!!!
    version: '2.0', // 指定要加载的 JSAPI 的版本,缺省时默认为 1.4.15
    plugins: ['AMap.ToolBar', 'AMap.Scale', 'AMap.PlaceSearch', 'AMap.AutoComplete', 'AMap.MoveAnimation'] // 需要使用的的插件列表
  })
    .then(AMap => {
      AMapIns = AMap
      mapIns = new AMap.Map(vChartRef.value, {
        resizeEnable: true,
        zoom: amapZindex.value, // 地图显示的缩放级别
        center: [amapLon.value, amapLat.value],
        lang: lang.value,
        features: features.value,
        pitch: pitch.value, // 地图俯仰角度,有效范围 0 度- 83 度
        skyColor: skyColor.value,
        viewMode: viewMode.value, // 地图模式
        willReadFrequently: true,
        buildingAnimation: true, //楼块出现是否带动画
        WebGLParams: {
          preserveDrawingBuffer: true
        }
      })
      let satellite = new AMap.TileLayer.Satellite()
      let roadNet = new AMap.TileLayer.RoadNet()
      if (newData.amapStyleKey === ThemeEnum.WEIXIN) {
        mapIns.add([satellite, roadNet])
      } else {
        mapIns.remove([satellite, roadNet])
        mapIns.setMapStyle(
          `amap://styles/${amapStyleKeyCustom.value !== '' ? amapStyleKeyCustom.value : amapStyleKey.value}`
        )
      }
      //实例化地图marker
      marker = new AMap.Marker({
        map: mapIns,
        position: [104.03, 30.39],
        icon: new AMap.Icon({
          image: iconMarker.value,
          size: new AMap.Size(32, 32), //图标大小
          imageSize: new AMap.Size(26, 26)
        }),
        offset: new AMap.Pixel(-13, -26)
      })
      //实例化地图线段
      polyLine = new AMapIns.Polyline({
        map: mapIns,
        strokeColor: lineColor.value, //线颜色
        strokeWeight: lineWidth.value, //线宽
        strokeOpacity: lineOpacity.value, //线透明度
        showDir: lineShowDir.value, //是否延路径显示白色方向箭头
      })
    })
    .catch(e => {
      console.error(e)
    })
}

// 绘制轨迹
const renderLocaLayerLine = (linePoints: number[][]) => {
  polyLine.setPath(linePoints)
  //marker移动直接获取最后坐标点
  handleMarkerMove([[linePoints.flat().at(-2), linePoints.flat().at(-1)]] as number[][])
}

//marker移动
const handleMarkerMove = (linePoints: number[][]) => {
  marker.setPosition(linePoints[0])
  mapIns.setFitView()
}

const stopWatch = watch(
  () => props.chartConfig.option.mapOptions,
  (option: mapOption) => {
    initAMap(option)
  },
  {
    immediate: true,
    deep: true
  }
)

// 预览
useChartDataFetch(props.chartConfig, useChartEditStore, newData => {
  const { data } = newData
  // 不是结构体
  if (Reflect.get(data, 'longitude') && Reflect.get(data, 'latitude')) {
    //必须有经纬度
    for (let _ in data) {
      //由于上报的是固定格式,所有直接获取对应索引值
      viewControlPaths.value.push([Number(data['longitude'][0][1]), Number(data['latitude'][0][1])])
    }
    renderLocaLayerLine(viewControlPaths.value)
  } else {
    // 序列化获取里面的经纬度
    const values = Object.values(data) as string[][]
    const serializeValue = JSON.parse(values[0][0][1])
    const { longitude, latitude } = serializeValue
    viewControlPaths.value.push([Number(longitude), Number(latitude)])
    renderLocaLayerLine(viewControlPaths.value)
  }
  stopWatch()
})
</script>

<style lang="scss" scoped>
.chart-amap {
  position: relative;
  height: 100%;
  width: 100%;
}
</style>