From f730591701b84b899a6fe1cdce851646402f6810 Mon Sep 17 00:00:00 2001 From: Jeff Jacobson Date: Tue, 20 Aug 2024 15:34:53 -0700 Subject: [PATCH 1/8] refactor: Add click / SRMP line offset CIM renderer --- .../Milepost Location Renderer.json | 0 .../MilepostLayer/MilepostOffsetLineRenderer.ts | 4 ++++ tests/CIM.test.ts | 11 +++++++++++ 3 files changed, 15 insertions(+) rename src/layers/{ => MilepostLayer}/Milepost Location Renderer.json (100%) create mode 100644 src/layers/MilepostLayer/MilepostOffsetLineRenderer.ts create mode 100644 tests/CIM.test.ts diff --git a/src/layers/Milepost Location Renderer.json b/src/layers/MilepostLayer/Milepost Location Renderer.json similarity index 100% rename from src/layers/Milepost Location Renderer.json rename to src/layers/MilepostLayer/Milepost Location Renderer.json diff --git a/src/layers/MilepostLayer/MilepostOffsetLineRenderer.ts b/src/layers/MilepostLayer/MilepostOffsetLineRenderer.ts new file mode 100644 index 00000000..3ca00c5e --- /dev/null +++ b/src/layers/MilepostLayer/MilepostOffsetLineRenderer.ts @@ -0,0 +1,4 @@ +import MilepostLocationRenderer from "./Milepost Location Renderer.json"; +import Renderer from "@arcgis/core/renderers/Renderer"; + +export default Renderer.fromJSON(MilepostLocationRenderer); diff --git a/tests/CIM.test.ts b/tests/CIM.test.ts new file mode 100644 index 00000000..ef81b4e9 --- /dev/null +++ b/tests/CIM.test.ts @@ -0,0 +1,11 @@ +import renderer from "../src/layers/MilepostLayer/MilepostOffsetLineRenderer"; +import { describe, test } from "vitest"; + +describe.concurrent( + "CIM renderer from JSON exported from ArcGIS Online", + () => { + test("renderer was created successfully", ({ expect }) => { + expect(renderer).toBeDefined(); + }); + }, +); From 28a0faa67a4f280864c9d3d3cacf65f8bb08d38c Mon Sep 17 00:00:00 2001 From: Jeff Jacobson Date: Thu, 22 Aug 2024 13:56:38 -0700 Subject: [PATCH 2/8] refactor: :truck: Moved milepost line layer files into separate folder --- .../{ => milepost-line-layer}/Milepost Location Renderer.json | 0 .../{ => milepost-line-layer}/MilepostOffsetLineRenderer.ts | 0 tests/CIM.test.ts | 2 +- 3 files changed, 1 insertion(+), 1 deletion(-) rename src/layers/MilepostLayer/{ => milepost-line-layer}/Milepost Location Renderer.json (100%) rename src/layers/MilepostLayer/{ => milepost-line-layer}/MilepostOffsetLineRenderer.ts (100%) diff --git a/src/layers/MilepostLayer/Milepost Location Renderer.json b/src/layers/MilepostLayer/milepost-line-layer/Milepost Location Renderer.json similarity index 100% rename from src/layers/MilepostLayer/Milepost Location Renderer.json rename to src/layers/MilepostLayer/milepost-line-layer/Milepost Location Renderer.json diff --git a/src/layers/MilepostLayer/MilepostOffsetLineRenderer.ts b/src/layers/MilepostLayer/milepost-line-layer/MilepostOffsetLineRenderer.ts similarity index 100% rename from src/layers/MilepostLayer/MilepostOffsetLineRenderer.ts rename to src/layers/MilepostLayer/milepost-line-layer/MilepostOffsetLineRenderer.ts diff --git a/tests/CIM.test.ts b/tests/CIM.test.ts index ef81b4e9..6d429356 100644 --- a/tests/CIM.test.ts +++ b/tests/CIM.test.ts @@ -1,4 +1,4 @@ -import renderer from "../src/layers/MilepostLayer/MilepostOffsetLineRenderer"; +import renderer from "../src/layers/MilepostLayer/milepost-line-layer/MilepostOffsetLineRenderer"; import { describe, test } from "vitest"; describe.concurrent( From 08cb04707b091dba34422f706057f307c4f6aa23 Mon Sep 17 00:00:00 2001 From: Jeff Jacobson Date: Thu, 22 Aug 2024 14:41:54 -0700 Subject: [PATCH 3/8] feat: Mileposts located by click now show connecting line --- src/layers/MilepostLayer/index.ts | 2 +- .../MilepostOffsetLineRenderer.ts | 7 ++- .../milepost-line-layer/index.ts | 38 ++++++++++++ src/main.ts | 60 ++++++++++++++----- 4 files changed, 88 insertions(+), 19 deletions(-) create mode 100644 src/layers/MilepostLayer/milepost-line-layer/index.ts diff --git a/src/layers/MilepostLayer/index.ts b/src/layers/MilepostLayer/index.ts index 953ea689..862c237d 100644 --- a/src/layers/MilepostLayer/index.ts +++ b/src/layers/MilepostLayer/index.ts @@ -25,7 +25,7 @@ export enum fieldNames { Direction = "Direction", } -const fields = [ +export const fields = [ { name: objectIdFieldName, type: "oid", diff --git a/src/layers/MilepostLayer/milepost-line-layer/MilepostOffsetLineRenderer.ts b/src/layers/MilepostLayer/milepost-line-layer/MilepostOffsetLineRenderer.ts index 3ca00c5e..ce3914b7 100644 --- a/src/layers/MilepostLayer/milepost-line-layer/MilepostOffsetLineRenderer.ts +++ b/src/layers/MilepostLayer/milepost-line-layer/MilepostOffsetLineRenderer.ts @@ -1,4 +1,7 @@ import MilepostLocationRenderer from "./Milepost Location Renderer.json"; -import Renderer from "@arcgis/core/renderers/Renderer"; +import SimpleRenderer from "@arcgis/core/renderers/SimpleRenderer"; -export default Renderer.fromJSON(MilepostLocationRenderer); +/** + * Simple Renderer using a CIM symbol. + */ +export default SimpleRenderer.fromJSON(MilepostLocationRenderer); diff --git a/src/layers/MilepostLayer/milepost-line-layer/index.ts b/src/layers/MilepostLayer/milepost-line-layer/index.ts new file mode 100644 index 00000000..8e9b4131 --- /dev/null +++ b/src/layers/MilepostLayer/milepost-line-layer/index.ts @@ -0,0 +1,38 @@ +import { fields } from ".."; +import waExtent from "../../../WAExtent"; +import { objectIdFieldName } from "../../../elc/types"; +import MilepostOffsetLineRenderer from "./MilepostOffsetLineRenderer"; +import FeatureLayer from "@arcgis/core/layers/FeatureLayer"; + +/** + * Creates a new feature layer that displays mileposts as lines. + * @param spatialReference - The spatial reference of the layer. + * @returns A new feature layer that displays mileposts as lines. + */ +export function createMilepostLineLayer( + spatialReference = waExtent.spatialReference, +) { + // Make a clone of the milepost point layer, as most of the properties + // will be the same aside from the geometry type and renderer. + const lineLayerProperties: __esri.FeatureLayerProperties = { + geometryType: "polyline", + title: "Near Mileposts", + fields, + objectIdField: objectIdFieldName, + id: "nearMileposts", + listMode: "hide", + fullExtent: waExtent, + spatialReference, + // Since there are no features at the beginning, + // need to add an empty array as the source. + renderer: MilepostOffsetLineRenderer, + source: [], + popupEnabled: true, + hasM: true, + }; + + const lineLayer = new FeatureLayer(lineLayerProperties); + lineLayer.popupTemplate = lineLayer.createPopupTemplate(); + + return lineLayer; +} diff --git a/src/main.ts b/src/main.ts index d835580e..240a9793 100644 --- a/src/main.ts +++ b/src/main.ts @@ -20,12 +20,13 @@ import { accessControlLayer } from "./layers/AccessControlLayer"; import { cityLimitsLayer } from "./layers/CityLimitsLayer"; import "./layers/MilepostLayer"; import { createMilepostLayer } from "./layers/MilepostLayer"; +import { createMilepostLineLayer } from "./layers/MilepostLayer/milepost-line-layer"; import "./layers/TempLayer"; import { tempLayer } from "./layers/TempLayer"; import "./layers/parcels"; import { createParcelsGroupLayer } from "./layers/parcels"; import "./types"; -import { UIAddPositions, isGraphicHit } from "./types"; +import { UIAddPositions, hasXAndY, isGraphicHit } from "./types"; import isInternal from "./urls/isIntranet"; import { setupSidebarCollapseButton } from "./widgets/CollapseButton"; import "./widgets/LayerList"; @@ -37,6 +38,7 @@ import EsriMap from "@arcgis/core/Map"; import Viewpoint from "@arcgis/core/Viewpoint"; import config from "@arcgis/core/config"; import { whenOnce } from "@arcgis/core/core/reactiveUtils"; +import Polyline from "@arcgis/core/geometry/Polyline"; import PortalItem from "@arcgis/core/portal/PortalItem"; import MapView from "@arcgis/core/views/MapView"; import Expand from "@arcgis/core/widgets/Expand"; @@ -283,6 +285,7 @@ if (!testWebGL2Support()) { * @returns - a promise that resolves to an array of {@link RouteLocation|RouteLocations} */ async function callFindNearestRouteLocation(event: __esri.ViewClickEvent) { + /* __PURE__ */ console.group(callFindNearestRouteLocation.name); const { x, y, spatialReference } = event.mapPoint; const locations = await findNearestRouteLocations({ coordinates: [x, y], @@ -298,7 +301,23 @@ if (!testWebGL2Support()) { } const locationGraphic = routeLocationToGraphic(location); - addGraphicsToLayer(milepostLayer, [locationGraphic]) + if (hasXAndY(locationGraphic.geometry)) { + const { x: routeX, y: routeY } = locationGraphic.geometry; + locationGraphic.geometry = new Polyline({ + paths: [ + [ + [x, y], + [routeX, routeY], + ], + ], + spatialReference, + }); + } + const layer = + locationGraphic.geometry.type === "point" + ? milepostPointLayer + : milepostLineLayer; + addGraphicsToLayer(layer, [locationGraphic]) .then((addResults) => { /* __PURE__ */ console.debug( "addResults returned by addGraphicsToLayer", @@ -308,7 +327,6 @@ if (!testWebGL2Support()) { .catch((error: unknown) => { console.error("addGraphicsToLayer failed", error); }); - return locations; } @@ -325,10 +343,11 @@ if (!testWebGL2Support()) { } request.httpsDomains.push("wsdot.wa.gov", "data.wsdot.wa.gov"); - const milepostLayer = createMilepostLayer(waExtent.spatialReference); + const milepostPointLayer = createMilepostLayer(waExtent.spatialReference); + const milepostLineLayer = createMilepostLineLayer(waExtent.spatialReference); // Show the instructions alert once the mileposts layer has been loaded. - milepostLayer.on("layerview-create", () => { + milepostPointLayer.on("layerview-create", () => { const alert = document.body.querySelector( "#instructionsAlert", @@ -355,7 +374,13 @@ if (!testWebGL2Support()) { const map = new EsriMap({ basemap: grayBasemap, - layers: [cityLimitsLayer, accessControlLayer, tempLayer, milepostLayer], + layers: [ + cityLimitsLayer, + accessControlLayer, + tempLayer, + milepostPointLayer, + milepostLineLayer, + ], }); map.add(createParcelsGroupLayer()); @@ -461,7 +486,7 @@ if (!testWebGL2Support()) { import("./widgets/ClearButton").then( ({ createClearButton }) => { const clearButton = createClearButton({ - layers: [milepostLayer, tempLayer], + layers: [milepostPointLayer, milepostLineLayer, tempLayer], }); view.ui.add([home, clearButton], UIAddPositions.topLeading); }, @@ -512,6 +537,9 @@ if (!testWebGL2Support()) { // Call findNearestRouteLocations try { await callFindNearestRouteLocation(event); + removeTempGraphic().catch((reason: unknown) => { + console.error("Failed to remove temporary graphic", reason); + }); } catch (error) { const message = "Could not find a route location near this location."; @@ -542,16 +570,16 @@ if (!testWebGL2Support()) { * Removes the temporary graphic. * @returns - a promise that resolves when the graphic is removed. */ - const removeTempGraphic = () => { + function removeTempGraphic() { // Remove the temporary graphic return tempLayer.applyEdits({ deleteFeatures: [tempGraphic], }); - }; + } }; view .hitTest(event, { - include: milepostLayer, + include: [milepostPointLayer, milepostLineLayer], }) .then(handleHitTestResult) .catch((reason: unknown) => { @@ -562,18 +590,18 @@ if (!testWebGL2Support()) { // Set up the form for inputting SRMPdata. import("./setupForm") - .then(({ setupForm }) => setupForm(view, milepostLayer)) + .then(({ setupForm }) => setupForm(view, milepostPointLayer)) .catch((reason: unknown) => { console.error("failed to setup form", reason); }); if (import.meta.env.DEV) { - milepostLayer + milepostPointLayer .when(async () => { const { createExportButton } = await import("./widgets/ExportButton"); const button = createExportButton({ - layer: milepostLayer, + layer: milepostPointLayer, }); view.ui.add(button, UIAddPositions.bottomTrailing); }) @@ -584,16 +612,16 @@ if (!testWebGL2Support()) { // Once the milepost layerview has been created, check for ELC data from the URL // and, if present, add the location to the map. - milepostLayer.on("layerview-create", () => { + milepostPointLayer.on("layerview-create", () => { /** * Calls the ELC API to retrieve graphics from the URL and adds them to the milepost layer. * @returns A promise that resolves when the graphics have been added to the layer and the view has been updated. */ const callElc = async () => { - const elcGraphics = await callElcFromUrl(milepostLayer); + const elcGraphics = await callElcFromUrl(milepostPointLayer); if (elcGraphics) { const addedFeatures = await addGraphicsToLayer( - milepostLayer, + milepostPointLayer, elcGraphics, ); const scale = Number.parseFloat(import.meta.env.VITE_ZOOM_SCALE); From 4eced33e95644c3496e97e9e627ce0e8d5a8c79e Mon Sep 17 00:00:00 2001 From: Jeff Jacobson Date: Tue, 3 Sep 2024 15:13:53 -0700 Subject: [PATCH 4/8] refactor: :recycle: refactoring --- src/addGraphicsToLayer.ts | 47 ++++++++++++++++++++++----------------- src/main.ts | 13 ++++++++++- 2 files changed, 38 insertions(+), 22 deletions(-) diff --git a/src/addGraphicsToLayer.ts b/src/addGraphicsToLayer.ts index 851747aa..12d27dc6 100644 --- a/src/addGraphicsToLayer.ts +++ b/src/addGraphicsToLayer.ts @@ -11,27 +11,32 @@ export async function addGraphicsToLayer( milepostLayer: FeatureLayer, locationGraphics: Graphic[], ) { - // 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(); - query.objectIds = editsResult.addFeatureResults.map((r) => r.objectId); - const results = await milepostLayer.queryFeatures(query); + /* __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 })), + ); - return results.features; -} + // 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); -if (import.meta.hot) { - import.meta.hot.accept((newModule) => { - if (newModule) { - console.log("hot module replacement", newModule); - } - }); + return results.features; + } finally { + /* __PURE__ */ console.groupEnd(); + } } diff --git a/src/main.ts b/src/main.ts index 240a9793..9226fcca 100644 --- a/src/main.ts +++ b/src/main.ts @@ -209,8 +209,15 @@ const elcMainlinesOnlyFilter = * @param view - The map view. */ function openPopup(hits: __esri.GraphicHit[], view: MapView) { + /* __PURE__ */ console.debug("openPopup", { + hits: hits.map((h) => h.graphic.toJSON() as unknown), + }); + function extractGraphic(graphicHit: __esri.GraphicHit): Graphic { + const { graphic } = graphicHit; + return graphic; + } // Get the features that were hit by the hit test. - const features = hits.map(({ graphic }) => graphic); + const features = hits.map(extractGraphic); const updateUrlSearch = () => { const routeLocation = features .map( @@ -231,6 +238,9 @@ function openPopup(hits: __esri.GraphicHit[], view: MapView) { updateUrlSearchParams(routeLocation); }; + /* __PURE__ */ console.debug("about to open popup", { + features: features.map((f) => f.toJSON() as unknown), + }); view .openPopup({ features, @@ -317,6 +327,7 @@ if (!testWebGL2Support()) { locationGraphic.geometry.type === "point" ? milepostPointLayer : milepostLineLayer; + /* __PURE__ */ console.debug("location graphic", locationGraphic.toJSON()); addGraphicsToLayer(layer, [locationGraphic]) .then((addResults) => { /* __PURE__ */ console.debug( From 9bb221a77b35d6e97172c212cbef74d585dc986b Mon Sep 17 00:00:00 2001 From: Jeff Jacobson Date: Thu, 12 Sep 2024 16:05:50 -0700 Subject: [PATCH 5/8] refactor: :recycle: Moved function to module level --- src/layers/MilepostLayer/index.ts | 108 ++++++++++++++++-------------- 1 file changed, 56 insertions(+), 52 deletions(-) diff --git a/src/layers/MilepostLayer/index.ts b/src/layers/MilepostLayer/index.ts index 862c237d..75714d53 100644 --- a/src/layers/MilepostLayer/index.ts +++ b/src/layers/MilepostLayer/index.ts @@ -86,63 +86,67 @@ function createActionButtons() { } /** - * Creates the {@link FeatureLayer} that displays located mileposts. - * @param spatialReference - The {@link SpatialReference} of the layer. - * @returns - A {@link FeatureLayer} + * A function that creates and adds field information for an expression. + * @param milepostExpressionInfo - The expression information to create the field info for. + * @returns The created field info. */ -export function createMilepostLayer(spatialReference: SpatialReference) { - /** - * A function that creates and adds field information for an expression. - * @param milepostExpressionInfo - The expression information to create the field info for. - * @returns The created field info. - */ - function createAndAddFieldInfoForExpression( - milepostExpressionInfo: MilepostExpressionInfo, - ) { - const fieldInfo = new FieldInfo({ - fieldName: `expression/${milepostExpressionInfo.name}`, - visible: !["webMercatorToWgs1984", "milepostLabel"].includes( - milepostExpressionInfo.name, - ), - }); - return fieldInfo; - } +function createAndAddFieldInfoForExpression( + milepostExpressionInfo: MilepostExpressionInfo, +) { + const fieldInfo = new FieldInfo({ + fieldName: `expression/${milepostExpressionInfo.name}`, + visible: !["webMercatorToWgs1984", "milepostLabel"].includes( + milepostExpressionInfo.name, + ), + }); + return fieldInfo; +} - /** - * Creates a popup template for the milepost layer by hiding certain fields and adding arcade expressions. - * @returns The created popup template. - */ - function createPopupTemplate() { - const popupTemplate = milepostLayer.createPopupTemplate({ - // Hide all of the initial fields. - // These fields are already displayed in the popup's title. - visibleFieldNames: new Set(), - }); - - const actions = createActionButtons(); - popupTemplate.actions = actions; - - // Import the Arcade expressions, add them to the popup template, and then - // add them to the popup template's fieldInfos array. - popupTemplate.expressionInfos = arcadeExpressions; - - // Append expressions to the PopupTemplate's fieldInfos array. - for (const xi of arcadeExpressions) { - const fieldInfo = createAndAddFieldInfoForExpression(xi); - // Hide the GeoURI and SRViewURL fields. - if (["geoURI"].includes(xi.name)) { - fieldInfo.visible = false; - } - popupTemplate.fieldInfos.push(fieldInfo); - } - popupTemplate.title = "{Route} ({Direction}) @ {expression/milepostLabel}"; +/** + * Creates a popup template for the milepost layer by hiding certain fields and adding arcade expressions. + * @param milepostLayer - The milepost layer. + * @returns The created popup template. + */ +function createPopupTemplate(milepostLayer: FeatureLayer) { + const popupTemplate = milepostLayer.createPopupTemplate({ + // Hide all of the initial fields. + // These fields are already displayed in the popup's title. + visibleFieldNames: new Set(), + }); + + const actions = createActionButtons(); + popupTemplate.actions = actions; - if (Array.isArray(popupTemplate.content)) { - popupTemplate.content = [locationLinksContent, ...popupTemplate.content]; + // Import the Arcade expressions, add them to the popup template, and then + // add them to the popup template's fieldInfos array. + popupTemplate.expressionInfos = arcadeExpressions; + + // Append expressions to the PopupTemplate's fieldInfos array. + for (const xi of arcadeExpressions) { + const fieldInfo = createAndAddFieldInfoForExpression(xi); + // Hide the GeoURI and SRViewURL fields. + if (["geoURI"].includes(xi.name)) { + fieldInfo.visible = false; } + popupTemplate.fieldInfos.push(fieldInfo); + } + popupTemplate.title = "{Route} ({Direction}) @ {expression/milepostLabel}"; - return popupTemplate; + if (Array.isArray(popupTemplate.content)) { + popupTemplate.content = [locationLinksContent, ...popupTemplate.content]; } + + milepostLayer.popupTemplate = popupTemplate; + + return popupTemplate; +} + +/** + * Creates the {@link FeatureLayer} that displays located mileposts. + * @param spatialReference - The {@link SpatialReference} of the layer. + * @returns - A {@link FeatureLayer} + */ +export function createMilepostLayer(spatialReference: SpatialReference) { /** * This is the symbol for the point on the route. */ @@ -164,7 +168,7 @@ export function createMilepostLayer(spatialReference: SpatialReference) { }); milepostLayer.renderer = createRenderer(); - milepostLayer.popupTemplate = createPopupTemplate(); + createPopupTemplate(milepostLayer); return milepostLayer; } From 5cf7829a11473930bb809b5286b5ba016c32e6e5 Mon Sep 17 00:00:00 2001 From: Jeff Jacobson Date: Thu, 17 Oct 2024 17:09:15 -0700 Subject: [PATCH 6/8] chore: :truck: moved ArcGIS style file --- .../milepost-line-layer/LocateMP.stylx | Bin 1 file changed, 0 insertions(+), 0 deletions(-) rename LocateMP.stylx => src/layers/MilepostLayer/milepost-line-layer/LocateMP.stylx (100%) diff --git a/LocateMP.stylx b/src/layers/MilepostLayer/milepost-line-layer/LocateMP.stylx similarity index 100% rename from LocateMP.stylx rename to src/layers/MilepostLayer/milepost-line-layer/LocateMP.stylx From a6c13691c2e734c7567ed84332060c8d7608d433 Mon Sep 17 00:00:00 2001 From: Jeff Jacobson Date: Mon, 25 Nov 2024 14:31:11 -0800 Subject: [PATCH 7/8] refactor: :recycle: move milepost-point-layer to own folder --- src/layers/MilepostLayer/index.ts | 58 +----------------- .../milepost-point-layer/index.ts | 60 +++++++++++++++++++ src/main.ts | 7 ++- src/types.ts | 2 +- 4 files changed, 68 insertions(+), 59 deletions(-) create mode 100644 src/layers/MilepostLayer/milepost-point-layer/index.ts diff --git a/src/layers/MilepostLayer/index.ts b/src/layers/MilepostLayer/index.ts index 75714d53..60e43fe9 100644 --- a/src/layers/MilepostLayer/index.ts +++ b/src/layers/MilepostLayer/index.ts @@ -1,20 +1,14 @@ import Collection from "@arcgis/core/core/Collection"; -import type SpatialReference from "@arcgis/core/geometry/SpatialReference"; -import FeatureLayer from "@arcgis/core/layers/FeatureLayer"; +import type FeatureLayer from "@arcgis/core/layers/FeatureLayer"; import type Field from "@arcgis/core/layers/support/Field"; import FieldInfo from "@arcgis/core/popup/FieldInfo"; -import SimpleRenderer from "@arcgis/core/renderers/SimpleRenderer"; import ActionButton from "@arcgis/core/support/actions/ActionButton"; -import { SimpleMarkerSymbol } from "@arcgis/core/symbols"; -import waExtent from "../../WAExtent"; -import { highwaySignBackgroundColor, highwaySignTextColor } from "../../colors"; import { objectIdFieldName } from "../../elc/types"; import type { MilepostExpressionInfo } from "./arcade"; import { expressions as arcadeExpressions, locationLinksContent, } from "./arcade"; -import labelClass from "./labelClass"; type FieldProperties = Required>[0]; @@ -107,7 +101,7 @@ function createAndAddFieldInfoForExpression( * @param milepostLayer - The milepost layer. * @returns The created popup template. */ -function createPopupTemplate(milepostLayer: FeatureLayer) { +export function createPopupTemplate(milepostLayer: FeatureLayer) { const popupTemplate = milepostLayer.createPopupTemplate({ // Hide all of the initial fields. // These fields are already displayed in the popup's title. @@ -140,51 +134,3 @@ function createPopupTemplate(milepostLayer: FeatureLayer) { return popupTemplate; } - -/** - * Creates the {@link FeatureLayer} that displays located mileposts. - * @param spatialReference - The {@link SpatialReference} of the layer. - * @returns - A {@link FeatureLayer} - */ -export function createMilepostLayer(spatialReference: SpatialReference) { - /** - * This is the symbol for the point on the route. - */ - const milepostLayer = new FeatureLayer({ - labelingInfo: [labelClass], - title: "Mileposts", - id: "mileposts", - listMode: "hide", - fields: fields, - geometryType: "point", - objectIdField: objectIdFieldName, - fullExtent: waExtent, - spatialReference, - // Since there are no features at the beginning, - // need to add an empty array as the source. - source: [], - popupEnabled: true, - hasM: true, - }); - - milepostLayer.renderer = createRenderer(); - createPopupTemplate(milepostLayer); - - return milepostLayer; -} -function createRenderer() { - const actualMPSymbol = new SimpleMarkerSymbol({ - color: highwaySignBackgroundColor, - size: 12, - style: "circle", - outline: { - width: 1, - color: highwaySignTextColor, - }, - }); - - const renderer = new SimpleRenderer({ - symbol: actualMPSymbol, - }); - return renderer; -} diff --git a/src/layers/MilepostLayer/milepost-point-layer/index.ts b/src/layers/MilepostLayer/milepost-point-layer/index.ts new file mode 100644 index 00000000..6c0b6275 --- /dev/null +++ b/src/layers/MilepostLayer/milepost-point-layer/index.ts @@ -0,0 +1,60 @@ +import type SpatialReference from "@arcgis/core/geometry/SpatialReference"; +import FeatureLayer from "@arcgis/core/layers/FeatureLayer"; +import SimpleRenderer from "@arcgis/core/renderers/SimpleRenderer"; +import { SimpleMarkerSymbol } from "@arcgis/core/symbols"; +import { createPopupTemplate, fields } from ".."; +import waExtent from "../../../WAExtent"; +import { + highwaySignBackgroundColor, + highwaySignTextColor, +} from "../../../colors"; +import { objectIdFieldName } from "../../../elc/types"; +import labelClass from "../labelClass"; + +/** + * Creates the {@link FeatureLayer} that displays located mileposts. + * @param spatialReference - The {@link SpatialReference} of the layer. + * @returns - A {@link FeatureLayer} + */ +export function createMilepostPointLayer(spatialReference: SpatialReference) { + /** + * This is the symbol for the point on the route. + */ + const milepostLayer = new FeatureLayer({ + labelingInfo: [labelClass], + title: "Mileposts", + id: "mileposts", + listMode: "hide", + fields: fields, + geometryType: "point", + objectIdField: objectIdFieldName, + fullExtent: waExtent, + spatialReference, + // Since there are no features at the beginning, + // need to add an empty array as the source. + source: [], + popupEnabled: true, + hasM: true, + }); + + milepostLayer.renderer = createRenderer(); + createPopupTemplate(milepostLayer); + + return milepostLayer; +} +function createRenderer() { + const actualMPSymbol = new SimpleMarkerSymbol({ + color: highwaySignBackgroundColor, + size: 12, + style: "circle", + outline: { + width: 1, + color: highwaySignTextColor, + }, + }); + + const renderer = new SimpleRenderer({ + symbol: actualMPSymbol, + }); + return renderer; +} diff --git a/src/main.ts b/src/main.ts index 9226fcca..faee0928 100644 --- a/src/main.ts +++ b/src/main.ts @@ -19,8 +19,8 @@ import "./layers/AccessControlLayer"; import { accessControlLayer } from "./layers/AccessControlLayer"; import { cityLimitsLayer } from "./layers/CityLimitsLayer"; import "./layers/MilepostLayer"; -import { createMilepostLayer } from "./layers/MilepostLayer"; import { createMilepostLineLayer } from "./layers/MilepostLayer/milepost-line-layer"; +import { createMilepostPointLayer } from "./layers/MilepostLayer/milepost-point-layer"; import "./layers/TempLayer"; import { tempLayer } from "./layers/TempLayer"; import "./layers/parcels"; @@ -59,6 +59,7 @@ import("./setupAnalytics") .then(({ default: a }) => { /* __PURE__ */ console.debug("Tag Manager loaded", a); analytics = a; + analytics?.page(); }) .catch((reason) => { console.error("Failed to load Tag Manager", reason); @@ -354,7 +355,9 @@ if (!testWebGL2Support()) { } request.httpsDomains.push("wsdot.wa.gov", "data.wsdot.wa.gov"); - const milepostPointLayer = createMilepostLayer(waExtent.spatialReference); + const milepostPointLayer = createMilepostPointLayer( + waExtent.spatialReference, + ); const milepostLineLayer = createMilepostLineLayer(waExtent.spatialReference); // Show the instructions alert once the mileposts layer has been loaded. diff --git a/src/types.ts b/src/types.ts index a1721bb3..7594377e 100644 --- a/src/types.ts +++ b/src/types.ts @@ -60,7 +60,7 @@ export interface TypedGraphic< * false otherwise. */ export function isGraphicHit( - viewHit: __esri.ViewHit, + viewHit: __esri.MapViewViewHit, ): viewHit is __esri.GraphicHit { return viewHit.type === "graphic"; } From f5008ac017ccb2e09dd1e449ab69fac5793069fc Mon Sep 17 00:00:00 2001 From: Jeff Jacobson Date: Mon, 25 Nov 2024 14:35:17 -0800 Subject: [PATCH 8/8] feat: :sparkles: Line layer now has same popup template as point layer --- .../milepost-line-layer/index.ts | 48 +++++++++---------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/src/layers/MilepostLayer/milepost-line-layer/index.ts b/src/layers/MilepostLayer/milepost-line-layer/index.ts index 8e9b4131..a72aa12a 100644 --- a/src/layers/MilepostLayer/milepost-line-layer/index.ts +++ b/src/layers/MilepostLayer/milepost-line-layer/index.ts @@ -1,8 +1,8 @@ -import { fields } from ".."; +import FeatureLayer from "@arcgis/core/layers/FeatureLayer"; +import { createPopupTemplate, fields } from ".."; import waExtent from "../../../WAExtent"; import { objectIdFieldName } from "../../../elc/types"; import MilepostOffsetLineRenderer from "./MilepostOffsetLineRenderer"; -import FeatureLayer from "@arcgis/core/layers/FeatureLayer"; /** * Creates a new feature layer that displays mileposts as lines. @@ -10,29 +10,29 @@ import FeatureLayer from "@arcgis/core/layers/FeatureLayer"; * @returns A new feature layer that displays mileposts as lines. */ export function createMilepostLineLayer( - spatialReference = waExtent.spatialReference, + spatialReference = waExtent.spatialReference, ) { - // Make a clone of the milepost point layer, as most of the properties - // will be the same aside from the geometry type and renderer. - const lineLayerProperties: __esri.FeatureLayerProperties = { - geometryType: "polyline", - title: "Near Mileposts", - fields, - objectIdField: objectIdFieldName, - id: "nearMileposts", - listMode: "hide", - fullExtent: waExtent, - spatialReference, - // Since there are no features at the beginning, - // need to add an empty array as the source. - renderer: MilepostOffsetLineRenderer, - source: [], - popupEnabled: true, - hasM: true, - }; + // Make a clone of the milepost point layer, as most of the properties + // will be the same aside from the geometry type and renderer. + const lineLayerProperties: __esri.FeatureLayerProperties = { + geometryType: "polyline", + title: "Near Mileposts", + fields, + objectIdField: objectIdFieldName, + id: "nearMileposts", + listMode: "hide", + fullExtent: waExtent, + spatialReference, + // Since there are no features at the beginning, + // need to add an empty array as the source. + renderer: MilepostOffsetLineRenderer, + source: [], + popupEnabled: true, + hasM: true, + }; - const lineLayer = new FeatureLayer(lineLayerProperties); - lineLayer.popupTemplate = lineLayer.createPopupTemplate(); + const lineLayer = new FeatureLayer(lineLayerProperties); + lineLayer.popupTemplate = createPopupTemplate(lineLayer); - return lineLayer; + return lineLayer; }