MapLibre GL JS第40课:添加可拉伸图像
学习目标掌握添加可拉伸图像的实现方法理解相关API的使用能够独立完成类似功能开发⭕️MapLibre GL JS全部课时目录⭕️ 核心概念向地图添加可拉伸图像。 完 整 代 码代码示例constmapnewmaplibregl.Map({container:map,style:https://demotiles.maplibre.org/style.json,zoom:0.1});constimages{popup:https://maplibre.org/maplibre-gl-js/docs/assets/popup.png,popup-debug:https://maplibre.org/maplibre-gl-js/docs/assets/popup_debug.png};map.on(load,async(){constdebugPopupawaitmap.loadImage(images[popup-debug]);constpopupawaitmap.loadImage(images[popup]);map.addImage(popup-debug,debugPopup.data,{// 两个蓝色的像素列可以水平拉伸// - x: 25 和 x: 55可以拉伸// - x: 85 和 x: 115可以拉伸stretchX:[[25,55],[85,115]],// 一个红色的像素行可以垂直拉伸// - y: 25 和 y: 100可以拉伸stretchY:[[25,100]],// 这部分图像可以包含文本[x1, y1, x2, y2]content:[25,25,115,100],// 这是一个高DPI图像pixelRatio:2});map.addImage(popup,popup.data,{stretchX:[[25,55],[85,115]],stretchY:[[25,100]],content:[25,25,115,100],pixelRatio:2});map.addSource(points,{type:geojson,data:{type:FeatureCollection,features:[{type:Feature,geometry:{type:Point,coordinates:[40,-30]},properties:{image-name:popup-debug,name:Line 1\nLine 2\nLine 3}},{type:Feature,geometry:{type:Point,coordinates:[40,30]},properties:{image-name:popup,name:Line 1\nLine 2\nLine 3}},{type:Feature,geometry:{type:Point,coordinates:[-40,-30]},properties:{image-name:popup-debug,name:One longer line}},{type:Feature,geometry:{type:Point,coordinates:[-40,30]},properties:{image-name:popup,name:One longer line}}]}});map.addLayer({id:points,type:symbol,source:points,layout:{text-field:[get,name],icon-text-fit:both,icon-image:[get,image-name],icon-overlap:always,text-overlap:always}});// 原始未拉伸的图像用于对比map.addSource(original,{type:geojson,data:{type:FeatureCollection,features:[{type:Feature,geometry:{type:Point,coordinates:[0,-70]}}]}});map.addLayer({id:original,type:symbol,source:original,layout:{text-field:non-stretched image,icon-image:popup-debug,icon-overlap:always,text-overlap:always}});});代码示例!DOCTYPEhtmlhtmllangenheadtitleAdd a stretchable image to the map/titlemetapropertyog:descriptioncontent使用可拉伸图像作为文本背景。/metapropertyog:createdcontent2025-06-25/metacharsetutf-8metanameviewportcontentwidthdevice-width, initial-scale1linkrelstylesheethrefhttps://unpkg.com/maplibre-gl5.24.0/dist/maplibre-gl.css/scriptsrchttps://unpkg.com/maplibre-gl5.24.0/dist/maplibre-gl.js/scriptstylebody{margin:0;padding:0;}html, body, #map{height:100%;}/style/headbodydividmap/divscriptconstmapnewmaplibregl.Map({container:map,style:https://demotiles.maplibre.org/style.json,zoom:0.1});constimages{popup:https://maplibre.org/maplibre-gl-js/docs/assets/popup.png,popup-debug:https://maplibre.org/maplibre-gl-js/docs/assets/popup_debug.png};map.on(load,async(){constdebugPopupawaitmap.loadImage(images[popup-debug]);constpopupawaitmap.loadImage(images[popup]);map.addImage(popup-debug,debugPopup.data,{// 可以水平拉伸的两列蓝色像素// - x: 25 到 x: 55 之间的像素可以拉伸// - x: 85 到 x: 115 之间的像素可以拉伸。stretchX:[[25,55],[85,115]],// 可以垂直拉伸的一行红色像素// - y: 25 到 y: 100 之间的像素可以拉伸stretchY:[[25,100]],// 图像中可以包含文本的部分 ([x1, y1, x2, y2])content:[25,25,115,100],// 这是一个高DPI图像pixelRatio:2});map.addImage(popup,popup.data,{stretchX:[[25,55],[85,115]],stretchY:[[25,100]],content:[25,25,115,100],pixelRatio:2});map.addSource(points,{type:geojson,data:{type:FeatureCollection,features:[{type:Feature,geometry:{type:Point,coordinates:[40,-30]},properties:{image-name:popup-debug,name:Line 1\nLine 2\nLine 3}},{type:Feature,geometry:{type:Point,coordinates:[40,30]},properties:{image-name:popup,name:Line 1\nLine 2\nLine 3}},{type:Feature,geometry:{type:Point,coordinates:[-40,-30]},properties:{image-name:popup-debug,name:One longer line}},{type:Feature,geometry:{type:Point,coordinates:[-40,30]},properties:{image-name:popup,name:One longer line}}]}});map.addLayer({id:points,type:symbol,source:points,layout:{text-field:[get,name],icon-text-fit:both,icon-image:[get,image-name],icon-overlap:always,text-overlap:always}});// 原始的、非拉伸图像用于对比map.addSource(original,{type:geojson,data:{type:FeatureCollection,features:[{type:Feature,geometry:{type:Point,coordinates:[0,-70]}}]}});map.addLayer({id:original,type:symbol,source:original,layout:{text-field:non-stretched image,icon-image:popup-debug,icon-overlap:always,text-overlap:always}});});/script/body/html 代码解析初始化地图使用new maplibregl.Map()创建地图实例配置基本参数。本示例的核心特色是展示如何添加可拉伸图像作为文本背景。关键配置项container: 地图容器的 DOM 元素 IDstyle: 使用 MapLibre 官方样式https://demotiles.maplibre.org/style.jsonzoom: 初始缩放级别为 0.1显示全球视图加载图像constimages{popup:https://maplibre.org/maplibre-gl-js/docs/assets/popup.png,popup-debug:https://maplibre.org/maplibre-gl-js/docs/assets/popup_debug.png};constdebugPopupawaitmap.loadImage(images[popup-debug]);constpopupawaitmap.loadImage(images[popup]);配置可拉伸图像map.addImage(popup,popup.data,{stretchX:[[25,55],// 水平可拉伸区域1[85,115]// 水平可拉伸区域2],stretchY:[[25,100]],// 垂直可拉伸区域content:[25,25,115,100],// 内容区域pixelRatio:2// 高清屏支持});创建数据源和符号图层map.addSource(points,{type:geojson,data:{type:FeatureCollection,features:[{type:Feature,geometry:{type:Point,coordinates:[40,30]},properties:{image-name:popup,name:Line 1\nLine 2\nLine 3}}]}});map.addLayer({id:points,type:symbol,source:points,layout:{text-field:[get,name],icon-text-fit:both,icon-image:[get,image-name],icon-overlap:always,text-overlap:always}});⚙️ 参数说明参数类型必填默认值说明containerstring是-地图容器元素的 IDstylestring/object是-地图样式 URL 或内联样式对象zoomnumber否0初始缩放级别范围 0-22map.addImage 可拉伸选项参数类型必填说明stretchXarray否水平拉伸区域数组[[start, end], ...]stretchYarray否垂直拉伸区域数组[[start, end], ...]contentarray否内容区域[x1, y1, x2, y2]pixelRationumber否像素比默认 1icon-text-fit 选项选项说明both同时适应宽度和高度width只适应宽度height只适应高度none不拉伸 效果说明运行代码后地图上会显示四个气泡标注上方两个气泡: 内容为三行文本气泡会垂直拉伸以适应多行文本下方两个气泡: 内容为一行较长文本气泡会水平拉伸以适应宽度底部对比气泡: 未拉伸的原始图像显示固定尺寸调试图popup-debug中蓝色区域: 水平可拉伸部分红色区域: 垂直可拉伸部分白色区域: 固定边框和角落 常 见 问 题Q1: 拉伸效果不生效怎么办A:按以下步骤排查确保在map.addImage()时正确传入了stretchX、stretchY和content参数在符号图层的layout中设置icon-text-fit为both、width或height确认图像尺寸足够大包含定义的拉伸区域Q2: 如何确定拉伸区域的像素坐标A:使用图像编辑软件如 Photoshop、GIMP打开图片查看像素坐标。调试图中的彩色区域直观显示了可拉伸区域。Q3: 高清屏幕上图像模糊怎么办A:设置pixelRatio: 2可以让图像在 Retina 屏幕上显示更清晰。同时确保提供的图像是 2x 分辨率的。Q4: 可以只拉伸一个方向吗A:可以。只设置stretchX或stretchY并将icon-text-fit设置为对应的方向。 练习任务基础练习修改stretchX和stretchY参数调整拉伸区域进阶挑战创建自己的可拉伸图像定义不同的拉伸区域拓展思考如何实现气泡的最大尺寸限制 最佳实践图像设计: 设计图像时预留可拉伸区域保持边框和角落固定拉伸区域: 选择图像中适合拉伸的部分通常是纯色或渐变区域像素比: 为高清屏幕提供 2x 图像并设置pixelRatio: 2内容区域: 准确定义content参数确保文本正确居中测试验证: 在不同文本长度下测试拉伸效果性能优化: 避免使用过大的图像影响加载性能降级方案: 提供不支持拉伸功能的浏览器降级方案 延伸阅读Map API文档MapLibre GL JS 官方文档[下一课预告]将继续学习地图图层的基础知识本文是MapLibre GL JS实践课程系列的一部分欢迎关注收藏