当前位置:网站首页>Openlayers 聚合图、权重聚合图以及聚合图点击事件

Openlayers 聚合图、权重聚合图以及聚合图点击事件

2022-08-11 08:05:00 Southejor

Openlayers 聚合图、权重聚合图以及聚合图点击事件

OpenLayers 教程

在实际工作中,Openlayers 渲染数据的方式有很多种(WMS、瓦片、矢量数据等),一次性渲染较大数据量的情况下,需要做成静态切片,比如WMTS、TMS;或者矢量切片,比如 Geojson、mvt 等。

对于数据量不是很大的数据,常常使用 热力图、聚合图 的方式在前端渲染,能够更好的体现数据特征。

本示例基于实际项目中的应用,介绍: 加载聚合图、权重聚合图、聚合图参数、聚合图点击事件 等功能的用法。

PS:如果数据量很大的话,建议数据入库,使用数据库的聚合函数来实现。

Openlayers 聚合图、权重聚合图、聚合图事件

<html lang="en">
<head>
    <meta charSet="utf-8">
    <!--注意:openlayers 原版的比较慢,这里引起自己服务器版-->
    <link rel="stylesheet" href="http://openlayers.vip/examples/css/ol.css" type="text/css">
    <style> /* 注意:这里必须给高度,否则地图初始化之后不显示;一般是计算得到高度,然后才初始化地图 */ .map {
       height: 700px; width: 100%; float: left; } </style>
    <!--注意:openlayers 原版的比较慢,这里引起自己服务器版-->
    <script src="http://openlayers.vip/examples/resources/ol.js"></script>
    <script src="http://openlayers.vip/examples/resources/jquery-3.5.1.min.js"></script>
    <script src="./tiandituLayers.js"></script>
    <title>OpenLayers example</title>
</head>
<body>
<h2>OpenLayers Cluster</h2>
<!--地图容器,需要指定 id -->
<div id="map" class="map"></div>

<script type="text/javascript"> var map = new ol.Map({
       // 地图容器 target: 'map', // 地图图层,比如底图、矢量图等 layers: [ getIMG_CLayer(), getIBO_CLayer(), getCIA_CLayer(), ], // 地图视野 view: new ol.View({
       projection: "EPSG:4326", // 定位 center: [115.67724700667199, 37.73879478106912], // 缩放 zoom: 6, maxZoom: 18, minZoom: 1, }) }); /** * @todo wkt格式数据转化成图形对象 * @param {string} wkt "POINT(112.7197265625,39.18164062499999)" 格式数据 * @param {string|Projection} sourceCode 源投影坐标系 * @param {string|Projection} targetCode 目标投影坐标系 * @returns {Feature} */ function getFeatureByWKT(wkt, sourceCode, targetCode) {
       try {
       let view = map.getView(); if (!wkt) {
       return null; } let format = new ol.format.WKT(); let feature; feature = format.readFeature(wkt, {
       featureProjection: targetCode || view.getProjection(), dataProjection: sourceCode || view.getProjection(), }); return feature; } catch (e) {
       console.log(e); return null; } } /** * @todo 颜色十六进制转为 rgba * @param sColor 格式数据 * @param opacity * @returns rgba颜色字符串 */ function colorToRgb(sColor, opacity) {
       //用于十六进制颜色和rgb转换的正则 var REG = /^#([0-9a-fA-f]{3}|[0-9a-fA-f]{6})$/; sColor = sColor.toLowerCase(); if (/^[A-Za-z]+$/.test(sColor)) return sColor; if (sColor && REG.test(sColor)) {
       if (sColor.length === 4) {
       let sColorNew = "#"; for (let i = 1; i < 4; i += 1) {
       sColorNew += sColor.slice(i, i + 1).concat(sColor.slice(i, i + 1)); } sColor = sColorNew; } //处理六位的颜色值 let sColorChange = []; for (let i = 1; i < 7; i += 2) {
       sColorChange.push(parseInt("0x" + sColor.slice(i, i + 2))); } if (opacity) sColorChange.push(opacity); return "rgba(" + sColorChange.join(",") + ")"; // return sColorChange; } else {
       return sColor; } }; // 地图事件 function clickFunction(evt) {
       let feature = map.forEachFeatureAtPixel(evt.pixel, function (feature, layerVetor) {
       return feature.getProperties().features; }); // 图形要素的点击事件 // 这里可以使用气泡框展示信息 if (feature && feature.length == 1) {
       console.log(feature[0]); alert('点击了:' + feature[0].get('name')); } else {
       feature && console.log(feature); feature && alert('点击了包含:' + feature.length + ' 个图形要素的聚合图!'); } } // 初始化点击事件标记 var initClickFlag = false; // 点击事件 function activateClickFunc() {
       initClickFlag && alert('已开启点击事件!'); map.on('click', clickFunction); initClickFlag = true; } // 关闭点击事件 function shutDownClick() {
       alert('已关闭点击事件!'); map.un('click', clickFunction); } // 点线面数组 var features = undefined; // 聚合图图层对象 var clusterLayer = undefined; // 资源对象 var vectorSource = undefined; // 聚合图对象 var clusterSource = undefined; // 初始化聚合图 function initCluster() {
       features = []; // 模拟数据 for (var i = 1; i <= 15; i++) {
       var feature = getFeatureByWKT( "POINT(" + (113 + (i / 10)) + " " + (35 + (i / 10)) + ")" ); var feature2 = getFeatureByWKT( "POINT(" + (113 + ((i + 5) / 10)) + " " + (35 + (i / 10)) + ")" ); var feature3 = getFeatureByWKT( "POINT(" + (113 + ((i + 9) / 10)) + " " + (35 + (i / 10)) + ")" ); var point = new ol.style.Style({
       // 点样式 image: new ol.style.Icon({
       // 允许跨域,如果不设置,打印地图不会打印 crossOrigin: 'anonymous', // 标注图片和文字之间的距离 anchor: [0.5, 0], // 图片的偏移 offset: [0.2, 0], // 图片的锚点,一般来说,都是右下角 anchorOrigin: 'bottom-right', //图标的url src: "http://api.tianditu.gov.cn/v4.0/image/marker-icon.png", scale: 1, }) }); feature.setStyle(point); feature.set('name', 'feature1-' + i); feature.set('capability', i / 15); feature2.setStyle(point); feature2.set('name', 'feature2-' + i); feature2.set('capability', i / 15); feature3.setStyle(point); feature3.set('name', 'feature3-' + i); feature3.set('capability', i / 15); features.push(feature) features.push(feature2) features.push(feature3) } /** * 资源 */ vectorSource = new ol.source.Vector({
      }); // 聚合图 clusterSource = new ol.source.Cluster({
       wrapX: false, source: vectorSource, }); // 图层 clusterLayer = new ol.layer.Vector({
       source: clusterSource, zIndex: 1, }); map.addLayer(clusterLayer); } /** * todo 增加聚合图 * @param dynamicData (参数是features) */ function addData(dynamicData, distance, original) {
       // 最大图形要素数量 var maxFeatureCount; // 当前分辨率 var currentResolution; // 普通样式,普通小圆圈 var originalStyle = function (feature) {
       var features = feature.get('features'); var size = features.length; return new ol.style.Style({
       image: new ol.style.Circle({
       radius: 30, stroke: new ol.style.Stroke({
       color: '#fff' }), fill: new ol.style.Fill({
       color: '#969696' }) }), text: new ol.style.Text({
       text: size.toString(), fill: new ol.style.Fill({
       color: '#fff' }) }) }); } // 动态样式样式,根据权重和数量计算 var varyStyle = function (feature) {
       var originalFeatures = feature.get('features'); var size = feature.get('features').length; var capability_avg = 0; var textName = ""; var j = (void 0), jj = (void 0); for (j = 0, jj = originalFeatures.length; j < jj; ++j) {
       capability_avg += (originalFeatures[j].get("capability") || 1) textName = originalFeatures[j].get("name") || ""; } capability_avg = (capability_avg / size).toFixed(2); var round = getPointArray(capability_avg); var opacity = Math.min(0.8, 0.4 + (size / maxFeatureCount)); var style = new ol.style.Style({
       image: new ol.style.Circle({
       radius: feature.get('radius'), fill: new ol.style.Fill({
       color: colorToRgb(round.split(",")[1], opacity) }) }), text: new ol.style.Text({
       // text: textName ? (textName + ":" + capability_avg) : feature.get('radius'), text: "权重平均值:" + capability_avg, font: 'normal bold 14px Arial,sans-serif', fill: new ol.style.Fill({
       color: '#fff' }), stroke: new ol.style.Stroke({
       color: 'rgba(0, 0, 0, 0.6)', width: 3 }) }) }); return style; } // 单体 feature 样式 var featureStyle = function (feature) {
       var originalFeatures = feature.get('features'); if (originalFeatures.length != 1) {
       return; } var originalFeature = originalFeatures[0]; var style = originalFeature.getStyle(); style && style.setText( new ol.style.Text({
       text: originalFeature.get("name"), // 偏移 offsetX: 0, offsetY: -54, // 居中 textAlign: 'center', // 比例 scale: 1, textBaseline: 'middle', // 边距 padding: [2, 2, 2, 2], // 覆盖显示:即文字超过多边形也会显示 overflow: true, // 字体颜色 fill: new ol.style.Fill({
       color: 'rgba(51,51,51, 1)' }), // 字体边框,可以配合 fill 是文字高亮 stroke: new ol.style.Stroke({
       color: 'rgba(0, 255, 255, 0.8)', width: 2, }), // 背景色 backgroundFill: new ol.style.Fill({
       color: 'rgba(252,254,255, 1)' }), }) ) return style; } // 样式方法 function styleFunction(feature, resolution) {
       // 如果是拖动地图,则不重新渲染样式 if (resolution != currentResolution) {
       calculateClusterInfo(resolution); currentResolution = resolution; } var style; var size = feature.get('features').length || 0; // size大于1,则表示是聚合状态 if (size > 1) {
       if (original == true) {
       style = originalStyle(feature); } else {
       style = varyStyle(feature); } // size 等于1,表示是单体 feature } else if (size == 1) {
       style = featureStyle(feature); } return style; } // 计算聚合图样式信息 var calculateClusterInfo = function () {
       if (!clusterLayer) {
       return; } maxFeatureCount = 0; var features = clusterLayer.getSource().getFeatures(); var feature, radius; for (var i = features.length - 1; i >= 0; --i) {
       feature = features[i]; var originalFeatures = feature.get('features'); // 计算权重 var capability = 0; var j = (void 0), jj = (void 0); for (j = 0, jj = originalFeatures.length; j < jj; ++j) {
       // 这是使用 capability 自定义属性的值计算权重 capability += (originalFeatures[j].get("capability") || 1) } // 根据实际的数据量,调整聚合显示半径的大小 // PS:这个需要更新项目实际调整 if (originalFeatures.length < 10) {
       radius = capability + originalFeatures.length; while (radius > 100) {
       radius = radius / 10; } radius = radius + 10; } else if (originalFeatures.length >= 10 && originalFeatures.length <= 50) {
       radius = capability + originalFeatures.length; while (radius > 100) {
       radius = radius / 10; } radius = radius + 20; } else if (originalFeatures.length > 100 && originalFeatures.length <= 5000) {
       radius = capability + originalFeatures.length; while (radius > 100) {
       radius = radius / 10; } } else if (originalFeatures.length > 5000 && originalFeatures.length <= 10000) {
       radius = capability + originalFeatures.length; while (radius > 100) {
       radius = radius / 10; } } else if (originalFeatures.length > 10000) {
       radius = capability + originalFeatures.length; while (radius > 100) {
       radius = radius / 10; } radius = radius; } // 取二者最大值 maxFeatureCount = Math.max(maxFeatureCount, jj); feature.set('radius', radius); } }; // 获取聚合图颜色 // 自定义颜色(图例和颜色以逗号拼接) var getPointArray = function (v) {
       if (v >= 0.8 && v <= 1) return '0.8-1.0,#FF0000' else if (v >= 0.6 && v < 0.8) return '0.6-0.8,#FFFF00' else if (v >= 0.4 && v < 0.6) return '0.4-0.6,#DAA520' else if (v >= 0.2 && v < 0.4) return '0.2-0.4,#0000FF' else if (v >= 0 && v < 0.2) return '0-0.2,#228B22' } // 设置聚合距离,也就是半径范围内聚合 clusterSource.setDistance(distance); // 添加数据 vectorSource.addFeatures(features); // 设置样式 clusterLayer && clusterLayer.setStyle(styleFunction) } // 添加聚合图 // flag, true 为加载原始样式,其他为加载权重样式 function addCluster(flag) {
       closeCluster(); initCluster(); flag ? addData(features, 60, flag) : addData(features, 40); } // 关闭聚合图 function closeCluster() {
       clusterLayer && map.removeLayer(clusterLayer); clusterLayer = undefined; } // 默认加载原始聚合图 addCluster(true); // 默认开始点击事件 activateClickFunc(); </script>
<button id="addCluster" onClick="addCluster(true)">添加聚合图</button>
<button id="addWeightCluster" onClick="addCluster()">添加权重聚合图</button>
<button id="closeCluster" onClick="closeCluster()">关闭聚合图</button>
<button id="activateClickFunc" onClick="activateClickFunc()">开启点击事件</button>
<button id="shutDownClick" onClick="shutDownClick()">关闭点击事件</button>
</body>
</html>

PS:点击弹出气泡框可参考 Openlayers 自定义气泡框以及定位到气泡框

在线示例

Openlayers 聚合图:Openlayers-cluster

原网站

版权声明
本文为[Southejor]所创,转载请带上原文链接,感谢
https://blog.csdn.net/linzi19900517/article/details/123571228