Skip to main content
Version: 1.4.3.X

Validate Drawn Shapes Against a Layer (Intersection Check)

This tutorial shows how to validate a user-drawn shape against a target layer and block save when an intersection is found.

You will:

  1. Listen for ShapeDrawingCompleted.
  2. Query features from a target sublayer instance near the drawn shape.
  3. Use Turf booleanIntersects to test geometry overlap.
  4. Show a warning to the user when an intersection is detected.
  5. Enforce the rule using Custom Validation.

This pattern is useful for zoning, protected areas, exclusion zones, easements, and service boundaries.

Use Case Context: Block Drawings in Restricted Areas

Assume users can draw service areas on a record form map. Your business rule is:

  • If the drawn shape intersects any restricted area layer feature, notify the user.
  • Prevent save while the intersection condition is true.

This ensures invalid geometry is identified immediately and cannot be submitted.


Prerequisites

Before you begin, make sure you have:

  • A record-level map where users can draw shapes.
  • A target ArcGIS/feature layer available on the map (the layer you want to check intersections against).
  • Access to Custom JavaScript and Custom Validation in your configuration profile.
  • Familiarity with Shape events.
  • Familiarity with Layer functions.
  • Familiarity with Enabled sublayer instances.

By the end of this tutorial, you will be able to:

  • Detect intersections between a drawn shape and a configured layer.
  • Notify users with a form-level warning message.
  • Block save when the geometry rule is violated.

To get started quickly, add this script to the Custom Code tab in your configuration profile.

For more complex implementations, store your JavaScript in a managed source location so it can be version-controlled and maintained with your broader solution.

If you host the script externally, make sure you either initialize it from the Custom Code section or wait until the map control has loaded before running it.

For more details, see Custom Code configuration.

Step 1: Get the Target sublayerInstanceId

The intersection query must use a sublayer instance ID, not a layer ID.

If you do not already have it, inspect enabled sublayer instances:

const control = globalThis.MaptaskrControlManager.getControl(controlId);
const instances = await control.getEnabledSublayerInstances();

Copy the correct sublayerInstanceId for the layer you want to validate against.


Step 2: Add Custom JavaScript (Intersection Detection)

Add the following script to your Custom JS area.

Update the value below if your target layer uses a different sublayerInstanceId.

// Get Maptaskr control
const control = globalThis.MaptaskrControlManager.getControl(controlId);

// IMPORTANT: this must be a SUBLAYER INSTANCE ID, not a SUBLAYER ID. This can be found in your Preloaded layers in Config Profile
const intersectSublayerInstanceId = 'be4b6bf1-1c7b-4589-b3d4-321260d1c752';

// Get Turf and Geo helpers from the control
const turf = control.getTurfHelper();
const geoHelper = control.getGeoHelper();

// Validation flag used by Custom Validation
globalThis.intersects = false;

const validateDrawnShape = async (shapeName, geojson, shapeId) => {
// Reset state and clear existing notification
globalThis.intersects = false;
Xrm.Page.ui.clearFormNotification('shape_intersection');

const geojsonObject = typeof geojson === 'string' ? JSON.parse(geojson) : geojson;
const shapeFeatures = geojsonObject?.features || [];

for (const shapeFeature of shapeFeatures) {
const geometry = shapeFeature?.geometry;
if (!geometry) continue;

// Query only features near the drawn geometry extent
const extent = geoHelper.calculateExtent(geometry);

const featuresInExtent = await control.querySublayerInstanceData(
intersectSublayerInstanceId,
extent,
1,
undefined,
undefined,
undefined,
true,
undefined,
);

const layerFeatures = featuresInExtent?.features || [];

for (const layerFeature of layerFeatures) {
const layerGeometry = layerFeature?.geometry;
if (!layerGeometry) continue;

const intersects = turf.booleanIntersects(geometry, layerGeometry);
if (intersects) {
globalThis.intersects = true;
Xrm.Page.ui.setFormNotification(
'Your shape intersects with an area of interest.',
'WARNING',
'shape_intersection',
);
return;
}
}
}

// If no intersections were found, ensure notification is clear
Xrm.Page.ui.clearFormNotification('shape_intersection');
};

// Validate whenever a shape is finished
control.on('ShapeDrawingCompleted', (shapeName, geojson, shapeId) => {
validateDrawnShape(shapeName, geojson, shapeId);
});

Step 3: Add Custom Validation (Block Save)

Add this to your Custom Validation section:

if (globalThis.intersects) {
return false;
}

return true;

When false is returned, save is blocked.


Step 4: Test the Flow

  1. Open a record form that uses your configured map profile.
  2. Draw a shape that should intersect your target layer.
  3. Confirm you see the warning notification.
  4. Try to save the record and confirm save is blocked.
  5. Draw a shape that does not intersect and confirm save succeeds.

Troubleshooting

No warning appears:

  • Verify you used a valid sublayerInstanceId (not layerId).
  • Confirm the target layer instance is enabled in the map profile.
  • Confirm ShapeDrawingCompleted is firing (add console.log in the handler).

Save is blocked even when shapes do not intersect:

  • Confirm globalThis.intersects is reset to false before each validation.
  • Confirm you clear shape_intersection notification when no intersection is found.

No features are returned from query:

  • Check that the target layer has data in the map extent.
  • Confirm the layer is visible and accessible for the current user.

Next Improvements

You can extend this pattern by:

  • Allowing intersections for specific feature categories only (via search filters).
  • Replacing the warning with richer guidance (for example, show the conflicting zone name).
  • Running additional geometry checks like containment (booleanWithin) or overlap-only logic (booleanOverlap).