kepler.gl
Version:
kepler.gl is a webgl based application to visualize large scale location data in the browser
220 lines (193 loc) • 6.79 kB
JavaScript
// Copyright (c) 2018 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 window from 'global/window';
import {ALL_FIELD_TYPES} from 'constants/default-settings';
import FieldToken from 'components/common/field-token';
import DatasetLabel from 'components/common/dataset-label';
import {Clock} from 'components/common/icons/index';
const ReactDataGrid = window.navigator ? require('react-data-grid/dist/react-data-grid.min') : null;
let shouldPreventScrollBack = false;
if (window.navigator && window.navigator.userAgent) {
const {navigator} = window;
// Detect browsers
// http://stackoverflow.com/questions/5899783/detect-safari-using-jquery
const isMac = navigator.userAgent.match(/Macintosh/);
const is_chrome = navigator.userAgent.indexOf('Chrome') > -1;
const is_safari = navigator.userAgent.indexOf('Safari') > -1;
const is_firefox = navigator.userAgent.indexOf('Firefox') > -1;
// prevent chrome scroll back
shouldPreventScrollBack = isMac && (is_chrome || is_safari || is_firefox);
}
const dgSettings = {
sidePadding: '38px'
};
const DataGridWrapper = styled.div`
.react-grid-Main {
outline: 0;
}
.react-grid-Grid {
border: 0;
}
.react-grid-Cell {
border-right: 0;
border-bottom: ${props => props.theme.panelBorderLT};
padding-left: 16px;
}
.react-grid-HeaderCell {
border-right: 0;
border-bottom: 0;
background: ${props => props.theme.panelBackgroundLT};
color: ${props => props.theme.titleColorLT};
padding: 14px 8px 14px 0;
}
.react-grid-Cell:first-child,
.react-grid-HeaderCell:first-child {
padding-left: ${dgSettings.sidePadding};
}
.react-grid-Cell:last-child,
.react-grid-HeaderCell:last-child {
padding-right: ${dgSettings.sidePadding};
}
.react-grid-Cell__value {
color: ${props => props.theme.labelColorLT};
}
.react-grid-Canvas {
${props => props.theme.modalScrollBar};
}
`;
const BooleanFormatter = ({value}) => <span>{String(value)}</span>;
export class DataTableModal extends Component {
_onMouseWheel = e => {
// Prevent futile scroll, which would trigger the Back/Next page event
// https://github.com/micho/jQuery.preventMacBackScroll
// This prevents scroll when reaching the topmost or leftmost
// positions of a container.
// react-data-grid canvas element can be scrolled
const canvas = this._root.querySelector('.react-grid-Canvas');
// If canvas can not be scrolled left anymore when we try to scroll left
const prevent_left = e.deltaX < 0 && canvas.scrollLeft <= 0;
// If canvas can not be scrolled up when we try to scroll up
const prevent_up = e.deltaY < 0 && canvas.scrollTop <= 0;
if (prevent_left || prevent_up) {
e.preventDefault();
}
};
render() {
const {datasets, dataId, showDatasetTable} = this.props;
if (!datasets || !dataId) {
return null;
}
const activeDataset = datasets[dataId];
const rows = activeDataset.data;
const columns = activeDataset.fields
.map((field, i) => ({
...field,
key: i,
headerRenderer: <FieldHeader {...field} />,
resizable: true,
formatter:
field.type === ALL_FIELD_TYPES.boolean ? BooleanFormatter : undefined
}))
.filter(({name}) => name !== '_geojson');
return (
<div ref={ref => {this._root = ref}} className="dataset-modal" style={{overflow: 'scroll'}}>
<DatasetTabs
activeDataset={activeDataset}
datasets={datasets}
showDatasetTable={showDatasetTable}
/>
<DataGridWrapper
onWheel={shouldPreventScrollBack ? this._onMouseWheel : null}
>
{ReactDataGrid ? (
<ReactDataGrid
headerRowHeight={72}
columns={columns}
minColumnWidth={172}
minWidth={this.props.width}
minHeight={this.props.height - 65}
rowGetter={i => rows[i]}
rowHeight={48}
rowsCount={rows.length}
/>
) : null}
</DataGridWrapper>
</div>
);
}
}
const tagContainerStyle = {
display: 'flex',
flexDirection: 'column',
justifyContent: 'space-between'
};
const FieldHeader = ({name, type}) => (
<div style={tagContainerStyle}>
<div style={{display: 'flex', alignItems: 'center'}}>
<div
style={{
marginRight: type === 'timestamp' ? '2px' : '18px',
height: '16px'
}}
>
{type === 'timestamp' ? <Clock height="16px" /> : null}
</div>
{name}
</div>
<div style={{marginLeft: '18px'}}>
<FieldToken type={type} />
</div>
</div>
);
const DatasetCatalog = styled.div`
display: flex;
padding: 0 ${dgSettings.sidePadding};
`;
export const DatasetModalTab = styled.div`
align-items: center;
border-bottom: 3px solid ${props => (props.active ? 'black' : 'transparent')};
cursor: pointer;
display: flex;
height: 35px;
margin: 0 3px;
padding: 0 5px;
:first-child {
margin-left: 0;
padding-left: 0;
}
`;
export const DatasetTabs = ({activeDataset, datasets, showDatasetTable}) => (
<DatasetCatalog className="dataset-modal-catalog">
{Object.values(datasets).map(dataset => (
<DatasetModalTab
className="dataset-modal-tab"
active={dataset === activeDataset}
key={dataset.id}
onClick={() => showDatasetTable(dataset.id)}
>
<DatasetLabel dataset={dataset}/>
</DatasetModalTab>
))}
</DatasetCatalog>
);
const DataTableModalFactory = () => DataTableModal;
export default DataTableModalFactory;