Skip to content

Commit

Permalink
feat: ✨ route segement via URL
Browse files Browse the repository at this point in the history
User can now zoom to a line segment as defined by
a RouteID, Direction, (Begin) Milepost, (Begin) Back,
End Milepost and End Back values via URL.

refactor: ♻️ Add route segment CIM definitions

refactor: ♻️ remove default export on layers/MilepostLayer/symbol

chore: 🔨 create-cim script now adds primitive overrides

refactor: 🔨 Refactor create-cim

refactor: 🚚 Moved create-cim into src subfolder

chore: 🔨 Restored script to create Milepost CIM

The original script was moved and turned into a
module. This new script calls this module, which
does most of the work.

refactor: ♻️ refactor milepost CIM definitions

build: ⬆️ upgrade vite

refactor: ♻️ simplify line symbol creation

refactor: ♻️ Added end MP fields to line layer

refactor: ♻️ add ability to read end MP

refactor: 🚨 Removed unneeded eslint comment

refactor: ♻️ Modifed types

build: 🔧 Update pnpm

build: ⬆️ upgrade dependencies

refactor: Added end milepost controls

refactor: 🚧 Add handling for end milepost in URLs

refactor: 🚧 Milepost segments can now added from URL

Need to modify renderer to show line segments with begin and end mileposts rather then ones showing where the user clicked to the milepost on the route.

build: 📌 Specify v1.0.1 tag for WSDOT-GIS/wsdot-web-styles dependency

refactor: ♻️ remove unused type import

refactor: 🚧 Added symbol for route segments
  • Loading branch information
JeffJacobson committed Dec 13, 2024
1 parent 3475ddd commit 86c93c4
Show file tree
Hide file tree
Showing 22 changed files with 976 additions and 647 deletions.
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"
}
603 changes: 304 additions & 299 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))
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
function webMercatorToWgs1984(geom) {
// Web Mercator coordinates
var xWebMercator = geom.x;
var yWebMercator = geom.y;
// Constants
var R_MAJOR = 6378137.0;

function xyWebMercatorToWgs1984(xy) {

// Constants
var R_MAJOR = 6378137.0;
var xWebMercator = xy[0];
var yWebMercator = xy[1];

// Convert Web Mercator (x) to longitude (WGS 1984)
var lonWGS84 = (xWebMercator / R_MAJOR) * (180 / PI);
Expand All @@ -13,8 +13,22 @@ function webMercatorToWgs1984(geom) {
var latWGS84 =
(Atan(Exp(yWebMercator / R_MAJOR)) * 2 - PI / 2) * (180 / PI);

return {
x: lonWGS84,
y: latWGS84,
};
return [lonWGS84, latWGS84];
}

function webMercatorToWgs1984(geom) {
if (geom.type == "Point") {
// Web Mercator coordinates
var xWebMercator = geom.x;
var yWebMercator = geom.y;

var wgsXY = xyWebMercatorToWgs1984([xWebMercator, yWebMercator]);

return {
x: wgsXY[0],
y: wgsXY[1],
};
}

return null;
}
Loading

0 comments on commit 86c93c4

Please sign in to comment.