超酷炫!Vue + Cesium 打造深色地图特效,惊艳全场!

906 阅读4分钟

image.png

点击此处预览效果

各位掘友,大家好,我是 安大桃子。在当下数字化地图与地理信息蓬勃发展的浪潮里,WebGIS 技术成为关键力量。而 VueCesium 作为 WebGIS 开发中的 “黄金搭档”,一个凭借组件化优势让开发高效有序,一个专注地理空间渲染,呈现逼真地图。接下来,我将结合实际项目案例,为大家深度解析如何巧用 Vue、Cesium 以及相关 WebGIS 技术,攻克复杂地理数据可视化与交互难题,开启 WebGIS 开发进阶之路。

一、引言

在 GIS 开发领域,Cesium 是一款功能强大的开源 JavaScript 库,它赋予开发者创建高性能 3D 地球和地图的能力,让我们能够轻松搭建功能丰富、交互性强的地图应用。本文将详细介绍如何基于 Vue 和 Cesium 实现深色地图效果,带你打造极具科技感的地图场景。

二、项目概述

本项目旨在基于 Cesium 构建一个地图视图,并通过设置滤镜颜色等操作,实现深蓝色地图效果,满足特定的设计需求。

image.png

三、模板部分

在 Vue 模板中,我们仅需创建一个div元素,代码如下:

    <template> 
        <div id="cesiumContainer" class="fullSize"></div> 
    </template> 

div元素的idcesiumContainer,类名为fullSize,它将作为 Cesium 地图的容器,后续地图视图会被渲染在此容器内。

四、脚本部分

4.1 引入依赖

    <script setup lang="ts"> 
    import { onMounted, nextTick, ref, reactive } from 'vue'; 
    import * as Cesium from "cesium"; 
    import 'cesium/Source/Widgets/widgets.css'; 
    import AmapMercatorTilingScheme from '@/modules/AmapMercatorTilingScheme/AmapMercatorTilingScheme'; 
    </script>

这里引入了 Vue 的组合式 API 函数,如onMounted用于组件挂载后执行操作、nextTick用于在 DOM 更新后执行回调、refreactive用于状态管理。同时,引入 Cesium 库及其样式文件,还有自定义的AmapMercatorTilingScheme模块,该模块用于支持高德地图的瓦片方案,当然也可选用其他地图数据作为地图图层。

4.2 配置 Cesium

Cesium.Ion.defaultAccessToken = "your token"; 
const viewModel = reactive({ 
    brightness: 0, 
    contrast: 0, 
    hue: 0, 
    saturation: 0, 
    gamma: 0, 
}) 
let viewer: Cesium.Viewer | undefined; 
const filterColor = ref('#003690') 
const imageryLayers = ref() 
  • Cesium.Ion.defaultAccessToken:设置 Cesium 的访问令牌,用于访问相关资源。
  • viewModel:通过reactive创建响应式对象,存储地图的亮度、对比度等属性。
  • viewer:定义变量存储 Cesium 视图对象。
  • filterColor:用ref创建响应式引用,存储地图颜色过滤的初始值。
  • imageryLayers:用ref创建响应式引用,存储地图图层信息。

4.3 地图样式设置相关函数

4.3.1 setBlackMap函数

typescript

const setBlackMap = () => {
    let { red, blue, green } = hexColorToRgba(filterColor.value)
    console.log(red, blue, green)
    if (viewer)
        modifyMap(viewer, {
            //反色
            invertColor: true,
            brightness: 0.8,
            filterRGB: [red, green, blue],
            hue: 0.5,
            gamma: 0.2,
            contrast: 3,
            saturation: 1.5,
        });
}

此函数先调用hexColorToRgba将十六进制颜色转为 RGB 值,再调用modifyMap函数修改地图样式,从而实现深色地图效果。

4.3.2 modifyMap函数

    const modifyMap = (viewer: Cesium.Viewer, options: any) => {
        const baseLayer = viewer.imageryLayers.get(0)
        baseLayer.brightness = options.brightness || 0.6
        baseLayer.contrast = options.contrast || 1.8
        baseLayer.gamma = options.gamma || 0.3
        baseLayer.hue = options.hue || 1
        baseLayer.saturation = options.saturation || 0
        const baseFragShader = (viewer.scene.globe as any)._surfaceShaderSet
          .baseFragmentShaderSource.sources
        for (let i = 0; i < baseFragShader.length; i++) {
            const strS = 'color = czm_saturation(color, textureSaturation);\n#endif\n'
            let strT = 'color = czm_saturation(color, textureSaturation);\n#endif\n'
            if (options.invertColor) {
                strT += `
                    color.r = 1.0 - color.r;
                    color.g = 1.0 - color.g;
                    color.b = 1.0 - color.b;
                    `
            }
            if (options.filterRGB.length > 0) {
                strT += `
                    color.r = color.r * ${options.filterRGB[0]}.0/255.0;
                    color.g = color.g * ${options.filterRGB[1]}.0/255.0;
                    color.b = color.b * ${options.filterRGB[2]}.0/255.0;
                    `
            }
            baseFragShader[i] = baseFragShader[i].replace(strS, strT)
        }
        nextTick(() => {
            updateViewModel()
        })
    }

该函数依据传入的options对象,修改地图图层的亮度、对比度等属性,并通过修改着色器代码实现颜色反转和颜色过滤效果。最后利用nextTick在 DOM 更新后调用updateViewModel更新视图模型。

4.3.3 updateViewModel函数

    const updateViewModel = () => {
        if (imageryLayers?.value?.length > 0) {
            const layer = imageryLayers.value.get(0);
            viewModel.brightness = layer.brightness;
            viewModel.contrast = layer.contrast;
            viewModel.hue = layer.hue;
            viewModel.saturation = layer.saturation;
            viewModel.gamma = layer.gamma;
        }
    }

此函数用于更新viewModel中的地图属性值,确保视图模型与地图图层的属性保持同步。

4.3.4 hexColorToRgba函数

    const hexColorToRgba = (color: string) => {
        // 检查输入颜色是否以 "#" 开头
        if (!color.startsWith('#')) {
            throw new Error('Invalid hex color format. Color should start with "#".');
        }
        // 获取去掉 "#" 后的颜色值部分
        const hexValue = color.slice(1);
        // 根据颜色值长度确定是 RGB 还是 RGBA
        const isRgba = hexValue.length === 8;
        // 确保颜色值长度合法(6 或 8 位)
        if (hexValue.length!== 6 && hexValue.length!== 8) {
            throw new Error(`Invalid hex color length. Expected 6 or 8 characters, got ${hexValue.length}.`);
        }
        // 将十六进制颜色值转换为十进制整数
        const hexToInt = (hex: string) => parseInt(hex, 16);
        // 提取 RGB 分量
        const redHex = hexValue.substring(0, 2);
        const greenHex = hexValue.substring(2, 4);
        const blueHex = hexValue.substring(4, 6);
        const red = hexToInt(redHex);
        const green = hexToInt(greenHex);
        const blue = hexToInt(blueHex);
        // 如果是 RGBA,提取 Alpha 分量
        let alpha = 1;
        if (isRgba) {
            const alphaHex = hexValue.substring(6, 8);
            alpha = hexToInt(alphaHex);
        }
        return {
            red: red,
            green: green,
            blue: blue,
            alpha: alpha
        };
    };

该函数用于将十六进制颜色值转换为 RGB 或 RGBA 值,并对输入颜色值进行合法性检查。由于作者习惯使用十六进制颜色,在获取红绿蓝通道数值时需要此转换过程。

4.4 挂载阶段

    onMounted(() => {
        viewer = new Cesium.Viewer("cesiumContainer", {
            infoBox: false,
            selectionIndicator: false,
            sceneModePicker: false,
            animation: false,    //左下角的动画仪表盘
            baseLayerPicker: false,  //右上角的图层选择按钮
            geocoder: false,  //搜索框
            homeButton: false,  //home按钮
            timeline: false,    //底部的时间轴
            navigationHelpButton: false,  //右上角的帮助按钮,
            fullscreenButton: false,
            terrain: Cesium.Terrain.fromWorldTerrain(),
        });
        if (viewer.imageryLayers.length > 0)
            viewer.imageryLayers.removeAll();
        (viewer.cesiumWidget.creditContainer as HTMLElement).style.display = "none";
        let gdvMap = new Cesium.UrlTemplateImageryProvider({
            url: 'https://webrd02.is.autonavi.com/appmaptile?lang=zh_cn&size=1&scale=2&style=8&x={x}&y={y}&z={z}',
            tileWidth: 256,
            tileHeight: 256,
            tilingScheme: new AmapMercatorTilingScheme() as any,
            maximumLevel: 18, // 根据高德地图的实际最大层级设置  
        })
        viewer.imageryLayers.addImageryProvider(gdvMap)
        setBlackMap()
    });
    

onMounted钩子中:

  • 创建Cesium.Viewer实例,并隐藏或移除地图的一些控件,简化地图界面。
  • 移除原有的地图图层,隐藏版权信息,确保只加载自定义的高德地图图层gdvMap
  • 调用setBlackMap函数设置深色地图效果。

五、总结

本文详细介绍了如何利用 Vue 和 Cesium 创建带有自定义样式的地图视图。借助 Vue 的组合式 API,我们能够便捷地管理组件状态和生命周期;同时,Cesium 强大的功能为地图渲染和样式修改提供了有力支持。这种开发方式为构建复杂地图应用提供了简洁高效的解决方案,希望能为大家的开发工作带来启发。

在线预览地址

图片描述
我是 安大桃子,专注前端代码世界的‘筑梦师’。这一趟前端开发的代码之旅暂时告一段落啦,希望文章中的代码思路和技巧能成为你构建前端项目的得力工具。前端技术日新月异,咱们一起在这充满挑战与机遇的领域持续探索,下次代码冒险,咱们不见不散!