kepler.gl.geoiq
Version:
kepler.gl is a webgl based application to visualize large scale location data in the browser
341 lines (318 loc) • 9.56 kB
JavaScript
// 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 {CenterFlexbox} from 'components/common/styled-components';
import {Layers} from 'components/common/icons';
import PropTypes from 'prop-types';
import {parseFieldValue} from 'utils/data-utils';
import axios from 'axios';
import {ON_PREMESIS_URL} from 'constants/default-settings';
export const StyledLayerName = styled(CenterFlexbox)`
color: ${props => props.theme.textColorHl};
font-size: 12px;
letter-spacing: 0.43px;
text-transform: capitalize;
padding-left: 14px;
margin-top: 12px;
svg {
margin-right: 4px;
}
`;
const Row = ({name, value, url}) => {
// Set 'url' to 'value' if it looks like a url
if (!url && value && typeof value === 'string' && value.match(/^http/)) {
url = value;
}
const asImg = /<img>/.test(name);
return (
<tr className="row" key={name}>
<td className="row__name">{name}</td>
<td className="row__value">
{asImg ? (
<img src={value} />
) : url ? (
<a target="_blank" rel="noopener noreferrer" href={url}>
{value}
</a>
) : (
value
)}
</td>
</tr>
);
};
const EntryInfo = ({fieldsToShow = [], fields, data}) => {
// const {properties} = data;
// console.log(
// 'properties,fieldsTOshow , fields and data inside EntryInfo ',
// properties,
// fieldsToShow,
// fields,
// data
// );
return (
<tbody>
{fieldsToShow.map(name => (
<EntryInfoRow
key={name}
name={name}
fields={fields}
data={Array.isArray(data) ? data : data.properties[name]}
/>
))}
</tbody>
);
};
const EntryInfoRow = ({name, fields, data}) => {
const field = fields.find(f => f.name === name);
if (!field) {
return null;
}
if (Array.isArray(data)) {
const valueIdx = field.tableFieldIndex - 1;
const displayValue = parseFieldValue(data[valueIdx], field.type);
return <Row name={name} value={displayValue} />;
} else {
const displayValue = data;
return <Row name={name} value={displayValue} />;
}
};
const CellInfo = ({data, layer}) => {
const {colorField, sizeField, heightField, visConfig} = layer.config;
const {properties} = data;
const {colorAggregation} = visConfig;
// console.log(
// 'properties, data, colorField and sizeField inside cellInfo',
// data,
// properties,
// colorField,
// sizeField
// );
return (
<tbody>
{properties && properties.name ? (
<Row name={'name'} key="name" value={properties.name} />
) : null}
<Row
name={'total points'}
key="count"
value={
properties ? properties.totalCount : data.points && data.points.length
}
/>
{colorField && layer.visualChannels.color ? (
<Row
name={layer.getVisualChannelDescription('color').measure}
key="color"
value={
properties ? properties.aggregatedData : data.colorValue || 'N/A'
}
/>
) : null}
{sizeField && layer.visualChannels.size ? (
<Row
name={layer.getVisualChannelDescription('size').measure}
key="size"
value={
properties
? properties.heightAggregatedData
: data.elevationValue || 'N/A'
}
/>
) : null}
{heightField && layer.visualChannels.height ? (
<Row
name={layer.getVisualChannelDescription('height').measure}
key="size"
value={
properties
? properties.heightAggregatedData
: data.elevationValue || 'N/A'
}
/>
) : null}
</tbody>
);
};
export default function LayerHoverInfoFactory() {
class LayerHoverInfo extends Component {
static propTypes = {
fields: PropTypes.arrayOf(PropTypes.any),
fieldsToShow: PropTypes.arrayOf(PropTypes.any),
layer: PropTypes.object,
data: PropTypes.oneOfType([
PropTypes.arrayOf(PropTypes.any),
PropTypes.object
])
};
constructor(props) {
super(props);
this.state = {
fieldsToShow: [],
fields: {},
data: {}
};
}
// state = {
// fieldsToShow: [],
// fields: {},
// data: {}
// };
componentWillReceiveProps(nextProps) {
const {data, layer, fields, fieldsToShow, datasets, auth} = this.props;
if (
layer.type === 'backendPoint' ||
layer.type === 'backendGeojson' ||
layer.type === 'geojson'
) {
if (nextProps.data.docId !== data.docId) {
const {uid} = auth;
const {indexName, fields} = datasets[layer.config.dataId];
const layerHoverApiData = {
docId: nextProps.data.docId,
fieldsToShow: JSON.stringify(fieldsToShow),
userId: uid,
indexName
};
const config = {
headers: {
'Content-Type': 'application/json'
}
};
axios
.post(
`${ON_PREMESIS_URL}/geoiqutilities/hover/v1.0/fetch`,
layerHoverApiData,
config
)
.then(response =>
this.setState({
fieldsToShow,
fields,
data: response.data.data
})
)
.catch(e => console.log('error in hoverAPI', e));
}
}
}
componentDidMount() {
const {data, layer, fields, fieldsToShow, datasets, auth} = this.props;
if (
layer.type === 'backendPoint' ||
layer.type === 'backendGeojson' ||
layer.type === 'geojson'
) {
const {uid} = auth;
const {indexName, fields} = datasets[layer.config.dataId];
const layerHoverApiData = {
docId: data.docId,
fieldsToShow: JSON.stringify(fieldsToShow),
userId: uid,
indexName
};
const config = {
headers: {
'Content-Type': 'application/json'
}
};
axios
.post(
`${ON_PREMESIS_URL}/geoiqutilities/hover/v1.0/fetch`,
layerHoverApiData,
config
)
.then(response =>
this.setState({
fieldsToShow,
fields,
data: response.data.data
})
)
.catch(e => console.log('error inside componentDidMount', e));
}
}
// componentDidMount() {
// this.setState({...this.state, ...this.props});
// }
render() {
const {data, layer, fields, fieldsToShow, datasets, auth} = this.props;
if (!data || !layer || !fieldsToShow.length) {
return null;
}
let prop = {
...this.state,
...this.props
};
return (
<div>
<StyledLayerName className="map-popover__layer-name">
<Layers height="12px" />
{layer.config.label}
</StyledLayerName>
<table className="map-popover__table">
{layer.isAggregated && !data.docId ? (
<CellInfo {...this.props} />
) : (
<EntryInfo {...prop} />
)}
</table>
</div>
);
}
}
return LayerHoverInfo;
}
const LayerHoverInfoFactorys = () => {
const LayerHoverInfo = props => {
const {data, layer, fields, fieldsToShow, datasets, auth} = props;
if (!data || !layer || !fieldsToShow.length) {
return null;
}
return (
<div>
<StyledLayerName className="map-popover__layer-name">
<Layers height="12px" />
{props.layer.config.label}
</StyledLayerName>
<table className="map-popover__table">
{props.layer.isAggregated ? (
<CellInfo {...props} />
) : (
<EntryInfo {...props} />
)}
</table>
</div>
);
// }
};
LayerHoverInfo.propTypes = {
fields: PropTypes.arrayOf(PropTypes.any),
fieldsToShow: PropTypes.arrayOf(PropTypes.any),
layer: PropTypes.object,
data: PropTypes.oneOfType([
PropTypes.arrayOf(PropTypes.any),
PropTypes.object
])
};
return LayerHoverInfo;
};
// export default LayerHoverInfoFactory;