Skip to content
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
7 changes: 7 additions & 0 deletions src/actions/defs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,13 @@ export type MapInfo = {
* @since 0.14
*/
initialExternalLayers: IInitialExternalLayer[];
/**
* Optional coordinate display format override for this map.
*
* @type {string | undefined}
* @since 0.15
*/
coordinateFormat?: string;
/**
* If set, this map has not been loaded yet and will be lazily created the first time it is switched to.
* Only applicable to MapGuide map definitions in multi-map flex layouts.
Expand Down
24 changes: 23 additions & 1 deletion src/actions/init-command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import type { ReduxDispatch, Dictionary, IMapSwipePair } from '../api/common';
import { IGenericSubjectMapLayer, IInitAppActionPayload, MapInfo } from './defs';
import { ToolbarConf, convertFlexLayoutUIItems, parseWidgetsInAppDef, prepareSubMenus } from '../api/registry/command-spec';
import { makeUnique } from '../utils/array';
import { ApplicationDefinition, MapConfiguration } from '../api/contracts/fusion';
import { ApplicationDefinition, MapConfiguration, MapSetGroup } from '../api/contracts/fusion';
import { warn, info } from '../utils/logger';
import { registerCommand } from '../api/registry/command';
import { tr, registerStringBundle, DEFAULT_LOCALE } from '../api/i18n';
Expand Down Expand Up @@ -56,6 +56,28 @@ export function parseSwipePairs(appDef: ApplicationDefinition): IMapSwipePair[]
return pairs;
}

/**
* Parses a map-level mouse coordinate format override from the first map
* configuration inside a MapGroup.
*
* Supported extension key on the first map's Extension object:
* - MouseCoordinatesFormat
*
* @hidden
* @since 0.15
*/
export function parseMapGroupCoordinateFormat(mapGroup: MapSetGroup): string | undefined {
const ext = mapGroup.Map?.[0]?.Extension;
if (!ext) {
return undefined;
}
const candidate = ext.MouseCoordinatesFormat;
if (typeof candidate === "string" && candidate.trim().length > 0) {
return candidate;
}
return undefined;
}

const TYPE_SUBJECT = "SubjectLayer";
const TYPE_EXTERNAL = "External";

Expand Down
4 changes: 3 additions & 1 deletion src/actions/init-mapguide.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { MgError } from '../api/error';
import { resolveProjectionFromEpsgCodeAsync } from '../api/registry/projections';
import { register } from 'ol/proj/proj4';
import proj4 from "proj4";
import { buildSubjectLayerDefn, getMapDefinitionsFromFlexLayout, isMapDefinition, isStateless, MapToLoad, ViewerInitCommand } from './init-command';
import { buildSubjectLayerDefn, getMapDefinitionsFromFlexLayout, isMapDefinition, isStateless, parseMapGroupCoordinateFormat, MapToLoad, ViewerInitCommand } from './init-command';
import { WebLayout } from '../api/contracts/weblayout';
import { convertWebLayoutUIItems, parseCommandsInWebLayout, prepareSubMenus, ToolbarConf } from '../api/registry/command-spec';
import { clearSessionStore, retrieveSelectionSetFromLocalStorage } from '../api/session-store';
Expand Down Expand Up @@ -575,13 +575,15 @@ export class DefaultViewerInitCommand extends ViewerInitCommand<SubjectLayerType
}

if (mapName) {
const coordinateFormat = parseMapGroupCoordinateFormat(mGroup);
const pendingEntry = pendingMapDefs?.[mapName];
dict[mapName] = {
mapGroupId: mGroup["@id"],
map: mapsByName[mapName],
initialView: initialView,
externalBaseLayers: externalBaseLayers,
initialExternalLayers: initExternalLayers,
coordinateFormat: coordinateFormat,
// If this map is pending lazy creation, store the mapDef for later use
...(pendingEntry ? { mapDef: pendingEntry.mapDef, metadata: pendingEntry.metadata } : {})
};
Expand Down
6 changes: 6 additions & 0 deletions src/api/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1668,6 +1668,12 @@ export interface IBranchedMapSubState {
* @since 0.14
*/
generic: IGenericLayerSubState | undefined;
/**
* Optional coordinate display format override for this map.
*
* @since 0.15
*/
coordinateFormat?: string;
}

/**
Expand Down
15 changes: 15 additions & 0 deletions src/containers/hooks-mapguide.ts
Original file line number Diff line number Diff line change
Expand Up @@ -128,3 +128,18 @@ export function useActiveMapFiniteScales() {
export function useActiveMapState() {
return useAppState<RuntimeMap | undefined>(state => getRuntimeMap(state));
}

/**
* Gets the coordinate display format override for the active map.
*
* @hidden
* @since 0.15
*/
export function useActiveMapCoordinateFormat() {
return useAppState<string | undefined>(state => {
if (state.config.activeMapName) {
return state.mapState[state.config.activeMapName]?.coordinateFormat;
}
return undefined;
});
}
6 changes: 4 additions & 2 deletions src/containers/mouse-coordinates.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { MouseCoordinates } from "../components/mouse-coordinates";
import * as olProj from "ol/proj";
import { getUnitOfMeasure } from "../utils/units";
import { useViewerLocale, useCurrentMouseCoordinates, useConfiguredCoordinateProjection, useConfiguredCoordinateDecimals, useConfiguredCoordinateFormat } from './hooks';
import { useActiveMapProjection } from './hooks-mapguide';
import { useActiveMapProjection, useActiveMapCoordinateFormat } from './hooks-mapguide';

export interface IMouseCoordinatesContainerProps {
style?: React.CSSProperties;
Expand All @@ -19,6 +19,7 @@ export const MouseCoordinatesContainer = (props: IMouseCoordinatesContainerProps
const projection = useConfiguredCoordinateProjection();
const decimals = useConfiguredCoordinateDecimals();
const format = useConfiguredCoordinateFormat();
const mapCoordinateFormat = useActiveMapCoordinateFormat();
const mouse = useCurrentMouseCoordinates();
const locale = useViewerLocale();
if (mouse) {
Expand Down Expand Up @@ -51,7 +52,8 @@ export const MouseCoordinatesContainer = (props: IMouseCoordinatesContainerProps

}
}
return <MouseCoordinates units={units} coords={coords} style={style} decimals={decimals} format={format} />;
const effectiveFormat = mapCoordinateFormat || format;
return <MouseCoordinates units={units} coords={coords} style={style} decimals={decimals} format={effectiveFormat} />;
} else {
return <div />;
}
Expand Down
4 changes: 3 additions & 1 deletion src/reducers/map-state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,8 @@ export const MAP_STATE_INITIAL_SUB_STATE: IBranchedMapSubState = {
layers: undefined,
mapguide: undefined,
generic: undefined,
clientSelection: undefined
clientSelection: undefined,
coordinateFormat: undefined
};

function applyMapGuideSubState(state: IBranchedMapState, mapName: string, applyFn: (current: IMapGuideSubState) => Partial<IMapGuideSubState>) {
Expand Down Expand Up @@ -194,6 +195,7 @@ export function mapStateReducer(state = MAP_STATE_INITIAL_STATE, action: ViewerA
...{ externalBaseLayers: maps[mapName].externalBaseLayers },
...{ initialExternalLayers: maps[mapName].initialExternalLayers },
...{ initialView: maps[mapName].initialView },
...{ coordinateFormat: maps[mapName].coordinateFormat },
...(cv || {}),
...{ mapguide: newMgSubState }
};
Expand Down
78 changes: 77 additions & 1 deletion test/actions/init-command.spec.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { describe, it, expect } from "vitest";
import { buildSubjectLayerDefn, isMapDefinition, isStateless, parseSwipePairs } from "../../src/actions/init-command";
import { buildSubjectLayerDefn, isMapDefinition, isStateless, parseMapGroupCoordinateFormat, parseSwipePairs } from "../../src/actions/init-command";
import { GenericSubjectLayerType, IGenericSubjectMapLayer } from "../../src/actions/defs";

describe("actions/init-command", () => {
Expand Down Expand Up @@ -132,4 +132,80 @@ describe("actions/init-command", () => {
expect(pairs[0].primaryMapName).toBe("MapA");
});
});

describe("parseMapGroupCoordinateFormat", () => {
it("returns undefined when Map array is empty", () => {
const mapGroup = { "@id": "MapA", Map: [] };
Comment thread
jumpinjackie marked this conversation as resolved.
expect(parseMapGroupCoordinateFormat(mapGroup as any)).toBeUndefined();
});

it("returns undefined when the first map has no extension", () => {
const mapGroup = { "@id": "MapA", Map: [{ Type: "MapGuide" }] };
expect(parseMapGroupCoordinateFormat(mapGroup as any)).toBeUndefined();
});

it("returns MouseCoordinatesFormat from the first map extension", () => {
const mapGroup = {
"@id": "MapA",
Map: [
{
Type: "MapGuide",
Extension: {
MouseCoordinatesFormat: "Lng: {x} {units}, Lat: {y} {units}"
}
}
]
};
expect(parseMapGroupCoordinateFormat(mapGroup as any)).toBe("Lng: {x} {units}, Lat: {y} {units}");
});

it("ignores non-canonical alias keys", () => {
const mapGroup = {
"@id": "MapA",
Map: [
{
Type: "MapGuide",
Extension: {
CoordinateFormat: "Easting: {x} {units}, Northing: {y} {units}"
}
}
]
};
expect(parseMapGroupCoordinateFormat(mapGroup as any)).toBeUndefined();
});

it("returns undefined for blank values", () => {
const mapGroup = {
"@id": "MapA",
Map: [
{
Type: "MapGuide",
Extension: {
MouseCoordinatesFormat: " "
}
}
]
};
expect(parseMapGroupCoordinateFormat(mapGroup as any)).toBeUndefined();
});

it("only reads from the first map", () => {
const mapGroup = {
"@id": "MapA",
Map: [
{
Type: "MapGuide",
Extension: {}
},
{
Type: "MapGuide",
Extension: {
MouseCoordinatesFormat: "Easting: {x} {units}, Northing: {y} {units}"
}
}
]
};
expect(parseMapGroupCoordinateFormat(mapGroup as any)).toBeUndefined();
});
});
});
Loading