三十六、openlayers官网示例Earthquake Clusters解析——在聚合图层鼠标触摸显示五角星
官网demo地址:
Earthquake Clusters
这篇展示了鼠标触摸聚合图层点位显示五角星的效果。
首先是初始化地图,加载了一个KML格式的矢量数据源,extractStyles为false表示不从kml数据源中提取样式。使用Select添加了鼠标选中的交互事件
vector = new VectorLayer({
source: new Cluster({
distance: 40,
source: new VectorSource({
url: "http://openlayers.org/en/latest/examples/data/kml/2012_Earthquakes_Mag5.kml",
format: new KML({
extractStyles: false,
}),
}),
}),
style: styleFunction,
});
const raster = new TileLayer({
source: new StadiaMaps({
layer: "stamen_toner",
}),
});
const map = new Map({
layers: [raster, vector],
interactions: defaultInteractions().extend([
new Select({
condition: function (evt) {
return evt.type == "pointermove" || evt.type == "singleclick";
},
style: selectStyleFunction,
}),
]),
target: "map",
view: new View({
center: [0, 0],
zoom: 2,
}),
});
其中有两个样式函数,先来看第一个styleFunction。
如果有子feature就显示为黄色圆圈,如果没有子feature则绘制成五角星。
let currentResolution;
function styleFunction(feature, resolution) {
if (resolution != currentResolution) {
calculateClusterInfo(resolution);
currentResolution = resolution;
}
let style;
const 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 {
const originalFeature = feature.get("features")[0];
style = createEarthquakeStyle(originalFeature);
}
return style;
}
使用calculateClusterInfo 函数计算圆圈的半径,将子feature的extent合并到了一起,结合分辨率算出半径。
const calculateClusterInfo = function (resolution) {
maxFeatureCount = 0;
const features = vector.getSource().getFeatures();
let feature, radius;
for (let i = features.length - 1; i >= 0; --i) {
feature = features[i];
const originalFeatures = feature.get("features");
const extent = createEmpty(); //创建一个空的范围对象,用来存储聚类的总范围。
let j, jj;
for (j = 0, jj = originalFeatures.length; j < jj; ++j) {
//获取当前原始特征的几何范围。将这个几何范围合并到总范围 extent 中
extend(extent, originalFeatures[j].getGeometry().getExtent());
}
maxFeatureCount = Math.max(maxFeatureCount, jj);
radius = (0.25 * (getWidth(extent) + getHeight(extent))) / resolution;
feature.set('radius',radius)
}
};
extend方法示例
假设你有一个聚类包含三个特征,其范围分别为:
- 特征1:
[0, 0, 1, 1]
- 特征2:
[2, 2, 3, 3]
- 特征3:
[1, 1, 4, 4]
通过逐步扩展 extent
:
- 初始
extent
是空的。 - 扩展第一个特征后,
extent
变为[0, 0, 1, 1]
。 - 扩展第二个特征后,
extent
变为[0, 0, 3, 3]
。 - 扩展第三个特征后,
extent
变为[0, 0, 4, 4]
。
最终的 extent
包含了所有特征的范围,即 [0, 0, 4, 4]
。
createEarthquakeStyle是绘制星星的方法,主要用了RegularShape这个类。
function createEarthquakeStyle(feature) {
const name = feature.get("name");
const magnitude = parseFloat(name.substr(2));
const radius = 5 + 20 * (magnitude - 5);
return new Style({
geometry: feature.getGeometry(),
image: new RegularShape({
radius: radius,
radius2: 3,
points: 5,
angle: Math.PI,
fill: earthquakeFill,
stroke: earthquakeStroke,
}),
});
}
写一个小demo来理解RegularShape
//小demo
let piontArr = [-213399.46385070545, -7204129.9025042085];
let pointFeature = new Feature({
geometry: new MultiPoint([piontArr]),
});
let newLayer = new VectorLayer({
source: new VectorSource({
features: [pointFeature],
}),
style: [
new Style({
image: new RegularShape({
radius: 50,
radius2:20,
points: 5,
angle: Math.PI,
fill: earthquakeFill,
stroke: earthquakeStroke,
}),
}),
],
});
map.addLayer(newLayer)
RegularShape参数解释:
radius
:- 含义: 图形的外半径,即从图形中心到外顶点的距离。
radius2
:- 含义: 图形的内半径,仅在绘制星形时有效。表示从图形中心到内顶点的距离。
points
:- 含义: 图形的顶点数。如果
radius2
被定义,则points
表示星形的顶点数(外顶点和内顶点的总数),否则表示多边形的边数。 - 示例值:
6
表示绘制一个六边形或六角星形。
- 含义: 图形的顶点数。如果
angle
:- 含义: 图形的旋转角度,以弧度为单位。
Math.PI
表示旋转 180 度。 - 示例值:
Math.PI
表示图形旋转 180 度。
- 含义: 图形的旋转角度,以弧度为单位。
然后是第二个样式函数selectStyleFunction
鼠标触摸的时候获取到feature自定义属性features取出来,把每一个子feature绘制成星星形状展示。
function selectStyleFunction(feature) {
const styles = [
new Style({
image: new CircleStyle({
radius: feature.get("radius"),
fill: invisibleFill,
}),
}),
];
const originalFeatures = feature.get("features");
let originalFeature;
for (let i = originalFeatures.length - 1; i >= 0; --i) {
originalFeature = originalFeatures[i];
styles.push(createEarthquakeStyle(originalFeature));
}
return styles;
}
完整代码:
Earthquake Clusters
#map {
width: 100%;
height: 500px;
}
.box {
height: 100%;
}