L7结合Turf.js实现空间分析与数据可视化
1. 概述
AntV L7 是蚂蚁集团 AntV 数据可视化团队推出的基于 WebGL 的开源大规模地理空间数据可视分析引擎,其特点是通过简单的代码进行配置,即可在前端网页中绘制精美的地图以及相关的图表,并且基于 WebGL 的渲染方式使得 L7 在大数据渲染时具有较为流畅体验
图1. AntV L7 官方图表截图
提到地理数据,就不得不说 GIS(Geographic Information System,地理理信息系统),它是一种用于捕捉、存储、管理、分析和展示地理空间数据的技术,通过 GIS ,用户可以将地理空间数据与属性数据相结合,进行复杂的空间分析、制作地图和展示地理信息,GIS 的核心包括地理数据的收集和整合、空间分析和地图制作
L7 专注于地理数据可视化,即地图制作,如果能有一个前端空间分析工具与 L7 结合,丰富 GIS 的核心,会极大地利好前端开发者和用户
Turf.js 就是一个经典地空间分析库,提供了许多用于处理地理空间数据的函数和算法,其基于JavaScript编写,可以用于浏览器端和Node.js环境
图2. Turf.js 的官网介绍
所以,将 Turf.js 与 L7 结合,就可以实现在前端进行空间分析与空间可视化,拓展 L7 的使用方向
以下章节,笔者首先记述 Turf.js 与 L7 的快速入门使用,然后记录一些实践案例
(笔者注:为了代码易于复现与使用,本文采用原始HTML的方式编写代码)
2. L7 的快速入门
第一步,使用CDN加载 L7
<! --引入最新版的L7,笔者使用时为2.20.5-->
<script src = 'https://unpkg.com/@antv/l7'></script>
- CDN 引用的方式,是在使用时通过 L7 命名空间获取所有对象并初始化,如 L7.scene、L7.GaodeMap
第二步,创建一个 DIV 容器并设置CSS样式
<div id="map"></div>
第三步,加载高德底图
<script>
const scene = new L7.Scene({
id: 'map',
map: new L7.GaodeMap({
center: [116.3956, 39.9392],
zoom: 10,
mapStyle: 'amap://styles/darkblue'
})
});
</script>
此时的完整代码如下:
<!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/@antv/l7'></script>
<style>
body,
#map {
height: 100vh;
width: 100vw;
margin: 0;
}
</style>
</head>
<body>
<div id="map"></div>
<script>
const scene = new L7.Scene({
id: 'map',
map: new L7.GaodeMap({
center: [116.3956, 39.9392],
zoom: 10,
mapStyle: 'amap://styles/darkblue'
})
});
</script>
</body>
</html>
结果图如下:
图3. 加载初始底图
第四步,加载GeoJSON矢量数据并设置样式
- L7 对于GeoJSON有很高的支持度,默认就支持GeoJSON数据
- 数据是北京地铁线路
// 加载底图之后
scene.on('loaded', () => {
fetch(
'https://gw.alipayobjects.com/os/basement_prod/0d2f0113-f48b-4db9-8adc-a3937243d5a3.json'
)
.then(res => res.json())
.then(data => {
const layer = new L7.LineLayer({})
.source(data)
.size(4)
.shape('line')
.color('标准名称', [ '#5B8FF9', '#5CCEA1', '#F6BD16' ])
.style({
borderWidth: 0.4,
borderColor: '#fff'
});
scene.addLayer(layer);
});
});
此时的完整代码如下:
<!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/@antv/l7'></script>
<style>
body,
#map {
height: 100vh;
width: 100vw;
margin: 0;
}
</style>
</head>
<body>
<div id="map"></div>
<script>
const scene = new L7.Scene({
id: 'map',
map: new L7.GaodeMap({
center: [116.3956, 39.9392],
zoom: 10,
mapStyle: 'amap://styles/darkblue'
})
});
scene.on('loaded', () => {
fetch(
'https://gw.alipayobjects.com/os/basement_prod/0d2f0113-f48b-4db9-8adc-a3937243d5a3.json'
)
.then(res => res.json())
.then(data => {
const layer = new L7.LineLayer({})
.source(data)
.size(4)
.shape('line')
.color('标准名称', ['#5B8FF9', '#5CCEA1', '#F6BD16'])
.style({
borderWidth: 0.4,
borderColor: '#fff'
});
scene.addLayer(layer);
});
});
</script>
</body>
</html>
结果图如下:
图4. 加载GeoJSON数据
由上述代码不难看出,使用 L7 进行可视化,只需要使用极少的代码,就可配置成精美的地图图表
文章篇幅有限,更多的样式配置信息,更详尽的API文档,请翻阅 官方文档 和 官方示例
3. Turf.js 的快速入门
第一步, 引入 Turf.js 的 CDN
<script src='https://unpkg.com/@turf/turf@6/turf.min.js'></script>
- CDN 的方式,通过 turf 命名空间访问 Turf.js 的函数,如 turf.bbox 等
第二步,引入GeoJSON数据
- 数据和上面一样,是北京地铁数据
<script>
fetch('https://gw.alipayobjects.com/os/basement_prod/0d2f0113-f48b-4db9-8adc-a3937243d5a3.json')
.then(res => res.json())
.then(data => {
console.log(data) // JSON对象
});
</script>
第三步,进行空间分析得到结果GeoJSON
- 这里示例为求地理包围盒 BBOX
<script>
fetch('https://gw.alipayobjects.com/os/basement_prod/0d2f0113-f48b-4db9-8adc-a3937243d5a3.json')
.then(res => res.json())
.then(data => {
const bbox = turf.bbox(data);
const bboxPolygon = turf.bboxPolygon(bbox);
console.log(bboxPolygon);
// 下面是地理包围盒的坐标数据
// 0: 116.10214436813241
// 1: 39.6703694682177
// 2: 116.68907341874268
// 3: 40.20693349910422
});
</script>
此时的完整代码为:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script src='https://unpkg.com/@turf/turf@6/turf.min.js'></script>
<script>
fetch('https://gw.alipayobjects.com/os/basement_prod/0d2f0113-f48b-4db9-8adc-a3937243d5a3.json')
.then(res => res.json())
.then(data => {
const bbox = turf.bbox(data);
const bboxPolygon = turf.bboxPolygon(bbox);
console.log(bboxPolygon);
});
</script>
</body>
</html>
上述 Turf.js 的代码可以看到,Turf.js 接收 GeoJSON 数据,输出 GeoJSON 结果数据
更多的空间分析函数与API可参考 Turf.js官方文档
Turf.js 专注于空间分析,L7 专注于数据可视化,并且两者对于 GeoJSON 格式有着最高优先度的支持,因此,可以将地理数据在 Turf.js 中进行处理,然后直接输出结果到 L7 中进行可视化,实现数据分析与数据可视化的连接
4. 案例一:寻找地铁站的换乘点
4.1 分析场景与数据
地铁换乘点,通常在不同地铁线路之间的交叉处,所以寻找换乘点,通常就是计算地铁线路的交叉处
如何计算交叉点呢?用空间分析的视角,就是进行求交运算
从 Turf.js 的官方文档中,可以找到计算线相交的函数lineIntersect
图5. lineIntersect 函数
上述的北京地铁线路数据示例如下:
{
"type": "FeatureCollection",
"crs": {
"type": "name",
"properties": {
"name": "urn:ogc:def:crs:OGC:1.3:CRS84"
}
},
"features": [
{
"type": "Feature",
"properties": {
"标准名称": "地铁二号线",
"分类代码": 430101,
"数据来源": "正射影像",
"现状时间": "2010/08/14",
"备注": null,
"SHAPE_LENG": 23177.0298819,
"Shape_Le_1": 23177.0298784,
"Shape_Le_2": 30241.8106532
},
"geometry": {
"type": "MultiLineString",
"coordinates": [
[
[
116.38050072430798,
39.94888011518406
],
[
116.38714780612922,
39.94892587302933
],
// ...
根据 Turf.js 的示例与文档,结合这份数据示例的类型为 FeatureCollection ,需要将里面的每个线路 MultiLineString 进行两两求交运算,最后将结果在 L7 中以点的形式绘制出来
4.2 进行空间分析
将 FeatureCollection 的每个 MultiLineString 进行两两求交运算得到交点的点集:
<script src='https://unpkg.com/@turf/turf@6/turf.min.js'></script>
<script>
fetch('https://gw.alipayobjects.com/os/basement_prod/0d2f0113-f48b-4db9-8adc-a3937243d5a3.json')
.then(res => res.json())
.then(data => {
const lines = data;
// 新建一个Point类型的FeatureCollection用来存储结果
const points = turf.featureCollection([]);
for (let i = 0; i < lines.features.length; i++) {
for (let j = i + 1; j < lines.features.length; j++) {
const intersections = turf.lineIntersect(lines.features[i], lines.features[j]);
if (intersections) {
if (intersections.features.length > 0) {
// 将交点添加到points中
intersections.features.forEach(item => {
points.features.push(item);
});
}
}
}
}
console.log(points); // 得到四十个交点的JSON对象
});
</script>
4.3 数据可视化
使用 L7 绘制结果代码很简单:
const pointLayer = new L7.PointLayer({})
.source(points)
.shape('circle')
.size(6)
.color('#f00')
.style({
stroke: '#fff',
strokeWidth: 2
});
scene.addLayer(pointLayer);
最后,地铁路线与路线交点的完整代码如下:
<!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/@antv/l7'></script>
<script src='https://unpkg.com/@turf/turf@6/turf.min.js'></script>
<style>
body,
#map {
height: 100vh;
width: 100vw;
margin: 0;
}
</style>
</head>
<body>
<div id="map"></div>
<script>
const scene = new L7.Scene({
id: 'map',
map: new L7.GaodeMap({
center: [116.3956, 39.9392],
zoom: 10,
mapStyle: 'amap://styles/darkblue'
})
});
scene.on('loaded', () => {
fetch(
'https://gw.alipayobjects.com/os/basement_prod/0d2f0113-f48b-4db9-8adc-a3937243d5a3.json'
)
.then(res => res.json())
.then(data => {
const layer = new L7.LineLayer({})
.source(data)
.size(4)
.shape('line')
.color('标准名称', ['#5B8FF9', '#5CCEA1', '#F6BD16'])
.style({
borderWidth: 0.4,
borderColor: '#fff'
});
scene.addLayer(layer);
const lines = data;
// 新建一个Point类型的FeatureCollection
const points = turf.featureCollection([]);
for (let i = 0; i < lines.features.length; i++) {
for (let j = i + 1; j < lines.features.length; j++) {
const intersections = turf.lineIntersect(lines.features[i], lines.features[j]);
if (intersections) {
if (intersections.features.length > 0) {
// 将交点添加到points中
intersections.features.forEach(item => {
points.features.push(item);
});
}
}
}
}
const pointLayer = new L7.PointLayer({})
.source(points)
.shape('circle')
.size(6)
.color('#f00')
.style({
stroke: '#fff',
strokeWidth: 2
});
scene.addLayer(pointLayer);
});
});
</script>
</body>
</html>
结果图如下(红点为换乘点):
图6. 寻找地铁换乘点
5. 案例二:计算地铁线路的服务范围
5.1 分析场景与数据
居民乘坐地铁,通常是前往最近的地铁站,地铁线路的服务范围其实就是地铁线路附近的区域
如果求地铁线路附近的区域呢?从空间分析的角度来说,就是进行缓冲区分析
那地铁线路的服务半径一般是多少呢?ChatGPT提示笔者是1-2公里,笔者这里就取1.5公里作为缓冲半径
地铁线路数据还是使用上述的那份北京地铁线路数据
从 Turf.js 的官方文档中,可以找到计算缓冲区的函数buffer
图7. buffer函数
根据 Turf.js 的示例与文档,结合这份数据示例的类型为 FeatureCollection ,所以只需要将数据传入 buffer 函数即可得到结果
5.2 进行空间分析
调用 turf.buffer 计算缓冲区:
<script src='https://unpkg.com/@turf/turf@6/turf.min.js'></script>
<script>
fetch('https://gw.alipayobjects.com/os/basement_prod/0d2f0113-f48b-4db9-8adc-a3937243d5a3.json')
.then(res => res.json())
.then(data => {
const lines = data;
const buffered = turf.buffer(data, 1500, { units: 'meters' });
console.log(buffered); // 缓冲区的JSON对象,Polygon
});
</script>
5.3 数据可视化
L7 进行可视化还是一如既往的简单
地铁路线与缓冲区分析完整代码如下:
<!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/@antv/l7'></script>
<script src='https://unpkg.com/@turf/turf@6/turf.min.js'></script>
<style>
body,
#map {
height: 100vh;
width: 100vw;
margin: 0;
}
</style>
</head>
<body>
<div id="map"></div>
<script>
const scene = new L7.Scene({
id: 'map',
map: new L7.GaodeMap({
center: [116.3956, 39.9392],
zoom: 10,
mapStyle: 'amap://styles/darkblue'
})
});
scene.on('loaded', () => {
fetch(
'https://gw.alipayobjects.com/os/basement_prod/0d2f0113-f48b-4db9-8adc-a3937243d5a3.json'
)
.then(res => res.json())
.then(data => {
const layer = new L7.LineLayer({})
.source(data)
.size(4)
.shape('line')
.color('标准名称', ['#5B8FF9', '#5CCEA1', '#F6BD16'])
.style({
borderWidth: 0.4,
borderColor: '#fff'
});
const lines = data;
const buffered = turf.buffer(data, 1500, { units: 'meters' });
const polygonLayer = new L7.PolygonLayer({})
.source(buffered)
.shape('fill')
.color('#fff')
.style({
opacity: 0.2
});
scene.addLayer(polygonLayer);
scene.addLayer(layer);
});
});
</script>
</body>
</html>
最后结果图如下:
图8. 计算地铁线路服务范围
6. 总结
经过上述两个小案例,可以说使用 L7 结合 Turf.js 进行简单的空间分析与可视化简直是易如反掌,尤其是对于前端开发人员来说,有时简单的空间分析功能在客户端完成即可,而不必进行后端开发
L7 具有强大的制图能力,在结合Turf.js后拥有了更广泛的使用场景
7. 参考资料
[1] L7·蚂蚁地理空间数据可视化 | AntV (antgroup.com)
[2] Turf.js | Advanced geospatial analysis (turfjs.org)
L7结合Turf.js实现空间分析与数据可视化的更多相关文章
- 前端使用d3.js调用地图api 进行数据可视化
前段时间自己研究了demo就是把某个区域的某个位置通过经纬度在地图上可视化.其实就是使用了第三方插件,比现在比较火的可视化插件d3.js echart.js.大致思路就是,把要用到的位置的geojso ...
- BI报表分析和数据可视化,推荐这三个开源工具!
开源篇 一.Superset 1.技术架构:Python + Flask + React + Redux + SQLAlchemy 2.使用人群: (1)开发/分析人员做好看板,业务人员浏览看板数据 ...
- JavaScript 空间分析库——JSTS和Turf【转】
https://blog.csdn.net/neimeng0/article/details/80363468 前言 项目中有管线的空间拓扑关系查询需求,在npm中检索到JSTS和Turf两个Java ...
- 从零开始的全栈工程师——js篇2.7(JS数据类型具体分析)
JS数据类型具体分析与数据的三大存储格式 1. 字符串 string2. 数字 number3. 布尔 boolean4. null 空5. undefined 未定义↑↑↑叫基本数据类型 基本数据类 ...
- d3.js:数据可视化利器之快速入门
hello,data! 在进入d3.js之前,我们先用一个小例子回顾一下将数据可视化的基本流程. 任务 用横向柱状图来直观显示以下数据: var data = [10,15,23,78,57,29,3 ...
- mapbox-gl空间分析插件turf.js使用介绍
mapbox-gl能够方便地显示地图,做一些交互,但是缺少空间分析功能,比如绘制缓冲区.判断点和面相交等等. turf.js是一个丰富的用于浏览器和node.js空间分析库,官网 http://tur ...
- JS内存空间详细图解
JS内存空间详细图解 变量对象与堆内存 var a = 20; var b = 'abc'; var c = true; var d = { m: 20 } 因为JavaScript具有自动垃圾回收机 ...
- GIS应用|快速开发REST空间分析服务
随着计算机的快速发展,GIS已经在各大领域得到应用,和我们的生活息息相关, 但是基于GIS几大厂商搭建服务,都会有一定的门槛,尤其是需要server,成本高,难度大,这里介绍一种在线GIS云平台,帮你 ...
- 基于IGServer的Web地图要素空间分析
1. 引言 MapGIS IGServer 是中地数码的一款跨平台GIS 服务器产品,提供了空间数据管理.分析.可视化及共享服务 MapGIS IGServer的下载(试用)地址:MapGIS IGS ...
- ArcGIS空间分析工具
1. 3D分析 1.1. 3D Features toolset 工具 工具 描述 3D Features toolset (3D 要素工具集) Add Z Information 添加 Z 信息 添 ...
随机推荐
- .Net Core + 微信赋能企业级智能客服系统--学习笔记
摘要 围绕目前需求猛增的微信及移动端企业智能客服业务,利用 .NET Core 的一系列优秀特性及 SignalR 模块打造全双工.跨微信/QQ/钉钉等应用平台.跨系统平台.跨终端.支持企业级并发的移 ...
- MySQL 8 查询优化新工具 Explain Analyze
1. Explain Analyze 介绍 Explain 是我们常用的查询分析工具,可以对查询语句的执行方式进行评估,给出很多有用的线索.但他仅仅是评估,不是实际的执行情况,比如结果中的 rows, ...
- Kakfa系列丛书推荐之《深入理解Kafka:核心设计与实践原理》
pdf格式文档下载见下文 编者推荐 本书从Kafka的基本概念入手,主要从生产端.消费端.服务端等3个方面进行全面的陈述,主要内容包括Kafka的基本使用方式.生产者客户端的使用.消费者客户端的使用. ...
- 从零开始手写 mybatis (三)jdbc pool 从零实现数据库连接池
前景回顾 第一节 从零开始手写 mybatis(一)MVP 版本 中我们实现了一个最基本的可以运行的 mybatis. 第二节 从零开始手写 mybatis(二)mybatis interceptor ...
- Error: testWhileIdle is true, validationQuery not set
说明 使用springboot连接数据库,启动的时候报错:testWhileIdle is true, validationQuery not set.但是不影响系统使用,数据库等一切访问正常.记录备 ...
- go build gcc报错 /usr/bin/ld | cannot find -ldl cannot find -lpthread cannot find -lc
之前一直在kali或者其他ubuntu设备编译sliver, 临时在centos7上编译时报错了 # github.com/bishopfox/sliver/server /usr/local/go/ ...
- QT - Day 5
1 event事件 用途:用于事件的分发 也可以做拦截操作,不建议 bool event( QEvent * e); 返回值 如果是true 代表用户处理这个事件,不向下分发了 e->ty ...
- Flutter——安装依赖包时,出现Waiting for another flutter command to release the startup lock
问题描述 运行 flutter packages get 时 出现 Waiting for another flutter command to release the startup lock 解决 ...
- 硬件开发笔记(三):硬件开发基本流程,制作一个USB转RS232的模块(二):设计原理图库
前言 上一篇了解了基本的过程,选型了相关的芯片,本篇描述原理图的设计过程,在原理图设计之前或者过程中需要不断新增原理图元器件. Allegro.OrCad Cadence公司针对PCB方面 ...
- .NET周刊【2月第3期 2024-02-25】
国内文章 4.1k Star!全面的C#/.NET/.NET Core学习.工作.面试指南 https://www.cnblogs.com/Can-daydayup/p/18027117 DotNet ...