vue+openlayers根据坐标点绘制多边形

5 篇文章 2 订阅
3 篇文章 0 订阅

需求:根据多边形轮廓点及中心点在天地图上绘制形状;不同类型的多边形轮廓以颜色区分
功能
1.中心点坐标实现聚合
2.根据地图的缩放级别显示或者隐藏多边形
3.鼠标移入多边形或者中心点实现高亮并显示弹框,移除恢复原来的效果
js代码

var map,layer_poly_A,layer_poly_B,layer_poly_C,layer_poi_A,layer_poi_B,layer_poi_C
const overlapOptions = ['A类', 'B类', 'C类'];
var app = new Vue({
	el: '#app',
	data: {
		loading:false,//加载标识
		arrow_show:true,//地图页的第一个箭头
		checkedA:false,//A类复选框
		checkedB:false,//B类复选框
		isLoadB:false,//控制B类数据加载的div
		checkedC:false,//C类复选框
		dkPopup1:false,//弹窗1,用于地块详情数据展示
		dkPopup2:false,//弹窗2,用于提示
		isPolygon:false,//弹窗1中,控制面积字段的显示
		//地图页地块提示语
		dk_detail:{
			lclass:"加载中……", pepeatCnt:"加载中……", belong :"加载中……", tbmj:"加载中……",clmj:"加载中……",
		},
	},
	mounted() {
		this.mapLoad();
	},
	methods: {
		mapLoad(){
			var that_=this
			//官方天地图
			var tdt_image =new ol.layer.Tile({
				source:new ol.source.XYZ({
					title: "天地图卫星影像图",
					url:"http://t0.tianditu.gov.cn/img_w/wmts?" +
					  "SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=img&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles" +
					  "&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}&tk=天地图秘钥"
				})
			})
			var tdt_text =new ol.layer.Tile({
				source:new ol.source.XYZ({
					title: "天地图卫星影像文字标注",
					url: "http://t0.tianditu.gov.cn/cia_w/wmts?" +
						  "SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=cia&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles" +
						  "&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}" +
						  "&tk=天地图秘钥"
				})
			})
			//地图容器
			map = new ol.Map({
				layers: [tdt_image ,tdt_text ], 
				target: 'map',
				view: new ol.View({
					center: ol.proj.fromLonLat([106.79274503710936, 22.517548223446013]),//ol.proj.fromLonLat后面如果不填要转换的坐标系,默认为3857。// 数据格式4326转为3857
					zoom: 13,
					minZoom: 2
				}),
				// interactions:ol.interaction.defaults({
				//    doubleClickZoom: false,// 取消双击放大功能交互
				//    mouseWheelZoom: false, // 取消滚动鼠标中间的滑轮交互
				//    shiftDragZoom: false, // 取消shift+wheel左键拖动交互
				//  })
			});
			//地图移动事件(包括放大或者缩小的移动)
			this.map_moveend()
			// 加载数据A类
			this.load_data("A")
			//先加入地图动作,鼠标移入动作
			this.map_pmove()
			this.map_secect()
			//加载数据B类
			this.load_data("B")		
		},
		//构造集合对象
		dkOutline(dk_data,dk_class){
			var that_ =this
			//多边形要素数组
			var poly_Features=[]
			var poi_Features=[]
			for (var i = 0; i < dk_data.length; i++){
				for (var j = 0; j <dk_data[i].parcels.length; j++){
					var attr1={
							jd:dk_data[i].jd,
							wed:dk_data[i].wed,
					        lclass:dk_data[i].lclass,
							pepeatCnt:dk_data[i].pepeatCnt,
							parcels:dk_data[i].parcels,
							cur_fea:j
					}
					var polygon = new ol.geom.Polygon([dk_data[i].parcels[j].coordinates])
					//坐标转换
					polygon.applyTransform(ol.proj.getTransform('EPSG:4326', 'EPSG:3857'));
					//附加信息
					var poly_Feature = new ol.Feature({
						geometry: polygon,
						attribute: attr1,//添加特征
					})
					poly_Features.push(poly_Feature)
					poi_Features.push(new ol.Feature({
						geometry: new ol.geom.Point(ol.proj.fromLonLat([dk_data[i].jd,dk_data[i].wed])),
						attribute: attr1
					})
					)
				}
			}
			//实例化一个矢量图层Vector作为绘制层
			var source_poly = new ol.source.Vector({
				features: poly_Features
			});
			//实例化一个矢量图层Vector作为绘制层
			var source_point = new ol.source.Vector({
				features: poi_Features
			});
			//聚合标注数据源
			var clusterSource = new ol.source.Cluster({
				distance: 20,               //聚合的距离参数,即当标注间距离小于此值时进行聚合,单位是像素
				source: source_point              //聚合的数据源,即矢量要素数据源对象
			});
			//判断A类还是B类,然后以A类还是B类控制聚合点的颜色
			if(dk_class=="A"){
				//layer矢量层
				layer_poly_A = new ol.layer.Vector({
					visible: false,
					source: source_poly,
					style: function (feature) {
						// var type=feature.values_.attribute.type//获取feature的属性的自定义信息	
						return new ol.style.Style({
							fill: new ol.style.Fill({               //填充样式
								color: 'rgba(0, 0, 0, 0.5'
							}),
							stroke: new ol.style.Stroke({           //线样式
								color: "red",
								width: 2
							}),
						})
					}
				});
				layer_poi_A = new ol.layer.Vector({
					source: clusterSource,
					style: function (feature) {
						var size = feature.get('features').length;   
						// var type=feature.values_.attribute.type//获取feature的属性的自定义信息	
						return new ol.style.Style({
							image: new ol.style.Circle({
								radius: 12,
								stroke: new ol.style.Stroke({
									color: '#fff'
								}),
								fill: new ol.style.Fill({
									color: "red"
								})
							}),
							text: new ol.style.Text({
								text: size.toString(),
								fill: new ol.style.Fill({
									color: '#fff'
								})
							}), 
						})
					}
				});
				
				//将绘制层添加到地图容器中
				map.addLayer(layer_poly_A)
				map.addLayer(layer_poi_A)
				// 勾选A类
				that_.checkedA=true
			}else if(dk_class=="B"){
				//layer矢量层
				layer_poly_B = new ol.layer.Vector({
					visible: false,
					source: source_poly,
					style: function (feature) {
						// var type=feature.values_.attribute.type//获取feature的属性的自定义信息	
						return new ol.style.Style({
							fill: new ol.style.Fill({               //填充样式
								color: 'rgba(0, 0, 0, 0.5'
							}),
							stroke: new ol.style.Stroke({           //线样式
								color: "#9b59b6",
								width: 2
							}),
						})
					}
				});
				layer_poi_B = new ol.layer.Vector({
					// visible: false,
					source: clusterSource,
					style: function (feature) {
						var size = feature.get('features').length;   
						// var type=feature.values_.attribute.type//获取feature的属性的自定义信息	
						return new ol.style.Style({
							image: new ol.style.Circle({
								radius: 12,
								stroke: new ol.style.Stroke({
									color: '#fff'
								}),
								fill: new ol.style.Fill({
									color: "#9b59b6",
								})
							}),
							text: new ol.style.Text({
								text: size.toString(),
								fill: new ol.style.Fill({
									color: '#fff'
								})
							}), 
						})
					}
				});
				
				//将绘制层添加到地图容器中
				map.addLayer(layer_poly_B)
				map.addLayer(layer_poi_B)
				// 勾选B类
				that_.checkedB=true
				that_.isLoadB=true
			}
			this.$message({
			  message: dk_class+'类地块轮廓渲染完成!',
			  type: 'success'
			});
		},
		//请求后端坐标点数据
		load_data(dk_class){
			//请求坐标点
			var that_=this
			that_.loading=true
			$.ajax({
					url : 'http://39.105.12.242:18080/lzfy/f/luokuo/getjsonstr?lclass='+dk_class,
					type : 'get',
					jsonp: 'jsonpCallback',
					dataType: 'jsonp',
					success: function(returnData) {
						that_.dkOutline(returnData,dk_class)
						that_.loading=false
			    },
			    error : function() {
					that_.$message.error('坐标点数据加载失败');
					// console.log(err.status)
					that_.loading=false
					console.log('坐标点数据加载失败')
			    },
			})
		},
		//地图移入动作
		map_pmove(){
			var that_=this				
			// 利用js浅拷贝原理实现要素高亮
			map.on("pointermove",function(evt){
				let elPopup1 = that_.$refs.popup1;
				//多边形的的弹窗
				var popup_overlay1 = new ol.Overlay({
					element: elPopup1,
					positioning: "bottom-center",
					stopEvent: false,
					offset: [-6, -40],
				});
				map.addOverlay(popup_overlay1);
				//判断当前单击处是否有要素,捕获到要素时弹出popup
				let feature = map.forEachFeatureAtPixel(
					evt.pixel,
					function(feature){ 
						feature.dispatchEvent({type: 'mouseout', event: event})
						return feature
					}
				);
				if (feature){ //捕捉到要素
					fea_type=feature.getGeometry().getType()  //要素类型
					var belong_Arr=[],clmj,tbmj,center_poly
					if (fea_type=="Polygon"){
						var attr1=feature.get('attribute')
						that_.isPolygon=true
						// console.log(feature.getGeometry().getCoordinates())
						if(attr1.lclass=="A"){
							for (i in attr1.parcels){
								var belong_str=attr1.parcels[i].znm+"-"+attr1.parcels[i].znName+"-"+attr1.parcels[i].parcelId
								belong_Arr.push(belong_str)
								tbmj=attr1.parcels[0].tbmj
								clmj=attr1.parcels[0].clmj
							}
							center_poly=[attr1.parcels[0].jd,attr1.parcels[0].wed]
						}
						if(attr1.lclass=="B"){
							fea_num=attr1.cur_fea
							var belong_str=attr1.parcels[fea_num].znm+"-"+attr1.parcels[fea_num].znName+"-"+attr1.parcels[fea_num].parcelId
							belong_Arr.push(belong_str)
							tbmj=attr1.parcels[fea_num].tbmj
							clmj=attr1.parcels[fea_num].clmj
							center_poly=[attr1.parcels[fea_num].jd,attr1.parcels[fea_num].wed]
						}
						that_.dk_detail={
							lclass:attr1.lclass, pepeatCnt:attr1.pepeatCnt, belong:belong_Arr, tbmj:tbmj,clmj:clmj,
						}
						// //设置中心点
						// map.getView().setCenter(ol.proj.transform([attr1.parcels[0].jd,attr1.parcels[0].wed], 'EPSG:4326', 'EPSG:3857'));
						that_.dkPopup1=true
						// 将弹窗显示坐标点上
						setTimeout(() => {
							popup_overlay1.setPosition(ol.proj.fromLonLat(center_poly));
						}, 0);
					}
					if (fea_type=="Point"){
						var curzoom = map.getView().getZoom();  //获取当前地图的缩放级别
						that_.isPolygon=false
						// 将弹窗显示坐标点上
						var attr2=feature.getProperties().features[0].values_.attribute
						let ceter_point = feature.getGeometry().getCoordinates();
						// console.log(feature.getGeometry().getCoordinates())
						if (curzoom>15){
							that_.dkPopup2=false
							that_.isPolygon=false
							for (i in attr2.parcels){
								var belong_str=attr2.parcels[i].znm+"-"+attr2.parcels[i].znName+"-"+attr2.parcels[i].parcelId
								belong_Arr.push(belong_str)
								tbmj=attr2.parcels[0].tbmj
								clmj=attr2.parcels[0].clmj
							}
							that_.dk_detail={
								lclass:attr2.lclass, pepeatCnt:attr2.pepeatCnt, belong:belong_Arr, tbmj:tbmj,clmj:clmj,
							}
							// map.getView().setCenter(ol.proj.transform([attr2.parcels[0].jd,attr2.parcels[0].wed], 'EPSG:4326', 'EPSG:3857'));
							that_.dkPopup1=true
							setTimeout(() => {
								popup_overlay1.setPosition(ceter_point);
							}, 0);
						}else{
							let elPopup2 = that_.$refs.popup2;
							var popup_overlay2 = new ol.Overlay({
								element: elPopup2,
								positioning: "bottom-center",
								stopEvent: false,
								offset: [-6, -15],
							});
							map.addOverlay(popup_overlay2);
							that_.dkPopup2 = true;
							setTimeout(() => {
								popup_overlay2.setPosition(ceter_point);
							}, 0);
						}
					}
					
				}else{
					that_.dkPopup1=false
					that_.dkPopup2=false
				}
			})
		},
		map_secect(){
			//交互时高亮
			var select_move=new ol.interaction.Select({
				condition:ol.events.condition.pointerMove,
				style:new ol.style.Style({
					fill: new ol.style.Fill({               //填充样式
						color: 'rgba(255, 255, 255, 0.5'
					}),
					stroke: new ol.style.Stroke({           //线样式
						color: '#ffcc33',
						width: 5
					}),
					image: new ol.style.Circle({             //点样式
						radius: 10,
						fill: new ol.style.Fill({
							color: '#e67e22'
						})
					})
				})
			});
			map.addInteraction(select_move)
		},
		//地图移动事件;地图扩大或者缩小到某个级别后需要隐藏图层
		map_moveend(){
			var that_=this
			//地图移动事件;地图扩大或者缩小到某个级别后需要隐藏图层
			map.on("moveend",function(evt){
				var curzoom = map.getView().getZoom();  //获取当前地图的缩放级别
				if(that_.checkedA){
					layer_poi_A.setVisible(true); //显示瓦片
					if(curzoom > 15){
						layer_poly_A.setVisible(true)//显示瓦片
					}else{
						layer_poly_A.setVisible(false)
					}
				}
				else{
					if(layer_poly_A){
						layer_poly_A.setVisible(false)
					}
					if(layer_poi_A){
						layer_poi_A.setVisible(false); 
					}
				}
				if(that_.checkedB){
					layer_poi_B.setVisible(true) //显示瓦片
					if(curzoom > 15){
						layer_poly_B.setVisible(true) //显示瓦片
					}else{
						layer_poly_B.setVisible(false)
					}
				}
				else{
					if(layer_poly_B){
						layer_poly_B.setVisible(false)
					}
					if(layer_poi_B){
						layer_poi_B.setVisible(false)
					}
				}
			})
		},
		//地图页中panel_box箭头切换时
		showArrow(){
			if (this.arrow_show){
				this.arrow_show=!this.arrow_show
				$("#panel_option").slideUp();
				// $("#form_show").css("display","block");
			}
			else if(!this.arrow_show) {
				this.arrow_show=!this.arrow_show
				$("#panel_option").slideDown();
				// $("#form_show").css("display","none");
			}
		},
		//地图页的复选框
		checkedChangeA(val){
			var curzoom = map.getView().getZoom();  //获取当前地图的缩放级别
			if(val){
				layer_poi_A.setVisible(true); //显示瓦片
				if(curzoom > 15){
					layer_poly_A.setVisible(true)
				}else{
					layer_poly_A.setVisible(false)
				}
			}
			else{
				if(layer_poly_A){
					layer_poly_A.setVisible(false)
				}
				if(layer_poi_A){
					layer_poi_A.setVisible(false); //显示瓦片
				}
			}

		},
		checkedChangeB(val){
			var curzoom = map.getView().getZoom();  //获取当前地图的缩放级别
			if(val){
				layer_poi_B.setVisible(true); //显示瓦片
				if(curzoom > 15){
					layer_poly_B.setVisible(true)
				}else{
					layer_poly_B.setVisible(false)
				}
			}
			else{
				if(layer_poly_B){
					layer_poly_B.setVisible(false)
				}
				if(layer_poi_B){
					layer_poi_B.setVisible(false); //显示瓦片
				}
			}
		},
	}
})

html代码

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8" />
		<meta http-equiv="Access-Control-Allow-Origin" content="*" />
		<title></title>
		<script src="js/vue.js" type="text/javascript" charset="utf-8"></script>
		<link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css">
		<script src="https://unpkg.com/element-ui/lib/index.js"></script>
		<script src="js/v6.5.0-dist/v6.5.0-dist/ol.js" type="text/javascript" charset="utf-8"></script>
		<link rel="stylesheet" type="text/css" href="js/v6.5.0-dist/v6.5.0-dist/ol.css"/>
		<link rel="stylesheet" type="text/css" href="css/index.css"/>
		<script src="js/jquery.min.js" type="text/javascript" charset="utf-8"></script>
	</head>
	<body>
		<div id="app">
			<div id="map">
				<div class="panel_box">
					<div class="panel_title flex_between_center">
						<el-badge is-dot class="item">地块重叠类型</el-badge>
						<span class="panel_p"><i @click="showArrow" :class="arrow_show==true?'el-icon-arrow-down':'el-icon-arrow-up'"></i></span>
					</div>
					<div class="panel_option" id="panel_option">
						<el-tooltip class="item" effect="dark" content="重叠率:100%" placement="right">
							<div class="flex_between_center panel_option1">
								<div><el-checkbox v-model="checkedA" @change="checkedChangeA"></el-checkbox>&nbsp;A类&nbsp;(重叠率:100%)</div>
								<div>231</div>
							</div>
						</el-tooltip>
						<el-tooltip class="item" effect="dark" content="50%<重叠率<100%" placement="right">
							<div class="flex_between_center panel_option2">
								<div v-show="!isLoadB"><el-checkbox disabled></el-checkbox>&nbsp;B类&nbsp;(重叠率:>50%)</div>
								<div v-show="isLoadB" ><el-checkbox v-model="checkedB" @change="checkedChangeB"></el-checkbox>&nbsp;B类&nbsp;(重叠率:>50%)</div>
								<div>1070</div>
							</div>
						</el-tooltip>
						<el-tooltip class="item" effect="dark" content="0<重叠率<50%" placement="right">
							<div class="flex_between_center panel_option3">
								<div><el-checkbox v-model="checkedC" disabled></el-checkbox>&nbsp;C类&nbsp;(重叠率:>0%)</div>
								<div>0</div>
							</div>
						</el-tooltip>
					</div>
				</div>
				<!-- 多边形弹窗 -->
				<div ref="popup1" class="popup1" v-show="dkPopup1">
					<table>
						<caption><i class="el-icon-star-on"></i><i class="el-icon-star-on"></i><i class="el-icon-star-on"></i><i class="el-icon-star-on"></i><i class="el-icon-star-on"></i></caption>
						<tr><td class="td1">重叠类型&nbsp;:</td><td class="td2">{{ dk_detail.lclass }}&nbsp;</td></tr>
						<tr><td class="td1">重叠次数&nbsp;:</td><td class="td2">{{ dk_detail.pepeatCnt }} &nbsp;</td></tr>
						<tr v-show="isPolygon"><td class="td1">填表面积&nbsp;:</td><td class="td2">{{ dk_detail.tbmj }}&nbsp;</td></tr>
						<tr v-show="isPolygon"><td class="td1">测量面积&nbsp;:</td><td class="td2">{{ dk_detail.tbmj }}&nbsp;</td></tr>
						<tr  v-for="(item,i) in dk_detail.belong">
							<td class="td1">
								<span v-show="dk_detail.belong.length==1">地块所属&nbsp;:</span>
								<span v-show="dk_detail.belong.length>1">地块所属{{ i+1 }}&nbsp;:</span>
							</td>
							<td class="td2">{{ item }}</td>
						</tr>
					</table>
				</div>
				<!-- 提示弹窗 -->
				<div ref="popup2" v-show="dkPopup2">
					<el-button size="mini" type="info">请将地图放大查看详情!</el-button>
				</div>
			</div>
		</div>
	</body>
	<script src="js/index.js" type="text/javascript" charset="utf-8"></script>
</html>

后端获取的数据格式
在这里插入图片描述
效果图:
在这里插入图片描述

  • 5
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值