Skip to content

Commit

Permalink
add hover on arrowlayer
Browse files Browse the repository at this point in the history
  • Loading branch information
lixun910 committed Oct 18, 2023
1 parent 1988d6e commit 4e42ad7
Show file tree
Hide file tree
Showing 8 changed files with 319 additions and 80 deletions.
4 changes: 2 additions & 2 deletions src/components/src/map-container.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -738,7 +738,7 @@ export default function MapContainerFactory(
mapboxApiAccessToken,
mapboxApiUrl,
layersForDeck,
editorInfo: false
editorInfo: primaryMap
? {
editor,
editorMenuActive,
Expand Down Expand Up @@ -931,7 +931,7 @@ export default function MapContainerFactory(
// TODO this should be part of onLayerHover arguments, investigate
// @ts-ignore (does not fail with local yarn-test)
data.mapIndex = index;

console.log(data);
this.props.visStateActions.onLayerHover(data);
}, DEBOUNCE_MOUSE_MOVE_PROPAGATE);

Expand Down
3 changes: 2 additions & 1 deletion src/constants/src/default-settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -430,7 +430,8 @@ export const ALL_FIELD_TYPES = keyMirror({
timestamp: null,
point: null,
array: null,
object: null
object: null,
geoarrow: null
});

// Data Table
Expand Down
116 changes: 68 additions & 48 deletions src/layers/src/arrow-layer/arrow-layer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,71 +18,47 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

import uniq from 'lodash.uniq';
import {DATA_TYPES} from 'type-analyzer';
import {Feature} from 'geojson';

import {BinaryFeatures} from '@loaders.gl/schema';
import {GeoJsonLayer as DeckGLGeoJsonLayer} from '@deck.gl/layers';
import {
GEOJSON_FIELDS,
HIGHLIGH_COLOR_3D,
CHANNEL_SCALES,
ColorRange,
LAYER_VIS_CONFIGS
} from '@kepler.gl/constants';
import {
VisConfigNumber,
VisConfigColorSelect,
VisConfigColorRange,
VisConfigRange,
VisConfigBoolean,
Merge,
RGBColor
} from '@kepler.gl/types';
import {HIGHLIGH_COLOR_3D} from '@kepler.gl/constants';
import {KeplerTable} from '@kepler.gl/table';
import { DataContainerInterface, getBinaryGeometriesFromGeoArrowPolygon } from '@kepler.gl/utils';

import Layer, {
colorMaker,
LayerBaseConfig,
LayerBaseConfigPartial,
LayerColorConfig,
LayerColumn,
LayerHeightConfig,
LayerRadiusConfig,
LayerSizeConfig,
LayerStrokeColorConfig
} from '../base-layer';
import {
getGeojsonDataMaps,
getGeojsonBounds,
getGeojsonFeatureTypes,
GeojsonDataMaps
} from '../geojson-layer/geojson-utils';
import GeoJsonLayer, {SUPPORTED_ANALYZER_TYPES} from '../geojson-layer/geojson-layer';
DataContainerInterface,
getBinaryGeometriesFromGeoArrowPolygon,
parseGeometryFromArrow
} from '@kepler.gl/utils';
import {Merge} from '@kepler.gl/types';

import {LayerColumn, LayerBaseConfig} from '../base-layer';
import GeoJsonLayer, {
SUPPORTED_ANALYZER_TYPES,
GeoJsonLayerVisConfig,
GeoJsonLayerVisualChannelConfig
} from '../geojson-layer/geojson-layer';

export default class ArrowLayer extends GeoJsonLayer {
dataToFeature: BinaryFeatures[];
binaryFeatures: BinaryFeatures[];
dataContainer: DataContainerInterface | null;

// constructor
constructor(props) {
super(props);

this.dataToFeature = [];
this.dataContainer = null;
this.binaryFeatures = [];
}

static findDefaultLayerProps({label, metadata, fields = []}: KeplerTable) {
const geojsonColumns = fields
.filter(f => f.type === 'geojson' && SUPPORTED_ANALYZER_TYPES[f.analyzerType])
static findDefaultLayerProps({label, fields = []}: KeplerTable) {
const geoarrowColumns = fields
.filter(f => f.type === 'geoarrow' && SUPPORTED_ANALYZER_TYPES[f.analyzerType])
.map(f => f.name);

const defaultColumns = {
geojson: uniq([...GEOJSON_FIELDS.geojson, ...geojsonColumns])
geojson: geoarrowColumns
};

const foundColumns = this.findDefaultColumnField(defaultColumns, fields);
if (!foundColumns || !foundColumns.length || metadata.format !== 'arrow') {
if (!foundColumns || !foundColumns.length) {
return {props: []};
}

Expand All @@ -106,26 +82,69 @@ export default class ArrowLayer extends GeoJsonLayer {
return 'GeoArrow';
}

get requiredLayerColumns() {
return ['geojson'];
}

calculateDataAttribute({dataContainer, filteredIndex}, getPosition) {
// TODO: filter arrow table using predicate
// filteredIndex.map(i => this.dataToFeature[i]).filter(d => d);
return this.dataToFeature;
this.dataContainer = dataContainer;
return this.binaryFeatures;
}

updateLayerMeta(dataContainer: DataContainerInterface) {
this.dataContainer = dataContainer;
const {geojson} = this.config.columns;
const geoColumn = dataContainer.getColumn(geojson.fieldIdx);

// create binary data from arrow data for GeoJsonLayer
const {binaryGeometries, bounds, featureTypes} = getBinaryGeometriesFromGeoArrowPolygon(
geoColumn
);
this.dataToFeature = binaryGeometries;
this.binaryFeatures = binaryGeometries;

const fixedRadius = false;
this.updateMeta({bounds, fixedRadius, featureTypes});
}

isLayerHovered(objectInfo): boolean {
// there could be multiple deck.gl layers created from multiple chunks in arrow table
// the objectInfo.layer id should be `${this.id}-${i}`
if (objectInfo?.picked) {
const deckLayerId = objectInfo?.layer?.props?.id;
console.log(deckLayerId);
return deckLayerId.startsWith(this.id);
}
return false;
}

hasHoveredObject(objectInfo) {
// hover object returns the index of the object in the data array
if (this.isLayerHovered(objectInfo) && objectInfo.index >= 0 && this.dataContainer) {
console.time('getHoverData');
const {geojson} = this.config.columns;
const col = this.dataContainer.getColumn(geojson.fieldIdx);
const rawGeometry = col.get(objectInfo.index);
const hoveredFeature = parseGeometryFromArrow({
encoding: col.metadata?.get('ARROW:extension:name'),
data: rawGeometry
});
console.timeEnd('getHoverData');
return hoveredFeature;
}
return null;
}

getHoverData(object, dataContainer) {
// index of dataContainer is saved to feature.properties
const index = object;
if (index >= 0) {
return dataContainer.row(index);
}
return null;
}

renderLayer(opts) {
const {data, gpuFilter, objectHovered, mapState, interactionConfig} = opts;

Expand Down Expand Up @@ -155,6 +174,7 @@ export default class ArrowLayer extends GeoJsonLayer {

const pickable = interactionConfig.tooltip.enabled;
const hoveredObject = this.hasHoveredObject(objectHovered);
console.log(hoveredObject);

const deckLayers = data.data.map((d, i) => {
return new DeckGLGeoJsonLayer({
Expand Down
1 change: 1 addition & 0 deletions src/layers/src/base-layer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1256,6 +1256,7 @@ class Layer {
}

hasHoveredObject(objectInfo) {
console.log('objectInfo.object', objectInfo?.object);
return this.isLayerHovered(objectInfo) && objectInfo.object ? objectInfo.object : null;
}

Expand Down
19 changes: 4 additions & 15 deletions src/layers/src/geojson-layer/geojson-layer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ export type GeoJsonLayerVisConfig = {
wireframe: boolean;
};

type GeoJsonLayerVisualChannelConfig = LayerColorConfig &
export type GeoJsonLayerVisualChannelConfig = LayerColorConfig &
LayerStrokeColorConfig &
LayerSizeConfig &
LayerHeightConfig &
Expand All @@ -168,7 +168,7 @@ export type GeoJsonLayerMeta = {
fixedRadius?: boolean;
};

export const geoJsonRequiredColumns: ['geojson'] = ['geojson'];
export const geoJsonRequiredColumns = ['geojson'];
export const featureAccessor = ({geojson}: GeoJsonLayerColumnsConfig) => (
dc: DataContainerInterface
) => d => dc.valueAt(d.index, geojson.fieldIdx);
Expand Down Expand Up @@ -276,7 +276,7 @@ export default class GeoJsonLayer extends Layer {
};
}

static findDefaultLayerProps({label, metadata, fields = []}: KeplerTable) {
static findDefaultLayerProps({label, fields = []}: KeplerTable) {
const geojsonColumns = fields
.filter(f => f.type === 'geojson' && SUPPORTED_ANALYZER_TYPES[f.analyzerType])
.map(f => f.name);
Expand All @@ -286,7 +286,7 @@ export default class GeoJsonLayer extends Layer {
};

const foundColumns = this.findDefaultColumnField(defaultColumns, fields);
if (!foundColumns || !foundColumns.length || metadata.format === 'arrow') {
if (!foundColumns || !foundColumns.length) {
return {props: []};
}

Expand Down Expand Up @@ -398,17 +398,6 @@ export default class GeoJsonLayer extends Layer {
return this;
}

hasLayerData(layerData) {
if (!layerData) {
return false;
}
return Boolean(
layerData.data &&
(layerData.data.length ||
('points' in layerData.data && 'polygons' in layerData.data && 'lines' in layerData.data))
);
}

renderLayer(opts) {
const {data, gpuFilter, objectHovered, mapState, interactionConfig} = opts;

Expand Down
2 changes: 1 addition & 1 deletion src/processors/src/data-processor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -437,7 +437,7 @@ export function processArrowTable(arrowTable: ApacheArrowTable): ProcessorResult
displayName: field.name,
format: '',
fieldIdx: index,
type: isGeometryColumn ? ALL_FIELD_TYPES.geojson : arrowDataTypeToFieldType(field.type),
type: isGeometryColumn ? ALL_FIELD_TYPES.geoarrow: arrowDataTypeToFieldType(field.type),
analyzerType: isGeometryColumn
? AnalyzerDATA_TYPES.GEOMETRY
: arrowDataTypeToAnalyzerDataType(field.type),
Expand Down
6 changes: 4 additions & 2 deletions src/table/src/kepler-table.ts
Original file line number Diff line number Diff line change
Expand Up @@ -149,8 +149,10 @@ class KeplerTable {
// }

const isArrow = info?.format === 'arrow';
const dataContainer = createDataContainer(
isArrow ? data.rawData._children : data.rows, {
const dataContainerData = isArrow
? [...Array(data.rawData?.numCols || 0).keys()].map(i => data.rawData.getColumnAt(i))
: data.rows
const dataContainer = createDataContainer(dataContainerData, {
// @ts-expect-error
fields: data.fields,
inputDataFormat: isArrow ? DataForm.COLS_ARRAY : DataForm.ROWS_ARRAY
Expand Down
Loading

0 comments on commit 4e42ad7

Please sign in to comment.