看过之前的文章,对于OpenLayers会有一个大致的了解。下面我们继续讲解 OpenLayer如何创建点标记。
下面示例是以 OpenLayersV8.2.0版本 作为依赖包。
点标记
在地图上经常会打点上图,这是一个常见业务场景需求。像 打点标记,矢量边界线,点位提示窗等,也会经常需要,这些我们后面都会说道,现在来看看,OpenLayer中点标记如何上图。
OpenLayer中点标记(Marker)属于矢量图形,即矢量点。GIS地图上,日常开发上图的点、线、面、几何体都属于矢量图形。由于点标记的使用最为频繁常见,所以将它单独拿出来讲解。
OpenLayer中,点标记创建需要 Feature
、Geometry
、Style
三者共同组合完成。Feature
作为点标记的实体,Geometry
创建几何体(点、线、圆、多边形),Style
创建样式(颜色、粗细、文本等)。
当然,点标记创建完成后,需要添加到矢量图层,如果只创建不添加,就类似于只创建DOM节点,但是不append到是视图上。(点标记添加实际流程:需要先添加到矢量Source
的要素上,Layer
再使用矢量数据源)
下面我们来看看关于创建点标记的API和示例。
官方示例:Icon Point
Feature
[ol.Feature](https://openlayers.org/en/v8.2.0/apidoc/module-ol_Feature-Feature.html)
:具有几何图形和其他属性特性的地理要素的矢量对象// 创建要素对象 const Feature = new ol.Feature({ // 创建geometry geometry: new ol.geom.Point([116.39, 39.91]), name: 'Marker' })
Feature
要素是地图上的可交互对象,可以是点、线、面等。要素需要添加到矢量图层中,才可展示。Geometry
Geometry
与Feature
是ol/geom/Geometry
:Abstract base class;ol.geom.Circle
:Circle geometry;ol.geom.LineString
:Linestring geometry;ol.geom.LinearRing
:Linear ring geometry. Only used as part of polygon; (无法单独使用);ol.geom.MultiLineString
:Multi-linestring geometry;ol.geom.MultiPoint
:Multi-point geometry.ol.geom.MultiPolygon
:Multi-polygon geometryol.geom.Point
:Point geometry;ol.geom.Polygon
:Polygon geometry;// 创建多边形 polygon const points = [ [ [121.478815, 32.24161], [120.160318, 31.293255], [118.79129166, 32.06046152], [121.478815, 32.24161] ] ]; var feature = new ol.Feature({ geometry: new ol.geom.Polygon(points) }); // 创建 MultiLine const points = [ [ [122.860194, 24.761729], [122.713016, 23.952719], [121.977124, 21.632922] ], [ [125.509405, 24.896053], [125.509405, 24.896053], [124.11121, 21.632922] ] ]; var feature = new ol.Feature({ geometry: new ol.geom.MultiLineString(points) });
Geometry
是用于创建几何体,创建Feature
要素时,可以指定Geometry
。Style
Style
即可直接在要素(Feature)设置,也可以在矢量数据源(Source)上设置。
ol.style.Style
:矢量要素渲染样式的容器;Fill
:设置矢量要素的填充样式;Icon
:设置矢量要素的icon样式;Text
:设置矢量要素的文本样式;Circle
:设置矢量要素的圆形样式;Stroke
:设置矢量要素的描边样式;RegularShape
:设置矢量要素的常规形状样式;const iconStyle = new ol.style.Style({ image: new ol.style.Icon({ anchor: [0.5, 0.5], color: 'red', src: './img/point.png', width: 50 }) })
官方示例:Icon Point、Marker Animation
示例
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>访问 Map</title> <link rel="stylesheet" href="./8.2.0/theme/ol.css"> <script src="./8.2.0/en/latest/ol/dist/ol.js"></script> <!-- 不想下载就直接用下面的 --> <!-- <script src="https://cdn.jsdelivr.net/npm/ol@v8.2.0/dist/ol.js"></script> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/ol@v8.2.0/ol.css"> --> </head> <body> <div id="map" style="height: 95vh; border: 6px solid;"></div> <script> const coordinate = [ [ 116.38390602111816, 39.91933196682435 ], [ 116.40862525939941, 39.89048282729144 ] ] let map = new ol.Map({ target: 'map', layers: [ new ol.layer.Tile({ // source: new ol.source.OSM() source: new ol.source.BingMaps({ key: 'Aud1dM5V1tT5Yvg2uX8Hp5ftaZZ4stEuJZ8i7IO1KSyLFj9A4UuamHK6_tUKEcGe', imagerySet: 'Road' // 指定加载的图层名,还可以替换为'AerialWithLabels' 'Aerial'或'Road' }) }), ], view: new ol.View({ center: [116.39, 39.91], zoom: 13, projection: 'EPSG:4326' }) }); // 地图点击事件 map.on('click', (e) => { console.log(e); }) // 创建Style const iconStyle = new ol.style.Style({ image: new ol.style.Icon({ anchor: [0.5, 0.5], color: 'red', src: './img/point.png', width: 50 }), text: new ol.style.Text({ text: '点标记', offsetY: -35, fill: new ol.style.Fill({color: '#c6287b'}) }) }) // 创建Feature要素 const features = coordinate.map((item) => { const Feature = new ol.Feature({ // 创建geometry geometry: new ol.geom.Point(item), name: 'Marker' }) // Style设置给Feature,也可直接放到Vector图层上 Feature.setStyle(iconStyle); return Feature; }) // 创建Vector图层 const vectorLayer = new ol.layer.Vector({ source: new ol.source.Vector(), // style: iconStyle }) // Feature要素添加到Vector图层 features.forEach((item) => vectorLayer.getSource().addFeature(item)) // Vector图层添加到地图 map.addLayer(vectorLayer); // 点标注点击 map.on('click', (evt) => { const Feature = map.forEachFeatureAtPixel(evt.pixel, (feature) => { return feature }) if(Feature && Feature.get('name') === 'Marker') { console.log('Marker点标注'); } }) </script> </body> </html>
创建好
Feature
对象后,如果想上图,需要先将其添加到矢量Source
上,Source
和Layer
是对应的,再将矢量Source
添加到图层上,最好图层添加到地图上,要素(Feature)就可以展示啦!
下面我们来预览效果吧!
点聚合
看完点标记之后,我们矢量图形上图的基本模式了解了,下面我们一起来看看点聚合怎么搞!
Cluster
首先我们想要点聚合,就不能不用矢量图层(Vector),因为点聚合也是失恋数据图形。既然是聚合,数据源(Source)当然要使用聚合。ol.source.Cluster
会对给到的矢量数据进行聚合,我们只需要提供矢量数据。
const source = new ol.source.Vector();
for(let i = 0; i < 200;i++) {
const coordinate = [116.39+Math.random(), 39.91+Math.random()];
const Feature = new ol.Feature(new ol.geom.Point(coordinate));
source.addFeature(Feature);
}
for(let i = 0; i < 200;i++) {
const coordinate = [116.40+Math.random(), 39.92+Math.random()];
const Feature = new ol.Feature(new ol.geom.Point(coordinate));
source.addFeature(Feature);
}
// 聚合
const Cluster = new ol.source.Cluster({
source: source,
distance: 100
})
Style
聚合数据源 + 要素 准备好之后,就只差要素的样式和上图了。下面来看看!
const Style = (options) => new ol.style.Style(options);
const Fill = (options) => new ol.style.Fill(options);
const Circle = (options) => new ol.style.Circle(options);
const Text = (options) => new ol.style.Text(options);
const Stroke = (options) => new ol.style.Stroke(options);
const Icon = (options) => new ol.style.Icon(options);
// 创建ClusterStyle
const createClusterStyle = (size) => {
console.log(size);
return Style({
image: Circle({
radius: 30,
stroke: Stroke({
color: '#fff'
}),
fill: Fill({
color: 'rgba(0,0,0, 0.7)'
})
}),
text: Text({
color: '#fff',
font: '14px sans-serif',
text: size.toString(),
fill: Fill({
color: '#fff'
})
})
})
}
// 创建MarkerStyle
const createMarkerStyle = (size) => {
return Style({
image: Icon({
anchor: [0.5, 0.5],
color: 'red',
src: './img/point.png',
width: 50
})
})
}
// 创建Vector图层
const vectorLayer = new ol.layer.Vector({
source: Cluster,
style: (feature) => {
const len = feature.get('features').length;
return len > 1 ? createClusterStyle(len) : createMarkerStyle(len);
}
})
分别创建ClusterStyle 和 MarkerStyle,然后通过Vector
图层的style函数进行判断,聚合主干的基本逻辑就完成了。
这里我们其实会发现,点聚合主要是数据源的聚合,配合ol.source.Cluster
即可完成以上聚合的主要逻辑。
示例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>点聚合 Map</title>
<link rel="stylesheet" href="./8.2.0/theme/ol.css">
<script src="./8.2.0/en/latest/ol/dist/ol.js"></script>
<!-- <script src="https://cdn.jsdelivr.net/npm/ol@v8.2.0/dist/ol.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/ol@v8.2.0/ol.css"> -->
</head>
<body>
<div id="map" style="height: 95vh; border: 6px solid;"></div>
<script>
let map = new ol.Map({
target: 'map',
layers: [
new ol.layer.Tile({
// source: new ol.source.OSM()
source: new ol.source.BingMaps({
key: 'Aud1dM5V1tT5Yvg2uX8Hp5ftaZZ4stEuJZ8i7IO1KSyLFj9A4UuamHK6_tUKEcGe',
imagerySet: 'Road' // 指定加载的图层名,还可以替换为'AerialWithLabels' 'Aerial'或'Road'
})
}),
],
view: new ol.View({
center: [116.39, 39.91],
zoom: 11,
projection: 'EPSG:4326'
})
});
// 地图点击事件
map.on('click', (e) => {
console.log(e);
})
// 矢量数据
const source = new ol.source.Vector();
for (let i = 0; i < 200; i++) {
const coordinate = [116.39 + Math.random(), 39.91 + Math.random()];
const Feature = new ol.Feature(new ol.geom.Point(coordinate));
source.addFeature(Feature);
}
for (let i = 0; i < 200; i++) {
const coordinate = [116.40 + Math.random(), 39.92 + Math.random()];
const Feature = new ol.Feature(new ol.geom.Point(coordinate));
source.addFeature(Feature);
}
// 聚合数据
const Cluster = new ol.source.Cluster({
source: source,
distance: 100
})
const Style = (options) => new ol.style.Style(options);
const Fill = (options) => new ol.style.Fill(options);
const Circle = (options) => new ol.style.Circle(options);
const Text = (options) => new ol.style.Text(options);
const Stroke = (options) => new ol.style.Stroke(options);
const Icon = (options) => new ol.style.Icon(options);
// 创建聚合Style
const createClusterStyle = (size) => {
console.log(size);
return Style({
image: Circle({
radius: 30,
stroke: Stroke({
color: '#fff'
}),
fill: Fill({
color: 'rgba(0,0,0, 0.7)'
})
}),
text: Text({
color: '#fff',
font: '14px sans-serif',
text: size.toString(),
fill: Fill({
color: '#fff'
})
})
})
}
// 创建Marker Style
const createMarkerStyle = (size) => {
return Style({
image: Icon({
anchor: [0.5, 0.5],
color: 'red',
src: './img/point.png',
width: 50
})
})
}
// 创建Vector图层
const vectorLayer = new ol.layer.Vector({
source: Cluster,
style: (feature) => {
const len = feature.get('features').length;
return len > 1 ? createClusterStyle(len) : createMarkerStyle(len);
}
})
map.addLayer(vectorLayer);
// 点标注点击
map.on('click', (evt) => {
const Feature = map.forEachFeatureAtPixel(evt.pixel, (feature) => {
return feature
})
if (Feature && Feature.get('name') === 'Marker') {
console.log('Marker点标注');
}
})
</script>
</body>
</html>
总结
Feature
、Geometry
、Style
三者结合,实现矢量图形的上图;Geometry
是feature对象的基本组成部分,存储一个要素的几何信息;Feature
对象会被挂载到矢量数据源的要素上,再上图;Style
是Feature
的样式;- 点聚合实际是数据源的聚合;
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。