openlayer在地图坐标系:4326上根据鼠标点击画线,并围绕路线生成闭环区域

最终效果:

1.参考官网地址:https://openlayers.org/en/latest/examples/jsts.html   官网默认坐标系是:3857

2.版本:

2.1 openlayer 版本:6.3.1 //js地图操作必要

2.2 jsts 版本:https://unpkg.com/jsts@2.0.2/dist/jsts.min.js  //生成闭环区域需要使用

2.3 rbush.js //画线需要使用

3.建立坐标系4326 的地图服务

var mapServer;

//地图中心点位

var gcenter = [114.025705,22.68988];

//初始化地图图层

var gzoom = 13;

//地图最小缩小图层

var gminZoom = 1;

//地图最大放大图层

var gmaxZoom  = 16;

//地图图片加载路径

var gispath="http://127.0.0.1:8082/map/{z}/{n}/{x}_{y}.png";

//地图坐标生成对应图片路径

function tileUrlFunction(tileCoord, pixelRatio, projection) {
var z = tileCoord[0];
var x = tileCoord[1];
var y = tileCoord[2] - 1; 
var height = (1 << z);
var num2 = (height * y) + x;
var num3 = parseInt(num2 / 10000);
var url = gispath.replace('{z}', z).replace('{y}', y).replace('{n}', num3).replace('{x}', x);
return url;
}
//地图layer
var Thai = new ol.layer.Tile({
source: new ol.source.XYZ({ 
tileUrlFunction: tileUrlFunction,
wrapX: false
})
});

function mapServerBuild(){

mapServer = new ol.Map({
layers: [Thai],
view: new ol.View({
center:gcenter,
projection: 'EPSG:4326',
zoom: gzoom,
minZoom: gminZoom,
maxZoom: gmaxZoom
//extent:extentPoint 地图可查看边界
}),
logo : false,
controls : new ol.control.defaults({
zoom : false
// 隐藏缩放按钮
}),
target: document.getElementById('sitemap')
});

}

4.创建点击事件并进行画线

var clickPoints = [];//保留地图点击点位

mapServer.on('click', function(event){
var currentPoint={} ;
currentPoint.x = event.coordinate[0];
currentPoint.y = event.coordinate[1];
console.log("x:"+currentPoint.x+" "+"y:"+currentPoint.y);
clickPoints.push(currentPoint);
//限制,最多画5条线
if(clickPoints.length > 1 && clickPoints.length <=6){
drawLines(clickPoints);
}

}

})

function drawLines(pointArray){
var arrayLine = [];
for(var i=0;i<pointArray.length;i++){
var point = pointArray[i];
//新增如果坐标无法识别,则过滤掉
if(isNaN(point.x)){ continue;}
if(isNaN(point.y)){ continue;}
// 新增坐标默认0的进行过滤 
if(point.x == 0 && point.y == 0){continue;}
arrayLine.push([point.x,point.y]);
}

if(arrayLine.length!=0){
//地图划线
if(arrayLine.length>1){
for(var i =0 ;i<arrayLine.length-1;i++){
var arrayLines = [];
arrayLines.push(arrayLine[i]);
arrayLines.push(arrayLine[i+1]);
lineString(arrayLines);
}
}else{
lineString(arrayLine);
}
}

}

/**
* eg: 
var arrayLines = [];
arrayLines.push([x,y]);
arrayLines.push([x1,y1]);
lineString(arrayLines);
* 画线
* @param zb
*/

function lineString(zb){
var vectorLine = new ol.source.Vector({}); //线
var lineLayer = new ol.layer.Vector({
style : function(feature){
return styleFunction(feature,0.000072);
}
});
mapServer.addLayer(lineLayer);
if(zb.length>1){
var line = new ol.Feature({
geometry : new ol.geom.LineString(zb)
});
vectorLine.addFeature(line);
lineLayer.setSource(vectorLine);

}
}

//轨迹线样式

var styleFunction = function(feature,res){
//轨迹线图形
var trackLine= feature.getGeometry();
var styles = [
new ol.style.Style({

stroke: new ol.style.Stroke({
color: '#fc0101',
width: 2
})
})
];

//对segments建立btree索引
let tree= rbush();//路段数
trackLine.forEachSegment(function(start, end) {
var dx = end[0] - start[0];
var dy = end[1] - start[1];
//计算每个segment的方向,即箭头旋转方向
let rotation = Math.atan2(dy, dx);
let geom=new ol.geom.LineString([start,end]);
let extent=geom.getExtent();
var item = {
minX: extent[0],
minY: extent[1],
maxX: extent[2],
maxY: extent[3],
geom: geom,
rotation:rotation
};
tree.insert(item);
});
//轨迹地理长度
let length=trackLine.getLength();
//像素间隔步长
let stpes=50;//像素步长间隔
//将像素步长转实际地理距离步长
let geo_steps=stpes*res;
//箭头总数
let arrowsNum=parseInt(length/geo_steps);
for(let i=1;i<arrowsNum;i++){
let arraw_coor=trackLine.getCoordinateAt(i*1.0/arrowsNum);
let tol=0.0001;//查询设置的点的容差,测试地图单位是米。如果是4326坐标系单位为度的话,改成0.0001.
let arraw_coor_buffer=[arraw_coor[0]-tol,arraw_coor[1]-tol,arraw_coor[0]+tol,arraw_coor[1]+tol];
//进行btree查询
var treeSearch = tree.search({
minX: arraw_coor_buffer[0],
minY: arraw_coor_buffer[1],
maxX: arraw_coor_buffer[2],
maxY: arraw_coor_buffer[3]
});
let arrow_rotation;
//只查询一个,那么肯定是它了,直接返回
if(treeSearch.length==1)
arrow_rotation=treeSearch[0].rotation;
else if(treeSearch.length>1){
let results=treeSearch.filter(function(item){
//箭头点与segment相交,返回结果。该方法实测不是很准,可能是计算中间结果
//保存到小数精度导致查询有点问题
// if(item.geom.intersectsCoordinate(arraw_coor))
// return true;

//换一种方案,设置一个稍小的容差,消除精度问题
let _tol=1;//消除精度误差的容差
if(item.geom.intersectsExtent([arraw_coor[0]-_tol,arraw_coor[1]-_tol,arraw_coor[0]+_tol,arraw_coor[1]+_tol]))
return true;
})
if(results.length>0)
arrow_rotation=results[0].rotation;
}
}
return styles;
}

 

5.根据所画线,生成闭环区域

var vectorCloseCycleSource = new ol.source.Vector({}); //闭环线资源
var vectorCloseCycleLayer = new ol.layer.Vector({
style : new ol.style.Style({
stroke: new ol.style.Stroke({
color: '#fc0101',
width: 1
})
})
});//比环线layer

/*
* 画闭环
* @param pointArray 坐标点位数组
* @param drawCloseCycle 闭环宽度设置 默认80
*/
function drawCloseCycle(pointArray){
if(pointArray.length <=1)return;
console.log(pointArray);
var json = constructFeatureJson(pointArray);
var format = new ol.format.GeoJSON();
var features = format.readFeatures(json, {featureProjection: 'EPSG:4326'});
var parser = new jsts.io.OL3Parser();

parser.inject(
ol.geom.Point, 
ol.geom.LineString, 
ol.geom.LinearRing, 
ol.geom.Polygon,
ol.geom.MultiPoint, 
ol.geom.MultiLineString, 
ol.geom.MultiPolygon
);

for (var i = 0; i < features.length; i++) {
var feature = features[i];
// convert the OpenLayers geometry to a JSTS geometry
var jstsGeom = parser.read(feature.getGeometry());

// create a buffer of 40 meters around each line
var buffered = jstsGeom.buffer(metertodegree(40,jstsGeom._points._coordinates[0].y));

// convert back from JSTS and replace the geometry on the feature
feature.setGeometry(parser.write(buffered));
console.log("feature:");
console.log(feature.getGeometry());
}

vectorCloseCycleLayer.setSource(vectorCloseCycleSource);
mapServer.addLayer(vectorCloseCycleLayer);
vectorCloseCycleSource.addFeatures(features);
console.log("------------");
console.log(features[0].getGeometry().flatCoordinates);
console.log("------------");
}
/*
* 构建闭环json
*/
function constructFeatureJson(pointArray){
var featuresJson = '{';
featuresJson += '"features": [{';
featuresJson += '"geometry": {';
featuresJson += '"coordinates": [';
var point;
for(var i=0;i<pointArray.length;i++){
featuresJson += '[';
//坐标系转换,默认地图的3857 要转为 4326坐标系。
//point = [pointArray[i].x,pointArray[i].y];
//point = ol.proj.transform(point,"EPSG:3857","EPSG:4326");
//featuresJson += point[0]+',';
//featuresJson += point[1];

featuresJson += pointArray[i].x+',';
featuresJson += pointArray[i].y;

featuresJson += ']';
if(i + 1 < pointArray.length){
featuresJson += ',';
}
}
featuresJson += '],';
featuresJson += '"type": "LineString"';
featuresJson += '},';
featuresJson += '"id": "way/33803251",';
featuresJson += '"type": "Feature"';
featuresJson += '}],';
featuresJson += '"type": "FeatureCollection"';
featuresJson += '}';
return featuresJson;
}
var radiusEarth = 6378137
/*米数 转换 度数*/
function metertodegree (distance, lat) {
return 180 * distance / (Math.PI * radiusEarth * Math.cos(lat * Math.PI / 180))
}

 

posted @ 2020-05-28 10:01  SimpleSmile  阅读(1785)  评论(2编辑  收藏  举报