Skip to content

Line symbol shows where user clicked #488

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 8 commits into from
Nov 25, 2024
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
47 changes: 26 additions & 21 deletions src/addGraphicsToLayer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}
}
140 changes: 45 additions & 95 deletions src/layers/MilepostLayer/index.ts
Original file line number Diff line number Diff line change
@@ -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<ConstructorParameters<typeof Field>>[0];

Expand All @@ -25,7 +19,7 @@ export enum fieldNames {
Direction = "Direction",
}

const fields = [
export const fields = [
{
name: objectIdFieldName,
type: "oid",
Expand Down Expand Up @@ -86,101 +80,57 @@ 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;
}

/**
* 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(),
});
function createAndAddFieldInfoForExpression(
milepostExpressionInfo: MilepostExpressionInfo,
) {
const fieldInfo = new FieldInfo({
fieldName: `expression/${milepostExpressionInfo.name}`,
visible: !["webMercatorToWgs1984", "milepostLabel"].includes(
milepostExpressionInfo.name,
),
});
return fieldInfo;
}

const actions = createActionButtons();
popupTemplate.actions = actions;
/**
* 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.
*/
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.
visibleFieldNames: new Set(),
});

// Import the Arcade expressions, add them to the popup template, and then
// add them to the popup template's fieldInfos array.
popupTemplate.expressionInfos = arcadeExpressions;
const actions = createActionButtons();
popupTemplate.actions = actions;

// 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}";
// Import the Arcade expressions, add them to the popup template, and then
// add them to the popup template's fieldInfos array.
popupTemplate.expressionInfos = arcadeExpressions;

if (Array.isArray(popupTemplate.content)) {
popupTemplate.content = [locationLinksContent, ...popupTemplate.content];
// 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];
}
/**
* 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();
milepostLayer.popupTemplate = createPopupTemplate();
milepostLayer.popupTemplate = popupTemplate;

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;
return popupTemplate;
}
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import MilepostLocationRenderer from "./Milepost Location Renderer.json";
import SimpleRenderer from "@arcgis/core/renderers/SimpleRenderer";

/**
* Simple Renderer using a CIM symbol.
*/
export default SimpleRenderer.fromJSON(MilepostLocationRenderer);
38 changes: 38 additions & 0 deletions src/layers/MilepostLayer/milepost-line-layer/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import FeatureLayer from "@arcgis/core/layers/FeatureLayer";
import { createPopupTemplate, fields } from "..";
import waExtent from "../../../WAExtent";
import { objectIdFieldName } from "../../../elc/types";
import MilepostOffsetLineRenderer from "./MilepostOffsetLineRenderer";

/**
* 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 = createPopupTemplate(lineLayer);

return lineLayer;
}
60 changes: 60 additions & 0 deletions src/layers/MilepostLayer/milepost-point-layer/index.ts
Original file line number Diff line number Diff line change
@@ -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;
}
Loading