移动地图查询矢量瓦片层的可视化特性并且通过输入过滤
<!DOCTYPE html> <html> <head> <meta charset='utf-8' /> <title></title> <meta name='viewport' content='initial-scale=1,maximum-scale=1,user-scalable=no' /> <script src='https://api.tiles.mapbox.com/mapbox-gl-js/v0.29.0/mapbox-gl.js'></script> <link href='https://api.tiles.mapbox.com/mapbox-gl-js/v0.29.0/mapbox-gl.css' rel='stylesheet' /> <style> body { margin:0; padding:0; } #map { position:absolute; top:0; bottom:0; width:100%; } </style> </head> <body> <style> #map { position:absolute; left:25%; top:0; bottom:0; width: 75%; } .map-overlay { position: absolute; width: 25%; top: 0; bottom: 0; left: 0; font: 12px/20px 'Helvetica Neue', Arial, Helvetica, sans-serif; background-color: #fff; max-height: 100%; overflow: hidden; } .map-overlay fieldset { display: none; background: #ddd; border: none; padding: 10px; margin: 0; } .map-overlay input { display: block; border: none; width: 100%; border-radius: 3px; padding: 10px; margin: 0; } .map-overlay .listing { overflow: auto; max-height: 100%; } .map-overlay .listing > * { display: block; padding: 5px 10px; margin: 0; } .map-overlay .listing a { border-bottom: 1px solid rgba(0, 0, 0, 0.1); color: #404; text-decoration: none; } .map-overlay .listing a:last-child { border: none; } .map-overlay .listing a:hover { background: #f0f0f0; } </style> <div id='map'></div> <!--
--><div class='map-overlay'> <fieldset> <input id='feature-filter' type='text' placeholder='Filter results by name' /> </fieldset> <div id='feature-listing' class='listing'></div> </div><script>mapboxgl.accessToken = '<your access token here>';var map = new mapboxgl.Map({ container: 'map', style: 'mapbox://styles/mapbox/streets-v9', center: [-98, 38.88], maxZoom: 5, minZoom: 1, zoom: 3});// Holds visible airport features for filteringvar airports = [];// Create a popup, but don't add it to the map yet.var popup = new mapboxgl.Popup({ /* new Popup(options: [Object]):Popup构造器 */ closeButton: false /* 设置Popup选项 */});var filterEl = document.getElementById('feature-filter');var listingEl = document.getElementById('feature-listing');function renderListings(features) { // Clear any existing listings listingEl.innerHTML = ''; /* 清除标签内部html文本内容 */ if (features.length) { /* 获取features,通过features的内容增加可视化的html */ features.forEach(function(feature) { /* 遍历 */ var prop = feature.properties; var item = document.createElement('a'); /* 创建html标签 */ item.href = prop.wikipedia; item.target = '_blank'; item.textContent = prop.name + ' (' + prop.abbrev + ')'; item.addEventListener('mouseover', function() { /* elem.addEventListener(type,callback)添加事件监听器 */ // Highlight corresponding feature on the map popup.setLngLat(feature.geometry.coordinates) /* setlngLat(lnglat):设置popup的位置并移动到那里 */ .setText(feature.properties.name + ' (' + feature.properties.abbrev + ')') /* setText(text)设置popup的文本显示内容 */ .addTo(map); /* addTo(map):将popup添加到地图上 */ }); listingEl.appendChild(item); /* 追加item html */ }); // Show the filter input filterEl.parentNode.style.display = 'block'; /* .style.display设置可见性 */ } else { var empty = document.createElement('p'); /* 添加<p>标签 */ empty.textContent = 'Drag the map to populate results'; /* .textContent属性设置文本内容 */ listingEl.appendChild(empty); // Hide the filter input filterEl.parentNode.style.display = 'none'; // remove features filter map.setFilter('airport', ['has', 'abbrev']); /* 过滤拥有"abbrev"的数据才显示 */ }}function normalize(string) { return string.trim().toLowerCase(); /* trim():移除字符串两端的空格,toLowerCase():改成小写 */}function getUniqueFeatures(array, comparatorProperty) { var existingFeatureKeys = {}; // Because features come from tiled vector data, feature geometries may be split // or duplicated across tile boundaries and, as a result, features may appear // multiple times in query results. var uniqueFeatures = array.filter(function(el) { /* array.filter(function(currentValue,index,arr), thisValue):filter() 方法创建一个新的数组,新数组中的元素是通过检查指定数组中符合条件的所有元素,currentValue,必须,当前元素的值;index,可选,当期元素的索引值;arr,可选,当期元素属于的数组对象;thisValue,可选。对象作为该执行回调时使用,传递给函数,用作 "this" 的值。 */ if (existingFeatureKeys[el.properties[comparatorProperty]]) { return false; } else { existingFeatureKeys[el.properties[comparatorProperty]] = true; return true; } }); return uniqueFeatures;}map.on('load', function() { // Add our vector tile source: World wide // airports provided by Natural Earth map.addSource('airports', { "type": "vector", "url": "mapbox://mapbox.04w69w5j" }); map.addLayer({ "id": "airport", "source": "airports", "source-layer": "ne_10m_airports", "type": "symbol", "layout": { /* 设置layout属性 */ "icon-image": "airport-15", "icon-padding": 0, "icon-allow-overlap":true } }); map.on('moveend', function() { var features = map.queryRenderedFeatures({layers:['airport']}); if (features) { var uniqueFeatures = getUniqueFeatures(features, "iata_code"); // Populate features for the listing overlay. renderListings(uniqueFeatures); // Clear the input container filterEl.value = ''; // Store the current features in sn `airports` variable to // later use for filtering on `keyup`. airports = uniqueFeatures; } }); map.on('mousemove', function(e) { var features = map.queryRenderedFeatures(e.point, { layers: ['airport'] }); // Change the cursor style as a UI indicator. map.getCanvas().style.cursor = features.length ? 'pointer' : ''; /* 设置光标属性 */ if (!features.length) { popup.remove(); return; } var feature = features[0]; // Populate the popup and set its coordinates // based on the feature found. popup.setLngLat(feature.geometry.coordinates) .setText(feature.properties.name + ' (' + feature.properties.abbrev + ')') .addTo(map); }); filterEl.addEventListener('keyup', function(e) { var value = normalize(e.target.value); // Filter visible features that don't match the input value. var filtered = airports.filter(function(feature) { var name = normalize(feature.properties.name); var code = normalize(feature.properties.abbrev); return name.indexOf(value) > -1 || code.indexOf(value) > -1; }); // Populate the sidebar with filtered results renderListings(filtered); // Set the filter to populate features into the layer. map.setFilter('airport', ['in', 'abbrev'].concat(filtered.map(function(feature) { /* concat() 方法用于连接两个或多个数组。该方法不会改变现有的数组,而仅仅会返回被连接数组的一个副本。map() 方法返回一个新数组,数组中的元素为原始数组元素调用函数处理后的值。map() 方法按照原始数组元素顺序依次处理元素。array.map(function(currentValue,index,arr), thisValue):currentValue,必须,当前元素的值;index,可选,当期元素的索引值;arr,可选,当期元素属于的数组对象;thisValue,可选。对象作为该执行回调时使用,传递给函数,用作 "this" 的值。 */ return feature.properties.abbrev; }))); }); // Call this function on initialization // passing an empty array to render an empty state renderListings([]);});</script></body></html><fieldset> 标签将表单内容的一部分打包,生成一组相关表单的字段。<fieldset> 标签没有必需的或唯一的属性。 当一组表单元素放到 <fieldset> 标签内时,浏览器会以特殊方式来显示它们,它们可能有特殊的边界、3D 效果,或者甚至可创建一个子表单来处理这些元素
原文:https://www.mapbox.com/mapbox-gl-js/example/filter-features-within-map-view/