kepler.gl | 网站 | 演示应用 | 文档
[Kepler.gl][web]是一个与数据无关的、高性能的基于Web的应用程序,用于大规模地理位置数据集的可视化探索。它基于MapLibre GL和deck.gl构建,kepler.gl可以渲染数百万个点,代表数千次行程,并实时执行空间聚合。
Kepler.gl也是一个React组件,使用Redux来管理其状态和数据流。它可以嵌入到其他React-Redux应用程序中,并且高度可定制。关于如何在你的应用中嵌入kepler.gl,请查看vis.academy上的这个分步[教程][vis-academy]。
链接
- [网站][web]
- [演示应用][demo-app]
- [示例][examples]
- [入门][get-started]
- [应用用户指南][user-guide]
- [Jupyter Widget用户指南][user-guide-jupyter]
- [教程][vis-academy]
- [Stack Overflow][stack]
- [贡献指南][contributing]
- [API参考][api-reference]
- [路线图][roadmap]
环境
使用Node 18.18.2或以上版本,不支持/未测试旧版本的node。
为获得最佳结果,使用nvm nvm install
。
安装kepler.gl
安装node(> 18.18.2
)、yarn和项目依赖
npm install --save kepler.gl
// 或
yarn add kepler.gl
kepler.gl基于[mapbox][mapbox]构建。你需要一个[Mapbox访问令牌][mapbox-token]才能使用它。
如果你不使用模块打包器,也没关系。Kepler.gl npm包在umd文件夹中包含预编译的生产UMD构建。 你可以按如下方式将脚本标签添加到你的html文件中:
<script src="https://unpkg.com/kepler.gl/umd/keplergl.min.js" />
或者如果你愿意,你可以加载特定版本
<script src="https://unpkg.com/kepler.gl@2.5.5/umd/keplergl.min.js" />
开发kepler.gl
查看[开发指南][developers]以在本地开发kepler.gl。
基本用法
以下是将kepler.gl导入到你的应用程序的基本步骤。你也可以查看examples文件夹。文件夹中的每个示例都可以安装和本地运行。
1. 挂载reducer
Kepler.gl使用Redux管理其内部状态,并使用[react-palm][react-palm]中间件处理副作用。
你还需要将react-palm
的taskMiddleware
添加到你的store中。我们正在积极开发一个不需要react-palm
的解决方案,但它仍然是一个非常轻量级的副作用管理工具,比react-thunk更容易测试。
import {createStore, combineReducers, applyMiddleware, compose} from 'redux';
import keplerGlReducer from '@kepler.gl/reducers';
import {enhanceReduxMiddleware} from '@kepler.gl/middleware';
const initialState = {};
const reducers = combineReducers({
// <-- 在你的应用中挂载kepler.gl reducer
keplerGl: keplerGlReducer,
// 你的其他reducers在这里
app: appReducer
});
// 使用createStore
export default createStore(
reducer,
initialState,
applyMiddleware(
enhanceReduxMiddleware([
/* 在这里添加其他中间件 */
])
)
);
或者如果使用enhancer:
// 使用enhancers
const initialState = {};
const middlewares = enhanceReduxMiddleware([
// 在这里添加其他中间件
]);
const enhancers = [applyMiddleware(...middlewares)];
export default createStore(reducer, initialState, compose(...enhancers));
如果你将kepler.gl reducer挂载在keplerGl
以外的地址,或者kepler.gl reducer没有挂载在你的状态的根部,你需要在使用getState
属性挂载组件时指定它的路径。
阅读更多关于[Reducers][reducers]的信息。
2. 挂载组件
import KeplerGl from '@kepler.gl/components';
const Map = props => (
<KeplerGl id="foo" width={width} mapboxApiAccessToken={token} height={height} />
);
属性
id
(字符串,必需)
- 默认值:
map
此KeplerGl实例的id。如果你的应用中有多个KeplerGl实例,则id
是必需的。它定义了存储在KeplerGl reducer中的KeplerGl状态的属性名。例如,id为foo
的KeplerGl组件的状态存储在state.keplerGl.foo
中。
如果你使用相同的id创建多个kepler.gl实例,由该条目定义的kepler.gl状态将被最新实例覆盖并重置为空白状态。
mapboxApiAccessToken
(字符串,必需*)
- 默认值:
undefined
默认情况下,kepler.gl使用mapbox-gl.js渲染其基础地图。你可以在[mapbox][mapbox]创建一个免费账户,并在[www.mapbox.com/account/access-tokens][mapbox-token]创建一个令牌。
如果你用自己的地图样式替换了kepler.gl的默认地图样式,并且它们不是Mapbox样式,则不需要mapboxApiAccessToken
。
阅读更多关于[自定义地图样式][custom-map-styles]的信息。
getState
(函数,可选)
- 默认值:
state => state.keplerGl
你的reducer中根keplerGl状态的路径。
width
(数字,可选)
- 默认值:
800
KeplerGl UI的宽度。
height
(数字,可选)
- 默认值:
800
appName
(字符串,可选)
- 默认值:
Kepler.Gl
在侧面板头部显示的应用名称
version
(字符串,可选)
- 默认值:
v1.0
在侧面板头部显示的版本
onSaveMap
(函数,可选)
- 默认值:
undefined
在侧面板头部点击保存地图URL时调用的操作。
onViewStateChange
(函数,可选)
- 默认值:
undefined
- 参数:
viewState
- 包含经度、纬度、缩放等参数的更新后的视图状态对象
当地图视口更新时触发的操作。
getMapboxRef(mapbox, index)
(函数,可选)
- 默认值:
undefined
当KeplerGL
添加或移除包含内部Mapbox地图的MapContainer
组件时调用的函数。
mapbox
参数在添加时是一个MapRef
,在移除时是null
。
index
参数对单个地图为0,对额外的地图为1(因为KeplerGL
支持可选的分屏地图视图)。
actions
(对象,可选)
- 默认值:
{}
用于替换默认kepler.gl action创建器的action创建器。仅在需要修改action payload时使用自定义action。
mint
(布尔值,可选)
- 默认值:
true
组件挂载时是否加载全新的空白状态。当传入mint: true
时,kepler.gl组件在重新挂载相同组件时总是加载新的状态,该组件内的状态在卸载时将被销毁。
传入mint: false
时,kepler.gl将在组件卸载后仍保留其状态在store中,并在重新挂载时将其用作初始状态。这在模态框中挂载kepler.gl并在重新打开时保持相同地图时很有用。
阅读更多关于[组件][components]的信息。
theme
(对象 | 字符串,可选)
- 默认值:
null
可选值为"dark"
、"light"
或"base"
你可以传入主题名称或用于自定义Kepler.gl样式的对象。Kepler.gl除默认的"dark"主题外还提供了"light"主题。当传入主题对象时,Kepler.gl将使用传入的值覆盖theme中的值。
阅读更多关于[自定义主题][custom-theme]的信息
mapboxApiUrl
(字符串,可选)
- 默认值:
https://api.mapbox.com
如果你使用自己的mapbox瓦片服务器,可以传入你自己的瓦片服务器API URL。
mapStylesReplaceDefault
(布尔值,可选)
- 默认值:
false
kepler.gl提供4种地图样式可供选择。如果你想提供自己的mapStyles
,请传入true
。详见下文。
mapStyles
(数组,可选)
- 默认值:
[]
你可以提供额外的地图样式在地图样式选择面板中显示。默认情况下,额外的地图样式将添加到默认地图样式中。如果传入mapStylesReplaceDefault: true
,它们将替换默认样式。kepler.gl将尝试根据你的样式的id
命名约定对图层进行分组,并用它来允许切换基础地图图层的可见性。提供你自己的layerGroups
来覆盖默认值以实现更准确的图层分组。
每个mapStyles
应具有以下属性:
id
(字符串,必需) 唯一字符串,不应为以下保留值之一:dark
light
muted
muted_night
label
(字符串,必需) 在地图样式选择面板中显示的名称url
(字符串,必需) mapbox样式url或指向按照Mapbox GL样式规范编写的地图样式json对象的urlicon
(字符串,可选) 样式的图标图片,可以是url或图片数据urllayerGroups
(数组,可选)
const mapStyles = [
{
id: 'my_dark_map',
label: 'Dark Streets 9',
url: 'mapbox://styles/mapbox/dark-v9',
icon: `${apiHost}/styles/v1/mapbox/dark-v9/static/-122.3391,37.7922,9.19,0,0/400x300?access_token=${accessToken}&logo=false&attribution=false`,
layerGroups: [
{
slug: 'label',
filter: ({id}) => id.match(/(?=(label|place-|poi-))/),
defaultVisibility: true
},
{
// 添加这个将保留3D建筑选项
slug: '3d building',
filter: () => false,
defaultVisibility: false
}
]
}
];
阅读更多关于[自定义地图样式][custom-map-styles]的信息。
initialUiState
(对象,可选)
- 默认值:
undefined
应用于uiState reducer的初始UI状态,值将与默认的INITIAL_UI_STATE
进行浅合并
localeMessages
(对象,可选)
- 默认值:
undefined
修改默认翻译或添加新翻译
阅读更多关于[本地化][localization]的信息。
3. 向keplerGl
reducer分发自定义actions。
使用reducer而不是React组件状态来处理keplerGl状态的一个优势是可以灵活地自定义其行为。如果你的应用中只有一个KeplerGl
实例,或者从不打算从组件外部向KeplerGl分发actions,
你无需担心转发dispatch,可以直接进入下一节。但生活充满定制,我们希望让你的体验尽可能愉快。
有多种方法可以向特定的KeplerGl
实例分发actions。
- 在根reducer中,使用reducer更新器。
kepler.gl中的每个action都映射到一个reducer更新器。你可以导入与特定action对应的reducer更新器,并使用前一个状态和action payload调用它来获取更新后的状态。
例如,updateVisDataUpdater
是ActionTypes.UPDATE_VIS_DATA
的更新器(查看每个reducer reducers/vis-state.js
以了解action到更新器的映射)。
这里有一个示例,说明如何监听应用action QUERY_SUCCESS
并调用updateVisDataUpdater
将数据加载到Kepler.Gl中。
import keplerGlReducer, {visStateUpdaters} from 'kepler.gl/reducers';
// 根Reducer
const reducers = combineReducers({
keplerGl: keplerGlReducer,
app: appReducer
});
const composedReducer = (state, action) => {
switch (action.type) {
case 'QUERY_SUCCESS':
return {
...state,
keplerGl: {
...state.keplerGl,
// 'map'是keplerGl实例的id
map: {
...state.keplerGl.map,
visState: visStateUpdaters.updateVisDataUpdater(state.keplerGl.map.visState, {
datasets: action.payload
})
}
}
};
}
return reducers(state, action);
};
export default composedReducer;
阅读更多关于[使用更新器修改kepler.gl状态][using-updaters]的信息
- 使用redux
connect
你可以使用connect为组件添加一个dispatch函数,该函数向特定的keplerGl
组件分发actions。
// 组件
import KeplerGl from '@kepler.gl/components';
// action和forward dispatcher
import {toggleFullScreen, forwardTo} 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)
});
export default connect(
mapStateToProps,
mapDispatchToProps
)(MapContainer);
- 包装action payload
你也可以简单地使用wrapTo
辅助函数将action包装成一个forward action
// 组件
import KeplerGl from '@kepler.gl/components';
// action和forward dispatcher
import {toggleFullScreen, wrapTo} from '@kepler.gl/actions';
// 创建一个函数将action payload包装到'foo'
const wrapToMap = wrapTo('foo');
const MapContainer = ({dispatch}) => (
<div>
<button onClick={() => dispatch(wrapToMap(toggleFullScreen())} />
<KeplerGl
id="foo"
/>
</div>
);
阅读更多关于[转发分发actions][forward-actions]的信息
4. 自定义样式。
Kepler.gl使用Styled-Components实现CSS样式。通过使用该框架,Kepler.gl提供了以下方式来自定义其样式/主题:
- 传递Theme prop
- 使用Styled-Components的ThemeProvider
可自定义的属性列表在这里theme。
传递Theme prop。
你可以通过向Kepler.gl React组件传递theme props来自定义Kepler.gl主题,如下所示:
const white = '#ffffff';
const customTheme = {
sidePanelBg: white,
titleTextColor: '#000000',
sidePanelHeaderBg: '#f7f7F7',
subtextColorActive: '#2473bd'
};
return (
<KeplerGl
mapboxApiAccessToken={MAPBOX_TOKEN}
id="map"
width={800}
height={800}
theme={customTheme}
/>
);
如你所见,customTheme 对象定义了某些属性,这些属性将覆盖 Kepler.gl 的默认样式规则。
Styled-Components 主题提供者
为了使用 ThemeProvider 自定义 Kepler.gl 主题,你可以简单地用 ThemeProvider 包装 Kepler.gl,如下所示:
import {ThemeProvider} from 'styled-components';
const white = '#ffffff';
const customTheme = {
sidePanelBg: white,
titleTextColor: '#000000',
sidePanelHeaderBg: '#f7f7F7',
subtextColorActive: '#2473bd'
};
return (
<ThemeProvider theme={customTheme}>
<KeplerGl mapboxApiAccessToken={MAPBOX_TOKEN} id="map" width={800} height={800} />
</ThemeProvider>
);
5. 渲染自定义 UI 组件
每个人都希望能灵活地渲染自定义的 kepler.gl 组件。Kepler.gl 有一个依赖注入系统,允许你注入组件到 KeplerGl 中替换现有的组件。你只需要为你想要替换的组件创建一个组件工厂,导入原始组件工厂,并在你的应用程序中挂载 KeplerGl 的根组件处调用 injectComponents
。
看看 examples/demo-app/src/app.js
,看它如何在 kepler.gl 中渲染自定义侧面板头部
import {injectComponents, PanelHeaderFactory} from '@kepler.gl/components';
// 定义自定义头部
const CustomHeader = () => <div>我的 kepler.gl 应用</div>;
const myCustomHeaderFactory = () => CustomHeader;
// 将自定义头部注入到 Kepler.gl 中,替换默认头部
const KeplerGl = injectComponents([[PanelHeaderFactory, myCustomHeaderFactory]]);
// 渲染 KeplerGl,它将渲染你的自定义头部而不是默认头部
const MapContainer = () => (
<div>
<KeplerGl id="foo" />
</div>
);
使用 withState
辅助函数将 reducer 状态和动作作为额外的 props 添加到自定义组件中。
import {withState, injectComponents, PanelHeaderFactory} from '@kepler.gl/components';
import {visStateLens} from '@kepler.gl/reducers';
// 自定义动作包装到挂载的实例
const addTodo = text =>
wrapTo('map', {
type: 'ADD_TODO',
text
});
// 定义自定义头部
const CustomHeader = ({visState, addTodo}) => (
<div onClick={() => addTodo('hello')}>{`已加载 ${
Object.keys(visState.datasets).length
} 个数据集`}</div>
);
// 现在 CustomHeader 将接收 `visState` 和 `addTodo` 作为额外的 props
const myCustomHeaderFactory = () =>
withState(
// keplerGl 状态镜头
[visStateLens],
// 自定义 mapStateToProps
headerStateToProps,
// 动作
{addTodo}
)(CustomHeader);
阅读更多关于[替换 UI 组件][replace-ui-component]的内容
6. 如何向地图添加数据
要与 kepler.gl 实例交互并向其添加新数据,你可以在应用程序内的任何地方调度 addDataToMap
动作。它向 kepler.gl 实例添加一个或多个数据集,并更新完整的配置(mapState、mapStyle、visState)。
参数
-
data
[Object][40] *必需-
datasets
([Array][41]<[Object][40]> | [Object][40]) *必需 datasets 可以是一个数据集或数据集数组 每个数据集对象需要有info
和data
属性。datasets.info
[Object][40] -数据集的信息datasets.info.id
[string][42] 此数据集的 id。如果定义了 config,id
应该与 config 中的dataId
匹配。datasets.info.label
[string][42] 此数据集的显示名称
datasets.data
[Object][40] *必需 数据对象,以表格格式包含 2 个属性fields
和rows
datasets.data.fields
[Array][41]<[Object][40]> *必需 字段数组,datasets.data.fields.name
[string][42] *必需 字段名称,
datasets.data.rows
[Array][41]<[Array][41]> *必需 行数组,以表格格式包含fields
和rows
-
options
[Object][40]options.centerMap
[boolean][43]默认值: true
如果centerMap
设置为true
,kepler.gl 将把地图视图放置在数据点边界内options.readOnly
[boolean][43]默认值: false
如果readOnly
设置为true
,左侧设置面板将被隐藏options.keepExistingConfig
[boolean][43]默认值: false
是否保留现有的地图配置,包括图层、过滤器和分割地图。
-
-
config
[Object][40] 此对象将包含完整的 kepler.gl 实例配置 {mapState, mapStyle, visState}
Kepler.gl 提供了一个简单的 API KeplerGlSchema.getConfigToSave
来生成当前 kepler 实例配置的 json blob。
示例
// app.js
import {addDataToMap} from '@kepler.gl/actions';
const sampleTripData = {
fields: [
{name: 'tpep_pickup_datetime', format: 'YYYY-M-D H:m:s', type: 'timestamp'},
{name: 'pickup_longitude', format: '', type: 'real'},
{name: 'pickup_latitude', format: '', type: 'real'}
],
rows: [
['2015-01-15 19:05:39 +00:00', -73.99389648, 40.75011063],
['2015-01-15 19:05:39 +00:00', -73.97642517, 40.73981094],
['2015-01-15 19:05:40 +00:00', -73.96870422, 40.75424576]
]
};
const sampleConfig = {
visState: {
filters: [
{
id: 'me',
dataId: 'test_trip_data',
name: 'tpep_pickup_datetime',
type: 'timeRange',
view: 'enlarged'
}
]
}
};
this.props.dispatch(
addDataToMap({
datasets: {
info: {
label: '纽约市示例出租车行程',
id: 'test_trip_data'
},
data: sampleTripData
},
option: {
centerMap: true,
readOnly: false
},
config: sampleConfig
})
);
阅读更多关于 addDataToMap 和[使用模式管理器保存和加载地图][saving-loading-w-schema]的内容。 [contributing]: contributing/README.md [demo-app]: http://kepler.gl/#/demo [github]: https://github.com/keplergl/kepler.gl [github-pr]: https://help.github.com/articles/creating-a-pull-request/ [mapbox]: https://www.mapbox.com [mapbox-token]: https://www.mapbox.com/help/define-access-token/ [developers]: contributing/DEVELOPERS.md [examples]: https://github.com/keplergl/kepler.gl/tree/master/examples [react-palm]: https://github.com/btford/react-palm [roadmap]: https://github.com/keplergl/kepler.gl/wiki/Kepler.gl-2019-Roadmap [stack]: https://stackoverflow.com/questions/tagged/kepler.gl [web]: http://www.kepler.gl/ [vis-academy]: http://vis.academy/#/kepler.gl/ [user-guide]: docs/user-guides/README.md [user-guide-jupyter]: docs/keplergl-jupyter/README.md [api-reference]: docs/api-reference/README.md [get-started]: ./docs/api-reference/get-started.md [reducers]: docs/api-reference/reducers/README.md [components]: docs/api-reference/components/README.md [custom-theme]: docs/api-reference/custom-theme/README.md [reducers]: docs/api-reference/reducers/README.md [actions-updaters]: docs/api-reference/actions/README.md [processors]: docs/api-reference/processors/README.md [schemas]: docs/api-reference/schemas/README.md [using-updaters]: ./docs/api-reference/advanced-usages/using-updaters.md [custom-map-styles]: ./docs/api-reference/advanced-usages/custom-map-styles.md [forward-actions]: ./docs/api-reference/advanced-usages/forward-actions.md [replace-ui-component]: ./docs/api-reference/advanced-usages/replace-ui-component.md [saving-loading-w-schema]: ./docs/api-reference/advanced-usages/saving-loading-w-schema.md [localization]: ./docs/api-reference/localization/README.md [40]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object [41]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array [42]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String [43]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean [44]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Number [45]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Statements/function