UNPKG

kepler.gl.geoiq

Version:

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

682 lines (624 loc) 19.4 kB
// Copyright (c) 2023 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, {Component} from 'react'; import styled from 'styled-components'; import PropTypes from 'prop-types'; import {Tooltip} from 'components/common/styled-components'; import KeplerGlLogo from 'components/common/logo'; import {Save, Files, Share, Picture, Map} from 'components/common/icons'; import ClickOutsideCloseDropdown from 'components/side-panel/panel-dropdown'; const StyledPanelHeader = styled.div.attrs({ className: 'side-side-panel__header' })` background-color: ${props => props.theme.sidePanelHeaderBg}; padding: 12px 16px 0 16px; `; const StyledPanelHeaderTop = styled.div.attrs({ className: 'side-panel__header__top' })` display: flex; justify-content: space-between; margin-bottom: 16px; width: 100%; `; const StyledPanelTopActions = styled.div.attrs({ className: 'side-panel__header__actions' })` display: flex; `; const StyledPanelAction = styled.div.attrs({ className: 'side-panel__header__actions' })` align-items: center; border-radius: 2px; color: ${props => props.active ? props.theme.textColorHl : props.theme.subtextColor}; display: flex; height: 26px; justify-content: space-between; margin-left: 4px; padding: 5px; font-weight: bold; p { display: inline-block; margin-right: 6px; } a { height: 20px; } :hover { cursor: pointer; background-color: ${props => props.theme.secondaryBtnActBgd}; color: ${props => props.theme.textColorHl}; a { color: ${props => props.theme.textColorHl}; } } `; const StyledPanelDropdown = styled.div` background-color: ${props => props.theme.dropdownListBgd}; box-shadow: ${props => props.theme.dropdownListShadow}; font-size: 11px; padding: 16px 0; position: absolute; left: 64px; transition: ${props => props.theme.transitionSlow}; display: flex; margin-top: ${props => (props.show ? '6px' : '20px')}; opacity: ${props => (props.show ? 1 : 0)}; transform: translateX(calc(-50% + 20px)); pointer-events: ${props => (props.show ? 'all' : 'none')}; z-index: 1000; .save-export-dropdown__inner { box-shadow: none; background-color: transparent; display: flex; } .save-export-dropdown__item { align-items: center; border-right: 1px solid ${props => props.theme.panelHeaderIcon}; color: ${props => props.theme.textColor}; display: flex; flex-direction: column; padding: 0 22px; :hover { cursor: pointer; color: ${props => props.theme.textColorHl}; } &:last-child { border-right: 0; } } .save-export-dropdown__title { white-space: nowrap; margin-top: 4px; } `; export const PanelAction = ({item, onClick}) => ( <StyledPanelAction className="side-panel__panel-header__action" data-tip data-for={`${item.id}-action`} onClick={onClick} > {item.label ? <p>{item.label}</p> : null} <a target={item.blank ? '_blank' : ''} href={item.href}> <item.iconComponent height="20px" /> </a> {item.tooltip ? ( <Tooltip id={`${item.id}-action`} place="bottom" delayShow={500} effect="solid" > <span>{item.tooltip}</span> </Tooltip> ) : null} </StyledPanelAction> ); const PanelItem = ({onClose, onClickHandler, label, icon}) => ( <div className="save-export-dropdown__item" onClick={e => { e.stopPropagation(); onClose(); onClickHandler(); }} > {icon} <div className="save-export-dropdown__title">{label}</div> </div> ); export const ExportImageFactory = () => { const ExportImage = props => <PanelItem {...props} />; ExportImage.defaultProps = { label: 'Export Image', icon: <Picture /> }; return ExportImage; }; export const ExportDataFactory = () => { const ExportData = props => <PanelItem {...props} />; ExportData.defaultProps = { label: 'Export Data', icon: <Files /> }; return ExportData; }; export const ExportMapFactory = () => { const ExportMap = props => <PanelItem {...props} />; ExportMap.defaultProps = { label: 'Export Map', icon: <Map /> }; return ExportMap; }; export const SaveMapFactory = () => { const SaveMap = props => <PanelItem {...props} />; SaveMap.defaultProps = { label: 'Save Map', icon: <Share /> }; return SaveMap; }; export const SaveExportDropdownFactory = ( ExportImage, ExportData, ExportMap, SaveMap ) => { const SaveExportDropdown = ({ onExportImage, onExportData, onExportConfig, onExportMap, onSaveMap, show, onClose }) => { return ( <StyledPanelDropdown show={show} className="save-export-dropdown"> <ClickOutsideCloseDropdown className="save-export-dropdown__inner" show={show} onClose={onClose} > <ExportImage onClickHandler={onExportImage} onClose={onClose} /> <ExportData onClickHandler={onExportData} onClose={onClose} /> <ExportMap onClickHandler={onExportMap} onClose={onClose} /> {onSaveMap ? ( <SaveMap onClickHandler={onSaveMap} onClose={onClose} /> ) : null} </ClickOutsideCloseDropdown> </StyledPanelDropdown> ); }; return SaveExportDropdown; }; SaveExportDropdownFactory.deps = [ ExportImageFactory, ExportDataFactory, ExportMapFactory, SaveMapFactory ]; PanelHeaderFactory.deps = [SaveExportDropdownFactory]; function PanelHeaderFactory(SaveExportDropdown) { return class PanelHeader extends Component { static propTypes = { appName: PropTypes.string, version: PropTypes.string, uiState: PropTypes.object, uiStateActions: PropTypes.object, logoComponent: PropTypes.oneOfType([PropTypes.element, PropTypes.func]), actionItems: PropTypes.arrayOf(PropTypes.any) }; static defaultProps = { logoComponent: KeplerGlLogo, actionItems: [ { id: 'save', iconComponent: Save, onClick: () => {}, label: 'Share', dropdownComponent: SaveExportDropdown } ] }; render() { const { appName, version, actionItems, onSaveMap, onExportImage, onExportData, onExportConfig, onExportMap, visibleDropdown, showExportDropdown, hideExportDropdown } = this.props; return ( <StyledPanelHeader className="side-panel__panel-header"> <StyledPanelHeaderTop className="side-panel__panel-header__top"> <this.props.logoComponent appName={appName} version={version} /> <StyledPanelTopActions> {actionItems.map(item => ( <div className="side-panel__panel-header__right" key={item.id} style={{position: 'relative'}} > <PanelAction item={item} onClick={() => { if (item.dropdownComponent) { showExportDropdown(item.id); } item.onClick(); }} /> {item.dropdownComponent ? ( <item.dropdownComponent onClose={hideExportDropdown} show={visibleDropdown === item.id} onSaveMap={onSaveMap} onExportData={onExportData} onExportImage={onExportImage} onExportConfig={onExportConfig} onExportMap={onExportMap} /> ) : null} </div> ))} </StyledPanelTopActions> </StyledPanelHeaderTop> </StyledPanelHeader> ); } }; } export default PanelHeaderFactory;// import React, {Component} from 'react'; // import styled from 'styled-components'; // import PropTypes from 'prop-types'; // import {Tooltip} from 'components/common/styled-components'; // import KeplerGlLogo from 'components/common/logo'; // import {Save, Files, Share, Picture, Map} from 'components/common/icons'; // import ClickOutsideCloseDropdown from 'components/side-panel/panel-dropdown'; // import Toolbar from 'components/common/toolbar'; // import ToolbarItem from 'components/common/toolbar-item'; // const StyledPanelHeader = styled.div.attrs({ // className: 'side-side-panel__header' // })` // background-color: ${props => props.theme.sidePanelHeaderBg}; // padding: 12px 16px 0 16px; // `; // const StyledPanelHeaderTop = styled.div.attrs({ // className: 'side-panel__header__top' // })` // display: flex; // justify-content: space-between; // margin-bottom: 16px; // width: 100%; // `; // const StyledPanelTopActions = styled.div.attrs({ // className: 'side-panel__header__actions' // })` // display: flex; // `; // const StyledPanelAction = styled.div.attrs({ // className: 'side-panel__header__actions' // })` // align-items: center; // border-radius: 2px; // color: ${props => // props.active ? props.theme.textColorHl : props.theme.subtextColor}; // display: flex; // height: 26px; // justify-content: space-between; // margin-left: 4px; // padding: 5px; // font-weight: bold; // p { // display: inline-block; // margin-right: 6px; // } // a { // height: 20px; // } // :hover { // cursor: pointer; // background-color: ${props => props.theme.secondaryBtnActBgd}; // color: ${props => props.theme.textColorHl}; // a { // color: ${props => props.theme.textColorHl}; // } // } // `; // // By assigning this style we can position the toolbar in the right place on the screen // const StyledToolbar = styled(Toolbar)` // position: absolute; // left: 64px; // `; // // transition: ${props => props.theme.transitionSlow}; // // display: flex; // // margin-top: ${props => (props.show ? '6px' : '20px')}; // // opacity: ${props => (props.show ? 1 : 0)}; // // transform: translateX(calc(-50% + 20px)); // // pointer-events: ${props => (props.show ? 'all' : 'none')}; // // z-index: 1000; // // .save-export-dropdown__inner { // // box-shadow: none; // // background-color: transparent; // // display: flex; // // } // // .save-export-dropdown__item { // // align-items: center; // // border-right: 1px solid ${props => props.theme.panelHeaderIcon}; // // color: ${props => props.theme.textColor}; // // display: flex; // // flex-direction: column; // // padding: 0 22px; // // :hover { // // cursor: pointer; // // color: ${props => props.theme.textColorHl}; // // } // // &:last-child { // // border-right: 0; // // } // // } // // .save-export-dropdown__title { // // white-space: nowrap; // // margin-top: 4px; // // } // export const PanelAction = ({item, onClick}) => ( // <StyledPanelAction // className="side-panel__panel-header__action" // data-tip // data-for={`${item.id}-action`} // onClick={onClick} // > // {item.label ? <p>{item.label}</p> : null} // <a target={item.blank ? '_blank' : ''} href={item.href}> // <item.iconComponent height="20px" /> // </a> // {item.tooltip ? ( // <Tooltip // id={`${item.id}-action`} // place="bottom" // delayShow={500} // effect="solid" // > // <span>{item.tooltip}</span> // </Tooltip> // ) : null} // </StyledPanelAction> // ); // // const PanelItem = ({onClose, onClickHandler, label, icon}) => ( // // <div // // className="save-export-dropdown__item" // // onClick={e => { // // e.stopPropagation(); // // onClose(); // // onClickHandler(); // // }} // // > // // {icon} // // <div className="save-export-dropdown__title">{label}</div> // // </div> // // ); // // export const ExportImageFactory = () => { // // const ExportImage = props => <PanelItem {...props} />; // export const ExportImageFactory = () => { // const ExportImage = props => <ToolbarItem {...props} />; // ExportImage.defaultProps = { // label: 'Export Image', // icon: <Picture /> // }; // return ExportImage; // }; // export const ExportDataFactory = () => { // // const ExportData = props => <PanelItem {...props} />; // const ExportData = props => <ToolbarItem {...props} />; // ExportData.defaultProps = { // label: 'Export Data', // icon: <Files /> // }; // return ExportData; // }; // export const ExportMapFactory = () => { // // const ExportMap = props => <PanelItem {...props} />; // const ExportMap = props => <ToolbarItem {...props} />; // ExportMap.defaultProps = { // label: 'Export Map', // icon: <Map /> // }; // return ExportMap; // }; // export const SaveMapFactory = () => { // // const SaveMap = props => <PanelItem {...props} />; // const SaveMap = props => <ToolbarItem {...props} />; // SaveMap.defaultProps = { // label: 'Save Map', // icon: <Share /> // }; // return SaveMap; // }; // SaveExportDropdownFactory.deps = [ // ExportImageFactory, // ExportDataFactory, // ExportMapFactory, // SaveMapFactory // ]; // export function SaveExportDropdownFactory( // ExportImage, // ExportData, // ExportMap, // // SaveMap // // ) => { // SaveMap // ) { // const SaveExportDropdown = ({ // onExportImage, // onExportData, // onExportConfig, // onExportMap, // onSaveMap, // show, // onClose // }) => { // return ( // // <StyledPanelDropdown show={show} className="save-export-dropdown"> // // <ClickOutsideCloseDropdown // // className="save-export-dropdown__inner" // // show={show} // // onClose={onClose} // // > // // <ExportImage onClickHandler={onExportImage} onClose={onClose} /> // // <ExportData onClickHandler={onExportData} onClose={onClose} /> // // <ExportMap onClickHandler={onExportMap} onClose={onClose} /> // // {onSaveMap ? ( // // <SaveMap onClickHandler={onSaveMap} onClose={onClose} /> // // ) : null} // <StyledToolbar // show={show} // onClose={onClose} // className="save-export-dropdown" // > // <ClickOutsideCloseDropdown // className="save-export-dropdown__inner" // show={show} // onClose={onClose} // > // <ExportImage // className="export-image" // onClick={() => { // onExportImage(); // onClose(); // }} // /> // <ExportData // className="export-data" // onClick={() => { // onExportData(); // onClose(); // }} // /> // <ExportMap // className="export-map" // onClick={() => { // onExportMap(); // onClose(); // }} // /> // {onSaveMap ? ( // <SaveMap // className="save-map" // onClick={() => { // onSaveMap(); // onClose(); // }} // /> // ) : null} // </ClickOutsideCloseDropdown> // </StyledToolbar> // ); // }; // return SaveExportDropdown; // } // PanelHeaderFactory.deps = [SaveExportDropdownFactory]; // function PanelHeaderFactory(SaveExportDropdown) { // return class PanelHeader extends Component { // static propTypes = { // appName: PropTypes.string, // version: PropTypes.string, // uiState: PropTypes.object, // uiStateActions: PropTypes.object, // logoComponent: PropTypes.oneOfType([PropTypes.element, PropTypes.func]), // actionItems: PropTypes.arrayOf(PropTypes.any) // }; // static defaultProps = { // logoComponent: KeplerGlLogo, // actionItems: [ // { // id: 'save', // iconComponent: Save, // onClick: () => {}, // label: 'Share', // dropdownComponent: SaveExportDropdown // } // ] // }; // render() { // const { // appName, // version, // actionItems, // onSaveMap, // onExportImage, // onExportData, // onExportConfig, // onExportMap, // visibleDropdown, // showExportDropdown, // hideExportDropdown // } = this.props; // return ( // <StyledPanelHeader className="side-panel__panel-header"> // <StyledPanelHeaderTop className="side-panel__panel-header__top"> // <this.props.logoComponent appName={appName} version={version} /> // <StyledPanelTopActions> // {actionItems.map(item => ( // <div // className="side-panel__panel-header__right" // key={item.id} // style={{position: 'relative'}} // > // <PanelAction // item={item} // onClick={() => { // if (item.dropdownComponent) { // showExportDropdown(item.id); // } // item.onClick(); // }} // /> // {item.dropdownComponent ? ( // <item.dropdownComponent // onClose={hideExportDropdown} // show={visibleDropdown === item.id} // onSaveMap={onSaveMap} // onExportData={onExportData} // onExportImage={onExportImage} // onExportConfig={onExportConfig} // onExportMap={onExportMap} // /> // ) : null} // </div> // ))} // </StyledPanelTopActions> // </StyledPanelHeaderTop> // </StyledPanelHeader> // ); // } // }; // } // export default PanelHeaderFactory;