当前位置:网站首页>Openlayers 自定义气泡框以及定位到气泡框
Openlayers 自定义气泡框以及定位到气泡框
2022-07-01 16:49:00 【Southejor】
Openlayers 自定义气泡框以及定位到气泡框
OpenLayers 教程
Openlayers 气泡框功能,主要用来展示地图要素的属性信息,也被称为气泡、卡片、弹出框等等,笔者习惯称为气泡框。
气泡框功能很常用,场景一般是,在地图叠加点线面的时候同时展示当前要素(Feature)的基础信息,比如名称、数量、地址等;还有就是点击地图叠加元素的时候再弹出气泡框,来展示信息。
气泡框因容器大小限制,一般只展示简略信息,想展示详细信息的话,往往通过新开页面或者弹出大的 div 容器展示。
一般来说,气泡框属于地图覆盖物(Overlay),属于 dom 元素,没有在 canvas 内部,层级位于图层之上,作为顶层元素存在;气泡框一般都会包含关闭图标或按钮,可以点击关闭,也有特殊场景,不允许关闭,不过如果不关闭的话,直接使用 dom 元素实现就可以。
气泡框作为地图对象元素加载的好处之一,就是可以跟随地图移动,效果更加符合使用习惯。
本文主要介绍,气泡框的初始化、气泡框展示信息、气泡框样式、气泡框定位。
Openlayers 自定义气泡框以及定位到气泡框
<html lang="en">
<head>
<meta charSet="utf-8">
<!--注意:openlayers 原版的比较慢,这里引起自己服务器版-->
<link rel="stylesheet" href="http://openlayers.vip/examples/css/ol.css" type="text/css">
<style> /* 注意:这里必须给高度,否则地图初始化之后不显示;一般是计算得到高度,然后才初始化地图 */ .map {
height: 700px; width: 100%; float: left; } /*气泡框容器样式*/ .leaflet-container {
position: absolute; -moz-box-shadow: 0 1px 4px rgba(0, 0, 0, 0.2); -webkit-filter: drop-shadow(0 1px 4px rgba(0, 0, 0, 0.2)); filter: drop-shadow(0 1px 4px rgba(0, 0, 0, 0.2)); bottom: -12px; } /*气泡框关闭按钮样式*/ .leaflet-container a.leaflet-popup-close-button {
position: absolute; top: 0; right: 0; padding: 4px 4px 0 0; width: 18px; height: 14px; background: 0; color: #ffffff; text-align: center; text-decoration: none; font: 1pc/14px Tahoma, Verdana, sans-serif; font-weight: 700 } /*气泡框内容样式*/ .common-popup .leaflet-popup-content-wrapper {
background: transparent; box-shadow: none; padding: 0; border-radius: 0; } /*气泡框下角*/ .common-popup .leaflet-popup-tip {
margin-left: 120px } .leaflet-popup-tip-container {
position: relative; overflow: hidden; margin: 0; height: 28px } .leaflet-popup-tip {
margin: -10px auto 0; padding: 1px; width: 17px; height: 18px; -webkit-transform: rotate(45deg); transform: rotate(45deg); -ms-transform: rotate(45deg) } .leaflet-popup-content-wrapper, .leaflet-popup-tip {
background: #fff; box-shadow: 0 3px 14px rgba(0, 0, 0, .4) } /*自定义气泡框样式*/ .customer-popup-southejor-style {
border: 1px solid #fff; border-radius: 5px; background: #1a90c587; color: #fff; box-shadow: inset 0 0 4px 2px #fff; } /*自定义气泡框标题样式*/ .customer-popup-southejor-title {
height: 10%; background-color: #03a9f48f; padding: 2px; font-size: 20px; text-align: center; } </style>
<!--注意:openlayers 原版的比较慢,这里引起自己服务器版-->
<script src="http://openlayers.vip/examples/resources/ol.js"></script>
<script src="http://openlayers.vip/examples/resources/jquery-3.5.1.min.js"></script>
<script src="./tiandituLayers.js"></script>
<title>OpenLayers example</title>
</head>
<body>
<h2>OpenLayers Popup</h2>
<!--地图容器,需要指定 id -->
<div id="map" class="map"></div>
<script type="text/javascript"> var map = new ol.Map({
// 地图容器 target: 'map', // 地图图层,比如底图、矢量图等 layers: [ getIMG_CLayer(), getIBO_CLayer(), getCIA_CLayer(), ], // 地图视野 view: new ol.View({
projection: "EPSG:4326", // 定位 center: [115.67724700667199, 37.73879478106912], // 缩放 zoom: 6, maxZoom: 18, minZoom: 1, }) }); // 开启图形要素点击事件 map.on('click', function (event) {
this.forEachFeatureAtPixel(event.pixel, function (feature) {
// 为点击的feature发送自定义的click消息 feature.dispatchEvent && feature.dispatchEvent({
type: 'click', event: event}); }); }); // 初始化气泡框 createPopup(); // 默认样式 var defaultStyle = new ol.style.Style({
//边框样式 stroke: new ol.style.Stroke({
color: 'white', width: 2, }), //填充样式 fill: new ol.style.Fill({
color: 'rgba(255, 255, 255, 0.7)', }), // 点样式 image: new ol.style.Icon({
// 允许跨域,如果不设置,打印地图不会打印 crossOrigin: 'anonymous', // 标注图片和文字之间的距离 anchor: [0.5, 0], // 图片的偏移 offset: [0, 0], // 图片的锚点,一般来说,都是右下角 anchorOrigin: 'bottom-right', //图标的url src: "http://api.tianditu.gov.cn/v4.0/image/marker-icon.png", scale: 1, }) }) // 初始化图层 var layer = initVectorLayer(); // 面和点 var feature = undefined, featurePoint = undefined; addFeatures(); // 添加点线面 function addFeatures() {
featurePoint = getFeatureByWKT("POINT(116.17983834030585 39.98298600752048)"); feature = getFeatureByWKT("POLYGON((115.13540462521966 37.877850766866445,116.31094173459466 39.042401548116445,117.23379329709466 38.130536313741445,117.10195735959466 37.295575376241445,115.64077571896966 36.976971860616445,115.26724056271966 37.174725766866445,115.13540462521966 37.877850766866445))"); //设置显示属性 feature.set('content:内容', '这是一个面状图形要素'); feature.set('other:其他属性', '还有其他面状属性'); featurePoint.set('content:内容', '这是一个点图形要素'); featurePoint.set('other:其他属性', '还有其他点属性'); //定义绑定事件 let clickFunc = function (e) {
// 获取要展示的属性信息 let popupStr = getPopupHtml(e.target); //获取地图对象 let temp = '<div class="customer-popup-southejor-style">' + ' <div class="customer-popup-southejor-title">\n' + ' <span>气泡框</span>\n' + ' </div>\n' + ' <div style="font-size: 16px; padding: 5px;">' + ' <div class="customer-popup-southejor-index" style="padding-left: 10px;">' + popupStr.content + ' </div>' + ' </div>\n' + ' </div>' //打开气泡框 openInfoWindowHtml(e.target, temp) } //绑定事件 feature.on('click', clickFunc); featurePoint.on('click', clickFunc); layer.getSource().addFeatures([feature, featurePoint]); } /** * @todo 矢量图层 * @returns {VectorLayer} * @constructor */ function initVectorLayer() {
//实例化一个矢量图层Vector作为绘制层 let source = new ol.source.Vector(); //创建一个图层 let customVectorLayer = new ol.layer.Vector({
source: source, zIndex: 2, //设置样式 style: defaultStyle, }); //将绘制层添加到地图容器中 map.addLayer(customVectorLayer); return customVectorLayer; } /** * @todo wkt格式数据转化成图形对象 * @param {string} wkt "POINT(112.7197265625,39.18164062499999)" 格式数据 * @param {string|Projection} sourceCode 源投影坐标系 * @param {string|Projection} targetCode 目标投影坐标系 * @returns {Feature} */ function getFeatureByWKT(wkt, sourceCode, targetCode) {
try {
let view = map.getView(); if (!wkt) {
return null; } let format = new ol.format.WKT(); let feature; feature = format.readFeature(wkt, {
featureProjection: targetCode || view.getProjection(), dataProjection: sourceCode || view.getProjection(), }); return feature; } catch (e) {
console.log(e); return null; } } /** * todo 创建 popup 气泡框元素 * @param */ function createPopup() {
// 气泡框容器字符串 var popupStr = "<div id='popup-leaflet-container-southejor' class=\"leaflet-container\" > \n" + " <div class=\"leaflet-popup-pane\">\n" + " <div class=\"leaflet-popup common-popup\">\n" + " <a id='popup-closer' class=\"leaflet-popup-close-button\" href=\"JavaScript:void(0)\">×</a>\n" + " <div class=\"leaflet-popup-content-wrapper\">\n" + " </div>\n" + " <div class=\"leaflet-popup-tip-container\">\n" + " <div class=\"leaflet-popup-tip\"></div>\n" + " </div>\n" + " </div>\n" + " </div>\n" + " </div>"; // 创建气泡框容器 let popupDiv = document.createElement("div"); //创建一个div标签 // 设置 id popupDiv.id = "mapPopup"; // 初始化不显示 popupDiv.style.display = 'none'; // 初始化容器 popupDiv.innerHTML = popupStr; //限制页面只能出现一个气泡框 if (document.getElementsByTagName('body')[0].contains(popupDiv)) {
document.getElementsByTagName('body')[0].removeChild(popupDiv); } document.getElementsByTagName('body')[0].appendChild(popupDiv); return initPopup(popupDiv); } // 气泡框,主体,关闭按钮 var popup, contentBody, closerPopup; /** * todo 初始化气泡框 * @returns {Overlay} */ function initPopup(popupContainer) {
//气泡框-内容ID contentBody = $('#popup-leaflet-container-southejor .leaflet-popup-content-wrapper')[0]; //气泡框-关闭ID closerPopup = document.getElementById('popup-closer'); // 设置为显示 popupContainer.style.display = 'block'; //气泡框覆盖层 popup = new ol.Overlay({
// 容器 element: popupContainer, // 当Popup超出地图边界时,为了Popup全部可见,自动移动到可视范围 autoPan: true, autoPanAnimation: {
//当Popup超出地图边界时,为了Popup全部可见,地图移动的速度. duration: 250 } }); return popup; } function openInfoWindowHtml(featureTemp, content) {
try {
// 如果没有图形要素参数,则打开默认气泡框 if (!featureTemp) {
contentBody.innerHTML.trim() ? map.addOverlay(popup) : alert('请先点击图形要素(面或点)!'); return; } // 更新显示属性 contentBody.innerHTML = content; // 获取图形要素中心点 var center = ol.extent.getCenter(featureTemp.getGeometry().getExtent()); // 气泡框设置中心点 popup.setPosition(center); // 移除上一个气泡框 map.removeOverlay(popup); // 获取图形要素类型 let featureType = featureTemp.getGeometry().getType(); //这 里面和线图形与点图形不一样;如果是点图层(图标),则气泡框上移 // 气泡框的 setOffset 可以根据实际调整 if (featureType == 'Point') {
let styleTemp = featureTemp.getStyle() || layer.getStyle(); if (styleTemp && styleTemp.getImage()) {
let size = styleTemp.getImage().getSize(); let scale = styleTemp.getImage().getScale(); if (size && size.length > 1) {
popup.setOffset([-10, -size[1] * scale]); } else {
popup.setOffset([0, -40]); } } else {
popup.setOffset([0, -5]); } //其他图形则正常 } else {
popup.setOffset([-10, 0]); } // 添加气泡框 map.addOverlay(popup); // 绑定关闭按钮事件 closerPopup.onclick = function () {
map.removeOverlay(popup); }; // 气泡框宽度 let popupWidth = 300; // 调整位置 let popupPointLeft = (popupWidth / 2); // 调整横向偏移 $(map.getTargetElement()).find(".leaflet-container").width(popupWidth + "px"); $(map.getTargetElement()).find(".leaflet-container").css('right', -popupPointLeft + "px"); $(map.getTargetElement()).find(".leaflet-popup-tip-container .leaflet-popup-tip").css("margin-left", popupPointLeft + "px"); return popup; } catch (e) {
console.log(e) } } // 获取气泡框属性 function getPopupHtml(feature) {
if (!feature) {
return; } let popup = {
}; // 定义 table 容器 let content = "<table class='popup-table-html-show-southejor' style='width: 100%;color:white'>"; // 获取图形要素所有属性 let featureProperties = feature.getProperties(); // 设置字段和属性宽度 let tdColumn = '35%', tdField = '65%'; for (let featureElement in featureProperties) {
// 这里需要跟前边 feature 属性定义对应; // 前边定义为:字段:值 if (featureElement && featureElement.indexOf(":") != -1) {
let featureElementArr = featureElement.split(":"); content += "<tr style='height: 25px;'>"; // 拼接属性信息 content += "<td style='border-width: 0px 0px 1px 0px;word-wrap:break-word;" + "word-break:break-all;width: " + tdColumn + "'><div>" + featureElementArr[1] + " : </div></td>" + "<td style='border-width: 0px 0px 1px 0px;word-wrap:break-word;word-break:break-all;" + "width: " + tdField + "'><div class='popupIdentity-" + featureElementArr[0] + "'>" + featureProperties[featureElement] + "</div></td>"; content += "</tr>"; } } popup.content = content += "</table>"; return popup; } /** * todo 定位到气泡框 */ function moveToPopup() {
// 用于定位的[x,y] let xy; // 图形要素的类型;面线和点获取 xy 方式不同 let type = feature.getGeometry().getType(); // 获取面线和点的 xy if ('Polygon' == type || 'LineString' == type) {
xy = ol.extent.getCenter(feature.getGeometry().getExtent()); } else {
xy = feature.getGeometry().getCoordinates(); } // 定位位置(y 轴) let init = 500; // 获取气泡框高度 let heightTemp = init + $('#popup-leaflet-container-southejor').height() - 40; heightTemp = heightTemp || 680; // 计算 y 轴间隔 let gap = map.getCoordinateFromPixel([300, heightTemp])[1] - map.getCoordinateFromPixel([300, init])[1]; xy && xy.length > 1 && (xy[1] = xy[1] - gap); // 定位;位置,定位时长 let flyTo = function (location, time) {
let duration = time ? time : 2000; let zoom = map.getView().getZoom(); let parts = 2; let called = false; // 定位回调 function callback(complete) {
--parts; if (called) {
return; } if (parts === 0 || !complete) {
called = true; } } // 定位动作 map.getView().animate({
center: location, duration: duration }, callback); // 定位动作 map.getView().animate({
zoom: zoom - 1, duration: duration / 2 }, {
zoom: zoom, duration: duration / 2 }, callback); } flyTo(xy, 1000); } /** * todo 关闭气泡框 * @param _map */ function closeInfoWindowHtml() {
map.removeOverlay(popup); } </script>
<button id="openInfoWindowHtml" onClick="openInfoWindowHtml()">打开气泡框</button>
<button id="moveToPopup" onClick="moveToPopup()">定位到气泡框</button>
<button id="closeInfoWindowHtml" onClick="closeInfoWindowHtml()">关闭气泡框</button>
</body>
</html>
在线示例
Openlayers 自定义气泡框:Openlayers feature popup
边栏推荐
- [mathematical modeling] [matlab] implementation of two-dimensional rectangular packing code
- sql刷题586. 订单最多的客户
- 模板引擎Velocity 基礎
- Computed property “xxx“ was assigned to but it has no setter.
- 中国超高分子量聚乙烯产业调研与投资前景报告(2022版)
- C語言輸入/輸出流和文件操作
- libcurl下载文件的代码示例
- The amazing open source animation library is not only awesome, but also small
- How to cancel automatic search and install device drivers for laptops
- String class
猜你喜欢
Hi Fun Summer, play SQL planner with starrocks!
Pytest learning notes (13) -allure of allure Description () and @allure title()
GameFramework食用指南
How to solve the keyboard key failure of notebook computer
6月刊 | AntDB数据库参与编写《数据库发展研究报告》 亮相信创产业榜单
Introduction to software engineering - Chapter 6 - detailed design
英特尔开源深度学习工具库 OpenVINO,将加大与本土软硬件方合作,持续开放
Babbitt | yuan universe daily must read: Naixue coin, Yuan universe paradise, virtual stock game Do you understand Naixue's tea's marketing campaign of "operation pull full"
Borui data integrated intelligent observable platform was selected into the "Yunyuan production catalogue" of China Academy of communications in 2022
National Security Agency (NSA) "sour Fox" vulnerability attack weapon platform technical analysis report
随机推荐
Machine learning 11 clustering, outlier discrimination
How wild are hackers' ways of making money? CTF reverse entry Guide
单例模式的懒汉模式跟恶汉模式的区别
China carbon disulfide industry research and investment strategy report (2022 Edition)
整形数组合并【JS】
Shenyu gateway development: enable and run locally
Encryption and decryption of tinyurl in leetcode
GameFramework食用指南
【flask入门系列】Cookie与Session
C语言输入/输出流和文件操作
可迭代对象与迭代器、生成器的区别与联系
PR basic clip operation / video export operation
vulnhub靶场-hacksudo - Thor
What are the differences between PHP and DW
判断一棵二叉树是否为平衡二叉树
Babbitt | yuan universe daily must read: Naixue coin, Yuan universe paradise, virtual stock game Do you understand Naixue's tea's marketing campaign of "operation pull full"
Yyds dry inventory MySQL RC transaction isolation level implementation
中国氮化硅陶瓷基板行业研究与投资前景报告(2022版)
[C language foundation] 12 strings
Template engine velocity Foundation