几个小时内的Web应用程序交互式地图

上一篇文章中,我简要介绍了kepler.gl的功能,kepler.gl是用于可视化和分析大型地理数据集的新的开放源代码工具。


使用kepler.gl创建的地图的选项
图1.使用kepler.gl创建的地图选项(由Uber提供)


该Web应用程序使您可以在几分钟内基于任意一组地理数据创建内容丰富,最重要的彩色交互式地图。 但是,问题出在下一步呢? 如何与同事,朋友或客户分享结果?


比较替代品


kepler.gl的所有“魔术”都发生在客户端上,因此该应用程序仅提供了两种与他人共享结果的方法:


  • 将可视化保存为静态图像(同时失去与地图交互的能力)
  • 将创建的配置和数据导出为文件,并将其发送给所有感兴趣的各方,并提供有关将接收的数据下载到kepler.gl的说明,以查看创建的地图

幸运的是,kepler.gl不仅是一个Web工具,而且还是一个React组件,您可以使用它快速创建带有可视化效果的演示站点,或者将它们集成到现有的Web应用程序中。


注意事项 快速处理和聚合数据,kepler.gl通常需要大量资源。 因此,将其集成到为移动量身定制的应用程序中时应格外小心。


此kepler.gl用例将允许:


  • 不会使查看可视化过程复杂化(只需将链接发送到您的应用程序)
  • 不要以显式形式访问原始数据集(根据2个基本案例的要求)
  • 限制用户可访问的格式以与可视化进行交互(例如,禁止对过滤器或数据显示方法进行自调整)
  • 保存用于与卡片互动的所有所需格式(工具提示,缩放,切换地图模式等)

所考虑的最后一个选项将需要地理可视化创建者付出更多的努力,并且如果没有编程,您将无法做。 但是,您将很快看到,以相同的方式实现它并不困难。


创建一个演示应用程序


现在是时候从理论转向实践了。 为了向您介绍将kepler.gl集成到您的代码中的基本步骤,我制作了一个小型演示应用程序。


它允许用户以两种或两种模式之一查看有关莫斯科付费停车场的信息。 同时,该应用程序仅允许查看我们创建的可视化效果,在它们之间切换以及以只读模式使用地图。 GitHub上提供了所有源代码和实时版本。


莫斯科付费停车示范申请
图2.演示应用程序提供的两种地图视图模式


为了创建这个演示,我使用了自己的项目模板。 但是,如果您决定自己玩kepler.gl,但仍然没有个人喜好,建议您使用create-react-app ,这将大大减少创建未来应用程序基础所需的时间。


将kepler.gl添加到项目


Kepler.gl是一个React组件,使用Redux来存储和管理其状态。 为了将其添加到项目中,只需安装适当的npm-package即可:


npm install --save kepler.gl 

此npm软件包包括:


  • 一组UI组件和工厂,可使用它们自己的组件重新定义它们
  • 用于添加/更改使用的数据以及如何显示它们的预定义方法
  • Redux减速器是他们工作所必需的

为kepler.gl配置Redux存储


Kepler.gl在创建和更新地图的过程中使用Redux来管理其状态。 因此,在使用KeplerGl组件之前,我们需要向应用程序减速器中添加适当的减速器。


 import { combineReducers } from 'redux'; import keplerGlReducer from 'kepler.gl/reducers'; import appReducer from './appReducer'; const reducers = combineReducers({ keplerGl: mapReducer, app: appReducer, }); export default reducers; 

重要的是要记住,默认情况下,KeplerGl组件将为用户提供所有可用于自编辑,下载,更新和过滤数据的选项。 要限制允许用户执行的一组操作,您需要在初始状态参数中传输有关地图模式(用于读取或编辑)和可用地图控件的信息:


 const mapReducer = keplerGlReducer .initialState({ uiState: { readOnly: true, mapControls: { visibleLayers: { show: false }, toggle3d: { show: false }, splitMap: { show: true }, mapLegend: { show: true, active: false } } } }); 

我们还需要安装react-palm ,kepler.gl用来控制副作用并将此npm包中的taskMiddleware添加到其应用程序的Redux存储库中:


 import {createStore, applyMiddleware, compose} from 'redux'; import {taskMiddleware} from 'react-palm'; import reducers from './reducers'; const initialState = { }; const middlewares = [ taskMiddleware ]; const enhancers = [applyMiddleware(...middlewares)]; export default createStore( reducers, initialState, compose(...enhancers) ); 

注意事项 目前,Uber工程团队正在积极开发kepler.gl的新版本,该版本将不依赖react-palm。


默认情况下,kepler.gl希望其状态对象位于整个应用程序状态的顶层,并且可以通过名称keplerGl访问。 如果Redux存储库的配置与预期的不同,则对于相应React组件的正确操作,足以使用getState属性指定其状态在层次结构中的位置。


嵌入KeplerGl React组件


为了快速渲染包含大量显示元素的地图(多达数百万个地理点!),Kepler.gl使用desk.gl(用于数据可视化的WebGL框架)和MapBox(开放源代码)地理平台,该平台提供了便捷的API和自定义创建的地图的广泛可能性。 因此,传递给KeplerGl组件的必需参数之一是用于访问MapBox服务的API令牌。


要获得令牌,您需要在网站www.mapbox.com上进行注册。 MapBox提供了几种不同的收费方案供您选择,但是对于小型应用程序,每月拥有50,​​000次浏览的免费版本就足够了。


创建帐户后,您需要转到令牌部分并生成一个公共密钥来访问该服务。


将收到的令牌设置为适当的环境变量:


 export MapboxAccessToken=<your_mapBox_token> 

现在,您可以继续创建一个React组件,以显示有关付费停车场的信息。 在我们的例子中,它只是KeplerGl组件的包装,该组件将地图的尺寸​​作为参数:


 import React from 'react'; import KeplerGl from 'kepler.gl'; const mapboxAccessToken = process.env.MapboxAccessToken; const ParkingMap = (props) => ( <KeplerGl id="parking_map" mapboxApiAccessToken={mapboxAccessToken} width={ props.width } height={ props.height } /> ); export default ParkingMap; 

将ParkingMap添加到应用程序。 在此阶段,由于停车位尚未显示,地图只是简单地显示,没有任何信息,因为我们尚未传输可视化数据所依据的数据。


下载数据和地图配置


为了在地图上显示数据,您需要将创建地图的数据集以及最终可视化的所需配置传输到KeplerGl。 可以使用以下两种方法之一完成此操作-addDataToMap或updateVisData。


第一种方法不仅允许您下载必要的数据集,而且还可以完全设置/更新KeplerGl组件的相应实例的配置,包括可视化设置(visState)和地图(mapState)以及所用地图的样式(mapStyle)。


AddDataToMap接受包含以下信息的对象作为方法的参数:


  • 用于建立可视化的数据集
  • 其他配置参数(选项)
  • 配置数据,包括mapState,mapStyle,visState
     addDataToMap({ datasets: { … } options: { … } config: { mapState { … }, mapStyle { … }, visState: { … } } }); 

注意事项 来自配置对象的数据始终优先于在选项对象中传递的设置。


updateVisData方法仅允许更新使用过的数据集,而无需完全更改使用过的组件的配置。 与第一种方法一样,它使用一个对象作为参数,该对象包含有关一个或多个新集的信息以及用于更新某些地图显示设置的“ options”参数。


地图初始化


因此,对于初始数据加载,我们需要addDataToMap方法。 在正在创建的演示应用程序中,首次通过单独的请求访问该应用程序时,将加载莫斯科的有偿停车数据库。 结果源数据必须准备好上传到KeplerGl。 为此,在大多数情况下,将csv / json数据移植为kepler.gl支持的数据格式的预定义处理器之一就足够了。


 export function loadParkingData(mapMode) { return (dispatch) => { dispatch( requestParkingData() ); fetch(demoDataUrl) .then(response => response.text()) .then(source => { dispatch( getParkingData() ); const data = Processors.processCsvData(source); const config = getMapConfig(mapMode); const datasets = [{ info, data }]; dispatch( wrapTo('parking_map', addDataToMap({ datasets, config }) )); }); }; } 

在模式之间切换


要在地图视图模式之间切换,我们需要定义另一个动作函数。 由于在当前版本的KeplerGl中,没有简单的方法可以仅更改地图的配置而不影响数据,因此addDataToMap方法也将是在模式之间进行切换的最合适方法:


 export function toggleMapMode(mode) { return (dispatch, getState) => { const config = getMapConfig( mode ); const datasets = getDatasets(getState()); dispatch( wrapTo('parking_map', addDataToMap({ datasets, config }) )); dispatch( setMapMode(mode) ); }; } 

必须使用数据集参数,因此,每次切换地图查看模式时,我们都会重新传输在应用程序启动时加载的原始数据集。 卡配置信息将每次更新。 在本文中,我将不介绍如何实现getMapConfig和getDatasets帮助器方法,您可以在GitHub上熟悉其源代码。


注意事项 当前,KeplerGl API非常有限,并且针对最基本的情况(添加和更新数据)而设计。 同时, 开发人员自己承认 ,当前版本未提供仅用于更新配置或用于实时数据更新的有效方法。 但是,不要忘记该项目正在积极开发中,并且希望能尽早扩展其功能。


自定义地图元素


KeplerGl不仅包括具有地理可视化功能的容器,还包括地图控件,工具提示,用于管理显示数据的侧面板,用于以csv,json或geojson格式加载数据的对话框等。 同时,可以使用依赖注入系统将列出的每个组件轻松替换为其自己的版本。


为了用其自定义版本替换基本组件,就足够了:


  • 导入默认组件工厂
  • 定义一个返回自定义组件的新工厂
  • 使用injectComponents方法嵌入新工厂

在我们创建的演示应用程序中,我们不想让用户有机会独立配置查看模式,过滤现有数据或加载新数据。


从理论上讲,这足以表明KeplerGl组件处于只读模式,仅在0.0.27版本中出现。但是,即使在此版本中,所有控件仍会在加载地图之前的最初几分钟内显示给用户,然后才隐藏。 为了避免这种情况,我们可以使用injectComponents方法用空组件显式替换不需要的组件:


 import React from 'react'; import { injectComponents, ModalContainerFactory, SidePanelFactory, } from 'kepler.gl/components'; // define null factory to don not render any unnecessary components const NullComponent = () => null; const nullComponentFactory = () => NullComponent; const KeplerGl = injectComponents([ [ModalContainerFactory, nullComponentFactory], [SidePanelFactory, nullComponentFactory], ]); export default KeplerGl; 

方便地,KeplerGl不仅允许您用自定义组件替换基本组件,而且借助withState方法允许您为新组件添加其他操作和状态参数。


如何一次使用多张卡


如果计划在同一应用程序中使用多个不同的KeplerGL组件,则必须在参数中设置每个组件的唯一ID,这对于添加/更新每个卡的数据和配置是必需的:


 const wrapToParking = wrapTo(' parking_map'); dispatch( wrapToParking( addDataToMap({ datasets, config }) )); 

一种替代方法是使用Redux中的connect函数和kepler.gl中的forwardTo函数。 在这种情况下,相应的调度程序功能可以很简单地指定相应卡的ID:


 import KeplerGl from 'kepler.gl'; import { forwardTo, toggleFullScreen } from 'kepler.gl/actions'; import {connect} from 'react-redux'; const MapContainer = props => ( <div> <button onClick=() => props.keplerGlDispatch(toggleFullScreen())/> <KeplerGl id="foo" /> </div> ) const mapStateToProps = state => state const mapDispatchToProps = (dispatch, props) => ({ dispatch, keplerGlDispatch: forwardTo('foo', dispatch) }); 

结论


KeplerGl允许您将彩色交互式地图添加到基于React的Web应用程序中。 由于使用了desk.gl组件框架,它可以轻松地以方便查看和分析的格式显示数百万个地理点。


KeplerGl不仅可以自定义创建的可视化效果,还可以自定义地图样式以及用户交互格式,这使它成为创建复杂的制图可视化效果和仪表盘的极具吸引力的工具。


但是,仅受基本API方案的限制,客户端上的数据处理以及无法选择其他地图源的MapBox的使用,都会减少可使用此工具的项目数量。


但是不要忘记,今天该项目还处于初期阶段,处于开发的活跃阶段,因此许多缺点在不久的将来可能变得无关紧要。


有用的链接


  1. 完整的演示代码
  2. Habr上有关Kepler.Gl的介绍性文章
  3. github上的Kepler.gl存储库
  4. kepler.gl的官方文档
  5. Vis.Academy上的Kepler.gl教程[zh]

Source: https://habr.com/ru/post/zh-CN422759/


All Articles