• openlayers6聚合图(附源码下载)


    前言

    之前写过一篇openlayers4版本的地图聚合图文章,但是由于是封装一层 js代码写的,很多初学者看起来比较有点吃力,所以本篇文章重新写一篇地图热力图文章,直接基于最新版本openlayers6写的,纯粹html + js + css形式,没有任何封装。

    内容概览

    1.基于openlayers6实现地图聚合图效果
    2.源代码demo下载

    效果图如下:

    大概实现思路如下:读取聚合图模拟数据源json,构造openlayers聚合图数据源features,然后创建聚合图图层(核心数据源类Cluster),设置Cluster的初始化一些参数值,参数详细说明自行看openlayers官网文档api。

    • 部分核心代码,完整的见源码demo下载
    import {Map, View} from 'ol';
    import XYZ from 'ol/source/XYZ';
    import {Circle as CircleStyle, Fill, Stroke, Style, Text} from 'ol/style';
    import {Heatmap as HeatmapLayer, Tile as TileLayer} from 'ol/layer';
    import VectorSource from 'ol/source/Vector';
    import VectorLayer from 'ol/layer/Vector';
    import Feature from 'ol/Feature';
    import Point from 'ol/geom/Point';
    import {Cluster} from 'ol/source';
    import {createEmpty} from 'ol/extent';
    import {extend} from 'ol/extent';
    import {getWidth} from 'ol/extent';
    import {getHeight} from 'ol/extent';
    import Overlay from 'ol/Overlay';
     
    var layer = null;//聚合图图层
    var isLoad = false;
     
    //设置原始样式
    var originalStyle = new Style({
    image: new CircleStyle({
    radius: 5,
    stroke: new Stroke({
    color: '#fff'
    }),
    fill: new Fill({
    color: '#3399CC'
    })
    })
    });
     
    var container = document.getElementById('popup');
    var content = document.getElementById('popup-content');
    var closer = document.getElementById('popup-closer');
     
     
    var overlay = new Overlay({
    element: container,
    autoPan: true,
    autoPanAnimation: {
    duration: 250
    }
    });
     
    closer.onclick = function() {
    overlay.setPosition(undefined);
    closer.blur();
    return false;
    };
     
    var view = new View({
    zoom: 13
    })
     
    var map = new Map({
    target: 'map',
    layers: [
    new TileLayer({
    source: new XYZ({
    //url: 'https://{a-c}.tile.openstreetmap.org/{z}/{x}/{y}.png'
    url: 'http://cache1.arcgisonline.cn/arcgis/rest/services/ChinaOnlineStreetPurplishBlue/MapServer/tile/{z}/{y}/{x}'
    })
    })
    ],
    overlays: [overlay],
    view: view
    });
     
    map.on("click", function (e) {//鼠标单击图标事件
    if (e.dragging) {
    return;
    }
    var feature = map.forEachFeatureAtPixel(e.pixel,
    function(feature) {
    return feature;
    });
    if(feature){//点击查询的搜索结果要素,弹出气泡窗口
    console.log(feature);
    if(feature.values_.features[0].values_.weight){
    //弹出气泡窗口
    var coordinate = e.coordinate;
    content.innerHTML = 'weight:'+feature.values_.features[0].values_.weight+'</br>region:'+feature.values_.features[0].values_.region+'</br>name:'+feature.values_.features[0].values_.name;
    overlay.setPosition(coordinate);
    }
    else{
    //隐藏气泡窗口
    overlay.setPosition(undefined);
    closer.blur();
    }
    }
    else{
    //隐藏气泡窗口
    overlay.setPosition(undefined);
    closer.blur();
    }
    });
     
    //初始化热力图
    initClusterLayer(qy);
     
    //热力图勾选监听事件
    $("#clustermapFeatureLayer input").bind("click", function () {
    if (this.checked) {
    if(!isLoad){
    initClusterLayer(qy);
    } else{
    showClusterLayer();
    }
    }
    else {
    hideClusterLayer();
    }
    })
     
    /**
    * 初始化加载-热力图
    */
    function initClusterLayer(data){
    isLoad = true;
    var num = data.features.length;
    if (num > 0) {
    var features = new Array(num);
    for (var i = 0; i < num; i++) {
    var geo = data.features[i].geometry;
    var coordinate = [geo.x, geo.y];
    features[i] = new Feature({
    geometry: new Point(coordinate),
    weight: data.features[i].attributes[field_qy],
    region: data.features[i].attributes[field_region],
    name: data.features[i].attributes[field_company_na]
     
    });
    }
    loadClusterLayer(features,originalStyle);
    }
    }
     
    /**
    * 创建聚合图层
    * @method loadClusterLayer
    * @param features 渲染聚合图层的要素集
    * @param originalStyle图层的原始样式style
    * @return null
    */
     
    function loadClusterLayer(features, originalStyle){
    var maxFeatureCount, currentResolution;
    var textFill = new Fill({
    color: '#fff'
    });
    var textStroke = new Stroke({
    color: 'rgba(0, 0, 0, 0.6)',
     3
    });
     
    var invisibleFill = new Fill({
    color: 'rgba(255, 255, 255, 0.01)'
    });
    var earthquakeFill = new Fill({
    color: 'rgba(255, 153, 0, 0.8)'
    });
    var earthquakeStroke = new Stroke({
    color: 'rgba(255, 204, 0, 0.2)',
     1
    });
    function createEarthquakeStyle(feature, style) {
    return new Style({
    geometry: feature.getGeometry(),
    image: new CircleStyle({
    radius: 5,
    stroke: new Stroke({
    color: '#fff'
    }),
    fill: new Fill({
    color: '#3399CC'
    })
    })
    });
    }
    /*
    *选中样式
    */
    function selectStyleFunction(feature) {
    var styles = [new Style({
    image: new CircleStyle({
    radius: feature.get('radius'),
    fill: invisibleFill
    })
    })];
    var originalFeatures = feature.get('features');
    var originalFeature;
    for (var i = originalFeatures.length - 1; i >= 0; --i) {
    originalFeature = originalFeatures[i];
    styles.push(createEarthquakeStyle(originalFeature, originalStyle));
    //styles.push(originalstyle);
    }
    return styles;
    }
    /*
    *设置没有聚合效果的原始样式
    */
    function createOriginalStyle(feature) {
    return new Style({
    image: new CircleStyle({
    radius: 8,
    stroke: new Stroke({
    color: '#fff'
    }),
    fill: new Fill({
    color: '#3399CC'
    })
    })
    });
    }
    /*
    *计算每个聚合点的半径大小
    */
    function calculateClusterInfo(resolution) {
    maxFeatureCount = 0;
    var features = layer.getSource().getFeatures();
    var feature, radius;
    for (var i = features.length - 1; i >= 0; --i) {
    feature = features[i];
    var originalFeatures = feature.get('features');
    var extent = createEmpty();
    var j, jj;
    for (j = 0, jj = originalFeatures.length; j < jj; ++j) {
    extend(extent, originalFeatures[j].getGeometry().getExtent());
    }
    maxFeatureCount = Math.max(maxFeatureCount, jj);
    radius = 0.25 * (getWidth(extent) + getHeight(extent)) /
    resolution;
    feature.set('radius', radius);
    }
    }
    /*
    *设置聚合样式
    */
    function styleFunction(feature, resolution) {
    //计算每个聚合点的半径大小
    if (resolution != currentResolution) {
    calculateClusterInfo(resolution);
    currentResolution = resolution;
    }
    var style;
    var size = feature.get('features').length;//每个点当前的聚合点数
    if (size > 1) {//设置聚合效果样式
    style = new Style({
    image: new CircleStyle({
    radius: feature.get('radius'),//获取聚合圆圈的半径大小,聚合的点数越多,圆圈的半径越大
    fill: new Fill({
    color: [255, 153, 0, Math.min(0.8, 0.4 + (size / maxFeatureCount))]
    })
    }),
    text: new Text({
    text: size.toString(),
    fill: textFill,
    stroke: textStroke
    })
    });
    } else {//设置没有聚合效果的原始样式
    style = originalStyle;
    }
    return style;
    }
    layer = new VectorLayer({
    source: new Cluster({//矢量图层的数据源为聚合类型
    distance: 40,//聚合距离
    source: new VectorSource({//聚合数据来源
    features: features
    })
    }),
    style: styleFunction//聚合样式
    });
    //selectStyleFunction = selectStyleFunction;
    map.addLayer(layer);
    //缩放至范围
    map.getView().setCenter([12637973.949997703, 2657176.0178779177]);
    map.getView().setZoom(10);
    }
     
     
    function showClusterLayer(){
    if (layer) {
    layer.setVisible(true);
    //缩放至范围
    map.getView().setCenter([12637973.949997703, 2657176.0178779177]);
    map.getView().setZoom(10);
    }
    }
     
    function hideClusterLayer(){
    if (layer) {
    layer.setVisible(false);
    }
    }

    完整源码demo在此篇文章尾部下载,感兴趣的话,可以关注一波

  • 相关阅读:
    使用Python验证常见的50个正则表达式
    空气开关为何叫空气开关?它跟空气有何关系?
    YOLO 算法最全综述:从 YOLOv1 到 YOLOv5
    深入理解部分 SQL 语句执行慢的原因
    KNN(k-nearest-neighbor)算法
    聚类分析方法
    SQL Database学习笔记
    statistic学习笔记
    MapReduce中的排序
    weka打开提示内存不足的解决方法
  • 原文地址:https://www.cnblogs.com/giserhome/p/12994104.html
Copyright © 2020-2023  润新知