vue openlayers八Cluster类实现聚合分散效果

1. 放大缩小地图实现聚合分散效果

在这里插入图片描述

2. 实现聚合分散代码(核心查看 addClusterclusterStyle 方法)

mounted :初始化一些数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
mounted() {
    let clusterData = {
        成都市: { center: { lng: 104.061902, lat: 30.609503 } },
        广安市: { center: { lng: 106.619126, lat: 30.474142 } },
        绵阳市: { center: { lng: 104.673612, lat: 31.492565 } },
        雅安市: { center: { lng: 103.031653, lat: 30.018895 } },
        自贡市: { center: { lng: 104.797794, lat: 29.368322 } },
        宜宾市: { center: { lng: 104.610964, lat: 28.781347 } },
        内江市: { center: { lng: 105.064555, lat: 29.581632 } }
    };
    let points = [
        { name: "成都市", value: 85 },
        { name: "绵阳市", value: 36 },
        { name: "广安市", value: 50 },
        { name: "雅安市", value: 555 },
        { name: "自贡市", value: 55 },
        { name: "宜宾市", value: 666 },
        { name: "内江市", value: 777 }
    ];
    // 实现聚合分散方法
    this.addCluster(clusterData, points, true);
}

addCluster 方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
// 设置聚合分散效果
addCluster(clusterData, points, clearup) {
    let source = new VectorSource();
    let clusterSource = new Cluster({
        distance: parseInt(20, 10), // 设置聚合多少范围间距会聚合
        source: source
    });
    let layer = new VectorLayer({
        source: clusterSource,
        style: this.clusterStyle.call(this)
    });
    this.map.addLayer(layer);
    for (const key in clusterData) {
        points.forEach(e => {
            if (e.name == key) {
                let point = fromLonLat([
                    clusterData[key].center.lng,
                    clusterData[key].center.lat
                ]);
                var f = new Feature({
                    geometry: new Point(point)
                });
                f.set("name", e.name); // 设置name值
                f.set("value", e.value); // 设置vaue值
                f.set("type", "cluster");
                source.addFeature(f);
                layer.getSource().addFeatures(f);
            }
        });
    }
},

clusterStyle 方法,详细说明看注释

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// 设置聚合分散的图标样式
clusterStyle() {
    return (feature, solution) => {
        var total = 0;
        feature.get("features").forEach((value, index) => {
            // 通过value.get("属性名") 获取设置的值
            total += value.get("value"); // 获取累加的数值
        });
        var style = new Style({
            image: new CircleStyle({
                radius: 15, //设置圆角大小
                stroke: new Stroke({
                    color: "blue" //设置园stroke颜色
                }),
                fill: new Fill({
                    color: "rgba(24,144,255,100)" //设置填充颜色
                })
            }),
            text: new Text({
                text: total.toString(), // 文字显示的数值
                fill: new Fill({
                    color: "#FFF" // 文字显示的颜色
                })
            })
        });
        return style;
    };
},
3. 完整代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
<template>
    <div id="app">
        <div id="Map" ref="map"></div>
    </div>
</template>
<script>
import "ol/ol.css";
import TileLayer from "ol/layer/Tile";
import VectorLayer from "ol/layer/Vector";
import VectorSource from "ol/source/Vector";
import XYZ from "ol/source/XYZ";
import { Map, View, Feature, ol } from "ol";
import {
    Style,
    Stroke,
    Fill,
    Icon,
    Text,
    Circle as CircleStyle
} from "ol/style";
import { Polygon, Point } from "ol/geom";
import { defaults as defaultControls } from "ol/control";
import { Cluster } from "ol/source";
import { fromLonLat } from "ol/proj";

import areaGeo from "@/geoJson/sichuan.json";
export default {
    data() {
        return {
            map: null
        };
    },
    methods: {
        /**
         * 初始化地图
         */
        initMap() {
            this.map = new Map({
                target: "Map",
                controls: defaultControls({
                    zoom: true
                }).extend([]),
                layers: [
                    new TileLayer({
                        source: new XYZ({
                            url:
                                "http://map.geoq.cn/ArcGIS/rest/services/ChinaOnlineStreetPurplishBlue/MapServer/tile/{z}/{y}/{x}"
                        })
                    })
                ],
                view: new View({
                    // projection: "EPSG:4326",
                    center: fromLonLat([104.065735, 30.659462]),
                    zoom: 6.5,
                    maxZoom: 19,
                    minZoom: 3
                })
            });
        },
        /**
         * 设置区域
         */
        addArea(geo = []) {
            if (geo.length == 0) {
                return false;
            }
            let features = [];
            geo.forEach(g => {
                let lineData = g.features[0];
                let routeFeature = "";
                if (lineData.geometry.type == "MultiPolygon") {
                    routeFeature = new Feature({
                        geometry: new MultiPolygon(
                            lineData.geometry.coordinates
                        ).transform("EPSG:4326", "EPSG:3857")
                    });
                } else if (lineData.geometry.type == "Polygon") {
                    routeFeature = new Feature({
                        geometry: new Polygon(
                            lineData.geometry.coordinates
                        ).transform("EPSG:4326", "EPSG:3857")
                    });
                }
                routeFeature.setStyle(
                    new Style({
                        fill: new Fill({
                            color: "#4e98f444"
                        }),
                        stroke: new Stroke({
                            width: 3,
                            color: [71, 137, 227, 1]
                        })
                    })
                );
                features.push(routeFeature);
            });
            // 设置图层
            let routeLayer = new VectorLayer({
                source: new VectorSource({
                    features: features
                })
            });
            // 添加图层
            this.map.addLayer(routeLayer);
        },
        addCluster(clusterData, points, clearup) {
            let source = new VectorSource();
            let clusterSource = new Cluster({
                distance: parseInt(20, 10),
                source: source
            });
            let layer = new VectorLayer({
                source: clusterSource,
                style: this.clusterStyle.call(this)
            });
            this.map.addLayer(layer);
            for (const key in clusterData) {
                points.forEach(e => {
                    if (e.name == key) {
                        let point = fromLonLat([
                            clusterData[key].center.lng,
                            clusterData[key].center.lat
                        ]);
                        var f = new Feature({
                            geometry: new Point(point)
                        });
                        f.set("name", e.name);
                        f.set("value", e.value);
                        f.set("type", "cluster");
                        source.addFeature(f);
                        layer.getSource().addFeatures(f);
                    }
                });
            }
        },
        clusterStyle() {
            return (feature, solution) => {
                var total = 0;
                feature.get("features").forEach((value, index) => {
                    total += value.get("value");
                });
                var style = new Style({
                    image: new CircleStyle({
                        radius: 15,
                        stroke: new Stroke({
                            color: "blue"
                        }),
                        fill: new Fill({
                            color: "rgba(24,144,255,100)"
                        })
                    }),
                    text: new Text({
                        text: total.toString(),
                        fill: new Fill({
                            color: "#FFF"
                        })
                    })
                });
                return style;
            };
        },
        /**
         * 鼠标悬浮改变图标样式
         */
        pointerMove() {
            let _that = this;
            this.map.on("pointermove", function(evt) {
                _that.map.getTargetElement().style.cursor = _that.map.hasFeatureAtPixel(
                    evt.pixel
                )
                    ? "pointer"
                    : "";
            });
        }
    },
    mounted() {
        this.initMap();
        this.addArea(areaGeo);
        this.pointerMove();
        let clusterData = {
            成都市: { center: { lng: 104.061902, lat: 30.609503 } },
            广安市: { center: { lng: 106.619126, lat: 30.474142 } },
            绵阳市: { center: { lng: 104.673612, lat: 31.492565 } },
            雅安市: { center: { lng: 103.031653, lat: 30.018895 } },
            自贡市: { center: { lng: 104.797794, lat: 29.368322 } },
            宜宾市: { center: { lng: 104.610964, lat: 28.781347 } },
            内江市: { center: { lng: 105.064555, lat: 29.581632 } }
        };
        let points = [
            { name: "成都市", value: 85 },
            { name: "绵阳市", value: 36 },
            { name: "广安市", value: 50 },
            { name: "雅安市", value: 555 },
            { name: "自贡市", value: 55 },
            { name: "宜宾市", value: 666 },
            { name: "内江市", value: 777 }
        ];
        this.addCluster(clusterData, points, true);
    }
};
</script>
<style lang="scss" scoped>
// 此处非核心,已经删除
</style>