1、前言
前一篇博客介绍了如何在OpenLayers
中使用WebGLPoints
加载海量数据点的方法,这篇博客就来介绍一下WebGLPoints
图层的样式设置问题。
2、样式运算符
在VectorLayer
图层中,我们只需要创建一个ol.style.Style
对象即可,WebGLPoints
则不同,它并不是基于Canvas
进行绘制,因此其样式渲染不能直接使用ol.style.Style
,取而代之的是使用样式表达式进行渲染。
2.1、读取运算符
1、['get', 'attributeName']
2、['var', 'varName']
3、['time']
4、['zoom']
5、['resolution']
2.2、数学运算符
1、['*', value1, value2]
2、['/', value1, value2]
3、['+', value1, value2]
4、['-', value1, value2]
5、['clamp', value, low, high]
6、['%', value1, value2]
7、['^', value1, value2]
2.3、变换运算符
1、['case', condition1, output1, ...conditionN, outputN, fallback]
2、['match', input, match1, output1, ...matchN, outputN, fallback]
3、['interpolate', interpolation, input, stop1, output1, ...stopN, outputN]
2.4、逻辑运算符
1、['<', value1, value2]
2、['<=', value1, value2]
3、['>', value1, value2]
4、['>=', value1, value2]
5、['==', value1, value2]
6、['!=', value1, value2]
7、['!', value1]
8、['between', value1, value2, value3]
2.5、转换运算符
1、['array', value1, ...valueN]
2、['color', red, green, blue, alpha]
3、简单渲染
简单颜色渲染很简单,只需要使用['color', red, green, blue, alpha]
即可,第一个参数为固定值‘color’
,后面的参数依次为红、绿、蓝、透明度。下面的代码会将要素渲染为红色点:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>WebGL</title>
<style>
html,
body,
#map {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
}
</style>
<link rel="stylesheet" href="ol/ol.css" />
<script src="ol/ol.js"></script>
</head>
<body>
<div id="map"></div>
<script>
// 创建图层
var layer = new ol.layer.WebGLPoints({
source: new ol.source.Vector({
features: [
new ol.Feature({
geometry: new ol.geom.Point([120.0, 30.0]),
"type": "学校",
"dbm": 1
}),
new ol.Feature({
geometry: new ol.geom.Point([120.0, 30.1]),
"type": "学校",
"dbm": 2
}),
new ol.Feature({
geometry: new ol.geom.Point([120.1, 30.0]),
"type": "超市",
"dbm": 3
}),
new ol.Feature({
geometry: new ol.geom.Point([120.1, 30.1]),
"type": "超市",
"dbm": 4
}),
new ol.Feature({
geometry: new ol.geom.Point([120.2, 30.0]),
"type": "医院",
"dbm": 5
}),
new ol.Feature({
geometry: new ol.geom.Point([120.2, 30.1]),
"type": "医院",
"dbm": 6
}),
]
}),
style: {
symbol: {
symbolType: 'circle',
size: 40,
color: ['color', 255, 0, 0, 1]
}
}
});
// 创建地图
var map = new ol.Map({
target: 'map',
layers: [
layer
],
view: new ol.View({
projection: 'EPSG:4326',
center: [120, 30],
zoom: 10
})
});
</script>
</body>
</html>
运行结果如下图所示:
4、分类渲染
测试数据中的type
字段将要素分成了3
类,即:学校、超市、医院
。现在要求将学校渲染为红色、超市渲染为绿色、医院渲染为蓝色。此时需要使用match
表达式,其形式如下所示:
['match', type的值, '学校', 红色, '超市', 绿色, '医院', 蓝色, 默认颜色]
那么type
的值又该如何获取?其实很简单,使用['get', 'attributeName']
表达式即可,所以最后的样式表达式如下所示:
['match', ['get', 'type'], '学校', 红色, '超市', 绿色, '医院', 蓝色, 默认颜色]
代码如下所示:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>WebGL</title>
<style>
html,
body,
#map {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
}
</style>
<link rel="stylesheet" href="ol/ol.css" />
<script src="ol/ol.js"></script>
</head>
<body>
<div id="map"></div>
<script>
// 创建图层
var layer = new ol.layer.WebGLPoints({
source: new ol.source.Vector({
features: [
new ol.Feature({
geometry: new ol.geom.Point([120.0, 30.0]),
"type": "学校",
"dbm": 1
}),
new ol.Feature({
geometry: new ol.geom.Point([120.0, 30.1]),
"type": "学校",
"dbm": 2
}),
new ol.Feature({
geometry: new ol.geom.Point([120.1, 30.0]),
"type": "超市",
"dbm": 3
}),
new ol.Feature({
geometry: new ol.geom.Point([120.1, 30.1]),
"type": "超市",
"dbm": 4
}),
new ol.Feature({
geometry: new ol.geom.Point([120.2, 30.0]),
"type": "医院",
"dbm": 5
}),
new ol.Feature({
geometry: new ol.geom.Point([120.2, 30.1]),
"type": "医院",
"dbm": 6
}),
]
}),
style: {
symbol: {
symbolType: 'circle',
size: 40,
color: [
'match',
['get', 'type'],
'学校', ['color', 255, 0, 0, 1],
'超市', ['color', 0, 255, 0, 1],
'医院', ['color', 0, 0, 255, 1],
['color', 255, 0, 0, 1]
]
}
}
});
// 创建地图
var map = new ol.Map({
target: 'map',
layers: [
layer
],
view: new ol.View({
projection: 'EPSG:4326',
center: [120, 30],
zoom: 10
})
});
</script>
</body>
</html>
运行结果如下图所示:
5、分级渲染
测试数据中包含一个dbm
字段,现在根据dbm
的范围进行分级渲染,规定如下:
1、dbm∈[1, 2]
,渲染为红色
2、dbm == 3
,渲染为绿色
3、dbm == 4
,渲染为蓝色
4、dbm∈[5, 6]
,渲染为黄色
此时需要使用case
表达式,其形式如下所示:
['case', 'dbm∈[1,2]', 红色, 'dbm==3', 绿色, 'dbm==4', 蓝色, 'dbm∈[5,6]', 红色, 默认颜色]
在判断dbm
的值的范围时,需要使用逻辑表达式:
['==', dbm, 3]
['==', dbm, 4]
['between', dbm, 1, 2]
['between', dbm, 5, 6]
最后,使用['get', 'attributeName']
表达式获取字段值:
['get', 'dbm']
代码如下所示:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>WebGL</title>
<style>
html,
body,
#map {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
}
</style>
<link rel="stylesheet" href="ol/ol.css" />
<script src="ol/ol.js"></script>
</head>
<body>
<div id="map"></div>
<script>
// 创建图层
var layer = new ol.layer.WebGLPoints({
source: new ol.source.Vector({
features: [
new ol.Feature({
geometry: new ol.geom.Point([120.0, 30.0]),
"type": "学校",
"dbm": 1
}),
new ol.Feature({
geometry: new ol.geom.Point([120.0, 30.1]),
"type": "学校",
"dbm": 2
}),
new ol.Feature({
geometry: new ol.geom.Point([120.1, 30.0]),
"type": "超市",
"dbm": 3
}),
new ol.Feature({
geometry: new ol.geom.Point([120.1, 30.1]),
"type": "超市",
"dbm": 4
}),
new ol.Feature({
geometry: new ol.geom.Point([120.2, 30.0]),
"type": "医院",
"dbm": 5
}),
new ol.Feature({
geometry: new ol.geom.Point([120.2, 30.1]),
"type": "医院",
"dbm": 6
}),
]
}),
style: {
symbol: {
symbolType: 'circle',
size: 40,
color: [
'case',
['between', ['get', 'dbm'], 1, 2], ['color', 255, 0, 0, 1],
['==', ['get', 'dbm'], 3], ['color', 0, 255, 0, 1],
['==', ['get', 'dbm'], 4], ['color', 0, 0, 255, 1],
['between', ['get', 'dbm'], 5, 6], ['color', 255, 255, 0, 1],
['color', 255, 0, 0, 1]
]
}
}
});
// 创建地图
var map = new ol.Map({
target: 'map',
layers: [
layer
],
view: new ol.View({
projection: 'EPSG:4326',
center: [120, 30],
zoom: 10
})
});
</script>
</body>
</html>
运行结果如下图所示:
6、根据地图缩放等级渲染
现做如下规定:
1、地图缩放等级zoom∈(0, 10]
,渲染为红色
2、地图缩放等级zoom∈(10, 12]
,渲染为绿色
3、地图缩放等级zoom∈(12, 14]
,渲染为蓝色
4、其余缩放等级,渲染为黄色
看了上面的例子之后,相信同志们应该想到了:利用['zoom']
获取地图缩放等级,然后利用case
表达式进行情况分类,最后每种情况利用逻辑表达式判断即可。代码如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>WebGL</title>
<style>
html,
body,
#map {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
}
</style>
<link rel="stylesheet" href="ol/ol.css" />
<script src="ol/ol.js"></script>
</head>
<body>
<div id="map"></div>
<script>
// 创建图层
var layer = new ol.layer.WebGLPoints({
source: new ol.source.Vector({
features: [
new ol.Feature({
geometry: new ol.geom.Point([120.0, 30.0]),
"type": "学校",
"dbm": 1
}),
new ol.Feature({
geometry: new ol.geom.Point([120.0, 30.1]),
"type": "学校",
"dbm": 2
}),
new ol.Feature({
geometry: new ol.geom.Point([120.1, 30.0]),
"type": "超市",
"dbm": 3
}),
new ol.Feature({
geometry: new ol.geom.Point([120.1, 30.1]),
"type": "超市",
"dbm": 4
}),
new ol.Feature({
geometry: new ol.geom.Point([120.2, 30.0]),
"type": "医院",
"dbm": 5
}),
new ol.Feature({
geometry: new ol.geom.Point([120.2, 30.1]),
"type": "医院",
"dbm": 6
}),
]
}),
style: {
symbol: {
symbolType: 'circle',
size: 40,
color: [
'case',
['<=', ['zoom'], 10], ['color', 255, 0, 0, 1],
['<=', ['zoom'], 12], ['color', 0, 255, 0, 1],
['<=', ['zoom'], 14], ['color', 0, 0, 255, 1],
['color', 255, 255, 0, 1]
]
}
}
});
// 创建地图
var map = new ol.Map({
target: 'map',
layers: [
layer
],
view: new ol.View({
projection: 'EPSG:4326',
center: [120, 30],
zoom: 10
})
});
</script>
</body>
</html>
运行结果如下图所示:
7、根据地图分辨率渲染
根据地图分辨率渲染也很简单,只需要把上面的['zoom']
替换成['resolution']
即可。不过考虑到resolution
值是一个小数,因此这里将resolution
乘以10000
之后再进行判断,代码如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>WebGL</title>
<style>
html,
body,
#map {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
}
</style>
<link rel="stylesheet" href="ol/ol.css" />
<script src="ol/ol.js"></script>
</head>
<body>
<div id="map"></div>
<script>
// 创建图层
var layer = new ol.layer.WebGLPoints({
source: new ol.source.Vector({
features: [
new ol.Feature({
geometry: new ol.geom.Point([120.0, 30.0]),
"type": "学校",
"dbm": 1
}),
new ol.Feature({
geometry: new ol.geom.Point([120.0, 30.1]),
"type": "学校",
"dbm": 2
}),
new ol.Feature({
geometry: new ol.geom.Point([120.1, 30.0]),
"type": "超市",
"dbm": 3
}),
new ol.Feature({
geometry: new ol.geom.Point([120.1, 30.1]),
"type": "超市",
"dbm": 4
}),
new ol.Feature({
geometry: new ol.geom.Point([120.2, 30.0]),
"type": "医院",
"dbm": 5
}),
new ol.Feature({
geometry: new ol.geom.Point([120.2, 30.1]),
"type": "医院",
"dbm": 6
}),
]
}),
style: {
symbol: {
symbolType: 'circle',
size: 40,
color: [
'case',
['<=', ['*', ['resolution'], 10000], 2], ['color', 255, 0, 0, 1],
['<=', ['*', ['resolution'], 10000], 3], ['color', 0, 255, 0, 1],
['<=', ['*', ['resolution'], 10000], 4], ['color', 0, 0, 255, 1],
['<=', ['*', ['resolution'], 10000], 5], ['color', 255, 255, 0, 1],
['<=', ['*', ['resolution'], 10000], 6], ['color', 255, 0, 255, 1],
['<=', ['*', ['resolution'], 10000], 7], ['color', 0, 255, 255, 1],
['color', 300, 200, 100, 1]
]
}
}
});
// 创建地图
var map = new ol.Map({
target: 'map',
layers: [
layer
],
view: new ol.View({
projection: 'EPSG:4326',
center: [120, 30],
zoom: 10
})
});
</script>
</body>
</html>
运行结果如下图所示:
8、设置要素的形状和透明度
在symbol
对象中,symbolType
参数用于定义要素的形状,它可以设置为circle、triangle、square、image
。例如将symbolType
设置为triangle
:
symbol: {
symbolType: 'circle',
size: 40,
color: ['color', 255, 0, 0, 1]
}
此时要素会被渲染为三角形,如下图所示:
将symbolType
设置为square
:
symbol: {
symbolType: 'square',
size: 40,
color: ['color', 255, 0, 0, 1]
}
此时要素会被渲染为正方形,如下图所示:
如果希望设置透明度,只需要添加opacity
属性即可,例如将透明度设置为0.3
:
symbol: {
symbolType: 'circle',
size: 40,
color: ['color', 255, 0, 0, 1],
opacity: 0.3
}
如下图所示:
9、设置要素的尺寸
上面的代码主要针对color
属性进行设置,其实不仅仅是color
,size
属性同样可以使用样式表达式。现在根据dbm
值生成不同大小的要素,代码如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>WebGL</title>
<style>
html,
body,
#map {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
}
</style>
<link rel="stylesheet" href="ol/ol.css" />
<script src="ol/ol.js"></script>
</head>
<body>
<div id="map"></div>
<script>
// 创建图层
var layer = new ol.layer.WebGLPoints({
source: new ol.source.Vector({
features: [
new ol.Feature({
geometry: new ol.geom.Point([120.0, 30.0]),
"type": "学校",
"dbm": 1
}),
new ol.Feature({
geometry: new ol.geom.Point([120.0, 30.1]),
"type": "学校",
"dbm": 2
}),
new ol.Feature({
geometry: new ol.geom.Point([120.1, 30.0]),
"type": "超市",
"dbm": 3
}),
new ol.Feature({
geometry: new ol.geom.Point([120.1, 30.1]),
"type": "超市",
"dbm": 4
}),
new ol.Feature({
geometry: new ol.geom.Point([120.2, 30.0]),
"type": "医院",
"dbm": 5
}),
new ol.Feature({
geometry: new ol.geom.Point([120.2, 30.1]),
"type": "医院",
"dbm": 6
}),
]
}),
style: {
symbol: {
symbolType: 'circle',
size: [
'case',
['==', ['get', 'dbm'], 1], 10,
['==', ['get', 'dbm'], 2], 20,
['==', ['get', 'dbm'], 3], 30,
['==', ['get', 'dbm'], 4], 40,
['==', ['get', 'dbm'], 5], 50,
['==', ['get', 'dbm'], 6], 60,
20
],
color: ['color', 255, 0, 0, 1],
}
}
});
// 创建地图
var map = new ol.Map({
target: 'map',
layers: [
layer
],
view: new ol.View({
projection: 'EPSG:4326',
center: [120, 30],
zoom: 10
})
});
</script>
</body>
</html>
运行结果如下图所示:
10、结语
本文主要介绍了OpenLayers
中WebGLPoints
图层的样式设置方法。其实刚接触样式表达式的时候觉得这种方法很反人类,但是习惯之后发现它的灵活度很高,本文也只列举了一些常见的用法,有兴趣的同志可以去官网查看更详细的文档。