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

fix(dynamic layers): fixed zoom issues in data table #2649

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -123,10 +123,18 @@ export class LegendEventProcessor extends AbstractEventProcessor {
* @param {string} mapId - The map identifier
* @param {string} layerPath - The layer path
* @param {string[]} objectIds - The IDs of features to get extents from.
* @param {string} outfield - ID field to return for services that require a value in outfields.
* @returns {Promise<Extent | undefined>} The extent of the feature, if available
*/
static getExtentFromFeatures(mapId: string, layerPath: string, objectIds: string[]): Promise<Extent | undefined> | undefined {
return MapEventProcessor.getMapViewerLayerAPI(mapId).getGeoviewLayerHybrid(layerPath)?.getExtentFromFeatures(layerPath, objectIds);
static getExtentFromFeatures(
mapId: string,
layerPath: string,
objectIds: string[],
outfield?: string
): Promise<Extent | undefined> | undefined {
return MapEventProcessor.getMapViewerLayerAPI(mapId)
.getGeoviewLayerHybrid(layerPath)
?.getExtentFromFeatures(layerPath, objectIds, outfield);
}

static getLayerIconImage(layerLegend: TypeLegend | null): TypeLegendLayerItem[] | undefined {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -300,7 +300,12 @@ function DataTable({ data, layerPath, tableHeight = '500px' }: DataTableProps):
let { extent } = feature;

// If there is no extent, the layer is ESRI Dynamic, get the feature extent using its OBJECTID
if (!extent) extent = await getExtentFromFeatures(layerPath, [feature.fieldInfo.OBJECTID!.value as string]);
// GV: Some layers do not use OBJECTID, these are the other values seen so far.
// TODO: Update field info types to include esriFieldTypeOID to identify the ID field.
const idFields = ['OBJECTID', 'OBJECTID_1', 'FID', 'STATION_NUMBER'];
const idField = idFields.find((fieldName) => feature.fieldInfo[fieldName]?.value !== undefined);
if (!extent && idField !== undefined)
extent = await getExtentFromFeatures(layerPath, [feature.fieldInfo[idField]!.value as string], idField);

if (extent) {
// Project
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ export interface ILayerState {

actions: {
deleteLayer: (layerPath: string) => void;
getExtentFromFeatures: (layerPath: string, featureIds: string[]) => Promise<Extent | undefined>;
getExtentFromFeatures: (layerPath: string, featureIds: string[], outfield?: string) => Promise<Extent | undefined>;
queryLayerEsriDynamic: (layerPath: string, objectIDs: number[]) => Promise<TypeFeatureInfoEntryPartial[]>;
getLayer: (layerPath: string) => TypeLegendLayer | undefined;
getLayerBounds: (layerPath: string) => number[] | undefined;
Expand Down Expand Up @@ -89,9 +89,9 @@ export function initializeLayerState(set: TypeSetStore, get: TypeGetStore): ILay
get().layerState.setterActions.setLayerDeleteInProgress(false);
},

getExtentFromFeatures: (layerPath: string, featureIds: string[]) => {
getExtentFromFeatures: (layerPath: string, featureIds: string[], outfield?: string) => {
// Redirect to event processor
return LegendEventProcessor.getExtentFromFeatures(get().mapId, layerPath, featureIds);
return LegendEventProcessor.getExtentFromFeatures(get().mapId, layerPath, featureIds, outfield);
},

/**
Expand Down
6 changes: 3 additions & 3 deletions packages/geoview-core/src/core/utils/constant.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,9 +73,9 @@ export const DATE_FILTER: Record<string, string> = {
};

export const STRING_FILTER: Record<string, string> = {
contains: `(filterId) like ('%value%')`,
startsWith: `(filterId) like ('value%')`,
endsWith: `(filterId) like ('%value')`,
contains: `lower(filterId) like lower('%value%')`,
startsWith: `lower(filterId) like lower('value%')`,
endsWith: `lower(filterId) like lower('%value')`,
empty: '(filterId) is null',
notEmpty: '(filterId) is not null',
equals: `filterId = 'value'`,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1395,11 +1395,12 @@ export abstract class AbstractGeoViewLayer {
* Overridable function that gets the extent of an array of features.
* @param {string} layerPath - The layer path
* @param {string[]} objectIds - The IDs of features to get extents from.
* @param {string} outfield - ID field to return for services that require a value in outfields.
* @returns {Promise<Extent | undefined>} The extent of the features, if available
*/
// Added eslint-disable here, because we do want to override this method in children and keep 'this'.
// eslint-disable-next-line @typescript-eslint/class-methods-use-this
getExtentFromFeatures(layerPath: string, objectIds: string[]): Promise<Extent | undefined> {
// eslint-disable-next-line @typescript-eslint/class-methods-use-this, @typescript-eslint/no-unused-vars
getExtentFromFeatures(layerPath: string, objectIds: string[], outfield?: string): Promise<Extent | undefined> {
logger.logError(`Feature geometry for ${objectIds} is unavailable from ${layerPath}`);
return Promise.resolve(undefined);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -969,9 +969,10 @@ export class EsriDynamic extends AbstractGeoViewRaster {
* Sends a query to get ESRI Dynamic feature geometries and calculates an extent from them.
* @param {string} layerPath - The layer path.
* @param {string[]} objectIds - The IDs of the features to calculate the extent from.
* @param {string} outfield - ID field to return for services that require a value in outfields.
* @returns {Promise<Extent | undefined>} The extent of the features, if available.
*/
override async getExtentFromFeatures(layerPath: string, objectIds: string[]): Promise<Extent | undefined> {
override async getExtentFromFeatures(layerPath: string, objectIds: string[], outfield?: string): Promise<Extent | undefined> {
// Get url for service from layer entry config
const layerEntryConfig = this.getLayerConfig(layerPath)! as EsriDynamicLayerEntryConfig;
let baseUrl = layerEntryConfig.source.dataAccessPath;
Expand All @@ -980,7 +981,10 @@ export class EsriDynamic extends AbstractGeoViewRaster {
if (baseUrl) {
// Construct query
if (!baseUrl.endsWith('/')) baseUrl += '/';
const queryUrl = `${baseUrl}${layerEntryConfig.layerId}/query?&f=json&where=&objectIds=${idString}&&geometryPrecision=1&returnGeometry=true`;
// GV: Outfields here is not wanted, it is included because some sevices require it in the query. It would be possible to use
// GV cont: objectid, but it is not universal through the services, so we pass a value through.
const outfieldQuery = outfield ? `&outFields=${outfield}` : '';
const queryUrl = `${baseUrl}${layerEntryConfig.layerId}/query?&f=json&where=&objectIds=${idString}${outfieldQuery}&returnGeometry=true`;

try {
const response = await fetch(queryUrl);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import {
import { esriGetFieldType, esriGetFieldDomain } from '../utils';
import { AbstractGVRaster } from './abstract-gv-raster';
import { TypeOutfieldsType } from '@/api/config/types/map-schema-types';
import { TypeJsonObject } from '@/api/config/types/config-types';

type TypeFieldOfTheSameValue = { value: string | number | Date; nbOccurence: number };
type TypeQueryTree = { fieldValue: string | number | Date; nextField: TypeQueryTree }[];
Expand Down Expand Up @@ -724,16 +725,27 @@ export class GVEsriDynamic extends AbstractGVRaster {
* @param {string[]} objectIds - The IDs of the features to calculate the extent from.
* @returns {Promise<Extent | undefined>} The extent of the features, if available.
*/
override async getExtentFromFeatures(layerPath: string, objectIds: string[]): Promise<Extent | undefined> {
override async getExtentFromFeatures(layerPath: string, objectIds: string[], outfield?: string): Promise<Extent | undefined> {
// Get url for service from layer entry config
const layerEntryConfig = this.getLayerConfig();
const serviceMetaData = layerEntryConfig.getServiceMetadata() as TypeJsonObject;
const wkid = serviceMetaData?.spatialReference.wkid ? serviceMetaData.spatialReference.wkid : undefined;
let baseUrl = layerEntryConfig.source.dataAccessPath;

const idString = objectIds.join('%2C');
if (baseUrl) {
// Construct query
if (!baseUrl.endsWith('/')) baseUrl += '/';
const queryUrl = `${baseUrl}${layerEntryConfig.layerId}/query?&f=json&where=&objectIds=${idString}&&geometryPrecision=1&returnGeometry=true`;
// GV: outFields here is not wanted, it is included because some sevices require it in the query. It would be possible to use
// GV cont: OBJECTID, but it is not universal through the services, so we pass a value through.
const outfieldQuery = outfield ? `&outFields=${outfield}` : '';
let precision = '';
let allowableOffset = '';
if ((serviceMetaData?.layers as Array<TypeJsonObject>).every((layer) => layer.geometryType !== 'esriGeometryPoint')) {
precision = '&geometryPrecision=1';
allowableOffset = '&maxAllowableOffset=7937.5158750317505';
}
const queryUrl = `${baseUrl}${layerEntryConfig.layerId}/query?&f=json&where=&objectIds=${idString}${outfieldQuery}${precision}&returnGeometry=true${allowableOffset}`;

try {
const response = await fetch(queryUrl);
Expand All @@ -743,7 +755,7 @@ export class GVEsriDynamic extends AbstractGVRaster {
const responseFeatures = new EsriJSON().readFeatures(
{ features: responseJson.features },
{
dataProjection: `EPSG:${responseJson.spatialReference.wkid}`,
dataProjection: wkid ? `EPSG:${wkid}` : `EPSG:${responseJson.spatialReference.wkid}`,
featureProjection: this.getMapViewer().getProjection().getCode(),
}
);
Expand Down
Loading