Skip to content

User can now add a route segment (both start and now END milepost) via URL search parameters #493

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

Merged
merged 24 commits into from
Dec 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
a7d17df
build: :arrow_up: upgrade dependencies in lockfile
JeffJacobson Dec 4, 2024
7be7b9a
chore: :technologist: ignore pnpm lockfile in cspell config
JeffJacobson Dec 4, 2024
f01a461
refactor: :recycle: Add route segment CIM definitions
JeffJacobson Dec 5, 2024
1a6e2f2
refactor: :recycle: remove default export on layers/MilepostLayer/symbol
JeffJacobson Dec 5, 2024
f655572
chore: :hammer: create-cim script now adds primitive overrides
JeffJacobson Dec 5, 2024
62a2f4e
refactor: :hammer: Refactor create-cim
JeffJacobson Dec 5, 2024
22135ce
refactor: :truck: Moved create-cim into src subfolder
JeffJacobson Dec 5, 2024
d0adfd0
chore: :hammer: Restored script to create Milepost CIM
JeffJacobson Dec 5, 2024
b78ac67
refactor: :recycle: refactor milepost CIM definitions
JeffJacobson Dec 5, 2024
d39560f
build: :arrow_up: upgrade vite
JeffJacobson Dec 5, 2024
9be99bc
refactor: :recycle: simplify line symbol creation
JeffJacobson Dec 9, 2024
6e690be
refactor: :recycle: Added end MP fields to line layer
JeffJacobson Dec 9, 2024
f1a7766
refactor: :recycle: add ability to read end MP
JeffJacobson Dec 10, 2024
27503dc
refactor: :rotating_light: Removed unneeded eslint comment
JeffJacobson Dec 10, 2024
b2e5b1f
refactor: :recycle: Modifed types
JeffJacobson Dec 10, 2024
f93795e
build: :wrench: Update pnpm
JeffJacobson Dec 10, 2024
388517e
build: :arrow_up: upgrade dependencies
JeffJacobson Dec 10, 2024
89d3e92
refactor: Added end milepost controls
JeffJacobson Dec 11, 2024
27d1bd7
refactor: :construction: Add handling for end milepost in URLs
JeffJacobson Dec 12, 2024
d499670
refactor: :construction: Milepost segments can now added from URL
JeffJacobson Dec 12, 2024
29f0c40
build: :pushpin: Specify v1.0.1 tag for WSDOT-GIS/wsdot-web-styles de…
JeffJacobson Dec 12, 2024
f02ac9b
refactor: :recycle: remove unused type import
JeffJacobson Dec 12, 2024
4edc1bb
refactor: :construction: Added symbol for route segments
JeffJacobson Dec 12, 2024
d0ce3a9
feat: :sparkles: route segement via URL
JeffJacobson Dec 12, 2024
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
3 changes: 2 additions & 1 deletion cspell.config.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
version: "0.2"
useGitignore: true
ignorePaths: []
ignorePaths:
- pnpm-lock.yaml
allowCompoundWords: true
features:
weighted-suggestions: true
Expand Down
22 changes: 18 additions & 4 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -47,13 +47,27 @@
</calcite-combobox>
</calcite-label>

<calcite-label layout="inline" for="decreaseInput"><calcite-checkbox name="decrease" id="decreaseInput"
title="Check this box if you want the decreasing route rather than increasing."></calcite-checkbox>Decrease</calcite-label>
<calcite-label layout="inline" for="decreaseInput">Increase<calcite-switch name="decrease"
id="decreaseInput"
title="Check this box if you want the decreasing route rather than increasing."></calcite-switch>Decrease</calcite-label>

<calcite-label for="mpInput">Milepost<calcite-input-number title="Enter the milepost value here."
id="mpInput" name="mp" type="number" min="0" step="0.01" required /></calcite-label>

<calcite-label for="backInput" layout="inline"><calcite-checkbox name="back" id="backInput"
title="Check this box if the SRMP is back mileage."></calcite-checkbox>Back</calcite-label>
<calcite-label for="backInput" layout="inline">Ahead<calcite-switch name="back" id="backInput"
title="Check this box if the SRMP is back mileage." label="Back"></calcite-switch>Back</calcite-label>

<!--
<calcite-block heading="End Milepost" description="End milepost (optional)" collapsible="true">
<calcite-label for="endMPInput">End Milepost<calcite-input-number
title="Enter the end milepost value here if you want to search for a route segment." id="endMPInput"
name="endMP" type="number" min="0" step="0.01" /></calcite-label>
<calcite-label layout="inline">Ahead <calcite-switch name="endBack" id="endBackInput"
title="Check this box if the SRMP is back mileage." label="Back"></calcite-switch>
Back</calcite-label>
</calcite-block>
-->

<div class="btn-container">
<calcite-button type="submit"
title="Click this button to find this route + milepost and add a point to the map." alignment="center"
Expand Down
10 changes: 5 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,9 @@
"@fontsource/inconsolata": "^5.1.0",
"@fontsource/lato": "^5.1.0",
"@fontsource/overpass": "^5.1.1",
"@types/geojson": "^7946.0.14",
"@types/geojson": "^7946.0.15",
"@wsdot/land-use-codes": "github:WSDOT-GIS/land-use",
"@wsdot/web-styles": "github:WSDOT-GIS/wsdot-web-styles",
"@wsdot/web-styles": "github:WSDOT-GIS/wsdot-web-styles#v1.0.1",
"analytics": "^0.8.14",
"browser-update": "^3.3.55",
"dms-conversion": "^3.1.3",
Expand All @@ -44,13 +44,13 @@
"browserslist-to-esbuild": "^2.1.1",
"cspell": "^8.16.1",
"jsdom": "^25.0.1",
"msw": "^2.6.6",
"msw": "^2.6.8",
"optionator": "^0.9.4",
"svgo": "^3.3.2",
"svgson": "^5.3.1",
"tsx": "^4.19.2",
"typescript": "^5.7.2",
"vite": "^6.0.2",
"vite": "^6.0.3",
"vitest": "^2.1.8"
},
"repository": {
Expand All @@ -68,5 +68,5 @@
],
"author": "Jeff Jacobson",
"license": "Unlicense",
"packageManager": "pnpm@9.14.4+sha512.c8180b3fbe4e4bca02c94234717896b5529740a6cbadf19fa78254270403ea2f27d4e1d46a08a0f56c89b63dc8ebfd3ee53326da720273794e6200fcf0d184ab"
"packageManager": "pnpm@9.15.0+sha512.76e2379760a4328ec4415815bcd6628dee727af3779aaa4c914e3944156c4299921a89f976381ee107d41f12cfa4b66681ca9c718f0668fa0831ed4c6d8ba56c"
}
611 changes: 308 additions & 303 deletions pnpm-lock.yaml

Large diffs are not rendered by default.

39 changes: 13 additions & 26 deletions src/addGraphicsToLayer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,32 +11,19 @@ export async function addGraphicsToLayer(
milepostLayer: FeatureLayer,
locationGraphics: Graphic[],
) {
/* __PURE__ */ console.group(addGraphicsToLayer.name, {
milepostLayer: { ...milepostLayer },
locationGraphics: locationGraphics.map((g) => g.toJSON() as unknown),
});
try {
// Add graphics to the layer and await for the edit to complete.
const editsResult = await milepostLayer.applyEdits(
{
addFeatures: locationGraphics,
},
{},
);
/* __PURE__ */ console.debug(
"editsResult",
editsResult.addFeatureResults.map((e) => ({ ...e })),
);
// Add graphics to the layer and await for the edit to complete.
const editsResult = await milepostLayer.applyEdits(
{
addFeatures: locationGraphics,
},
{},
);

// Get the added features from the edits result by querying the milepost layer
// for the features with matching object IDs.
const query = milepostLayer.createQuery();
/* __PURE__ */ console.debug("query", query.toJSON());
query.objectIds = editsResult.addFeatureResults.map((r) => r.objectId);
const results = await milepostLayer.queryFeatures(query);
// Get the added features from the edits result by querying the milepost layer
// for the features with matching object IDs.
const query = milepostLayer.createQuery();
query.objectIds = editsResult.addFeatureResults.map((r) => r.objectId);
const results = await milepostLayer.queryFeatures(query);

return results.features;
} finally {
/* __PURE__ */ console.groupEnd();
}
return results.features;
}
38 changes: 25 additions & 13 deletions src/elc/arcgis.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import Graphic from "@arcgis/core/Graphic";
import Point from "@arcgis/core/geometry/Point";
import { hasXAndY } from "../types";
import Polyline from "@arcgis/core/geometry/Polyline";
import { hasPaths, hasXAndY } from "../types";
import { ElcError } from "./errors";
import type {
DateType,
Expand Down Expand Up @@ -39,12 +40,23 @@ export function routeLocationToGraphic<
if (routeLocation instanceof ElcError) {
throw routeLocation;
}
let geometry: __esri.Point | undefined;
if (routeLocation.RouteGeometry && hasXAndY(routeLocation.RouteGeometry)) {
const { x, y, spatialReference } = routeLocation.RouteGeometry;
geometry = new Point({ x, y, spatialReference });
let geometry: __esri.Point | __esri.Polyline | undefined;
if (routeLocation.RouteGeometry) {
if (hasXAndY(routeLocation.RouteGeometry)) {
const { x, y, spatialReference } = routeLocation.RouteGeometry;
geometry = new Point({ x, y, spatialReference });
} else if (hasPaths(routeLocation.RouteGeometry)) {
const { paths, spatialReference } = routeLocation.RouteGeometry;
geometry = new Polyline({
paths,
spatialReference,
});
}
} else {
console.warn("Input does not have valid point geometry.", routeLocation);
console.warn(
"Input does not have valid point or polyline geometry.",
routeLocation,
);
}
let attributes:
| (Record<string, unknown> & {
Expand All @@ -53,17 +65,18 @@ export function routeLocationToGraphic<
Direction: "D" | "I";
Srmp?: number;
Back: "B" | "";
"Township Subdivision": null;
City: null;
County: null;
EndSrmp?: number;
EndBack?: "B" | "";
})
| undefined;
if (hasValidSrmpData(routeLocation)) {
const {
Route,
Decrease,
Srmp,
Back,
Decrease,
EndSrmp,
EndBack,
// Angle,
// Arm,
// ArmCalcReturnCode,
Expand All @@ -82,9 +95,8 @@ export function routeLocationToGraphic<
Direction: Decrease ? "D" : "I",
Srmp,
Back: Back ? "B" : "",
"Township Subdivision": null,
City: null,
County: null,
EndSrmp: EndSrmp,
EndBack: EndBack ? "B" : "",
};
oid++;
} else {
Expand Down
17 changes: 10 additions & 7 deletions src/elc/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,9 @@ export interface RouteLocation<D extends DateType, G extends RouteGeometry> {
RouteGeometry?: G;
Srmp?: number;
LocatingError?: string | null;
EndArm?: number;
EndSrmp?: number;
EndBack?: boolean;
}

export type ArmRouteLocation<
Expand All @@ -134,6 +137,12 @@ export type SrmpRouteLocation<
G extends RouteGeometry,
> = RouteLocation<D, G> & Required<Pick<RouteLocation<D, G>, "Srmp" & "Back">>;

export type SrmpRouteLineLocation<
D extends DateType,
G extends RouteGeometry,
> = RouteLocation<D, G> &
Required<Pick<RouteLocation<D, G>, "EndSrmp" & "EndBack">>;

export type ValidRouteLocationForMPInput<
D extends DateType,
G extends RouteGeometry,
Expand Down Expand Up @@ -176,13 +185,7 @@ export interface ElcAttributes
Srmp: number;
}

export interface LayerFeatureAttributes
extends ElcAttributes,
AttributesObject {
"Township Subdivision": string | null;
County: string | null;
City: string | null;
}
export type LayerFeatureAttributes = ElcAttributes & AttributesObject;

/**
* A milepost point {@link Graphic}.
Expand Down
33 changes: 25 additions & 8 deletions src/elc/url.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ import type {
ValidRouteLocationForMPInput,
} from "./types";

type UrlParamMapKey = "sr" | "rrt" | "rrq" | "dir" | "mp";
type UrlParamMapKey = "sr" | "rrt" | "rrq" | "dir" | "mp" | "endMP";

/**
* Regular expression patterns to validate URL parameters.
Expand All @@ -43,8 +43,10 @@ const keyRegExps = new Map([
["rrq", /^R{1,2}Q/i],
["dir", /^D(?:IR)?/i],
["mp", /^(?:SR)?MP/i],
["endMP", /^E(ND)?(SR)?MP/i],
] as const);

const milepostAndBackIndicatorRegex = /^(?<mp>\d+(?:\.\d+)?)(?<back>B)?$/i;
/**
* Regular expression patterns to validate URL parameter values.
*/
Expand All @@ -64,7 +66,8 @@ const valueRegExps = new Map([
* @example
* // matches "123", "123.45", "123B", "123.45B"
*/
["mp", /^(?<mp>\d+(?:\.\d+)?)(?<back>B)?$/i],
["mp", milepostAndBackIndicatorRegex],
["endMP", milepostAndBackIndicatorRegex],
] as const);

type KeyValueRegExpTuple = [keyRegexp: RegExp, valueRegexp: RegExp];
Expand All @@ -91,6 +94,8 @@ export function getUrlSearchParameter(
urlParams: URLSearchParams,
key: UrlParamMapKey,
) {
let output: string | null = null;

// Retrieve the regular expression tuple from the regExpMap based on the key.
const reTuple = regExpMap.get(key);
if (!reTuple) {
Expand All @@ -105,7 +110,6 @@ export function getUrlSearchParameter(
}

const [keyRe, valueRe] = reTuple;
let output: string | null = null;

// Iterate over each key-value pair in the URL search parameters.
for (const [k, v] of urlParams.entries()) {
Expand Down Expand Up @@ -160,7 +164,6 @@ export function* enumerateUrlParameters(
} else if (Array.isArray(value)) {
outValue = JSON.stringify(value);
} else {
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
outValue = `${value}`;
}
yield [key, outValue];
Expand Down Expand Up @@ -245,7 +248,7 @@ function parseSrmp(mp: string): { srmp: number; back: boolean } {
*/
export function getElcParamsFromUrl(
url: string | URL | URLSearchParams = window.location.href,
): ValidRouteLocationForMPInput<Date, RouteGeometry> | null {
) {
// If the URL is a URL object, use its search params.
let searchParams: URLSearchParams;
if (url instanceof URL) {
Expand Down Expand Up @@ -281,14 +284,22 @@ export function getElcParamsFromUrl(

const route = `${sr}${rrt}${rrq}`;

return {
const emp = getUrlSearchParameter(searchParams, "endMP");

const { srmp: endSrmp, back: endBack } = emp
? parseSrmp(emp)
: { srmp: null, back: null };
const output = {
Route: route,
Srmp: srmp,
Back: back,
Decrease: /dD/i.test(direction),
ReferenceDate: today,
ResponseDate: today,
};
EndSrmp: endSrmp,
EndBack: endBack,
} as ValidRouteLocationForMPInput<Date, RouteGeometry>;
return output;
}

/**
Expand All @@ -301,6 +312,7 @@ export function getElcParamsFromUrl(
*/
export async function callElcFromUrl(
milepostLayer: __esri.FeatureLayer,
lineMilepostLayer: __esri.FeatureLayer,
options: Pick<FindRouteLocationParameters, "outSR"> = { outSR: 3857 },
) {
const routeLocation = getElcParamsFromUrl();
Expand All @@ -325,5 +337,10 @@ export async function callElcFromUrl(

const graphic = routeLocationToGraphic(location);

return addGraphicsToLayer(milepostLayer, [graphic]);
const layer =
graphic.geometry.type === "polyline" ? lineMilepostLayer : milepostLayer;

const addedGraphics = addGraphicsToLayer(layer, [graphic]);

return addedGraphics;
}
2 changes: 1 addition & 1 deletion src/layers/MilepostLayer/arcade/County.arcade
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,4 @@ for (var f in match) {
return f.JURISDICT_LABEL_NM
}

return $userInput;
// return $userInput;
8 changes: 7 additions & 1 deletion src/layers/MilepostLayer/arcade/WGS 1984 Coordinates.arcade
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
// import fromWebMercatorFunction from "./parts/fromWebMercator.function.arcade"

webMercatorToWgs1984(Geometry($feature))
var featureGeometry = Geometry($feature);

if (TypeOf(featureGeometry) == "Point") {
webMercatorToWgs1984(Geometry($feature))
} else {
webMercatorToWgs1984(Point($userInput))
}
Loading
Loading