Cesium学习笔记10——通过WFS服务实现交互式属性查询
1.Cesium学习笔记1——安装配置2.Cesium学习笔记2——第一个Cesium程序3.地图服务器GeoServer4.Geoserver发布地图服务5.Cesium学习笔记3——调用Geoserver发布的WMS服务6.Cesium学习笔记4——加载天地图地图服务7.Cesium学习笔记5——加载topojson和Geojson8.Cesium学习笔记6——加载倾斜摄影模型9.Cesium开发遇到的问题解决10.Cesium学习笔记7——几何体绘制11.Cesium学习笔记8——加载城市建筑物火柴盒模型12.Cesium学习笔记9——鼠标交互绘制
13.Cesium学习笔记10——通过WFS服务实现交互式属性查询
14.Cesium学习笔记11——坐标量测15.Cesium学习笔记12——基于Cesium的分层分户模型构建与可视化1.功能说明:
鼠标绘制多边形进行查询,通过多边形范围,调用Geoserver发布的WFS服务,查询相交的地图要素,将返回结果高亮显示。
单击高亮显示的要素,显示要素的属性信息。
2.网页html代码:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no" /> <meta name="description" content="Draw point on terrain with mouse clicks."> <meta name="cesium-sandcastle-labels" content="Showcases"> <title>WFS属性查询</title> <script src="http://libs.baidu.com/jquery/2.1.4/jquery.min.js"></script> <script type="text/javascript" src="Sandcastle-header.js"></script> <script type="module" src="load-cesium-es6.js"></script> <script src="./Build/CesiumUnminified/Cesium.js"></script> <script>window.CESIUM_BASE_URL = "./Build/CesiumUnminified/";</script> </head> <body class="sandcastle-loading" data-sandcastle-bucket="bucket-requirejs.html"> <style> @import url(bucket.css); html, body, #cesiumContainer { width: 100%; height: 100%; margin: 0; padding: 0; overflow: hidden; } </style> <div id="cesiumContainer" class="fullSize"></div> <div id="loadingOverlay"><h1>Loading...</h1></div> <div id="toolbar"> <table class="infoPanel"> <tbody> <tr> <td>左键单击绘制点,右击结束线矩形框绘制。</td> </tr> </tbody> </table> </div> <div id="infowindow" style="position:absolute;top:10px;right:10px;z-index:999;background:rgb(18, 100, 138);width:200px;height:50px;font-size:13px;display:none;line-height:25px;"></div> <script src="./code.js"> </script> </body> </html>
3.编写的code.js代码:
Cesium.Ion.defaultAccessToken='你的Token'; window.startup = async function (Cesium) { 'use strict'; //增加视图区 const viewer = new Cesium.Viewer("cesiumContainer", { geocoder: false, homeButton: true, sceneModePicker: false, fullscreenButton: false, vrButton: false, baseLayerPicker: false, infoBox: false, selectionIndicator: false, animation: false, timeline: false, shouldAnimate: true, navigationHelpButton: false, navigationInstructionsInitiallyVisible: false, terrainProvider: Cesium.createWorldTerrain(), imageryProvider: new Cesium.UrlTemplateImageryProvider({ //url: 'http://mt0.google.cn/vt/lyrs=t,r&hl=zh-CN&gl=cn&x={x}&y={y}&z={z}', //url: 'https://server.arcgisonline.com/arcgis/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}', url: "http://map.geoq.cn/ArcGIS/rest/services/ChinaOnlineStreetPurplishBlue/MapServer/tile/{z}/{y}/{x}", //tilingScheme : new Cesium.GeographicTilingScheme(), credit: '' }), }); //绘制geojson图层样式 var geoJsonStyle = { stroke: Cesium.Color.YELLOW, strokeWidth: 3, fill: Cesium.Color.YELLOW.withAlpha(0.1) }; var geoserverUrl = 'http://127.0.0.1:8180/geoserver/NtuWrokspace'; viewer.cesiumWidget.screenSpaceEventHandler.removeInputAction( Cesium.ScreenSpaceEventType.LEFT_DOUBLE_CLICK ); function createPoint(worldPosition) { const point = viewer.entities.add({ position: worldPosition, point: { color: Cesium.Color.RED, pixelSize: 5, heightReference: Cesium.HeightReference.CLAMP_TO_GROUND, }, }); return point; } let drawingMode = "polygon"; function drawShape(positionData) { let shape; if (drawingMode === "rectangle") { } else if (drawingMode === "polygon") { shape = viewer.entities.add({ polygon: { hierarchy: positionData, material: new Cesium.ColorMaterialProperty( Cesium.Color.RED.withAlpha(0.7) ), }, }); } return shape; } /*空间查询图层 *@method queryByPolygon *@param polygon 空间范围 *@param typeName 图层名称 *@return null */ function queryByPolygon(polygon, typeName, callback){ var filter = '<Filter xmlns="http://www.opengis.net/ogc" xmlns:gml="http://www.opengis.net/gml">'; /*filter += '<And>';*/ filter += '<Intersects>'; filter += '<PropertyName>the_geom</PropertyName>'; filter += '<gml:Polygon>'; filter += '<gml:outerBoundaryIs>'; filter += '<gml:LinearRing>'; filter += '<gml:coordinates>' + polygon + '</gml:coordinates>'; filter += '</gml:LinearRing>'; filter += '</gml:outerBoundaryIs>'; filter += '</gml:Polygon>'; filter += '</Intersects>'; /*filter += '<PropertyIsLike wildCard="*" singleChar="#" escapeChar="!">'; filter += '<PropertyName>map_num</PropertyName>'; filter += '<Literal>*201911_440114*</Literal>'; filter += '</PropertyIsLike>'; */ /*filter += '</And>';*/ filter += '</Filter>'; var urlString = geoserverUrl + '/ows'; var param = { service: 'WFS', version: '1.0.0', request: 'GetFeature', typeName: typeName, outputFormat: 'application/json', filter: filter }; var geojsonUrl = urlString + getParamString(param, urlString); $.ajax({ url: geojsonUrl, async: true, type:'GET', dataType: 'json', success(result) { callback(result); }, error(err) { console.log(err); } }) } function getParamString(obj, existingUrl, uppercase){ var params = []; for (var i in obj) { params.push(encodeURIComponent(uppercase ? i.toUpperCase() : i) + '=' + encodeURIComponent(obj[i])); } return ((!existingUrl || existingUrl.indexOf('?') === -1) ? '?' : '&') + params.join('&'); } /* * 图层空间查询回调函数 */ function callbackLastQueryWFSService(data){ console.log('data',data); if(data && data.features.length>0){ clearGeojsonLayer(); loadGeojsonLayer(data); } } /* * 绘制图形函数 */ function loadGeojsonLayer(geojson){ var promise = Cesium.GeoJsonDataSource.load(geojson,geoJsonStyle); promise.then(function(dataSource) { viewer.dataSources.add(dataSource); viewer.zoomTo(dataSource); }).otherwise(function(error){ //Display any errrors encountered while loading. window.alert(error); }); } /* * 清空绘制图形函数 */ function clearGeojsonLayer(){ viewer.dataSources.removeAll(); } function clearMap(){ clearGeojsonLayer(); } function getExtentByPoints(points) { if (points) { // 指定世界范围 let lonMin = 180; let lonMax = -180; let latMin = 90; let latMax = -180; points.forEach(function (point) { const longitude = point[0]; const latitude = point[1]; // 计算边界 lonMin = longitude < lonMin ? longitude : lonMin; latMin = latitude < latMin ? latitude : latMin; lonMax = longitude > lonMax ? longitude : lonMax; latMax = latitude > latMax ? latitude : latMax; }); const xRange = lonMax - lonMin ? lonMax - lonMin : 1; const yRange = latMax - latMin ? latMax - latMin : 1; // 返回数据 return [lonMin - xRange / 10, latMin - yRange / 10, lonMax + xRange / 10, latMax + yRange / 10]; } return [-180,-90,180,90]; } /** * @todo 弧度坐标转经纬度坐标 * @param {Cartographic} cartographic - 弧度坐标 * @return {Object} - {longitude: x, latitude: y, height: h} - 返回经纬度 */ function cartographicToDegrees(cartographic) { const result = {}; result.longitude = Cesium.Math.toDegrees(cartographic.longitude); result.latitude = Cesium.Math.toDegrees(cartographic.latitude); if (cartographic.height > 0) { result.height = cartographic.height; } return result; } /** * @todo 获取 Cartesian3 四至范围 * @param {Cartesian3} cartesian3s - 世界坐标对象 * @return {*[]} */ function getExtentByCartesian3(cartesian3s) { if(cartesian3s instanceof Array && cartesian3s.length>0){ const points = []; for (let i = 0; i < cartesian3s.length; i++) { const cartesian3 = cartesian3s[i]; // 将 cartesian3 转为经纬度数组 const cartographic = Cesium.Cartographic.fromCartesian(cartesian3); const point = cartographicToDegrees(cartographic); points.push([point.longitude,point.latitude]); } return getExtentByPoints(points); } } let activeShapePoints = []; let activeShape; let floatingPoint; //窗口事件句柄 const handler = new Cesium.ScreenSpaceEventHandler(viewer.canvas); handler.setInputAction(function (event) { const ray = viewer.camera.getPickRay(event.position);//根据鼠标点击坐标和相机坐标构建射线 const earthPosition = viewer.scene.globe.pick(ray, viewer.scene);//射线与球面求交,在地面的交点 // `earthPosition` will be undefined if our mouse is not over the globe. if (Cesium.defined(earthPosition)) //鼠标点击在地球范围内 { if (activeShapePoints.length === 0) { floatingPoint = createPoint(earthPosition); activeShapePoints.push(earthPosition); const dynamicPositions = new Cesium.CallbackProperty(function () { if (drawingMode === "polygon") { return new Cesium.PolygonHierarchy(activeShapePoints); } return activeShapePoints; }, false);//回调函数 activeShape = drawShape(dynamicPositions); } activeShapePoints.push(earthPosition); // createPoint(earthPosition); } }, Cesium.ScreenSpaceEventType.LEFT_CLICK);//鼠标左键 handler.setInputAction(function (event) { if (Cesium.defined(floatingPoint)) { const ray = viewer.camera.getPickRay(event.endPosition); const newPosition = viewer.scene.globe.pick(ray, viewer.scene); if (Cesium.defined(newPosition)) { floatingPoint.position.setValue(newPosition); activeShapePoints.pop(); activeShapePoints.push(newPosition); } } }, Cesium.ScreenSpaceEventType.MOUSE_MOVE);//鼠标移动 //移除临时绘制图像. function terminateShape() { activeShapePoints.pop(); // drawShape(activeShapePoints); viewer.entities.remove(floatingPoint); viewer.entities.remove(activeShape); floatingPoint = undefined; activeShape = undefined; activeShapePoints = []; } handler.setInputAction(function (event) { var polygon = drawShape(activeShapePoints); //polygon.setVisible(false); var extent =getExtentByCartesian3(activeShapePoints); viewer.entities.remove(polygon); terminateShape(); drawingMode = "unknown"; if(extent && extent.length>0){ //构造polygon polygon = ''; polygon += extent[0] + ',' + extent[1] + ' ' ; polygon += extent[2] + ',' + extent[1] + ' ' ; polygon += extent[2] + ',' + extent[3] + ' ' ; polygon += extent[0] + ',' + extent[3] + ' ' ; polygon += extent[0] + ',' + extent[1] + ' ' ; } console.log('polygon',polygon); if(polygon){ queryByPolygon(polygon,'NtuWrokspace:省界_region',callbackLastQueryWFSService); } }, Cesium.ScreenSpaceEventType.RIGHT_CLICK);//鼠标右键 var highlightFace = null; viewer.screenSpaceEventHandler.setInputAction(function onLeftClick(movement) { var pickedFeature = viewer.scene.pick(movement.position); console.log('pickedFeature',pickedFeature); if(pickedFeature){ //判断之前是否有高亮面存在 if (highlightFace) { highlightFace.material = highlightFace.material0; } if(pickedFeature.id.polygon.material){ pickedFeature.id.polygon.material0 = pickedFeature.id.polygon.material; pickedFeature.id.polygon.material = Cesium.Color.DEEPSKYBLUE.withAlpha(0.8); highlightFace = pickedFeature.id.polygon; console.log('properties',pickedFeature.id.properties); //气泡窗口显示 var content = "<div>"+ "<span>图斑编号:</span><span>"+pickedFeature.id.properties.CODE+"</span></br>"+ "<span>图斑描述::</span><span>"+pickedFeature.id.properties.NAME+"</span></br>"+ "</div>"; $("#infowindow").show(); $("#infowindow").empty(); $("#infowindow").append(content); } } else{ if (highlightFace) { highlightFace.material = highlightFace.material0; } $("#infowindow").hide(); } }, Cesium.ScreenSpaceEventType.LEFT_CLICK); Sandcastle.addDefaultToolbarButton("框选查询", function () { terminateShape(); drawingMode = "polygon"; }); //Example 2: Load with basic styling options. Sandcastle.addToolbarButton("点选查询", function () { clearMap(); drawingMode = "unknown"; }); Sandcastle.reset = function () { viewer.dataSources.removeAll(); //Set the camera to a US centered tilted view and switch back to moving in world coordinates. viewer.camera.lookAt(Cesium.Cartesian3.fromDegrees(115.0, 45.0), new Cesium.Cartesian3(0.0, -4790000.0, 3930000.0) ); viewer.camera.lookAtTransform(Cesium.Matrix4.IDENTITY); }; //Sandcastle_End Sandcastle.finishedLoading(); }; if (typeof Cesium !== 'undefined') { window.startupCalled = true; window.startup(Cesium).catch((error) => { "use strict"; console.error(error); }); }
4.效果如下:
作者:太一吾鱼水
文章未经说明均属原创,学习笔记可能有大段的引用,一般会注明参考文献。
欢迎大家留言交流,转载请注明出处。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了