Openlayers 自定义地图瓦片加载(二)

一、概要

在前文中,探讨了Openlayers自定义瓦片网格(tileUrlFunction)的实现及其应用。本文将继续探究 自定义瓦片加载(tileLoadFunction)的使用,并探讨其实际应用场景

tileLoadFunction 是自定义地图瓦片加载过程的函数。默认情况下,地图框架自动从指定的 URL 加载瓦片图像。此时可以对加载的图像进行额外处理,如添加水印修改图像效果添加元数据信息等。

二、 自定义瓦片加载探究

  • 加载谷歌影像:

new XYZ({})实际可以接受一个 tileLoadFunction 参数,用于自定义瓦片加载行为,其默认执行的函数是这样的:

   const map = new Map({
    target,
    layers: [
      new TileLayer({
        source: new XYZ({
          url: 'https://www.google.com/maps/vt?lyrs=y&gl=cn&x={x}&y={y}&z={z}',
          tileLoadFunction, // 设置自定义的 tileLoadFunction
          crossOrigin: 'anonymous',
          wrapX: true,
        })
      })
    ],
    view: new View({
      projection: 'EPSG:3857', // 坐标系EPSG:4326或EPSG:3857
      zoom: 0, // 打开页面时默认地图缩放级别
      center: fromLonLat([121.5, 25]), // 转到墨卡托坐标系
    })
  })
  // tileLoadFunction 的默认返回
  function tileLoadFunction(imageTile: Tile, src: string) {
  if (imageTile instanceof ImageTile) {
    //获取图像元素
    const image = imageTile.getImage() as HTMLImageElement;
    // 设置图像源
    image.src = src;
  }

加载结果:
请添加图片描述
tileLoadFunction 接受两个参数:
① imageTile:当前正在加载的瓦片对象。通常是一个 Tile 实例。
② src:瓦片的源 URL。


tileLoadFunction 可以替换为自定义加载方法

  • 作用:
    自定义瓦片内容:对每个瓦片绘制水印、标记或图形等内容。
    图像处理:对瓦片调整亮度、对比度,或添加滤镜效果。
  • 使用场景:
    添加水印:在地图瓦片上添加标识性水印。
    图像修改:调整瓦片的色调,以符合应用的视觉风格。
    特殊效果:在瓦片上叠加半透明的图层,来实现特定的视觉效果。
    数据可视化:在瓦片上添加数据相关的图形或标记。

三、 使用场景

  • 添加水印
 <template>
  <!--地图-->
  <div ref="mapContainer" class="mapContainer" id="mapContainer"></div>
</template>
<script lang="ts" setup>
import { onMounted, shallowRef } from 'vue'
import { View, Map, ImageTile } from "ol"
import { fromLonLat } from 'ol/proj'
import TileLayer from 'ol/layer/Tile'
import { XYZ } from 'ol/source'
import Tile, { LoadFunction } from 'ol/Tile'
// 地图容器
const mapContainer = shallowRef<HTMLDivElement>()
// 地图对象
const map = shallowRef<Map>()
/**
 * @description 创建地图实例
 * @param {Document | DocumentId} target 地图容器
 * @returns 地图对象
 */
const createMap = function (target: HTMLElement | string,): Map {
  // 创建地图
  const map = new Map({
    target,
    layers: [
      new TileLayer({
        source: new XYZ({
          url: 'https://www.google.com/maps/vt?lyrs=y&gl=cn&x={x}&y={y}&z={z}',
          tileLoadFunction,
          crossOrigin: 'anonymous',
          wrapX: true,
        })
      })
    ],
    view: new View({
      projection: 'EPSG:3857', // 坐标系EPSG:4326或EPSG:3857
      zoom: 0, // 打开页面时默认地图缩放级别
      center: fromLonLat([121.5, 25]), // 转到墨卡托坐标系
    })
  })
  return map
}
/**
 * @description 自定义瓦片加载函数,每个瓦片增加自定义水印。
 * @param {Tile} imageTile 当前正在加载的瓦片对象。通常是一个 `Tile` 实例。
 * @param {string} src 瓦片的源 URL。
 */
function tileLoadFunction(imageTile: Tile, src: string) {
  if (tile instanceof ImageTile) {
    // 创建一个新的 Image 对象用于加载瓦片图像
    const tileImage = new Image();
    tileImage.crossOrigin = 'anonymous'; // 允许跨域请求
    // 获取瓦片的目标图像对象
    const waterMakeImage = tile.getImage() as HTMLImageElement;
    // 创建 Canvas 元素用于绘制和处理图像
    const canvas = document.createElement('canvas');
    const context = canvas.getContext('2d');
    // 确保在设置图像源之前,onload 事件处理函数已经设置
    tileImage.onload = () => {
      if (context) {
        // 设置 Canvas 的宽度和高度为图像的尺寸
        canvas.width = tileImage.width;
        canvas.height = tileImage.height;
        // 在 Canvas 上绘制加载的图像
        context.drawImage(tileImage, 0, 0);
        // 添加水印
        context.font = '30px Arial'; // 设置字体样式
        context.fillStyle = 'rgba(255, 255, 255, 0.8)'; // 设置半透明白色
        context.textAlign = 'center'; // 水平居中
        context.textBaseline = 'middle'; // 垂直居中
        // 在 Canvas 中绘制水印
        context.fillText('自定义水印', canvas.width / 2, canvas.height / 2);
        // 将 Canvas 内容转换为 Blob 对象
        canvas.toBlob((blob) => {
          if (blob) {
            // 创建一个 Object URL 以供图像源使用
            const objectURL = URL.createObjectURL(blob);
            // 设置瓦片图像的源,触发图像的 onload 事件
            waterMakeImage.src = objectURL;
            // 确保在图像加载完成后释放 Object URL
            waterMakeImage.onload = () => {
              URL.revokeObjectURL(objectURL);
            };
          }
        }, 'image/png');
      }
    };
    // 设置图像源,开始加载图像
    tileImage.src = src;
  }
};
onMounted(async () => {
  map.value = createMap(mapContainer.value!);
})
</script>
<style lang="scss">
#mapContainer {
  position: absolute;
  top: 0;
  z-index: 0;
  width: 100%;
  height: 100%;
}
</style>

效果:
请添加图片描述

  • 图像修改(仅放 tileLoadFunction ,替换即可,下同)
/**
 * @description 自定义瓦片加载函数,修改瓦片为灰度图像。
 * @param {Tile} imageTile 当前正在加载的瓦片对象。通常是一个 `Tile` 实例。
 * @param {string} src 瓦片的源 URL。
 */
function tileLoadFunction(imageTile: Tile, src: string) {
  if (imageTile instanceof ImageTile) {
    const image = imageTile.getImage() as HTMLImageElement;
    const canvas = document.createElement('canvas');
    const context = canvas.getContext('2d');
    const img = new Image();
    img.crossOrigin = 'anonymous';
    img.onload = () => {
      if (context) {
        canvas.width = img.width;
        canvas.height = img.height;
        context.drawImage(img, 0, 0);
        // 转换为灰度图像
        const imageData = context.getImageData(0, 0, canvas.width, canvas.height);
        const data = imageData.data;
        for (let i = 0; i < data.length; i += 4) {
          const avg = (data[i] + data[i + 1] + data[i + 2]) / 3;
          data[i] = avg; // 红色通道
          data[i + 1] = avg; // 绿色通道
          data[i + 2] = avg; // 蓝色通道
        }
        context.putImageData(imageData, 0, 0);
        // 将 Canvas 内容转换为 Blob 对象
        canvas.toBlob((blob) => {
          if (blob) {
            const objectURL = URL.createObjectURL(blob);
            image.src = objectURL;
            image.onload = () => {
              URL.revokeObjectURL(objectURL);
            };
          }
        }, 'image/png');
      }
    };
    img.src = src;
  }
}

效果:
请添加图片描述

  • 添加遮罩
/**
 * @description 自定义瓦片加载函数,添加绿色半透明遮罩。
 * @param {Tile} imageTile 当前正在加载的瓦片对象。通常是一个 `Tile` 实例。
 * @param {string} src 瓦片的源 URL。
 */
 function tileLoadFunction(imageTile: Tile, src: string) {
  if (imageTile instanceof ImageTile) {
    const image = imageTile.getImage() as HTMLImageElement;
    const canvas = document.createElement('canvas');
    const context = canvas.getContext('2d');
    const img = new Image();
    img.crossOrigin = 'anonymous';
    img.onload = () => {
      if (context) {
        canvas.width = img.width;
        canvas.height = img.height;
        context.drawImage(img, 0, 0);
        // 添加半透明阴影层
        context.fillStyle = 'rgba(0, 255, 0, 0.3) '; // 半透明绿
        context.fillRect(0, 0, canvas.width, canvas.height);
        // 将 Canvas 内容转换为 Blob 对象
        canvas.toBlob((blob) => {
          if (blob) {
            const objectURL = URL.createObjectURL(blob);
            image.src = objectURL;
            image.onload = () => {
              URL.revokeObjectURL(objectURL);
            };
          }
        }, 'image/png');
      }
    };
    img.src = src;
  }
}

效果:
请添加图片描述

  • 添加元数据信息
/**
 * @description 自定义瓦片加载函数,添加瓦片坐标和分界。
 * @param {Tile} imageTile 当前正在加载的瓦片对象。通常是一个 `Tile` 实例。
 * @param {string} src 瓦片的源 URL。
 */
function tileLoadFunction(imageTile: Tile, src: string) {
  if (imageTile instanceof ImageTile) {
    const image = imageTile.getImage() as HTMLImageElement;
    const canvas = document.createElement('canvas');
    const context = canvas.getContext('2d');
    // 创建一个新的图像对象并加载图像
    const img = new Image();
    img.crossOrigin = 'anonymous';
    // 从瓦片源 URL 中提取 X、Y 和 Z 坐标
    const urlPattern = /x=(\d+)&y=(\d+)&z=(\d+)/;
    const match = src.match(urlPattern);
    const x = match ? match[1] : 'unknown';
    const y = match ? match[2] : 'unknown';
    const z = match ? match[3] : 'unknown';
    img.onload = () => {
      if (context) {
        // 设置 Canvas 尺寸以匹配图像
        canvas.width = img.width;
        canvas.height = img.height;
        // 将图像绘制到 Canvas 上
        context.drawImage(img, 0, 0);
        // 绘制白色边框
        context.strokeStyle = 'white'; // 边框颜色
        context.lineWidth = 2; // 边框宽度
        context.strokeRect(0, 0, canvas.width, canvas.height); // 绘制边框
        // 添加瓦片元数据信息
        context.font = '25px Arial';
        context.fillStyle = 'white'; // 白色文本
        context.textAlign = 'left'; // 水平左对齐
        context.textBaseline = 'top'; // 垂直顶部对齐
        // 绘制瓦片信息
        context.fillText(`X: ${x}`, 10, 10); // X 坐标
        context.fillText(`Y: ${y}`, 10, 40); // Y 坐标
        context.fillText(`Z: ${z}`, 10, 70); // Z 坐标
        // 可以添加更多的元数据或视觉效果
        // 例如显示经纬度或瓦片的范围
        // 将 Canvas 内容转换为 Blob 对象
        canvas.toBlob((blob) => {
          if (blob) {
            const objectURL = URL.createObjectURL(blob);
            image.src = objectURL; // 更新瓦片的图像源
            image.onload = () => {
              URL.revokeObjectURL(objectURL); // 释放 Object URL
            };
          }
        }, 'image/png');
      }
    };
    img.src = src; // 设置图像源并开始加载
  }
}

效果:
请添加图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

無可言喻

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值