UNPKG

kepler.gl

Version:

kepler.gl is a webgl based application to visualize large scale location data in the browser

254 lines (233 loc) 8.71 kB
// Copyright (c) 2021 Uber Technologies, Inc. // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. import React, {useCallback, useMemo} from 'react'; import {FormattedMessage} from 'localization'; import { EXPORT_DATA_ID, EXPORT_MAP_ID, SHARE_MAP_ID, SIDEBAR_PANELS, OVERWRITE_MAP_ID, SAVE_MAP_ID, EXPORT_IMAGE_ID, ADD_DATA_ID, ADD_MAP_STYLE_ID } from 'constants/default-settings'; import SidebarFactory from './side-panel/side-bar'; import PanelHeaderFactory from './side-panel/panel-header'; import PanelToggleFactory from './side-panel/panel-toggle'; import LayerManagerFactory from './side-panel/layer-manager'; import FilterManagerFactory from './side-panel/filter-manager'; import InteractionManagerFactory from './side-panel/interaction-manager'; import MapManagerFactory from './side-panel/map-manager'; import CustomPanelsFactory from './side-panel/custom-panel'; import PanelTitleFactory from './side-panel/panel-title'; import styled from 'styled-components'; import get from 'lodash.get'; export const StyledSidePanelContent = styled.div` ${props => props.theme.sidePanelScrollBar}; flex-grow: 1; padding: ${props => props.theme.sidePanelInnerPadding}px; overflow-y: scroll; overflow-x: hidden; .side-panel__content__inner { display: flex; height: 100%; flex-direction: column; } `; SidePanelFactory.deps = [ SidebarFactory, PanelHeaderFactory, PanelToggleFactory, PanelTitleFactory, LayerManagerFactory, FilterManagerFactory, InteractionManagerFactory, MapManagerFactory, CustomPanelsFactory ]; /** * Vertical sidebar containing input components for the rendering layers */ export default function SidePanelFactory( Sidebar, PanelHeader, PanelToggle, PanelTitle, LayerManager, FilterManager, InteractionManager, MapManager, CustomPanels ) { // inject components const SIDEBAR_COMPONENTS = { layer: LayerManager, filter: FilterManager, interaction: InteractionManager, map: MapManager }; // We should defined sidebar panels here but keeping them for backward compatible const fullPanels = SIDEBAR_PANELS.map(component => ({ ...component, component: SIDEBAR_COMPONENTS[component.id] })); const getCustomPanelProps = get(CustomPanels, ['defaultProps', 'getProps']) || (() => ({})); /** @type {typeof import('./side-panel').SidePanel} */ // eslint-disable-next-line max-statements const SidePanel = props => { const { appName, appWebsite, availableProviders, datasets, filters, layers, layerBlending, layerClasses, layerOrder, interactionConfig, panels, mapInfo, mapSaved, mapStateActions, mapStyle, mapStyleActions, onSaveMap, uiState, uiStateActions, visStateActions, version, width } = props; const {openDeleteModal, toggleModal, toggleSidePanel} = uiStateActions; const {activeSidePanel} = uiState; const {setMapInfo, showDatasetTable} = visStateActions; const {hasShare, hasStorage} = availableProviders; const {title} = mapInfo; const isOpen = Boolean(activeSidePanel); const _onOpenOrClose = useCallback(() => toggleSidePanel(activeSidePanel ? null : 'layer'), [ activeSidePanel, toggleSidePanel ]); const onClickExportImage = useCallback(() => toggleModal(EXPORT_IMAGE_ID), [toggleModal]); const onClickExportData = useCallback(() => toggleModal(EXPORT_DATA_ID), [toggleModal]); const onClickExportMap = useCallback(() => toggleModal(EXPORT_MAP_ID), [toggleModal]); const onClickSaveToStorage = useCallback( () => toggleModal(mapSaved ? OVERWRITE_MAP_ID : SAVE_MAP_ID), [mapSaved, toggleModal] ); const onClickSaveAsToStorage = useCallback(() => { setMapInfo({ title: `${title || 'Kepler.gl'} (Copy)` }); toggleModal(SAVE_MAP_ID); }, [title, setMapInfo, toggleModal]); const onClickShareMap = useCallback(() => toggleModal(SHARE_MAP_ID), [toggleModal]); const onShowDatasetTable = useCallback(dataId => showDatasetTable(dataId), [showDatasetTable]); const onShowAddDataModal = useCallback(() => toggleModal(ADD_DATA_ID), [toggleModal]); const onShowAddMapStyleModal = useCallback(() => toggleModal(ADD_MAP_STYLE_ID), [toggleModal]); const onRemoveDataset = useCallback(dataId => openDeleteModal(dataId), [openDeleteModal]); const onSaveToStorage = useMemo(() => ((hasStorage ? onClickSaveToStorage : null)), [ hasStorage, onClickSaveToStorage ]); const onSaveAsToStorage = useMemo( () => ((hasStorage && mapSaved ? onClickSaveAsToStorage : null)), [hasStorage, mapSaved, onClickSaveAsToStorage] ); const currentPanel = useMemo(() => panels.find(({id}) => id === activeSidePanel) || {}, [ activeSidePanel, panels ]); const onShareMap = useMemo(() => ((hasShare ? onClickShareMap : null)), [ hasShare, onClickShareMap ]); const customPanelProps = useMemo(() => getCustomPanelProps(props), [props]); const PanelComponent = currentPanel.component; return ( <Sidebar width={width} isOpen={isOpen} minifiedWidth={0} onOpenOrClose={_onOpenOrClose}> <PanelHeader appName={appName} version={version} appWebsite={appWebsite} visibleDropdown={uiState.visibleDropdown} showExportDropdown={uiStateActions.showExportDropdown} hideExportDropdown={uiStateActions.hideExportDropdown} onExportImage={onClickExportImage} onExportData={onClickExportData} onExportMap={onClickExportMap} onSaveMap={onSaveMap} onSaveToStorage={onSaveToStorage} onSaveAsToStorage={onSaveAsToStorage} onShareMap={onShareMap} /> {/* the next two components should be moved into one */} {/* but i am keeping them because of backward compatibility */} <PanelToggle panels={panels} activePanel={activeSidePanel} togglePanel={uiStateActions.toggleSidePanel} /> <StyledSidePanelContent className="side-panel__content"> <div className="side-panel__content__inner"> <PanelTitle className="side-panel__content__title"> <FormattedMessage id={currentPanel.label} /> </PanelTitle> {PanelComponent ? ( <PanelComponent datasets={datasets} filters={filters} layers={layers} layerClasses={layerClasses} layerOrder={layerOrder} layerBlending={layerBlending} mapStyle={mapStyle} mapStyleActions={mapStyleActions} mapStateActions={mapStateActions} interactionConfig={interactionConfig} removeDataset={onRemoveDataset} showDatasetTable={onShowDatasetTable} showAddDataModal={onShowAddDataModal} showAddMapStyleModal={onShowAddMapStyleModal} uiStateActions={uiStateActions} visStateActions={visStateActions} /> ) : null} <CustomPanels {...customPanelProps} activeSidePanel={activeSidePanel} /> </div> </StyledSidePanelContent> </Sidebar> ); }; SidePanel.defaultProps = { panels: fullPanels, sidebarComponents: SIDEBAR_COMPONENTS, uiState: {}, visStateActions: {}, mapStyleActions: {}, uiStateActions: {}, availableProviders: {}, mapInfo: {} }; return SidePanel; }