效果展示

初始化地图
<template>
<div id="map" class="map"></div>
</template>
<script>
import Map from "ol/Map.js";
import View from "ol/View.js";
import { centerPoint } from "@/utils/showPage.js";
import { gaodeMapLayer } from "@/utils/MapLayer.js";
import { clusters, clusterCircleStyle, clusterCircles } from "@/utils/cluster";
import { createEmpty, extend, getHeight, getWidth } from "ol/extent.js";
export default {
name: "cluster",
data() {
return {
map: null
};
},
mounted() {
const map = new Map({
layers: [gaodeMapLayer, clusters, clusterCircles],
target: "map",
view: new View({
center: centerPoint,
zoom: 11,
minZoom: 2,
maxZoom: 30,
projection: "EPSG:4326",
rotation: 0,
}),
});
},
};
</script>
<style scoped>
.map {
width: 100%;
height: 900px;
}
</style>
图层详解
- 公共方法和样式
function gasPointType() {
let customPoint = config.CUSTOM_POINT.val,
GAS_POINT_TYPE = config.GAS_POINT_TYPE.children;
GAS_POINT_TYPE.forEach((item) => {
item.type = item.val.typeId.value;
});
return [
...GAS_POINT_TYPE,
{ type: customPoint.typeId.value, val: customPoint },
];
}
function getICon(properties) {
let typeId = properties.typeId || "1",
allPoint = gasPointType();
return allPoint.find((i) => i.type == typeId).val;
}
function clusterMemberStyle(clusterMember) {
let properties = clusterMember.getProperties();
let item = getICon(properties);
return new Style({
geometry: clusterMember.getGeometry(),
image: new Icon({
rotation: 0,
src: item.iconUrl.value,
anchorXUnits: "fraction",
imgSize: [item.width.value, item.height.value],
}),
});
}
function generatePointsCircle(count, clusterCenter, resolution) {
const circumference =
circleDistanceMultiplier * circleFootSeparation * (2 + count);
let legLength = circumference / (Math.PI * 2);
const angleStep = (Math.PI * 2) / count;
const res = [];
let angle;
legLength = Math.max(legLength, 35) * resolution;
for (let i = 0; i < count; ++i) {
angle = circleStartAngle + i * angleStep;
res.push([
clusterCenter[0] + legLength * Math.cos(angle),
clusterCenter[1] + legLength * Math.sin(angle),
]);
}
return res;
}
- clusters图层
const vectorSource = new VectorSource({
features: new GeoJSON().readFeatures({
type: devList.type,
features: _devList,
}),
});
const clusterSource = new Cluster({
distance: 35,
source: vectorSource,
});
}
function clusterStyle(feature) {
const size = feature.get("features").length;
if (size > 1) {
return [
new Style({
image: outerCircle,
}),
new Style({
image: innerCircle,
text: new Text({
text: size.toString(),
fill: textFill,
stroke: textStroke,
}),
}),
];
}
const originalFeature = feature.get("features")[0];
return clusterMemberStyle(originalFeature);
}
const clusters = new VectorLayer({
source: clusterSource,
style: clusterStyle,
});
- clusterCircles图层
const clusterCircles = new VectorLayer({
source: clusterSource,
style: clusterCircleStyle,
});
function clusterCircleStyle(
cluster,
resolution,
clickFeature,
clickResolution
) {
if (cluster !== clickFeature || resolution !== clickResolution) {
return null;
}
const clusterMembers = cluster.get("features");
const centerCoordinates = cluster.getGeometry().getCoordinates();
return generatePointsCircle(
clusterMembers.length,
cluster.getGeometry().getCoordinates(),
resolution
).reduce((styles, coordinates, i) => {
const point = new Point(coordinates);
const line = new LineString([centerCoordinates, coordinates]);
styles.unshift(
new Style({
geometry: line,
stroke: convexHullStroke,
})
);
styles.push(
clusterMemberStyle(
new Feature({
...clusterMembers[i].getProperties(),
geometry: point,
})
)
);
return styles;
}, []);
}
地图pointermove和click
map.on("pointermove", (event) => {
clusters.getFeatures(event.pixel).then((features) => {
map.getTargetElement().style.cursor =
features[0] && features[0].get("features").length > 1
? "pointer"
: "";
});
});
map.on("click", (event) => {
clusters.getFeatures(event.pixel).then((features) => {
if (features.length > 0) {
const clusterMembers = features[0].get("features");
if (clusterMembers.length > 1) {
const extent = createEmpty();
clusterMembers.forEach((feature) =>
extend(extent, feature.getGeometry().getExtent())
);
const view = map.getView();
const resolution = map.getView().getResolution();
if (
view.getZoom() === view.getMaxZoom() ||
(getWidth(extent) < resolution && getHeight(extent) < resolution)
) {
let clickFeature = features[0];
let clickResolution = resolution;
clusterCircles.setStyle((cluster, resolution) => {
clusterCircleStyle(
cluster,
resolution,
clickFeature,
clickResolution
);
});
} else {
view.fit(extent, { duration: 500, padding: [50, 50, 50, 50] });
}
}
}
});
});