index.vue 5.64 KB
<template>
  <div>
    <div class="chart-amap" ref="vChartRef"></div>
    <div class="map-action-card">
      <n-card :title="t('common.historyAction.title')">
        <n-space>
          <n-button @click="handleStartAnimation">{{ t('common.historyAction.startAnimation') }}</n-button>
          <n-button @click="handlePauseAnimation">{{ t('common.historyAction.pauseAnimation') }}</n-button>
        </n-space>
        <div style="height: 1rem"></div>
        <n-space>
          <n-button @click="handleResumeAnimation">{{ t('common.historyAction.resumeAnimation') }}</n-button>
          <n-button @click="handleStopAnimation">{{ t('common.historyAction.stopAnimation') }}</n-button>
        </n-space>
      </n-card>
    </div>
  </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 t = window['$t']

const {
  amapKey,
  amapStyleKey,
  amapLon,
  amapLat,
  amapZindex,
  lang,
  amapStyleKeyCustom,
  features,
  viewMode,
  pitch,
  skyColor,
  lineColor,
  lineWidth,
  iconMarker,
  lineDuration,
  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

let passedPolyline: any = null
//

const vChartRef = ref<HTMLElement>()

const linePoints = 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 //线宽
      })
      //实例化地图线段
      passedPolyline = new AMapIns.Polyline({
        map: mapIns,
        strokeColor: lineColor.value, //线颜色
        strokeWeight: lineWidth.value, //线宽
        strokeOpacity: lineOpacity.value, //线透明度
        showDir: lineShowDir.value, //是否延路径显示白色方向箭头
        lineCap: 'square' //是否延路径显示白色方向箭头
      })
    })
    .catch(e => {
      console.error(e)
    })
}

// 绘制轨迹
const renderLocaLayerLine = () => {
  polyLine?.setPath(linePoints.value)
}

//marker移动
const handleMarkerMove = () => {
  marker.on('moving', function (e: Recordable) {
    passedPolyline?.setPath(e.passedPath)
    // 设置地图中心点
    // mapIns.setCenter(e.target.getPosition())
    // 设置旋转角
    // mapIns.setRotation(-e.target.getOrientation())
  })
  mapIns.setFitView()
}

//开启动画
const handleStartAnimation = () => {
  renderLocaLayerLine()
  marker.moveAlong(linePoints.value, {
    // 每一段的时长
    duration: lineDuration.value,
    // JSAPI2.0 是否延道路自动设置角度在 moveAlong 里设置
    autoRotation: true
  })
  handleMarkerMove()
}

//暂停动画
const handlePauseAnimation = () => marker.pauseMove()

//继续动画
const handleResumeAnimation = () => marker.resumeMove()

//停止动画
const handleStopAnimation = () => marker.stopMove()

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

// 预览
useChartDataFetch(props.chartConfig, useChartEditStore, newData => {
  //这里是坐标集数据
  linePoints.value = newData
  stopWatch()
})
</script>

<style lang="scss" scoped>
.chart-amap {
  position: relative;
  height: 100%;
  width: 100%;
}
.map-action-card {
  z-index: 1;
  position: absolute;
  bottom: 1.5rem;
  right: 1.5rem;
}
</style>