OpenLayers 综合案例-底图换肤(变色)

看过的知识不等于学会。唯有用心总结、系统记录,并通过温故知新反复实践,才能真正掌握一二

作为一名摸爬滚打三年的前端开发,开源社区给了我饭碗,我也将所学的知识体系回馈给大家,助你少走弯路!
OpenLayers、Leaflet 快速入门 ,每周保持更新 2 个案例
Cesium 快速入门,每周保持更新 4 个案例

OpenLayers 综合案例-底图换肤(变色)

Vue 3 + OpenLayers 实现的 WebGIS 应用提供了完整的底图变色功能

使用RasterSource栅格数据源,图层必须使用ImageLayer来渲染

主要功能

  1. 通过属性operationType: "image", 设置为 image 模式,保持无卡顿高效渲染
  2. 通过调节RGB取色来修改底图颜色,同时保证底图字体随着颜色变化而变化

MP4效果动画链接地址&官网hcl调色案例教程

技术栈

该环境下代码即拿即用

bash 复制代码
Vue 3.5.13+
Openlayers 10.5.0+
Vite 6.3.5+
vue 复制代码
<template>
  <div>
    <div id="map" class="map"></div>
    <table class="controls">
      <tr>
        <td><label for="red">Red</label></td>
        <td>
          <input id="red" type="range" min="0" max="500" v-model="redValue" />
        </td>
        <td>
          <span>{{ redValue }}</span> %
        </td>
      </tr>
      <tr>
        <td><label for="green">Green</label></td>
        <td>
          <input
            id="green"
            type="range"
            min="0"
            max="500"
            v-model="greenValue"
          />
        </td>
        <td>
          <span>{{ greenValue }}</span> %
        </td>
      </tr>
      <tr>
        <td><label for="blue">Blue</label></td>
        <td>
          <input id="blue" type="range" min="0" max="500" v-model="blueValue" />
        </td>
        <td>
          <span>{{ blueValue }}</span> %
        </td>
      </tr>
    </table>
  </div>
</template>

<script setup>
import { ref, onMounted, onUnmounted, watch } from "vue";
import Map from "ol/Map.js";
import View from "ol/View.js";
import XYZ from "ol/source/XYZ.js";
import ImageLayer from "ol/layer/Image.js";
import RasterSource from "ol/source/Raster.js";
import "ol/ol.css";

let map = null;
let raster = null;

// 定义响应式变量,用于双向绑定
const redValue = ref(89);
const greenValue = ref(223);
const blueValue = ref(325);

onMounted(() => {
  // 定义RGB调节函数
  const adjustRGB = function (imageData, data) {
    const pixels = imageData.data;
    const redMultiplier = data.red || 89;
    const greenMultiplier = data.green || 223;
    const blueMultiplier = data.blue || 325;
    // 遍历所有像素 (每4个值代表一个像素: R, G, B, A)
    for (let i = 0; i < pixels.length; i += 4) {
      pixels[i] = redMultiplier - pixels[i]; // Red
      pixels[i + 1] = greenMultiplier - pixels[i + 1]; // Green
      pixels[i + 2] = blueMultiplier - pixels[i + 2]; // Blue
    }
  };

  // 创建栅格源 - 使用XYZ瓦片源
  raster = new RasterSource({
    sources: [
      new XYZ({
        url: "https://webrd04.is.autonavi.com/appmaptile?lang=zh_cn&size=1&scale=1&style=7&x={x}&y={y}&z={z}",
        crossOrigin: "anonymous", // 添加跨域支持
      }),
    ],
    operationType: "image", // 设置为image模式,无卡顿高效渲染
    operation: function (pixels, data) {
      // 在image模式下,pixels[0]是ImageData对象
      const imageData = pixels[0];
      // 调用RGB调节函数
      adjustRGB(imageData, data);
      // 返回修改后的ImageData
      return imageData;
    },
    // 将函数添加到lib中
    lib: {
      adjustRGB: adjustRGB,
    },
  });

  // 监听栅格操作前事件,将响应式变量的值传递给操作数据
  raster.on("beforeoperations", function (event) {
    const data = event.data;
    data.red = redValue.value;
    data.green = greenValue.value;
    data.blue = blueValue.value;
  });

  // 创建地图
  map = new Map({
    layers: [
      // 使用ImageLayer显示处理后的栅格
      new ImageLayer({
        source: raster,
      }),
    ],
    target: "map",
    view: new View({
      center: [12958752, 4825923], // 中国中心坐标 (Web Mercator)
      zoom: 4,
      maxZoom: 18,
    }),
  });

  // 监听响应式变量的变化,并触发栅格图层更新
  watch([redValue, greenValue, blueValue], () => {
    if (raster) {
      raster.changed();
    }
  });
});

onUnmounted(() => {
  if (map) {
    map.setTarget(null);
    map = null;
  }
});
</script>

<style scoped>
.map {
  width: 100vw;
  height: 100vh;
}
table.controls {
  position: absolute;
  top: 10px;
  right: 10px;
  background: rgba(255, 255, 255, 0.9);
  border-radius: 5px;
  padding: 10px;
  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
  z-index: 1000;
}
table.controls td {
  padding: 2px 5px;
}
table.controls td:nth-child(3) {
  text-align: right;
  min-width: 4.5em;
}
table.controls label {
  font-weight: bold;
  color: #333;
}
table.controls input[type="range"] {
  width: 150px;
}
table.controls span {
  color: #666;
  font-family: monospace;
}
/* 为不同的滑块添加颜色提示 */
table.controls tr:nth-child(1) input[type="range"] {
  accent-color: #ff4444;
}
table.controls tr:nth-child(2) input[type="range"] {
  accent-color: #44ff44;
}
table.controls tr:nth-child(3) input[type="range"] {
  accent-color: #4444ff;
}
</style>
相关推荐
程序员黑豆7 小时前
Java类型推断完全指南:从var到菱形运算符,掌握使用限制与最佳实践
java·前端·ai编程
To_OC7 小时前
踩了个 TS 的坑之后,我终于把 type 和 interface 掰明白了
前端·react.js·typescript
GreenTea8 小时前
深度解读 Anthropic 多智能体报告:更强的模型 ≠ 更好的协调
前端·后端·算法
浮生望8 小时前
前端API工程化:用 Mock 数据与 Axios 配置实现独立于后端的并行开发
前端
万少8 小时前
给 DeepSeek Harness 装个"应用商店":一条命令,595 个插件随你逛
前端·javascript·后端
波波0079 小时前
C# 15 重磅新特性: 带标签 break 与 continue:重新定义嵌套循环控制流
服务器·前端·c#
Brown.alexis9 小时前
es6知识点1-自备使用
前端·ecmascript·es6
小爬的老粉丝10 小时前
JavaScript 纯前端预览 WPS:先识别容器,再路由解析器
前端·javascript·wps
计算机魔术师11 小时前
新兴多智能体系统的模式与问题
前端
用户0595401744611 小时前
AI Agent 上下文污染踩坑实录:用 pytest + Redis 揪出 3 类记忆串号 bug,排查 6 小时
前端·css