1. 引言

坐标数据是空间数据文件的核心,空间数据的数据量往往是很大的。数据可视化是GIS的一个核心应用,绘制海量的坐标数据始终是一个考验设备性能的难题,使用GPU进行绘制可有效减少CPU的负载,提升绘制时的速度

shapefile是空间数据文件常用的格式,Shapefile-js提供了编写简单的JavaScript程序以读取ESRI Shapefile 以及关联的属性文件的功能,它可以在网页端使用,也可在Node.js环境下使用

Shapefile-js的GitHub地址:calvinmetcalf/shapefile-js: Convert a Shapefile to GeoJSON. Not many caveats. (github.com)

本文基于JavaScript语言,使用Shapefile-js库来读取shp文件,并使用WebGL绘制空间数据

2. 数据准备

数据为2015年中国省级行政边界数据(province),来源为:中国科学院资源环境科学与数据中心 (resdc.cn)

下图为数据的主要信息:

3. shp解析

原始的shp文件包含多个文件:

  • shp文件
  • dbf文件
  • prj文件
  • ......

方便起见,笔者把它们打包为一个zip文件,文件名为province.zip,当然,这一步非必须

根据GitHub的示例,很简单就可以解析shp为json:

<script src='https://unpkg.com/shpjs@latest/dist/shp.js'> </script>
<script>
shp('http://127.0.0.1:5500/province/province.zip').then(function (data) {
console.log(data)
}
</script>

进行绘制需要读取shp文件的四至范围和每个Geometry的坐标数据,这里笔者使用OpenLayers进行加载GeoJSON

不妨使用OpenLayers绘制一下地图,读取四至范围:

<!DOCTYPE html>
<html lang="en"> <head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<!-- openlayers cdn -->
<script src="https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io@master/en/v6.14.1/build/ol.js"></script>
<link rel="stylesheet"
href="https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io@master/en/v6.14.1/css/ol.css">
</head> <body>
<div id="map" style="height: 800px;"></div> <script src='https://unpkg.com/shpjs@latest/dist/shp.js'> </script>
<script>
shp('http://127.0.0.1:5500/province/province.zip').then(function (data) {
console.log(data)
const map = new ol.Map({
target: 'map',
layers: [
new ol.layer.Tile({
source: new ol.source.OSM()
}),
new ol.layer.Vector({
source: new ol.source.Vector({
features: new ol.format.GeoJSON().readFeatures(data, {
featureProjection: 'EPSG:3857'
})
}),
style: new ol.style.Style({
stroke: new ol.style.Stroke({
color: '#f00',
width: 2
})
})
}), ],
view: new ol.View({
center: ol.proj.fromLonLat([104.114129, 37.550339]),
zoom: 3
})
});
console.log(map.getAllLayers()[1].getSource())
}); </script>
</body> </html>

结果图如下:

4. WebGL绘制

WebGL详细的绘制流程可以参考:基于JavaScript的OpenGL 01 之Hello Triangle - 当时明月在曾照彩云归 - 博客园 (cnblogs.com)

使用OpenGL绘制shp文件可以参考:使用Shapefile C Library读取shp文件并使用OpenGL绘制 - 当时明月在曾照彩云归 - 博客园 (cnblogs.com)

本文所使用的方法是每个Geometry绑定一个VAO和VBO,然后进行绘制

完整代码如下:

<!DOCTYPE html>
<html lang="en"> <head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src='https://unpkg.com/shpjs@latest/dist/shp.js'> </script>
<!-- openlayers cdn -->
<script src="https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io@master/en/v6.14.1/build/ol.js"></script>
<link rel="stylesheet"
href="https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io@master/en/v6.14.1/css/ol.css"> <style>
html,
body,
canvas {
width: 100%;
height: 100%;
}
</style>
</head> <body>
<canvas></canvas>
<script>
var canvas = document.querySelector('canvas');
canvas.width = canvas.clientWidth;
canvas.height = canvas.clientHeight;
var gl = canvas.getContext('webgl');
if (!gl) {
console.log('WebGL not supported, falling back to experimental-webgl');
}
gl.clearColor(0.2, 0.3, 0.3, 1.0);
gl.clear(gl.COLOR_BUFFER_BIT); const vertexShader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vertexShader, `
attribute vec3 aPos; void main()
{
gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);
}
`);
gl.compileShader(vertexShader);
if (!gl.getShaderParameter(vertexShader, gl.COMPILE_STATUS)) {
alert('An error occurred compiling the shaders: ' + gl.getShaderInfoLog(vertexShader));
gl.deleteShader(vertexShader); } const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fragmentShader, `
#version 100
void main()
{
gl_FragColor = vec4(1.0, 0.5, 0.2, 1.0);
}
`);
gl.compileShader(fragmentShader);
if (!gl.getShaderParameter(fragmentShader, gl.COMPILE_STATUS)) {
alert('An error occurred compiling the shaders: ' + gl.getShaderInfoLog(fragmentShader));
gl.deleteShader(fragmentShader); }
const shaderProgram = gl.createProgram();
gl.attachShader(shaderProgram, vertexShader);
gl.attachShader(shaderProgram, fragmentShader);
gl.linkProgram(shaderProgram);
if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) {
alert('Unable to initialize the shader program: ' + gl.getProgramInfoLog(shaderProgram));
} gl.useProgram(shaderProgram); shp('http://127.0.0.1:5500/province/province.zip').then(function (data) {
console.log(data)
var features = new ol.format.GeoJSON().readFeatures(data, {
featureProjection: 'EPSG:3857'
})
var source = new ol.source.Vector({
features: features
})
console.log(source)
var minx, miny, maxx, maxy;
[minx, miny, maxx, maxy] = source.getExtent();
console.log(minx, miny, maxx, maxy)
for (let i = 0; i < features.length; i++) {
const feature = features[i];
const geometry = feature.getGeometry();
const coordinate = geometry.getCoordinates()[0];
let lineString = []
for (let j = 0; j < coordinate.length; j++) {
const point = coordinate[j];
let x = (point[0] - minx) / (maxx - minx) * 2 - 1;
let y = (point[1] - miny) / (maxy - miny) * 2 - 1;
lineString.push(x, y, 0.0);
}
const lineStringBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, lineStringBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(lineString), gl.STATIC_DRAW); gl.vertexAttribPointer(gl.getAttribLocation(shaderProgram, 'aPos'), 3, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(0) gl.drawArrays(gl.LINE_STRIP, 0, lineString.length / 3);
}
})
</script>
</body> </html>

绘制结果图如下:

5. 参考资料

[1]calvinmetcalf/shapefile-js: Convert a Shapefile to GeoJSON. Not many caveats. (github.com)

[2]OpenLayers v6.14.1 API - Index

[3]使用Shapefile C Library读取shp文件并使用OpenGL绘制 - 当时明月在曾照彩云归 - 博客园 (cnblogs.com)

[4]基于JavaScript的OpenGL 01 之Hello Triangle - 当时明月在曾照彩云归 - 博客园 (cnblogs.com)

最新文章

  1. .NET LINQ 元素操作
  2. js整理3
  3. 《linux内核设计与实现》读书笔记第三章
  4. asp.net mvc razor html encoding
  5. hbase多用户入库,regionserver下线问题
  6. 网页前台的iframe控制内部刷新子页
  7. ReactiveSwift源码解析(七) Signal的CombineLatest的代码实现
  8. 【Impala篇】---Hue从初始到安装应用
  9. py文件的运行
  10. [android] activity横竖屏切换的生命周期
  11. 三、taro路由及设计稿及尺寸单位
  12. Socket实现断线重连
  13. Android : 跟我学Binder --- (5) C++实现
  14. firedac数据集数据序列为JSON
  15. Linux配置自动发送邮件
  16. bzr: ERROR: No push location known or specified.
  17. 【OpenJudge9272】【DP】偶数个数字3
  18. zend studio,操作记录
  19. Lucene 源码分析之倒排索引(一)
  20. linux中两个缓冲区

热门文章

  1. Day33:String类及其常用方法详解
  2. 万字干货|Synchronized关键字详解
  3. WPF中的“资源”
  4. C# 操作IIS加强版(添加,删除,启动,暂停网站,默认页,绑定信息)
  5. gtest学习教程(从0到1)
  6. 如何让铁威马NAS可以通过互联网访问?
  7. 浅谈入行Qt桌面端开发程序员-从毕业到上岗(1):当我们说到桌面端开发时,我们在谈论什么?
  8. 使用pip命令安装库时提示Could not build wheels for six, since package &#39;wheel&#39; is not installed
  9. [OpenCV实战]32 使用OpenCV进行非真实感渲染
  10. python之路24之 面向对象动静态方法、继承、派生