当前位置: 首页 > article >正文

38.在 Vue 3 中使用 OpenLayers 导出地图为 PDF

在现代 web 应用开发中,地图显示和数据可视化已经成为许多应用的核心功能。OpenLayers 是一个强大的开源 JavaScript 库,它为开发者提供了丰富的地图绘制功能。今天,我们将介绍如何在 Vue 3 中使用 OpenLayers,并实现一个非常实用的功能:将地图导出为 PDF 文件。

背景

OpenLayers 允许我们创建互动式地图,并支持多种地图服务,如瓦片地图(TileLayer)、矢量地图(VectorTileLayer)等。Vue 3 引入的 Composition API 提供了更灵活和清晰的方式来管理组件的状态和行为。我们将在 Vue 3 中使用 OpenLayers,并结合 jsPDF 库来实现导出地图为 PDF 的功能。

技术栈

  • Vue 3:构建应用的框架,采用 Composition API。
  • OpenLayers:用于展示地图和加载不同类型的地图数据。
  • jsPDF:用于将地图导出为 PDF 文件。

实现步骤

1. 安装依赖

首先,我们需要安装 openlayersjspdf 两个依赖。可以使用 npm 或 yarn 来安装:

npm install ol jspdf

2. 配置 Vue 组件

在我们的 Vue 组件中,我们将创建一个地图,允许用户点击按钮将当前地图导出为 PDF。

完整代码
<!--
 * @Author: 彭麒
 * @Date: 2024/12/20
 * @Email: 1062470959@qq.com
 * @Description: 此源码版权归吉檀迦俐所有,可供学习和借鉴或商用。
 -->
<template>
  <button class="back-button" @click="goBack">返回</button>
  <div class="container">
    <h3>vue+openlayers: 导出地图(pdf)</h3>
    <h4>
      <el-button type="primary" @click="exportPDF" size="small">导出 pdf 地图</el-button>
    </h4>
    <div id="vue-openlayers"></div>
  </div>
</template>

<script setup>
import { ref, onMounted } from 'vue'; // 引入 Vue 3 的 ref 和 onMounted 钩子
import 'ol/ol.css'; // 引入 OpenLayers 样式
import Map from 'ol/Map'; // 引入 OpenLayers 的 Map 类
import View from 'ol/View'; // 引入 OpenLayers 的 View 类
import TileLayer from 'ol/layer/Tile'; // 引入 OpenLayers 的 TileLayer 类
import OSM from 'ol/source/OSM'; // 引入 OpenLayers 的 OSM 数据源类
import WMTSTileGrid from 'ol/tilegrid/WMTS'; // 引入 OpenLayers 的 WMTSTileGrid 类
import VectorTileLayer from 'ol/layer/VectorTile'; // 引入 OpenLayers 的 VectorTileLayer 类
import VectorTile from 'ol/source/VectorTile'; // 引入 OpenLayers 的 VectorTile 类
import MVT from 'ol/format/MVT'; // 引入 OpenLayers 的 MVT 格式类
import Fill from 'ol/style/Fill'; // 引入 OpenLayers 的 Fill 样式类
import Style from 'ol/style/Style'; // 引入 OpenLayers 的 Style 类
import Circle from 'ol/style/Circle'; // 引入 OpenLayers 的 Circle 样式类
import { jsPDF } from 'jspdf'; // 引入 jsPDF 库
import router from "@/router"; // 引入 Vue Router

const goBack = () => {
  router.push('/OpenLayers'); // 返回到 OpenLayers 页面
};

const map = ref(null); // 定义地图的响应式引用

// 初始化地图
const initMap = () => {
  map.value = new Map({
    layers: [
      new TileLayer({
        source: new OSM(), // 使用 OSM 数据源
      }),
    ],
    target: 'vue-openlayers', // 目标容器 ID
    view: new View({
      center: [0, 0], // 地图中心点
      projection: 'EPSG:4326', // 投影为 EPSG:4326
      zoom: 4, // 初始缩放级别
    }),
  });
};

// 设置样式
const style = () => {
  return new Style({
    image: new Circle({
      radius: 5, // 圆形半径为 5
      fill: new Fill({
        color: 'LawnGreen', // 填充颜色为草绿色
      }),
    }),
  });
};

// 加载 MVT 数据
const readMVT = () => {
  const myLayer = new VectorTileLayer({
    style: style(), // 设置图层样式
    source: new VectorTile({
      visible: true, // 图层可见
      url: 'https://gibs-{a-c}.earthdata.nasa.gov/wmts/epsg4326/best/wmts.cgi?TIME=2020-03-18T00:00:00Z&layer=GRanD_Dams&tilematrixset=2km&Service=WMTS&Request=GetTile&Version=1.0.0&FORMAT=application%2Fvnd.mapbox-vector-tile&TileMatrix={z}&TileCol={x}&TileRow={y}', // 数据源 URL
      format: new MVT(), // 数据格式为 MVT
      projection: 'EPSG:4326', // 投影为 EPSG:4326
      tileGrid: new WMTSTileGrid({
        extent: [-180, -90, 180, 90], // 瓦片网格范围
        resolutions: [0.5625, 0.28125, 0.140625, 0.0703125, 0.03515625, 0.017578125], // 分辨率数组
        tileSize: [512, 512], // 瓦片大小
      }),
    }),
  });
  map.value.addLayer(myLayer); // 将图层添加到地图
};

// 导出地图为 PDF
const exportPDF = () => {
  map.value.once('rendercomplete', () => {
    const mapCanvas = document.createElement('canvas'); // 创建 canvas 元素
    const size = map.value.getSize(); // 获取地图大小

    // 设置尺寸为 A4(297*210),分辨率为 150dpi
    const width = Math.round((297 * 150) / 25.4);
    const height = Math.round((210 * 150) / 25.4);

    mapCanvas.width = width; // 设置 canvas 宽度
    mapCanvas.height = height; // 设置 canvas 高度

    const mapContext = mapCanvas.getContext('2d'); // 获取 canvas 上下文
    Array.prototype.forEach.call(
      map.value.getViewport().querySelectorAll('.ol-layer canvas, canvas.ol-layer'),
      (canvas) => {
        if (canvas.width > 0) {
          const opacity = canvas.parentNode.style.opacity || canvas.style.opacity; // 获取透明度
          mapContext.globalAlpha = opacity === '' ? 1 : Number(opacity); // 设置全局透明度

          const backgroundColor = canvas.parentNode.style.backgroundColor; // 获取背景颜色
          if (backgroundColor) {
            mapContext.fillStyle = backgroundColor; // 设置填充样式
            mapContext.fillRect(0, 0, canvas.width, canvas.height); // 填充背景颜色
          }

          let matrix;
          const transform = canvas.style.transform; // 获取变换样式
          if (transform) {
            matrix = transform
              .match(/^matrix\(([^\(]*)\)$/)[1]
              .split(',')
              .map(Number); // 解析变换矩阵
          } else {
            matrix = [
              parseFloat(canvas.style.width) / canvas.width,
              0,
              0,
              parseFloat(canvas.style.height) / canvas.height,
              0,
              0,
            ]; // 默认变换矩阵
          }

          CanvasRenderingContext2D.prototype.setTransform.apply(mapContext, matrix); // 应用变换矩阵
          mapContext.drawImage(canvas, 0, 0); // 绘制图像
        }
      }
    );
    mapContext.globalAlpha = 1; // 重置全局透明度

    // 导出地图为 PDF
    const pdf = new jsPDF('landscape', undefined, [width, height]);
    pdf.addImage(mapCanvas.toDataURL('image/jpeg'), 'JPEG', 0, 0, width, height);
    pdf.save('map.pdf'); // 保存 PDF 文件
  });
  map.value.renderSync(); // 同步渲染地图
};

// 挂载地图
onMounted(() => {
  initMap(); // 初始化地图
  readMVT(); // 加载 MVT 数据
});
</script>

<style scoped>
.container {
  width: 840px;
  height: 590px;
  margin: 50px auto;
  border: 1px solid #42B983;
}

#vue-openlayers {
  width: 800px;
  height: 400px;
  margin: 0 auto;
  border: 1px solid #42B983;
  position: relative;
}
</style>

3. 代码解析

3.1 初始化地图

setup 函数中,我们使用 ref 声明了 map 变量,后续会用它来保存 OpenLayers 的地图实例。然后,initMap 函数负责初始化地图,并将其显示在页面上的 #vue-openlayers 容器中。

3.2 加载地图图层

我们使用 VectorTileLayer 来加载一个 WMTS 图层(世界大坝数据)。通过配置 OpenLayers 的 VectorTile 来源和瓦片网格,地图会加载来自 NASA Earth Data 的地理信息数据。

3.3 导出地图为 PDF

exportPDF 函数是实现导出功能的核心。在地图渲染完成后,我们通过 rendercomplete 事件来触发导出操作。具体步骤如下:

  1. 创建一个新的 canvas 元素,将地图内容渲染到该 canvas 上。
  2. 使用 jsPDF 将该 canvas 转换为 PDF 并下载。
3.4 样式与布局

我们使用了 scoped 样式,确保样式仅应用于当前组件。在容器 #vue-openlayers 上设置了地图的显示区域,并定义了容器的宽度和高度。

导出后

4. 总结

通过以上步骤,我们成功实现了在 Vue 3 中使用 OpenLayers 加载地图,并通过 jsPDF 库将地图导出为 PDF 文件。这个功能非常适合需要地图展示和分享功能的应用。你可以根据需求调整地图的样式和导出的尺寸,以满足不同的需求。

希望这篇文章能帮助你理解如何在 Vue 3 中使用 OpenLayers 和 jsPDF 实现导出地图为 PDF 的功能!


http://www.kler.cn/a/445867.html

相关文章:

  • linux普通用户使用sudo不需要输密码
  • 批量DWG文件转dxf(CAD图转dxf)——c#插件实现
  • dolphinscheduler服务RPC框架源码解析(八)RPC提供者服务整合Spring框架实现
  • 15.初识接口1 C#
  • 【Java基础面试题024】Java中包装类型和基本类型的区别是什么?
  • 怿星科技联合赛力斯举办workshop活动,进一步推动双方合作
  • C#.net CAD二次开发调试时进行日志记录并输出错误
  • 【Python】【数据分析】深入探索 Python 数据可视化:Plotly 绘图库全面解析
  • 使用LS-DYNA对秸秆进行切削仿真(记录版)
  • 免费开源!推荐一款网页版数据库管理工具!
  • edge_tts 实现实时流式语音播放输出
  • 安装指定版本的python这里以3.11为例子
  • 【Tomcat】第五站:Servlet容器
  • mfc140.dll是什么东西?mfc140.dll缺失的几种具体解决方法
  • 腾讯云云开发 Copilot 深度探索与实战分享
  • STM32单片机芯片与内部33 ADC 单通道连续DMA
  • 子域提取工具,子域名收集神器,支持多种数据源和枚举选项,域名发现工具,可以为任何目标枚举海量的有效子域名,安全侦察工具,利用证书透明原则监控部署的新子域
  • html在线转换工具集合大全
  • AFL-Fuzz 的使用
  • 五十个网络安全学习项目——(九)无线网络安全分析
  • windows 钉钉缓存路径不能修改 默认C盘解决方案
  • Python 【大模型】之 使用千问Qwen2-VL 大模型训练LaTeX数学公式图,并进行LaTeX图识别测试
  • 校园快领系统|Java|SSM|VUE| 前后端分离
  • 模型训练之优化器
  • #渗透测试#漏洞挖掘#红蓝攻防#护网#sql注入介绍05-基于堆叠查询的SQL注入(Stacked Queries SQL Injection)
  • java全栈day17--Web后端实战(java操作数据库)