1、
我們老師的書籍《WebGIS之Openlayers全面解析》上面有關於popup的例子,作爲例子,肯定是寫死的,沒有查詢數據庫,也就是隻有一個地理位置。(先不要管爲什麼看不到地圖 )如下圖:
2、
我想要的效果就是,查詢數據庫,找出所有的監測站點,並把這些站點顯示在地圖上,點擊不同的站點能彈出不同的信息。如下圖,是我想要的效果:
3、
先給出書本上參考例子的代碼,接下來對例子的代碼進行修改,達到我想要的效果。(要想看到地圖,更換另一種地圖即可,MapQuest地圖不能用)
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>添加Popup標註</title>
<link href="../../libs/ol/ol.css" rel="stylesheet" type="text/css" />
<script src="../../libs/ol/ol.js" type="text/javascript"></script>
<!-- <script src="../../libs/ol/ol-debug.js" type="text/javascript"></script>-->
<!-- 引入第三方插件庫 -->
<script src="../../libs/jquery-1.11.2.min.js" type="text/javascript"></script>
<style type="text/css">
body,html{
border:none;padding:0;margin:0;
}
#menu{
width:100%;
height:20px;
padding:5px 10px;
font-size:14px;
font-family:"微軟雅黑";
left:10px;
}
#map{
width:100%;
height:570px;
position: relative;
}
.ol-popup {
position: absolute;
background-color: white;
-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));
padding: 15px;
border-radius: 10px;
border: 1px solid #cccccc;
bottom: 12px;
left: -50px;
}
.ol-popup:after, .ol-popup:before {
top: 100%;
border: solid transparent;
content: " ";
height: 0;
width: 0;
position: absolute;
pointer-events: none;
}
.ol-popup:after {
border-top-color: white;
border-width: 10px;
left: 48px;
margin-left: -10px;
}
.ol-popup:before {
border-top-color: #cccccc;
border-width: 11px;
left: 48px;
margin-left: -11px;
}
.ol-popup-closer {
text-decoration: none;
position: absolute;
top: 2px;
right: 8px;
}
.ol-popup-closer:after {
content: "✖";
}
#popup-content{
font-size:14px;
font-family:"微軟雅黑";
}
#popup-content .markerInfo {
font-weight:bold;
}
</style>
</head>
<body>
<div id="menu">
鼠標單擊標註點彈出Popup標註
</div>
<div id="map" >
<!-- Popup -->
<div id="popup" class="ol-popup" >
<a href="#" id="popup-closer" class="ol-popup-closer"></a>
<div id="popup-content">
</div>
</div>
</div>
<script type="text/javascript">
var beijing = ol.proj.fromLonLat([116.28, 39.54]);
//示例標註點北京市的信息對象
var featuerInfo = {
geo: beijing,
att: {
title: "北京市(中華人民共和國首都)", //標註信息的標題內容
titleURL: "http://www.openlayers.org/", //標註詳細信息鏈接
text: "北京(Beijing),簡稱京,中華人民共和國首都、直轄市,中國的政治、文化和國際交往中心……", //標註內容簡介
imgURL: "../../images/label/bj.png" //標註的圖片
}
}
/**
* 實例化Map對象加載地圖,默認底圖加載MapQuest地圖
*/
var map = new ol.Map({
layers: [
new ol.layer.Tile({
source: new ol.source.MapQuest({ layer: 'osm' })
})
],
target: 'map',
view: new ol.View({
center: beijing,
zoom: 3
})
});
/**
* 創建標註樣式函數,設置image爲圖標ol.style.Icon
* @param {ol.Feature} feature 要素
*/
var createLabelStyle = function (feature) {
return new ol.style.Style({
image: new ol.style.Icon(/** @type {olx.style.IconOptions} */({
anchor: [0.5, 60],
anchorOrigin: 'top-right',
anchorXUnits: 'fraction',
anchorYUnits: 'pixels',
offsetOrigin: 'top-right',
// offset:[0,10],
// scale:0.5, //圖標縮放比例
opacity: 0.75, //透明度
src: '../../images/label/blueIcon.png' //圖標的url
})),
text: new ol.style.Text({
textAlign: 'center', //位置
textBaseline: 'middle', //基準線
font: 'normal 14px 微軟雅黑', //文字樣式
text: feature.get('name'), //文本內容
fill: new ol.style.Fill({ color: '#aa3300' }), //文本填充樣式(即文字顏色)
stroke: new ol.style.Stroke({ color: '#ffcc33', width: 2 })
})
});
}
//實例化Vector要素,通過矢量圖層添加到地圖容器中
var iconFeature = new ol.Feature({
geometry: new ol.geom.Point(beijing),
name: '北京市', //名稱屬性
population: 2115 //大概人口數(萬)
});
iconFeature.setStyle(createLabelStyle(iconFeature));
//矢量標註的數據源
var vectorSource = new ol.source.Vector({
features: [iconFeature]
});
//矢量標註圖層
var vectorLayer = new ol.layer.Vector({
source: vectorSource
});
map.addLayer(vectorLayer);
/**
* 實現popup的html元素
*/
var container = document.getElementById('popup');
var content = document.getElementById('popup-content');
var closer = document.getElementById('popup-closer');
/**
* 在地圖容器中創建一個Overlay
*/
var popup = new ol.Overlay(/** @type {olx.OverlayOptions} */({
element: container,
autoPan: true,
positioning: 'bottom-center',
stopEvent: false,
autoPanAnimation: {
duration: 250
}
}));
map.addOverlay(popup);
/**
* 添加關閉按鈕的單擊事件(隱藏popup)
* @return {boolean} Don't follow the href.
*/
closer.onclick = function () {
popup.setPosition(undefined); //未定義popup位置
closer.blur(); //失去焦點
return false;
};
/**
* 動態創建popup的具體內容
* @param {string} title
*/
function addFeatrueInfo(info) {
//新增a元素
var elementA = document.createElement('a');
elementA.className = "markerInfo";
elementA.href = info.att.titleURL;
//elementA.innerText = info.att.title;
setInnerText(elementA, info.att.title);
content.appendChild(elementA); // 新建的div元素添加a子節點
//新增div元素
var elementDiv = document.createElement('div');
elementDiv.className = "markerText";
//elementDiv.innerText = info.att.text;
setInnerText(elementDiv, info.att.text);
content.appendChild(elementDiv); // 爲content添加div子節點
//新增img元素
var elementImg = document.createElement('img');
elementImg.className = "markerImg";
elementImg.src = info.att.imgURL;
content.appendChild(elementImg); // 爲content添加img子節點
}
/**
* 動態設置元素文本內容(兼容)
*/
function setInnerText(element, text) {
if (typeof element.textContent == "string") {
element.textContent = text;
} else {
element.innerText = text;
}
}
/**
* 爲map添加點擊事件監聽,渲染彈出popup
*/
map.on('click', function (evt) {
var coordinate = evt.coordinate;
//判斷當前單擊處是否有要素,捕獲到要素時彈出popup
var feature = map.forEachFeatureAtPixel(evt.pixel, function (feature, layer) { return feature; });
if (feature) {
content.innerHTML = ''; //清空popup的內容容器
addFeatrueInfo(featuerInfo); //在popup中加載當前要素的具體信息
if (popup.getPosition() == undefined) {
popup.setPosition(coordinate); //設置popup的位置
}
}
});
/**
* 爲map添加鼠標移動事件監聽,當指向標註時改變鼠標光標狀態
*/
map.on('pointermove', function (e) {
var pixel = map.getEventPixel(e.originalEvent);
var hit = map.hasFeatureAtPixel(pixel);
map.getTargetElement().style.cursor = hit ? 'pointer' : '';
});
</script>
</body>
</html>
4、
- 想要達到動態效果,上面的地方有兩處需要修改,
先找到下面的代碼塊
//實例化Vector要素,通過矢量圖層添加到地圖容器中
var iconFeature = new ol.Feature({
geometry: new ol.geom.Point(beijing),
name: '北京市', //名稱屬性
population: 2115 //大概人口數(萬)
});
iconFeature.setStyle(createLabelStyle(iconFeature));
//矢量標註的數據源
var vectorSource = new ol.source.Vector({
features: [iconFeature]
});
- 然後在後面追加如下代碼:
$.post("../FindAlllStationServlet",function (data)
{
for(var i=0;i<data.length;i++)
{
var obj=data[i];
var longitude=obj.longitude;
var latitude=obj.latitude;
var stationName=obj.stationName;
//實例化Vector要素,通過矢量圖層添加到地圖容器中
var iconFeature2 = new ol.Feature({
geometry: new ol.geom.Point(ol.proj.fromLonLat([longitude,latitude])),
name: stationName, //名稱屬性
population: 2115 //大概人口數(萬)
});
iconFeature2.setStyle(createLabelStyle(iconFeature2));
//矢量標註的數據源
vectorSource.addFeature(iconFeature2)
}
});
代碼說明:向服務器發送Ajax請求,服務器響應回來許多個站點的數據,站點表如下:
用一個for循環,遍歷一個站點對象數組,把這些監測站點全部顯示在地圖上。
還有一處的代碼需要修改
先找到爲地圖綁定單擊事件的代碼
/**
* 爲map添加點擊事件監聽,渲染彈出popup
*/
map.on('click', function (evt) {
把這個單擊事件修改成如下樣子:
map.on('click', function (evt) {
var coordinate = evt.coordinate;
var zuobiao4326=ol.proj.transform(coordinate, 'EPSG:3857' ,'EPSG:4326');
var jingdu=zuobiao4326[0];
var weidu=zuobiao4326[1];
var zuobiao=jingdu+","+weidu;
//判斷當前單擊處是否有要素,捕獲到要素時彈出popup
var feature = map.forEachFeatureAtPixel(evt.pixel, function (feature, layer) { return feature; });
if (feature)
{
$.post("../FindSimIntroServlet",{zuobiao:zuobiao},function (data)
{
var introduction=data.introduction;
var stationName=data.stationName;
featuerInfo.att.text=introduction;//正文
featuerInfo.att.title=stationName;//標題
content.innerHTML = ''; //清空popup的內容容器
addFeatrueInfo(featuerInfo); //在popup中加載當前要素的具體信息
if (popup.getPosition() == undefined)
{
popup.setPosition(coordinate); //設置popup的位置
}
});
}
});
代碼說明:獲取鼠標點擊位置的經緯度,然後把經緯度發送到後臺,後臺拿到了經緯度的信息後,根據經緯度查詢數據庫,
我的SQL語句如下:
SELECT * FROM water_quality_station WHERE ABS(longitude-?)<0.1 AND ABS(latitude-?)<0.1;
SQL語句的含義:abs()是求絕對值的函數,這條語句就是找出與給定位置經度之差小於0.1,並且緯度之差小於0.1的監測站。
這裏是有個小小的問題,假如兩個監測站黏在一塊的話(當然事實上不存在這種監測站),那麼查出來的就是兩條記錄,我們只能選擇其中的一條記錄發送給前端了。用戶這時可能會抱怨:我明明點擊的是A監測站,你爲什麼給我顯示B監測站的信息?
誤差範圍我選擇的是0.1,經過測試,這個值不能取得太大,也不能取得太小。太大的話,就會查出很多的記錄;太小的話一條都查不到,也就是用戶明明點擊了圖標,卻沒有彈出相應的信息。
5、測試效果
先點擊河南駐馬店班臺:
在點擊安徽阜陽徐莊:
已經實現了點擊不同圖標彈出不同信息的效果。實際上點擊一次圖標就會向後臺發送一次請求。
總結
- 想要實現點擊不同popup彈出不同信息的效果,只需修改書本例子中的兩處代碼。
- 實現的原理就是獲取鼠標點擊處的經緯度,然後把經緯度發送到後臺。後臺根據經緯度,返回一個監測站對象。