Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Chore]: Technical: Translate geojson-layer #1757

Merged
merged 10 commits into from
Apr 11, 2022
5 changes: 5 additions & 0 deletions src/layers/base-layer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,11 @@ export type LayerCoverageConfig = {
coverageDomain: VisualChannelDomain;
coverageScale: VisualChannelScale;
};
export type LayerRadiusConfig = {
radiusField: VisualChannelField;
radiusDomain: VisualChannelDomain;
radiusScale: VisualChannelScale;
};
export type LayerWeightConfig = {
weightField: VisualChannelField;
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@

import React, {Component} from 'react';
import PropTypes from 'prop-types';
import Base from 'components/common/icons/base';
import Base from '../../components/common/icons/base';

export default class GeojsonLayerIcon extends Component {
static propTypes = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,37 @@
import uniq from 'lodash.uniq';
import {DATA_TYPES} from 'type-analyzer';

import Layer, {colorMaker} from '../base-layer';
import Layer, {
colorMaker,
LayerBaseConfig,
LayerColorConfig,
LayerColumn,
LayerHeightConfig,
LayerRadiusConfig,
LayerSizeConfig,
LayerStrokeColorConfig
} from '../base-layer';
import {GeoJsonLayer as DeckGLGeoJsonLayer} from '@deck.gl/layers';
import {getGeojsonDataMaps, getGeojsonBounds, getGeojsonFeatureTypes} from './geojson-utils';
import {
getGeojsonDataMaps,
getGeojsonBounds,
getGeojsonFeatureTypes,
GeojsonDataMaps
} from './geojson-utils';
import GeojsonLayerIcon from './geojson-layer-icon';
import {GEOJSON_FIELDS, HIGHLIGH_COLOR_3D, CHANNEL_SCALES} from 'constants/default-settings';
import {LAYER_VIS_CONFIGS} from 'layers/layer-factory';
import {GEOJSON_FIELDS, HIGHLIGH_COLOR_3D, CHANNEL_SCALES} from '../../constants/default-settings';
import {
LAYER_VIS_CONFIGS,
VisConfigNumber,
VisConfigColorSelect,
VisConfigColorRange,
VisConfigRange,
VisConfigBoolean
} from '../layer-factory';
import {DataContainerInterface} from '../../utils/table-utils/data-container-interface';
import {Merge, RGBColor} from '../../reducers';
import {ColorRange} from '../../constants/color-ranges';
import {Feature} from 'geojson';

const SUPPORTED_ANALYZER_TYPES = {
[DATA_TYPES.GEOMETRY]: true,
Expand Down Expand Up @@ -60,15 +85,82 @@ export const geojsonVisConfigs = {
wireframe: 'wireframe'
};

export const geoJsonRequiredColumns = ['geojson'];
export const featureAccessor = ({geojson}) => dc => d => dc.valueAt(d.index, geojson.fieldIdx);
export type GeoJsonVisConfigSettings = {
opacity: VisConfigNumber;
strokeOpacity: VisConfigNumber;
thickness: VisConfigNumber;
strokeColor: VisConfigColorSelect;
colorRange: VisConfigColorRange;
strokeColorRange: VisConfigColorRange;
radius: VisConfigNumber;

sizeRange: VisConfigRange;
radiusRange: VisConfigRange;
heightRange: VisConfigRange;
elevationScale: VisConfigNumber;
enableElevationZoomFactor: VisConfigBoolean;
stroked: VisConfigBoolean;
filled: VisConfigBoolean;
enable3d: VisConfigBoolean;
wireframe: VisConfigBoolean;
};

export type GeoJsonLayerColumnsConfig = {
geojson: LayerColumn;
};

export type GeoJsonLayerVisConfig = {
opacity: number;
strokeOpacity: number;
thickness: number;
strokeColor: RGBColor;
colorRange: ColorRange;
strokeColorRange: ColorRange;
radius: number;

sizeRange: [number, number];
radiusRange: [number, number];
heightRange: [number, number];
elevationScale: number;
enableElevationZoomFactor: boolean;
stroked: boolean;
filled: boolean;
enable3d: boolean;
wireframe: boolean;
};

type GeoJsonLayerVisualChannelConfig = LayerColorConfig &
LayerStrokeColorConfig &
LayerSizeConfig &
LayerHeightConfig &
LayerRadiusConfig;
export type GeoJsonLayerConfig = Merge<
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

type GeoJsonLayerVisualChannelConfig = LayerColorConfig & LayerStrokeColorConfig 
LayerSizeConfig & LayerHeightConfig & LayerRadiusConfig

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is meant by LayerRadiusConfig?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can add this to base-layer

export type LayerRadiusConfig = {
  radiusField: VisualChannelField;
  radiusDomain: VisualChannelDomain;
  radiusScale: VisualChannelScale;
};

LayerBaseConfig,
{columns: GeoJsonLayerColumnsConfig; visConfig: GeoJsonLayerVisConfig}
> &
GeoJsonLayerVisualChannelConfig;

export type GeoJsonLayerMeta = {
featureTypes?: {polygon: boolean; point: boolean; line: boolean};
fixedRadius?: boolean;
};

export const geoJsonRequiredColumns: ['geojson'] = ['geojson'];
export const featureAccessor = ({geojson}: GeoJsonLayerColumnsConfig) => (
dc: DataContainerInterface
) => d => dc.valueAt(d.index, geojson.fieldIdx);

// access feature properties from geojson sub layer
export const defaultElevation = 500;
export const defaultLineWidth = 1;
export const defaultRadius = 1;

export default class GeoJsonLayer extends Layer {
declare config: GeoJsonLayerConfig;
declare visConfigSettings: GeoJsonVisConfigSettings;
declare meta: GeoJsonLayerMeta;
dataToFeature: GeojsonDataMaps;

constructor(props) {
super(props);

Expand All @@ -78,10 +170,13 @@ export default class GeoJsonLayer extends Layer {
}

get type() {
return GeoJsonLayer.type;
}
static get type(): 'geojson' {
return 'geojson';
}

get name() {
get name(): 'Polygon' {
return 'Polygon';
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,26 @@ import wktParser from 'wellknown';
import normalize from '@mapbox/geojson-normalize';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please types below to type the functions in this file

import {KeplerTable} from '../../utils';
import {Feature, BBox} from 'geojson';
import {LayerColumns} from '../index';

type GetFeature = (d: any) => Feature;
type GeojsonDataMaps = Array<Feature | null>;

export enum FeatureTypes {
  Point = 'Point',
  MultiPoint = 'MultiPoint',
  LineString = 'LineString',
  MultiLineString = 'MultiLineString',
  Polygon = 'Polygon',
  MultiPolygon = 'MultiPolygon'
}

type FeatureTypeMap = {
  [key in FeatureTypes]: boolean;
};
export function parseGeoJsonRawFeature(rawFeature: unknown): Feature | null;

export function getGeojsonDataMaps(
  allData: KeplerTable['allData'],
  getFeature: GetFeature
): GeojsonDataMaps;

export function getGeojsonBounds(features: Feature[]): BBox | null;

export function getGeojsonFeatureTypes(allFeatures: Feature[]): FeatureTypeMap;

export function parseGeometryFromString(geoString: string): Feature | null;

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

KeplerTable does not contain property allData

import bbox from '@turf/bbox';

import {getSampleData} from 'utils/data-utils';
import {getSampleData} from '../../utils/data-utils';
import {Feature, BBox} from 'geojson';

export type GetFeature = (d: any) => Feature;
export type GeojsonDataMaps = Array<Feature | null>;

export enum FeatureTypes {
Point = 'Point',
MultiPoint = 'MultiPoint',
LineString = 'LineString',
MultiLineString = 'MultiLineString',
Polygon = 'Polygon',
MultiPolygon = 'MultiPolygon'
}

type FeatureTypeMap = {
[key in FeatureTypes]: boolean;
};

export function parseGeoJsonRawFeature(rawFeature) {
export function parseGeoJsonRawFeature(rawFeature: unknown): Feature | null {
if (typeof rawFeature === 'object') {
// Support GeoJson feature as object
// probably need to normalize it as well
Expand All @@ -45,7 +62,8 @@ export function parseGeoJsonRawFeature(rawFeature) {
// why do we need to flip it...
coordinates: rawFeature.map(pts => [pts[1], pts[0]]),
type: 'LineString'
}
},
properties: {}
};
}

Expand All @@ -57,7 +75,7 @@ export function parseGeoJsonRawFeature(rawFeature) {
* @param getFeature
* @returns {{}}
*/
export function getGeojsonDataMaps(dataContainer, getFeature) {
export function getGeojsonDataMaps(dataContainer: any, getFeature: GetFeature): GeojsonDataMaps {
const acceptableTypes = [
'Point',
'MultiPoint',
Expand All @@ -68,7 +86,7 @@ export function getGeojsonDataMaps(dataContainer, getFeature) {
'GeometryCollection'
];

const dataToFeature = [];
const dataToFeature: (Feature | null)[] = [];

for (let index = 0; index < dataContainer.numRows(); index++) {
const feature = parseGeoJsonRawFeature(getFeature({index}));
Expand Down Expand Up @@ -97,7 +115,7 @@ export function getGeojsonDataMaps(dataContainer, getFeature) {
* @param {String} geoString
* @returns {null | Object} geojson object or null if failed
*/
export function parseGeometryFromString(geoString) {
export function parseGeometryFromString(geoString: string): Feature | null {
let parsedGeo;

// try parse as geojson string
Expand Down Expand Up @@ -131,7 +149,7 @@ export function parseGeometryFromString(geoString) {
return normalized.features[0];
}

export function getGeojsonBounds(features = []) {
export function getGeojsonBounds(features: Feature[] = []): BBox | null {
// 70 ms for 10,000 polygons
// here we only pick couple
const maxCount = 10000;
Expand Down Expand Up @@ -165,8 +183,9 @@ export const featureToDeckGlGeoType = {
* @param {Array<Object>} allFeatures
* @returns {Object} mapping of feature type existence
*/
export function getGeojsonFeatureTypes(allFeatures) {
const featureTypes = {};
export function getGeojsonFeatureTypes(allFeatures: Feature[]): FeatureTypeMap {
// @ts-expect-error
const featureTypes: FeatureTypeMap = {};
for (let f = 0; f < allFeatures.length; f++) {
const feature = allFeatures[f];
const geoType = featureToDeckGlGeoType[feature && feature.geometry && feature.geometry.type];
Expand Down
4 changes: 3 additions & 1 deletion src/layers/trip-layer/trip-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,10 +81,11 @@ export function isTripGeoJsonField(dataContainer: DataContainerInterface, field)
const features = sampleRawFeatures
.mapIndex(field.valueAccessor)
.map(parseGeoJsonRawFeature)
.filter(f => f);
.filter(notNullorUndefined);
const featureTypes = getGeojsonFeatureTypes(features);

// condition 1: contain line string
// @ts-expect-error
if (!featureTypes.line) {
return false;
}
Expand All @@ -95,6 +96,7 @@ export function isTripGeoJsonField(dataContainer: DataContainerInterface, field)
}

// condition 3:the 4th coordinate of the first feature line strings is valid time
// @ts-expect-error
const tsHolder = features[0].geometry.coordinates.map(coord => coord[3]);

return Boolean(containValidTime(tsHolder));
Expand Down