Openlayers 6 aggregation diagram (download with source code)

preface

I wrote a map aggregation map article in openlayers 4 before, but because it is written by encapsulating a layer of js code, many beginners seem to be a bit laborious, so this article rewrites a map thermal map article, directly based on the latest version of openlayers 6, in the form of pure html + js + css, without any encapsulation.

Content overview

1. Realize the effect of map aggregation based on openlayers6
2. Download the source code demo

The renderings are as follows:

The main idea is as follows: read the aggregation graph simulation data source json, construct the openlayers aggregation graph data source features, then create the aggregation graph layer (core data source class Cluster), set some parameter values of Cluster initialization, and see the openlayers official document api for parameter details.

  • Part of the core code, see the source demo download for the complete code
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;//Aggregate layer
var isLoad = false;
 
//Set original style
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) {//Mouse click icon event
if (e.dragging) {
return;
}
var feature = map.forEachFeatureAtPixel(e.pixel,
function(feature) {
return feature;
});
if(feature){//Click search result elements of query,Pop up bubble window
console.log(feature);
if(feature.values_.features[0].values_.weight){
//Pop up bubble window
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{
//Hide bubble window
overlay.setPosition(undefined);
closer.blur();
}
}
else{
//Hide bubble window
overlay.setPosition(undefined);
closer.blur();
}
});
 
//Initial heat map
initClusterLayer(qy);
 
//Thermograph check monitoring event
$("#clustermapFeatureLayer input").bind("click", function () {
if (this.checked) {
if(!isLoad){
initClusterLayer(qy);
} else{
showClusterLayer();
}
}
else {
hideClusterLayer();
}
})
 
/**
* Initial loading - thermodynamic diagram
*/
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);
}
}
 
/**
* Create aggregate layer
* @method loadClusterLayer
* @param features Rendering feature sets for aggregate layers
* @param originalStyle The original style of the layer
* @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)',
width: 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)',
width: 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'
})
})
});
}
/*
*Selected style
*/
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;
}
/*
*Set the original style without aggregation effect
*/
function createOriginalStyle(feature) {
return new Style({
image: new CircleStyle({
radius: 8,
stroke: new Stroke({
color: '#fff'
}),
fill: new Fill({
color: '#3399CC'
})
})
});
}
/*
*Calculate the radius size of each aggregation point
*/
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);
}
}
/*
*Set aggregation style
*/
function styleFunction(feature, resolution) {
//Calculate the radius size of each aggregation point
if (resolution != currentResolution) {
calculateClusterInfo(resolution);
currentResolution = resolution;
}
var style;
var size = feature.get('features').length;//Current aggregate points per point
if (size > 1) {//Set aggregation effect style
style = new Style({
image: new CircleStyle({
radius: feature.get('radius'),//Get the radius of the aggregation circle. The more points you aggregate, the larger the radius of the circle
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 {//Set the original style without aggregation effect
style = originalStyle;
}
return style;
}
layer = new VectorLayer({
source: new Cluster({//The data source of vector layer is aggregation type
distance: 40,//Aggregation distance
source: new VectorSource({//Aggregate data source
features: features
})
}),
style: styleFunction//Aggregate style
});
//selectStyleFunction = selectStyleFunction;
map.addLayer(layer);
//Zoom to range
map.getView().setCenter([12637973.949997703, 2657176.0178779177]);
map.getView().setZoom(10);
}
 
 
function showClusterLayer(){
if (layer) {
layer.setVisible(true);
//Zoom to range
map.getView().setCenter([12637973.949997703, 2657176.0178779177]);
map.getView().setZoom(10);
}
}
 
function hideClusterLayer(){
if (layer) {
layer.setVisible(false);
}
}

The full source demo is downloaded at the end of this article. If you are interested, you can pay attention to a wave

Tags: JSON REST

Posted on Sun, 31 May 2020 00:33:30 -0400 by mattr