最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

基于Vue3+ECharts實(shí)現(xiàn)動(dòng)態(tài)地圖切換與平滑過(guò)渡的動(dòng)畫效果

 更新時(shí)間:2025年08月06日 10:09:53   作者:CF14年老兵  
本文基于Vue3與ECharts5,實(shí)現(xiàn)市級(jí)地圖展示及區(qū)縣視圖切換,通過(guò)universalTransition和Canvas圖像處理技術(shù),打造平滑動(dòng)畫與區(qū)域高亮效果,結(jié)合響應(yīng)式布局與交互優(yōu)化提升用戶體驗(yàn),需要的朋友可以參考下

本文將詳細(xì)解析如何使用 Vue3 和 ECharts 實(shí)現(xiàn)市級(jí)地圖展示功能,并添加地圖切換時(shí)的平滑過(guò)渡動(dòng)畫效果。

  1. 使用 ECharts 的 universalTransition 實(shí)現(xiàn)地圖切換動(dòng)畫
  2. 通過(guò) Canvas 動(dòng)態(tài)處理圖像實(shí)現(xiàn)區(qū)域高亮效果
  3. 設(shè)計(jì)響應(yīng)式布局確保地圖適應(yīng)不同屏幕尺寸
  4. 實(shí)現(xiàn)層級(jí)導(dǎo)航和交互反饋提升用戶體驗(yàn)

功能概述

本組件實(shí)現(xiàn)了一個(gè)具有以下特性的地圖展示系統(tǒng):

  1. 展示河南省周口市行政區(qū)劃地圖
  2. 點(diǎn)擊地圖區(qū)域可切換到區(qū)縣級(jí)別視圖
  3. 地圖切換時(shí)帶有平滑的過(guò)渡動(dòng)畫
  4. 自定義地圖樣式和交互效果
  5. 響應(yīng)式布局適應(yīng)不同屏幕尺寸

技術(shù)棧

  • Vue3(Composition API)
  • ECharts 5
  • TypeScript
  • Canvas 圖像處理

核心功能實(shí)現(xiàn)

1. 組件結(jié)構(gòu)與依賴

<template>
  <div id="mapChart" class="mt-4 w-full" ref="mapChartRef"></div>
</template>

<script setup lang="ts">
import * as echarts from 'echarts';
import mapBgImgSrc from '@/assets/images/map-bg.png';
import geoData from '@/assets/jeo/jeoMap.json';
import { ref, onMounted, nextTick } from 'vue';

// 組件引用和數(shù)據(jù)
const mapChartRef = ref<HTMLElement | null>(null);
const selectDistrictVal = ref('zhoukou'); // 當(dāng)前選中的地區(qū)
let myChart: echarts.ECharts | null = null; // ECharts實(shí)例

2. 動(dòng)態(tài)創(chuàng)建遮罩背景圖

// 創(chuàng)建帶遮罩的背景圖像(用于高亮區(qū)域)
function createMaskedBgImg(src: string, maskColor = 'rgba(0,0,0,0.1)'): Promise<string> {
  return new Promise((resolve) => {
    const img = new Image();
    img.src = src;
    const canvas = document.createElement('canvas');
    
    img.onload = () => {
      canvas.width = img.width;
      canvas.height = img.height;
      const ctx = canvas.getContext('2d')!;
      
      // 繪制原始圖像
      ctx.drawImage(img, 0, 0);
      
      // 添加遮罩層
      ctx.fillStyle = maskColor;
      ctx.fillRect(0, 0, img.width, img.height);
      
      resolve(canvas.toDataURL());
    };
    
    img.onerror = () => resolve(src); // 失敗時(shí)返回原圖
  });
}

3. 地圖配置生成器

// 生成ECharts地圖配置
const getMapOption = (mapType = 'zhoukou', maskedBgImg = mapBgImgSrc) => {
  // 從GeoJSON數(shù)據(jù)中提取當(dāng)前區(qū)域
  const feature = geoData.features.find(
    (f: any) => f.properties.name === mapType
  );
  
  const mapGeoData = mapType === 'zhoukou' 
    ? geoData 
    : { 
        type: 'FeatureCollection', 
        features: feature ? [feature] : [] 
      };
  
  // 注冊(cè)地圖數(shù)據(jù)
  echarts.registerMap('zhoukou', mapGeoData as any);
  
  return {
    // 動(dòng)畫配置
    animation: true,
    animationDuration: 800,
    animationEasing: 'cubicOut' as any,
    animationDurationUpdate: 800,
    animationEasingUpdate: 'cubicOut' as any,
    
    // 標(biāo)題
    title: {
      top: 10,
      text: mapType === 'zhoukou' ? '河南省 - 周口市' : `周口市 - ${mapType}`,
      x: 'center',
      textStyle: {
        color: '#2564AD',
        fontWeight: 600,
        fontSize: 16
      }
    },
    
    // 地理坐標(biāo)系配置
    geo: {
      map: 'zhoukou',
      aspectScale: 0.8,
      layoutCenter: ['50.6%', '51%'],
      layoutSize: '91.5%',
      roam: false,
      z: 0,
      itemStyle: {
        areaColor: '#2564AD',
        borderColor: '#2564AD',
        borderWidth: 1
      }
    },
    
    // 地圖系列
    series: [{
      type: 'map',
      map: 'zhoukou',
      universalTransition: { 
        enabled: true, 
        divideShape: 'clone'  // 關(guān)鍵:?jiǎn)⒂眯螤罘指顒?dòng)畫
      },
      zoom: 1.2,
      itemStyle: {
        areaColor: { image: mapBgImgSrc, repeat: 'repeat' },
        borderColor: '#80AACC',
        borderWidth: 2
      },
      emphasis: { // 鼠標(biāo)懸停樣式
        itemStyle: {
          areaColor: { image: maskedBgImg, repeat: 'repeat' },
          borderColor: '#80AACC'
        },
        label: { color: '#409eff', fontWeight: 'bold' }
      },
      select: { // 選中區(qū)域樣式
        itemStyle: {
          areaColor: { image: maskedBgImg, repeat: 'repeat' },
          borderColor: '#80AACC'
        },
        label: { color: '#409eff', fontWeight: 'bold' }
      },
      label: { // 區(qū)域標(biāo)簽
        show: true,
        color: '#80AACC',
        fontWeight: 'bold'
      }
    }]
  };
};

4. 地圖初始化與交互

// 初始化地圖
const initMap = async () => {
  if (!mapChartRef.value) return;
  
  // 創(chuàng)建ECharts實(shí)例
  myChart = echarts.init(mapChartRef.value);
  
  // 創(chuàng)建遮罩背景圖
  const maskedBgImg = await createMaskedBgImg(
    mapBgImgSrc, 
    'rgba(0,0,0,0.1)'
  );
  
  // 設(shè)置初始配置
  myChart.setOption(getMapOption('zhoukou', maskedBgImg), false);
  
  // 添加點(diǎn)擊事件處理
  myChart.on('click', function (e: any) {
    if (!e.name || typeof e.name !== 'string') return;
    
    // 只有在地級(jí)市視圖時(shí)才能點(diǎn)擊進(jìn)入?yún)^(qū)縣
    if (selectDistrictVal.value === 'zhoukou') {
      myChart.setOption(getMapOption(e.name, maskedBgImg), false);
      selectDistrictVal.value = e.name;
    }
  });
};

// 響應(yīng)式調(diào)整地圖尺寸
const setMapView = async () => {
  await nextTick();
  if (mapChartRef.value?.parentNode) {
    const parentHeight = mapChartRef.value.parentNode.offsetHeight;
    const siblingHeight = mapChartRef.value.previousSibling?.offsetHeight || 0;
    mapChartRef.value.style.height = `${parentHeight - siblingHeight - 16}px`;
  }
  
  // 窗口大小變化時(shí)重繪
  window.addEventListener('resize', () => {
    myChart?.resize();
  });
};

// 組件掛載時(shí)初始化
onMounted(async () => {
  await setMapView();
  initMap();
});

// 暴露外部控制方法
defineExpose({
  getCurrentDistrict: () => selectDistrictVal.value,
  
  setDistrict: async (district: string) => {
    selectDistrictVal.value = district;
    const maskedBgImg = await createMaskedBgImg(
      mapBgImgSrc, 
      'rgba(0,0,0,0.1)'
    );
    myChart?.setOption(getMapOption(district, maskedBgImg), false);
  }
});
</script>

關(guān)鍵技術(shù)與優(yōu)化點(diǎn)

1. 平滑過(guò)渡動(dòng)畫實(shí)現(xiàn)

通過(guò)以下配置實(shí)現(xiàn)地圖切換時(shí)的平滑動(dòng)畫效果:

// 關(guān)鍵動(dòng)畫配置
universalTransition: { 
  enabled: true, 
  divideShape: 'clone'  // 形狀分割動(dòng)畫
},
animationDuration: 800,
animationEasing: 'cubicOut',
animationDurationUpdate: 800,
animationEasingUpdate: 'cubicOut'

universalTransition 是 ECharts 5 引入的強(qiáng)大功能,它允許在數(shù)據(jù)更新時(shí)自動(dòng)生成過(guò)渡動(dòng)畫,特別適合地理區(qū)域的切換。

2. Canvas 動(dòng)態(tài)圖像處理

使用 Canvas 動(dòng)態(tài)生成帶遮罩的背景圖,實(shí)現(xiàn)區(qū)域高亮效果:

// 創(chuàng)建帶遮罩的背景圖
ctx.drawImage(img, 0, 0); // 繪制原圖
ctx.fillStyle = maskColor; // 設(shè)置遮罩顏色
ctx.fillRect(0, 0, img.width, img.height); // 繪制遮罩層

3. 響應(yīng)式布局處理

// 動(dòng)態(tài)計(jì)算地圖容器高度
const parentHeight = mapChartRef.value.parentNode.offsetHeight;
const siblingHeight = mapChartRef.value.previousSibling?.offsetHeight || 0;
mapChartRef.value.style.height = `${parentHeight - siblingHeight - 16}px`;

// 監(jiān)聽(tīng)窗口大小變化
window.addEventListener('resize', () => {
  myChart?.resize();
});

4. 交互體驗(yàn)優(yōu)化

  • 層級(jí)導(dǎo)航:只能從市級(jí)視圖進(jìn)入?yún)^(qū)縣視圖,防止無(wú)限深入
  • 視覺(jué)反饋:懸停和選中狀態(tài)有明顯樣式變化
  • 標(biāo)題動(dòng)態(tài)更新:根據(jù)當(dāng)前視圖級(jí)別顯示不同標(biāo)題
  • 性能優(yōu)化:使用 false 參數(shù)避免不必要的重繪
myChart.setOption(getMapOption(e.name, maskedBgImg), false);

使用示例

在父組件中使用地圖組件

<template>
  <div class="container">
    <h1>河南省行政區(qū)劃地圖</h1>
    <div class="controls">
      <button @click="backToCity">返回市級(jí)視圖</button>
      <select v-model="selectedDistrict" @change="changeDistrict">
        <option value="zhoukou">周口市</option>
        <option value="taikang">太康縣</option>
        <option value="huaiyang">淮陽(yáng)縣</option>
        <!-- 其他區(qū)縣選項(xiàng) -->
      </select>
    </div>
    <MapComponent ref="mapRef" />
  </div>
</template>

<script setup lang="ts">
import { ref } from 'vue';
import MapComponent from './MapComponent.vue';

const mapRef = ref();
const selectedDistrict = ref('zhoukou');

// 切換區(qū)縣
const changeDistrict = () => {
  mapRef.value.setDistrict(selectedDistrict.value);
};

// 返回市級(jí)視圖
const backToCity = () => {
  selectedDistrict.value = 'zhoukou';
  mapRef.value.setDistrict('zhoukou');
};
</script>

總結(jié)

以上就是基于Vue3+ECharts實(shí)現(xiàn)動(dòng)態(tài)地圖切換與平滑過(guò)渡的動(dòng)畫效果的詳細(xì)內(nèi)容,更多關(guān)于Vue3 ECharts地圖切換與平滑過(guò)渡的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • vue中axios封裝使用的完整教程

    vue中axios封裝使用的完整教程

    這篇文章主要給大家介紹了關(guān)于vue中axios封裝使用的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2021-03-03
  • vue登錄成功之后的token處理詳細(xì)步驟

    vue登錄成功之后的token處理詳細(xì)步驟

    Token是身份驗(yàn)證后服務(wù)端返回的令牌,常用于訪問(wèn)授權(quán)API和頁(yè)面權(quán)限校驗(yàn),Token數(shù)據(jù)可存儲(chǔ)在本地或Vuex中,本地存儲(chǔ)可實(shí)現(xiàn)數(shù)據(jù)持久化,這篇文章主要介紹了vue登錄成功之后的token處理詳細(xì)步驟,需要的朋友可以參考下
    2024-10-10
  • Vue2中實(shí)現(xiàn)輸入中文自動(dòng)轉(zhuǎn)化為拼音且不帶音調(diào)的實(shí)現(xiàn)方案

    Vue2中實(shí)現(xiàn)輸入中文自動(dòng)轉(zhuǎn)化為拼音且不帶音調(diào)的實(shí)現(xiàn)方案

    文章介紹了在Vue2中實(shí)現(xiàn)輸入中文自動(dòng)轉(zhuǎn)化為拼音且不帶音調(diào)的幾種方案,包括使用pinyin庫(kù)、自定義指令、計(jì)算屬性、帶防抖的優(yōu)化版本以及使用其他拼音庫(kù),推薦使用方案一和方案三,因其實(shí)現(xiàn)簡(jiǎn)單且易于維護(hù),感興趣的朋友跟隨小編一起看看吧
    2025-12-12
  • Vue中的組件詳談

    Vue中的組件詳談

    這篇文章主要介紹了Vue的組件,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-10-10
  • 關(guān)于vue-router的使用及實(shí)現(xiàn)原理

    關(guān)于vue-router的使用及實(shí)現(xiàn)原理

    這篇文章主要介紹了關(guān)于vue-router的使用及實(shí)現(xiàn)原理,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-06-06
  • vue實(shí)現(xiàn)數(shù)字滾動(dòng)效果

    vue實(shí)現(xiàn)數(shù)字滾動(dòng)效果

    這篇文章主要為大家詳細(xì)介紹了vue實(shí)現(xiàn)數(shù)字滾動(dòng)效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-06-06
  • Vue學(xué)習(xí)筆記進(jìn)階篇之過(guò)渡狀態(tài)詳解

    Vue學(xué)習(xí)筆記進(jìn)階篇之過(guò)渡狀態(tài)詳解

    本篇文章主要介紹了Vue學(xué)習(xí)筆記進(jìn)階篇之過(guò)渡狀態(tài)詳解,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-07-07
  • vue實(shí)現(xiàn)簡(jiǎn)易的計(jì)算器功能

    vue實(shí)現(xiàn)簡(jiǎn)易的計(jì)算器功能

    這篇文章主要為大家詳細(xì)介紹了vue實(shí)現(xiàn)簡(jiǎn)易的計(jì)算器功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-11-11
  • 詳解如何運(yùn)行vue項(xiàng)目

    詳解如何運(yùn)行vue項(xiàng)目

    這篇文章主要介紹了如何運(yùn)行vue項(xiàng)目,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-04-04
  • vue中使用scrollTo沒(méi)有效果的完美解決方法

    vue中使用scrollTo沒(méi)有效果的完美解決方法

    這篇文章主要介紹了在vue中使用scrollTo沒(méi)有效果的解決方法,本文給大家分享具體操作步驟,在這里需要注意scrollTo要作用在可滾動(dòng)的元素上,不然不生效,scrollTop就會(huì)一直為0,需要的朋友可以參考下
    2023-10-10

最新評(píng)論

乌审旗| 永年县| 舟山市| 旺苍县| 军事| 东港市| 溧水县| 泸西县| 涞源县| 永州市| 闽侯县| 嘉禾县| 阜宁县| 河南省| 肥城市| 晋江市| 阿拉善左旗| 和政县| 永兴县| 绥芬河市| 饶阳县| 博爱县| 齐河县| 马关县| 礼泉县| 周宁县| 永修县| 定边县| 台前县| 彭阳县| 青神县| 丽江市| 汤原县| 安徽省| 临高县| 武强县| 和林格尔县| 阳信县| 兴业县| 台北县| 阜新|