文章目录

  • 1 前言
  • 2 JSTS
  • 3 turf
  • 4 安装使用
    • 4.1 jsts
      • 4.1.1 直接引入
      • 4.1.2 NPM
    • 4.2 turf
      • 4.1.1 直接引入
      • 4.1.2 NPM
  • 5 空间分析
    • 5.1 判断是否包含
    • 5.2 判断是否交叉
    • 5.3 判断是否重叠
    • 5.4 缓冲
  • 6 体积和性能
    • 6.1 体积
    • 6.2 性能
      • 6.2.1 jsts在node端
      • 6.2.2 jsts和turf对比

1 前言

通常,提到GIS的空间分析,我们会联系到ArcGIS,QGIS等这些GIS软件。这些工具软件,在空间处理能力方面,非常强大,是我们处理空间数据的非常有力的武器,也是一个GISer入门时很有必要掌握的关键技能。但是,这些软件,作为桌面软件时代的产品,其空间处理功能,作为软件的基本功能,并不能脱离软件独立运行,也很难满足我们的一些定制化需求。而基于这些软件进行的二次开发,虽然能一定程度上满足的我们的定制要求,但是产出通常桌面软件,不符合现今这个互联网时代的基本诉求。

在现今互联网时代,在前后端技术框架下,数据通常都是动态的,我们遇到一些空间分析的需求,通常我们可能会想到把空间分析需求放到后台去处理。这样做的好处是:1、不占用客户端资源,所有计算由服务器完成,充分发货服务器性能;2、技术路线相对比较成熟,有许多可供选择的工具包,比较Geotools、geoserver、PostGIS、Geopandas等等,参考资料也比较多。

然而,有时候关于空间分析的需求,可能只是一些功能相对较为简单的需求,为了这些需求而去引入相对复杂的工具包,似乎有些大材小用。

随着开发技术的进步,个人计算机性能的提升,以及浏览器的进化,当一个前端开发人员,再次拿到GIS空间分析的问题时,开始思考,有没有可能在浏览器端来处理这个问题?

答案是肯定的。
哈哈,废话这么多,其实就是为了引出本文的两个主角JSTS以及turf。

2 JSTS

jsts是一个javascript包,可用于处理和分析简单的空间几何。它是Java包JTS通过源码转换而来,并保留了原JTS的API。
另外,它的io模块支持与WKT、GeoJSON以及openlayers3+进化数据互转。这个功能会非常友好。

3 turf

turf是mapbox出品的用javascript写的模块化空间分析引擎,它使用geojson数据格式来进行空间处理。它包含传统的空间操作,用于创建GeoJSON数据的辅助函数以及数据分类和统计工具。

这两个包都可以在浏览器端或者在node中运行。

4 安装使用

4.1 jsts

4.1.1 直接引入

<script src="https://unpkg.com/jsts/dist/jsts.min.js"></script>

4.1.2 NPM

1) 安装

npm install jsts

2) 引入-node环境

const jsts = require('jsts')

3) 引入-esModule
这里要稍微注意下,直接 import jsts from ‘jsts’ 并不能正确引入jsts包。这里需要按需引入具体的模块,根路径是’jsts/org/locationtech/jts’。比如引入jsts的overlayOp模块

import OverlayOp from 'jsts/org/locationtech/jts/operation/overlay/OverlayOp'

4.2 turf

4.1.1 直接引入

<!-- 使用unpkg -->
<script src="https://unpkg.com/@turf/turf/turf.min.js"></script><!-- 在BootCDN上下载指定版本 -->
<script src="https://www.bootcdn.cn/Turf.js/"></script>

4.1.2 NPM

下载安装,可以一次安装所有模块或者只安装部分模块

1) 安装所有

安装

$ npm install @turf/turf

一次引入所有模块

import * as turf from '@turf/turf'

或者单独引入

import { lineString, along } from '@turf/turf'

node环境引入

const turf = require('@turf/turf')

2) 独立安装

安装

$ npm install @turf/collect

引入

import collect from '@turf/collect';

5 空间分析

这里举几个常见的判断空间位置关系的例子,分别使用jsts和turf进行判断

5.1 判断是否包含

// turf
const line = turf.lineString([[1, 1], [1, 2], [1, 3], [1, 4]]);
const point = turf.point([1, 2]);
console.log('turf运算结果:', turf.booleanContains(line, point))// jsts
const reader = new jsts.io.WKTReader()
const jstsLine = reader.read('LINESTRING (1 1, 1 2, 1 3, 1 4)')
const jstsPoint = reader.read('POINT (1 2)')
console.log('jsts运算结果:', jsts.operation.relate.RelateOp.contains(jstsLine, jstsPoint))

运算结果

turf运算结果: true
jsts运算结果: true

5.2 判断是否交叉

// turf
const line1 = turf.lineString([[-2, 2], [4, 2]]);
const line2 = turf.lineString([[1, 1], [1, 2], [1, 3], [1, 4]]);
console.log('turf运算结果:', turf.booleanCrosses(line1, line2))// jsts
const reader = new jsts.io.WKTReader()
const jstsLine1 = reader.read('LINESTRING (-2 2, 4 2)')
const jstsLine2 = reader.read('LINESTRING (1 1, 1 2, 1 3, 1 4)')
console.log('jsts运算结果:',jsts.operation.relate.RelateOp.crosses(jstsLine1, jstsLine2))

运算结果

turf运算结果: true
jsts运算结果: true

5.3 判断是否重叠

// turf
var poly1 = turf.polygon([[[0,0],[0,5],[5,5],[5,0],[0,0]]]);
var poly2 = turf.polygon([[[1,1],[1,6],[6,6],[6,1],[1,1]]])
console.log('turf运算结果:', turf.booleanOverlap(poly1, poly2))// jsts
var reader = new jsts.io.WKTReader()
var jstsPoly1 = reader.read('POLYGON ((0 0, 0 5, 5 5, 5 0, 0 0))')
var jstsPoly2= reader.read('POLYGON ((1 1, 1 6, 6 6, 6 1, 1 1))')
console.log('jsts运算结果:',jsts.operation.relate.RelateOp.overlaps(jstsPoly1, jstsPoly2))

运算结果

turf运算结果: true
jsts运算结果: true

5.4 缓冲

// turf
const point = turf.point([-90.548630, 14.616599]);
const buffered = turf.buffer(point, 500, {units: 'miles'});
console.log('turf运算结果:', buffered)// jsts
const reader = new jsts.io.WKTReader()
const jstsPoint = reader.read('POINT (-90.548630 14.616599)')
const jstsBuffer = jsts.operation.buffer.BufferOp.bufferOp(jstsPoint, 500)
console.log('jsts运算结果:', jstsBuffer)

运算结果

turf运算结果: {type: 'Feature', properties: {…}, geometry: {…}}
jsts运算结果: it {_shell: ut, _holes: Array(0), _envelope: null, _userData: null, _factory: Ct, …}

以上只是抛砖引玉,如果你以为这两个包只能干这点事,那就大错特错了。实际上,这两个包的功能都非常强大,里面有非常多的GIS相关的计算操作,jsts甚至支持3维空间上的计算,欢迎大家去研究挖掘。

6 体积和性能

6.1 体积

先说体积,对于项目体积比较苛刻的同仁,可能会比较关注这点。由于功能强大,所以包体积相对来说也较大。以下是两个包最新完整版的体积大小。

项目 版本 源码体积 压缩后 *.min.js
jsts 2.6.1 914k 475k
turf 6.3.0 590k

如果不经常做前端性能优化,对体积大小不是很敏感,这里提供一个参考数据, openlayers6,压缩后的代码体积在接近1M,约是这两个的两倍。
如果我们的项目是前端工程化开发,你有特别在乎流量问题,那可以通过按需引入来减少项目最终的打包体积。

6.2 性能

6.2.1 jsts在node端

在性能方面,以判断空间包含关系为例,笔者分别在node环境和浏览器环境中,做了一些测试,查看它们的耗时情况。以下是拿jsts包在node端的测试部分代码:

var i = 0
var count = 1000000var time1 = new Date().getTime()
var reader = new jsts.io.WKTReader()
var jstsPolygon = reader.read('POLYGON((1 1, 35 1, 35 84, 1 84, 1 1))')
while (i < count) {var x = Math.random() * 100var y = Math.random() * 100var p = reader.read(`POINT(${x} ${y})`)jsts.operation.relate.RelateOp.contains(jstsPolygon, p)i++
}
var time2 = new Date().getTime()
console.log(`jsts test done, ${time2 - time1}ms`)

jtst在node端,计算1万次空间包含关系,耗时91ms。

jsts test done, 91ms

如果总数设置为100w,大约需要3s。

jsts test done, 3042ms

这个耗时,似乎有点长。
不过上面代码有个问题,用了wktreader把数据翻译成jsts的几何对象。在循环次数大的情况下,这个可能会造成比较大的误差。如果只单纯考虑判断空间关系的耗时,再对比看一看。对代码稍微做调整。

const reader = new jsts.io.WKTReader()
const jstsPolygon = reader.read('POLYGON ((1 1, 35 1, 35 84, 1 84, 1 1))')
let jstsPoints = []
let i = 0
let max = 10000while (i < max) {let x = Math.random() * 100let y = Math.random() * 100var jstsPoint = reader.read(`POINT (${x} ${y})`)jstsPoints.push(jstsPoint)i++
}const time1 = new Date().getTime()
jstsPoints.forEach((p) => {var r = jsts.operation.relate.RelateOp.contains(jstsPolygon, p)
})
const time2 = new Date().getTime()
console.log(`jsts test done, ${time2 - time1}ms`)

好,在来跑一次看下。
1万次19ms。

jsts test done, 19ms

100万次233ms

jsts test done, 233ms

1万次从91ms变成19ms,100次从3042ms变成233ms。看来在WKTReader里确实耗费了很多时间成本。

6.2.2 jsts和turf对比

起初,笔者并没有对比两者的意思,估计两者计算速度应该相当。出于测试结果完整性考虑,将两个包都拿来跑一下。

function testJsts (count) {const reader = new jsts.io.WKTReader()const jstsPolygon = reader.read('POLYGON ((1 1, 35 1, 35 84, 1 84, 1 1))')let jstsPoints = []let i = 0while (i < count) {let x = Math.random() * 100let y = Math.random() * 100var jstsPoint = reader.read(`POINT (${x} ${y})`)jstsPoints.push(jstsPoint)i++}const time1 = new Date().getTime()jstsPoints.forEach((p) => {var r = jsts.operation.relate.RelateOp.contains(jstsPolygon, p)})const time2 = new Date().getTime()console.log(`jsts test done, ${time2 - time1}ms`)
}testJsts(10000)
function testTurf (count) {const turfPoints = []const polygon = turf.polygon([[[1, 1],[35, 1],[35, 84],[1, 84],[1, 1]]])let i = 0while (i < count) {let x = Math.random() * 100let y = Math.random() * 100turfPoints.push(turf.point([x, y]))i++}const time1 = new Date().getTime()turfPoints.forEach((p) => {turf.booleanContains(polygon, p)})const time2 = new Date().getTime()console.log(`turf test done, ${time2 - time1}ms`)
}
testTurf(10000)

在个人笔记本上分别运行上面代码,count分别取10000,1000000, 10000000,每个count跑三次并取结果中位数。
结果,意料之外…

node环境下

10000次 1000000次 10000000次
jsts 20 251 3395
turf 9 137 1257

浏览器环境下

10000次 1000000次 10000000次
jsts 19 447 4074
turf 10 97 797

横向看貌似turf计算效率更高,纵向看似乎turf在浏览器端表现更好于node环境,而jsts似乎更适应node环境。不过,这里只是用了一个案例做对比,不能以点概全。

由于在后端,GIS空间分析方面有很多路可以选,所以在node中的运用,机会相对来说的比较少。这里我们更多考虑在前端开始中应用。

两个包都非常优秀好用,可以弥补像openlayers、leaflet等这些前端GIS可视化库的不足,让我们处理GIS数据和进行空间分析,不再依赖于后端。

本文参考
1、Turf.js中文网 https://turfjs.fenxianglu.cn/
2、https://www.npmjs.com/package/jsts
3、http://bjornharrtell.github.io/jsts/
4、https://docs.mapbox.com/help/glossary/turf/

开源的前端GIS空间分析库介绍 (一)jsts与turf相关推荐

  1. 开源的前端GIS空间分析库介绍 (三)turf与ol结合

    前言 turf是mapbox出品的前端空间分析库,官网:http://turfjs.org/ turf库中包含的空间分析计算功能比较多,也非常简单易用.相比于jsts,turf的官方文档维护的非常好, ...

  2. JavaScript 空间分析库——JSTS和Turf

    前言 项目中有管线的空间拓扑关系查询需求,在npm中检索到JSTS和Turf两个JavaScript 空间分析库. JSTS JSTS是一个符合OGC规范的简单要素空间位置判定函数JavaScript ...

  3. 基于ArcGIS:GIS空间分析复习-理论概念+案例分析

    目录 01 第一章 1.1 GIS空间分析的概念 1.2 GIS空间分析的研究对象.研究目标 1.3 研究目标是:认知.解释.预报.调控. 1.4 道路拓宽案例分析 1.5 GIS空间分析的核心问题 ...

  4. GIS空间分析 数字地形分析2 基本地形因子的提取

    目录 一.实验名称 二.实验目的 三.实验背景 四.实验准备 1.数据 2.软件 五.实验步骤: 本文数据免费下载 其他GIS空间分析文章 一.实验名称 数字地形分析之基本地形因子的提取 二.实验目的 ...

  5. GIS空间分析(五)—— 位置与几何关系分析

    位置与几何关系分析 位置是空间对象的基本特征,矢量叠加分析.地图代数.选址分析等经典GIS空间分析方法都是基于位置特征分析方法的代表.空间几何关系分析主要是对空间目标之间由位置.形状.方位.连通性和相 ...

  6. 使用GIS空间分析进行植物生长区域选址(附练习数据下载)

    经过观察可以发现某种珍贵植物在山区的某个区域位置生长状况明显要比其他区域好很多,通过研究了解到这种植物生长具有严格的生长条件.为了能更好地保护该种植物的生长环境,现在需要使用GIS空间分析方法,将适合 ...

  7. GIS空间分析 栅格数据分析1 欧氏距离分析

    目录 一.实验名称 二.实验准备 1.基本概念: 2.实验目的: 3.实验背景: 4.实验要求: 5.实验数据: 6.实验流程: 三.实验步骤 其他GIS空间分析文章 一.实验名称 栅格分析之欧氏距离 ...

  8. turfjs前端地理空间分析类库

    一.简介 turfjs是一个地理空间分析库,处理各种地图算法. 1. 简单 模块化,易于理解的JavaScript函数处理GeoJSON 2. 模块化 Turf是一系列小模板的集合,可以按需使用 3. ...

  9. GIS空间分析 网络分析2规划最佳路径

    实验数据:见个人资源<GIS空间分析教学数据>免费下载,仅供学习使用 一.实验名称 网络分析之规划最佳路径 二.实验目的 某公司班车需要接送员工上下班,已知停靠的站点,请使用网络分析提供一 ...

最新文章

  1. linux系统用户属组,关于 Linux系统用户、组和权限管理
  2. MVC下HtmlHelper自带BeginForm表单提交与异步Ajax请求
  3. hadoop学习--单表关联
  4. Dll注入经典方法完整版
  5. 关于团队发展的若干想法(欢迎讨论)
  6. linux获取指定字符,shell 获取用户输入指定范围的单个字符的两种方法
  7. boost::fusion::make_map用法的测试程序
  8. 分享几个路由器设置小技巧,总有用得到的一天!
  9. 【直观详解】支持向量机SVM
  10. JavaScript知识笔记(三)——内置对象、浏览器对象
  11. openStack 手动部署文档
  12. 【Qt教程】1.4 - Qt5第一个控件 按钮QPushButton 指定父对象
  13. 麟龙指标通达信指标公式源码_麟龙指标套三 麟龙特色指标 通达信主图+副图指标 贴图...
  14. PowerShell中使用WMI或CIM
  15. 【Java 8 新特性】Java LocalDateTime 和 Epoch 互相转换
  16. 如何实现一个sandbox?
  17. 内存泄漏的原因及解决方法
  18. 复杂网络-标准公开数据集
  19. ARM最强CPU/GPU来了!A75、G72首发:性能爆炸
  20. 人人都是产品经理总结 第五章

热门文章

  1. linux常见的解压命令,linux常见解压命令
  2. 织梦模板修改方法(转)
  3. oauth2 spring-authorization-server OAuth2AuthorizationService支持redis
  4. 吃货的痛点:鱼龙混杂,究竟我该相信谁
  5. signature=4c7f5ea5ee6ba300a8851e5bd937b405,拦截到崩溃scrollViewContainer 错误
  6. 如此行事的人怎能不优秀?
  7. 【HTML基础】CSS样式表
  8. ATL属性包(PropertyBag)
  9. 注册电子邮箱有哪些品牌?163VIP邮箱有什么好处?
  10. 计算机基础考试题(答案在最后)