各位掘友,大家好,我是 安大桃子。在当下数字化地图与地理信息蓬勃发展的浪潮里,WebGIS 技术成为关键力量。而 Vue 和 Cesium 作为 WebGIS 开发中的 “黄金搭档”,一个凭借组件化优势让开发高效有序,一个专注地理空间渲染,呈现逼真地图。接下来,我将结合实际项目案例,为大家深度解析如何巧用 Vue、Cesium 以及相关 WebGIS 技术,攻克复杂地理数据可视化与交互难题,开启 WebGIS 开发进阶之路。
一、引言
在 GIS 开发领域,Cesium 是一款功能强大的开源 JavaScript 库,它赋予开发者创建高性能 3D 地球和地图的能力,让我们能够轻松搭建功能丰富、交互性强的地图应用。本文将详细介绍如何基于 Vue 和 Cesium 实现深色地图效果,带你打造极具科技感的地图场景。
二、项目概述
本项目旨在基于 Cesium 构建一个地图视图,并通过设置滤镜颜色等操作,实现深蓝色地图效果,满足特定的设计需求。
三、模板部分
在 Vue 模板中,我们仅需创建一个div
元素,代码如下:
<template>
<div id="cesiumContainer" class="fullSize"></div>
</template>
该div
元素的id
为cesiumContainer
,类名为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 更新后执行回调、ref
和reactive
用于状态管理。同时,引入 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 强大的功能为地图渲染和样式修改提供了有力支持。这种开发方式为构建复杂地图应用提供了简洁高效的解决方案,希望能为大家的开发工作带来启发。
我是 安大桃子,专注前端代码世界的‘筑梦师’。这一趟前端开发的代码之旅暂时告一段落啦,希望文章中的代码思路和技巧能成为你构建前端项目的得力工具。前端技术日新月异,咱们一起在这充满挑战与机遇的领域持续探索,下次代码冒险,咱们不见不散! |