Cesium实现深色地图效果

点击此处预览效果

一、引言

Cesium作为一款强大的开源JavaScript库,为我们提供了创建高性能3D地球和地图的能力。我们可以轻松地构建出功能丰富、交互性强的地图应用。本文将详细介绍一个基于Vue和Cesium的深色地图实现方案,展示如何创建一个充满科技感的地图。

二、项目概述

主要用于创建一个基于Cesium的地图视图,并对地图根据滤镜颜色进行一些设置,以实现深蓝色地图的效果,已达到领导们的需求。

三、模板部分

vue 复制代码
<template> 
    <div id="cesiumContainer" class="fullSize"></div> 
</template> 

在模板部分,我们创建了一个div元素,其idcesiumContainer,类名为fullSize。这个div元素将作为Cesium地图的容器,后续的地图视图将被渲染到这个容器中。

四、脚本部分

4.1 引入依赖

typescript 复制代码
<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函数,如onMountednextTickrefreactive,用于处理组件的生命周期和状态管理。同时,引入了Cesium库和相关的样式文件,以及自定义的AmapMercatorTilingScheme模块,用于支持高德地图的瓦片方案,当然,你也可以使用其他的地图数据作为地图图层。

4.2 配置Cesium

typescript 复制代码
Cesium.Ion.defaultAccessToken = "your token"; 
const viewModel = reactive({ 
    brightness: 0, 
    contrast: 0, 
    hue: 0, 
    saturation: 0, 
    gamma: 0, 
}) // 获取 Cesium 视图对象 
let viewer: Cesium.Viewer | undefined; 
const filterColor = ref('#003690') 
const imageryLayers = ref() 
  • Cesium.Ion.defaultAccessToken:设置Cesium的访问令牌,用于访问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函数

typescript 复制代码
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函数

typescript 复制代码
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函数

typescript 复制代码
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值,同时会对输入的颜色值进行合法性检查,确保输入的颜色格式正确,这个方法对整个项目没什么影响,只是我个人习惯用16进制的颜色,这里需要获取红绿蓝各个通道的数值,所以得有一个转换的过程。

4.4 挂载阶段

typescript 复制代码
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创建一个带有自定义样式的地图视图。通过组合式API的使用,我们可以方便地管理组件的状态和生命周期,同时利用Cesium的强大功能实现地图的渲染和样式修改。这种方式为我们开发复杂的地图应用提供了一种简洁、高效的解决方案,希望本文能对大家有所帮助。

在线预览地址

相关推荐
祈澈菇凉15 分钟前
Webpack的基本功能有哪些
前端·javascript·vue.js
小纯洁w22 分钟前
Webpack 的 require.context 和 Vite 的 import.meta.glob 的详细介绍和使用
前端·webpack·node.js
想睡好1 小时前
css文本属性
前端·css
qianmoQ1 小时前
第三章:组件开发实战 - 第五节 - Tailwind CSS 响应式导航栏实现
前端·css
zhoupenghui1681 小时前
golang时间相关函数总结
服务器·前端·golang·time
White graces1 小时前
正则表达式效验邮箱格式, 手机号格式, 密码长度
前端·spring boot·spring·正则表达式·java-ee·maven·intellij-idea
庸俗今天不摸鱼1 小时前
Canvas进阶-4、边界检测(流光,鼠标拖尾)
开发语言·前端·javascript·计算机外设
bubusa~>_<2 小时前
解决npm install 出现error,比如:ERR_SSL_CIPHER_OPERATION_FAILED
前端·npm·node.js
[廾匸]2 小时前
cesium视频投影
javascript·无人机·cesium·cesium.js·视频投影
流烟默3 小时前
vue和微信小程序处理markdown格式数据
前端·vue.js·微信小程序