leaflets学习——geoJSON图层
关注公众号,分享GIS知识、ArcGIS教程、SCI论文与科研日常等
提供实现从后端数据库postGIS提取矢量数据到前端,以及前端的矢量数据传到后端进行空间关系查询的思路。
这里数据的传输形式即为geoJSON格式。什么是geoJSON
1.前端leaflets-geoJSON图层
首先假定已经获取一个geoJSON对象,本质上是JSON格式:
var geojsonFeature = {
"type": "Feature",
"properties": {
"name": "Coors Field",
"amenity": "Baseball Stadium",
"popupContent": "This is where the Rockies play!"
},
"geometry": {
"type": "Point",
"coordinates": [-104.99404, 39.75621]
}
};
两种方式将它添加到地图:
L.geoJSON(geojsonFeature).addTo(map);
或者
var myLayer = L.geoJSON().addTo(map);
myLayer.addData(geojsonFeature);
其次还可以用geoJSON()的第二个参数options定义样式:
L.geoJSON(geojsonFeature, {
style: {
"color": "#ff7800",
"weight": 5,
"opacity": 0.65
}
}).addTo(map);
进一步,使用onEachFeature属性,在加入图层之前对feature进行调用处理,如绑定泡泡:
function onEachFeature(feature, layer) {
// does this feature have a property named popupContent?
if (feature.properties && feature.properties.popupContent) {
layer.bindPopup(feature.properties.popupContent);
}
}
L.geoJSON(geojsonFeature, {
style: {
"color": "#ff7800",
"weight": 5,
"opacity": 0.65
},
onEachFeature:onEachFeature
}).addTo(map);
2. 后端postGIS数据库geoJSON的使用
a. 从PostGIS数据库获取geoJSON格式。
从数据库查询到前端展示的过程。
假设数据库中有个简单的关系表mytable,它的元数据如下:
列名 | 值类型 |
---|---|
id | number |
name | text |
geom | geometry |
geom列存储的为几何信息。类型为geometry。后端Java连接数据库并查询该关系表。
查询SQL语句:
SELECT name,ST_AsGeoJSON(geom)::jsonb geomjson FROM mytable
ST_AsGeoJSON()为postgres的内置函数,名字很容易看出来,就是获取geometry的geoJSON格式。Java中,获取的结果为string,再处理一下,转为JSONObject格式。
JSONObject jsonObject =new JSONObject();
//大多数情况下为feaurecollection
ArrayList<JSONObject> featureslist = new ArrayList<JSONObject>();
while (resultSet.next()) {
JSONObject featureJsonObject = new JSONObject();
JSONObject featurePrpoJsonObject = new JSONObject();
String geometryJsonObjectstr=null;
JSONObject geometryJsonObject = null;
ResultSetMetaData schema = resultSet.getMetaData();
int columnCount = schema.getColumnCount();
int type;
String columnName;
for (int i=1;i<=columnCount;i++){
columnName = schema.getColumnName(i);
if(columnName.equals("name")){
featurePrpoJsonObject.put("name",resultSet.getString(i));
}
if (columnName.equals("geomjson")){
geometryJsonObjectstr = resultSet.getString(i);
//这里读取的查询结果,读成String类型,下一步再转为JSONObject
geometryJsonObject = new JSONObject(geometryJsonObjectstr);
}
}
featureJsonObject.put("type","Feature");
featureJsonObject.put("properties",featurePrpoJsonObject);
featureJsonObject.put("geometry",geometryJsonObject);
featureslist.add(featureJsonObject);
}
JSONObject[] features = list2jsonarr(featureslist);
jsonObject.put("features",features);
jsonObject.put("type","FeatrueCollection");
JsonContent =jsonObject.toString();
//response JsonContent到前端
private JSONObject[] list2jsonarr(ArrayList<JSONObject> featureslist){
JSONObject[] features=new JSONObject[featureslist.size()];
for (int i=0;i<featureslist.size();i++)
{
features[i]=featureslist.get(i);
}
return features;
}
b. geoJSON格式数据转为Post数据库的geom并执行空间关系查询
前端提交请求到后端数据库使用请求数据的过程。一般webGIS都需要处理空间查询工作。比如用户想要查询在河南省范围内的要素。
PostGIS数据库的内置函数ST_GeomFromGeoJSON()可以将geoJSON格式的数据或者geoJSON格式的字符串转为geometry。
geometry ST_GeomFromGeoJSON(text geomjson);
geometry ST_GeomFromGeoJSON(json geomjson);
geometry ST_GeomFromGeoJSON(jsonb geomjson);
例如进行下面的空间查询:
SELECT ST_AsGeoJSON(geom)::jsonb geomjson FROM mytable WHERE ST_Within(ST_SetSRID(geom,4326), ST_GeomFromGeoJSON('{"type":"Polygon","coordinates":[[[112.502324,44.543145],[105.558485,40.230489],[111.00808,36.723943],[117.336643,36.582973],[123.357567,45.072967],[116.765314,46.361079],[112.502324,44.543145]]]}'))
首先将geoJSON转化为geometry,在进行空间查询,这里的geojson不包含属性字段。只包含type和coordinates。因此如果是featurecollection的GeoJSON需要进一步处理。
{ "type":"Polygon",
"coordinates":[[[112.502324,44.543145],[105.558485,40.230489],[111.00808,36.723943],[117.336643,36.582973],[123.357567,45.072967],[116.765314,46.361079],[112.502324,44.543145]]]
}
拓展,postgis空间几何关系函数:
ST_Distance(geometry, geometry)
返回两个几何对象的距离(笛卡儿距离),不使用索引。
ST_DWithid(geometry, geometry, float)
如果一个几何对象(geometry)在另一个几何对象描述的距离(float)内,返回TRUE。如果有索引,会用到索引。
ST_Equals(geometry, geometry)
如果两个空间对象相等,则返回TRUE。用这个函数比用“=”更好,例如:
equals(‘LINESTRING(0 0, 10 10)’,’LINESTRING(0 0, 5 5, 10 10)’) 返回 TRUE。
ST_Disjoint(geometry, geometry)
如果两个对象不相连,则返回TRUE。不要使用GeometryCollection作为参数。
ST_Intersects(geometry, geometry)
判断两个几何空间数据是否相交,如果相交返回true,不要使用GeometryCollection作为参数。
Intersects(g1, g2 ) –> Not (Disjoint(g1, g2 ))
不使用索引可以用_ST_Intersects.
ST_Touches(geometry, geometry)
如果两个几何空间对象存在接触,则返回TRUE。不要使用GeometryCollection作为参数。
a.Touches(b) -> (I(a) intersection I(b) = {empty set} ) and (a intersection b) not empty
不使用索引可以用_ST_Touches.
ST_Crosses(geometry, geometry)
如果两个几何空间对象存在交叉,则返回TRUE。不要使用GeometryCollection作为参数。
不使用索引可以用_ST_Crosses.
ST_Within(geometry A, geometry B)
如果几何空间对象A存在空间对象B中,则返回TRUE,不要使用GeometryCollection作为参数。
不使用索引可以用_ST_Within
ST_Overlaps(geometry, geometry)
如果两个几何空间数据存在交迭,则返回 TRUE,不要使用GeometryCollection作为参数。
不使用索引可以用_ST_Overlaps.
ST_Contains(geometry A, geometry B)
如果几何空间对象A包含空间对象B,则返回 TRUE,不要使用GeometryCollection作为参数。
这个函数类似于ST_Within(geometry B, geometry A)
不使用索引可以用_ST_Contains.
ST_Covers(geometry A, geometry B)
如果几何空间对象B中的所有点都在空间对象A中,则返回 TRUE。
不要使用GeometryCollection作为参数。
不使用索引可以用_ST_Covers.
ST_CoveredBy(geometry A, geometry B)
如果几何空间对象A中的所有点都在空间对象B中,则返回 TRUE。
3. 前后端传输—AJAX
下面函数提供POST提交请求,进行空间查询,并将返回结果添加到map。查询条件包括数据集名称、特定区域内、起始时间等信息。与地理空间数据云的筛选数据差不多。
function fun(){
postdata={
//请求内容,根据后端框架自己定义
request:"getfeature",
requestContent:"measuredssm",
outputFormat:"application/json",
geomJson:JSON.stringify(shapefileLayer.toGeoJSON().features[0].geometry),
starttime:"2020-06-15",
endtime:"2020-07-15",
typeName:datasetname
};
$.post({
url:"/cai/WebFeatureServlet",
data:postdata,
dataType:"json",
success:function (res) {
geojsonlayer = L.geoJSON(res.features,
{
onEachFeature:onEachFeature2
}
).addTo(leafletmap);
},
error:function (err) {
window.alert(err);
}
});
}