Skip to content

Commit

Permalink
fix(dynamic layers): fixed zoom issues in data table
Browse files Browse the repository at this point in the history
Closes #2592
  • Loading branch information
DamonU2 committed Dec 11, 2024
1 parent fc3ebda commit b5c21b0
Show file tree
Hide file tree
Showing 7 changed files with 43 additions and 16 deletions.
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,24 @@ 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}` : '';
const precision = (serviceMetaData?.layers as Array<TypeJsonObject>).every((layer) => layer.geometryType !== 'esriGeometryPoint')
? '&geometryPrecision=1'
: '';
const queryUrl = `${baseUrl}${layerEntryConfig.layerId}/query?&f=json&where=&objectIds=${idString}${outfieldQuery}${precision}&returnGeometry=true`;

try {
const response = await fetch(queryUrl);
Expand All @@ -743,7 +752,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

0 comments on commit b5c21b0

Please sign in to comment.