如何使用mapbox选择拾取地图要素
前言
你好! 最近在研究地图元素和客户端交互的方法,我将项目中的应用技能分享给大家!这是关于使用mapbox(点、线、多边形)选择或者称作拾取地图界面要素信息的一篇文章!
需要引入的js、css
我们除了最基本的jquery和mapbox之外,还需要引入turf.min.js,这是一个mapbox多边形和点、线选的插件。
<script type="text/javascript" src="jquery.min.js"></script>
<script type="text/javascript" src="mapbox-gl-draw.js"></script>
<script type="text/javascript" src="mapbox-gl.min.js"></script>
<script src='turf.min.js'></script>
<link type="text/css" rel="stylesheet" href="mapbox-gl.min.css"/>
<link type="text/css" rel="stylesheet" href="mapbox-gl-draw.css"/>
如何加载地图
页面内容如下,需要三个div;一个存放地图需要的展示信息、一个存放地图控件、一个存放地图。
<body>
<div id="draw_area" style="color: chocolate; font-weight: bold;"></div>
<div id="draws"></div>
<div id='map'></div>
</body>
我们需要定义一个demo.js;用来编写如何加载地图和如何拾取要素,页面上引用它,并在demo.js里先加载地图和地图控件,我们用iclient官网上的地图和要素数据。
var host = window.isLocal ? window.server : "https://iserver.supermap.io";
var drawHandleModel;
var attribution = "我的mapbox要素拾取demo";
var map = new mapboxgl.Map({
container: 'map', // container id
style: {
"version": 8,
"sources": {
"vector-tiles": {
"attribution": attribution,
"type": "vector",
"tiles": [host + "/iserver/services/map-beijing/rest/maps/beijingMap/tileFeature.mvt?"+
"returnAttributes=true&compressTolerance=-1&width=512&height=512&viewBounds={bbox-epsg-3857}"+
"&expands=0:0_2,132_128,138_64,141_32,143_16,145_8,147_4"
]
},
},
"sprite": "https://iclient.supermap.io/web/styles/street/sprite",
"glyphs": host + "/iserver/services/map-beijing/rest/maps/beijingMap/tileFeature/sdffonts/{fontstack}/{range}.pbf",
"layers": []
},
center: [116.4, 39.9],
minZoom: 10,
zoom: 11
});
map.addControl(new mapboxgl.NavigationControl(), 'top-left');
var map = getMap();
var draw = new MapboxDraw({
displayControlsDefault: false,
controls: {
point: true,
line_string: true,
polygon: true,
trash: true
}
});
window.Draw = draw;
map.addControl(draw, "top-right");
map.on("draw.create", this.updateArea);
map.on("draw.update", this.updateArea);
map.on("draw.delete", this.delArea);
然后加载地图要素
map.on('load', function() {
map.addLayer({
"id": "background",
"type": "background",
"layout": {},
"paint": {
"background-color": "#75CFF0"
}
});
map.addLayer({
"id": "面区界R@北京",
"type": "fill",
"source": "vector-tiles",
"source-layer": "面区界R@北京",
"paint": {
"fill-color": "#EFE9E1",
}
});
map.addLayer({
"id": "界线@北京",
"type": "line",
"source": "vector-tiles",
"source-layer": "界线@北京",
"paint": {
"line-color": "hsl(240, 8%, 51%)",
"line-width": 0.5
}
});
map.addLayer({
"id": "立交桥绿地R@北京",
"type": "fill",
"source": "vector-tiles",
"source-layer": "立交桥绿地R@北京",
"paint": {
"fill-color": "hsl(100, 58%, 76%)",
"fill-opacity": {
"base": 1,
"stops": [
[
5,
0
],
[
6,
0.5
]
]
}
},
});
map.addLayer({
"id": "绿地R@北京",
"type": "fill",
"source": "vector-tiles",
"source-layer": "绿地R@北京",
"paint": {
"fill-color": "hsl(100, 58%, 76%)",
"fill-opacity": {
"base": 1,
"stops": [
[
5,
0
],
[
6,
0.5
]
]
}
},
});
map.addLayer({
"id": " 双线河R@北京",
"type": "fill",
"source": "vector-tiles",
"source-layer": "双线河R@北京",
"paint": {
"fill-color": "hsl(196, 80%, 70%)"
}
});
map.addLayer({
"id": "湖泊、水库R@北京",
"type": "fill",
"source": "vector-tiles",
"source-layer": "湖泊、水库R@北京",
"paint": {
"fill-color": "hsl(196, 80%, 70%)"
}
});
map.addLayer({
"id": " 四级道路L@北京",
"type": "line",
"source": "vector-tiles",
"source-layer": "四级道路L@北京",
"paint": {
"line-width": {
"base": 1.5,
"stops": [
[
11,
1
],
[
18,
10
]
]
},
"line-color": "hsl(0, 0%, 100%)",
}
});
});
地图上就是这样的效果
如何使用地图空间选择要素
先做地图点击事件
/**
* mapBox 提供强大的地图可视化功能
* */
map.on('click', function(e) {
// 以此点*px范围内的正方形算为点击反应区
var bbox = [
[e.point.x - 1, e.point.y - 1],
[e.point.x + 1, e.point.y + 1]
];
// mapbox 返回查询要素的图层属性
var features = map.queryRenderedFeatures(bbox, {
layers: ['湖泊、水库R@北京','一级道路L@北京','绿地R@北京']
});
// 返回查询图层属性feature合集
var filter_hp = features.reduce(
function(memo, feature) {
//console.log(feature);
if (feature.sourceLayer == '湖泊、水库R@北京') {
memo.push(feature.properties.SmID);
//alert(feature.properties.NAME);
} else {
console.log(feature.properties);
}
return memo;
},['in', 'SmID']
);
//返回符合查询要素集合后设置符合这些图层要素的属性
//map.setFilter('counties-highlighted-hp', filter_hp);
var filter_dl1 = features.reduce(
function(memo, feature) {
//console.log(feature);
if (feature.sourceLayer == '一级道路L@北京') {
memo.push(feature.properties.SmID);
alert(feature.properties.道路所属区域 + "——" +feature.properties.道路名称);
} else {
console.log(feature.properties);
}
return memo;
},
['in', 'SmID']
);
//map.setFilter('counties-highlighted-dl1', filter_dl1);
var filter_ld = features.reduce(
function(memo, feature) {
//console.log(feature);
if (feature.sourceLayer == '绿地R@北京') {
memo.push(feature.properties.SmID);
//alert(feature.properties.NAME);
} else {
console.log(feature.properties);
}
return memo;
},
['in', 'SmID']
);
//map.setFilter('counties-highlighted-ld', filter_ld);
});
还记的加载地图时的控件方法吗?我们需要定义控件方法的实现!
function newArea(){
//画新区域的方法
}
function delArea(){
//清除区域时
var answer = document.getElementById('draw_area');
answer.innerHTML = '';
}
function updateArea(e){
//更新区域时
var data = draw.getAll();
var answer = document.getElementById('draw_area');
if (data.features.length > 0) {
// 计算面积
var area = turf.area(data);
// restrict to area to 2 decimal points
var rounded_area = Math.round(area*100)/100;
answer.innerHTML = '<p><strong>' + rounded_area + '</strong> ㎡</p>';
//查询选中要素
var draw_polygon = turf.bbox(e.features[0]);
var southWest = [draw_polygon[0], draw_polygon[1]];
var northEast = [draw_polygon[2], draw_polygon[3]];
var northEastPointPixel = map.project(northEast);
var southWestPointPixel = map.project(southWest);
var features = map.queryRenderedFeatures([southWestPointPixel, northEastPointPixel], { layers: ['湖泊、水库R@北京','一级道路L@北京','绿地R@北京'] });
//框选结果
var filter_hp = features.reduce(
function(memo, feature) {
//console.log(feature);
if (feature.sourceLayer == '湖泊、水库R@北京') {
memo.push(feature.properties.SmID);
//alert(feature.properties.NAME);
} else {
console.log(feature.properties);
}
return memo;
},['in', 'SmID']
);
//返回符合查询要素集合后设置符合这些图层要素的属性
map.setFilter('counties-highlighted-hp', filter_hp);
var filter_dl1 = features.reduce(
function(memo, feature) {
//console.log(feature);
if (feature.sourceLayer == '一级道路L@北京') {
memo.push(feature.properties.SmID);
//alert(feature.properties.道路所属区域 + "——" +feature.properties.道路名称);
} else {
console.log(feature.properties);
}
return memo;
},
['in', 'SmID']
);
map.setFilter('counties-highlighted-dl1', filter_dl1);
var filter_ld = features.reduce(
function(memo, feature) {
//console.log(feature);
if (feature.sourceLayer == '绿地R@北京') {
memo.push(feature.properties.SmID);
//alert(feature.properties.NAME);
} else {
console.log(feature.properties);
}
return memo;
},
['in', 'SmID']
);
map.setFilter('counties-highlighted-ld', filter_ld);
// var filter_polygon = features.reduce(function(memo, feature) {
// if (! (undefined === turf.intersect(feature, e.features[0]))) {
// memo.push(feature.properties.SmID);
// //alert(feature.properties.NAME);
// }
// return memo;
// // memo.push(feature.properties.SmID);
// // //alert(feature.properties.NAME);
// // return memo;
// }, ['in', 'SmID']);
// map.setFilter("counties-highlighted-hp", filter_polygon);
} else {
answer.innerHTML = '';
if (e.type !== 'draw.delete') alert("请用绘制工具绘制图形后再试!");
}
}
这里我们高亮了选中图层的区域
我们需要定义这些layer
/**
* 下面添加选中变色layer
*/
map.addLayer({
'id': 'counties-highlighted-hp',
'type': 'fill',
'source': 'vector-tiles',
'source-layer': '湖泊、水库R@北京',
'paint': {
'fill-outline-color': '#484896',
'fill-color': '#6e599f',
'fill-opacity': 0.75
},
'filter': ['in', 'SmID', '']
}
); // Place polygon under these labels.
map.addLayer({
'id': 'counties-highlighted-dl1',
'type': 'fill',
'source': 'vector-tiles',
'source-layer': '一级道路L@北京',
'paint': {
'fill-outline-color': '#484896',
'fill-color': '#6e599f',
'fill-opacity': 0.75
},
'filter': ['in', 'SmID', '']
}
); // Place polygon under these labels.
map.addLayer({
'id': 'counties-highlighted-ld',
'type': 'fill',
'source': 'vector-tiles',
'source-layer': '绿地R@北京',
'paint': {
'fill-outline-color': '#484896',
'fill-color': '#6e599f',
'fill-opacity': 0.75
},
'filter': ['in', 'SmID', '']
}
); // Place polygon under these labels.
});
最后返回一个提供外部js访问的方法
var getMap = function (){
if (map) {
return map;
}
};
效果