一、引言
Cesium作为一款强大的开源JavaScript库,为我们提供了创建高性能3D地球和地图的能力。我们可以轻松地构建出功能丰富、交互性强的地图应用。本文将详细介绍一个基于Vue和Cesium的深色地图实现方案,展示如何创建一个充满科技感的地图。
二、项目概述
主要用于创建一个基于Cesium的地图视图,并对地图根据滤镜颜色进行一些设置,以实现深蓝色地图的效果,已达到领导们的需求。
三、模板部分
vue
<template>
<div id="cesiumContainer" class="fullSize"></div>
</template>
在模板部分,我们创建了一个div
元素,其id
为cesiumContainer
,类名为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函数,如onMounted
、nextTick
、ref
和reactive
,用于处理组件的生命周期和状态管理。同时,引入了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的强大功能实现地图的渲染和样式修改。这种方式为我们开发复杂的地图应用提供了一种简洁、高效的解决方案,希望本文能对大家有所帮助。