Configuring Custom.JS
Below is a snippet of the Custom.JS code for your reference:
/* place your custom JS Code here. */
const onValidateFailErrorMessage = 'Please upload a file or draw a shape'; //error message to display when the map validation errors
const onUploadFailErrorMessage = 'Something has gone wrong during submission, please check your connection and try again.';
const onIntersectionMessage = 'Intersections / Exclusions have been found, please check your shapes and try again.';
async function clientValidationFunction(executionContext, controlId) {
//user defined validation function, can use the following for getting the list of shapes, annotations and uploaded files.
//if the user needs to fix the shapes, throw an error.
console.log('Validating shapes with:');
console.log(executionContext);
console.log(controlId);
let maptaskrControl = globalThis && globalThis.top && globalThis.top.maptaskrCORE && globalThis.top.maptaskrCORE[controlId];
if (!maptaskrControl) {
console.error('Maptaskr Control not found');
return;
}
//let shapes = _getShapes();
//let annotation = _getAnnotation();
//let uploads = _getUploadedFiles();
//testing shape intersections and determine what to do with them
const shapeIntersections = await maptaskrControl.getShapeIntersections();
if (shapeIntersections && shapeIntersections.length > 0) {
if (shapeIntersections.some((res) => res.intersectionType == 'Warning')) {
//decide what to do with warnings
//if you want them resolved, throw an error here..
//throw new Error(onIntersectionMessage);
}
if (shapeIntersections.some((res) => res.intersectionType == 'Error')) {
//decide what to do with warnings
//if you want them resolved, throw an error here..
throw new Error(onIntersectionMessage);
}
if (shapeIntersections.some((res) => res.intersectionType == 'Exclusion')) {
//decide what to do with warnings
//if you want them resolved, throw an error here..
throw new Error(onIntersectionMessage);
}
}
//you can also test to make sure your shapes are in the correct position, orintation, contained within eachother, any geometric tests here.
//shapes will come in the format:
// {
// "type": "FeatureCollection",
// "features": [
// {
// "type": "Feature",
// "geometry": {
// "type": "Polygon",
// "coordinates": [
// [
// [
// 12899598.276481498,
// -3758060.96802893
// ],
// ...
// ]
// ]
// },
// "properties": {
// "uploadDocType": "Envelope",
// "markerType": "MARKER_SHAPE"
// }
// }
// ],
// "DocumentType": "Envelope",
// "annotationId": "1ffb72d6-c7c3-ed11-83fd-002248e1bcf1",
// "longlat": [
// 12899440.776481498,
// -3758143.46802893
// ],
// "styleProperty": {
// "geometry_": null,
// "fill_": {
// "color_": "rgba(149,255,0,0.1)"
// },
// ...
// }
// }
//if you require a specific subset of objects, please look into the shapes, annotations, or uploads to ensure specific number of shapes or named shapes are included.
}
if (globalThis && globalThis.top) {
globalThis.top.maptaskrReady = function (pageContext, controlId) {
console.log('Maptaskr Map ID: ' + controlId + ' has Loaded');
let maptaskrControl = globalThis && globalThis.top && globalThis.top.maptaskrCORE && globalThis.top.maptaskrCORE[controlId];
if (maptaskrControl) {
/* Use the following console logs to uniquely identify your map */
// console.log(pageContext);
// console.log(maptaskrControl.registeredLocation);
// console.log(maptaskrControl.webresourceLocation);
/* register the correct client validation function here */
maptaskrControl.clientValidationFunction = clientValidationFunction;
/* put your setup methods here */
/* e.g. maptaskrControl.disableSaving = true; - this will disable the inbuilt save methods, you an use maptaskrControl.saveShapes() to save your own shapes.*/
/* put your event registrations here. */
/* e.g. maptaskrControl.on("FeaturesSelected", ...) */
}
};
}
At the very bottom of the file, let's declare a variable that we will use to control an Interval
.
let layerWatcher;
Next, we need to add a three new functions at the bottom of the file that will be responsible for disabling the checkbox for a given layer and turning it off if you happen to zoom past the threshold with the layer on.
enableLayer
accepts a name
parameter which is the display name of the Layer we would like to enable.
disableAndTurnOffLayer
accepts accepts a name
parameter which is the display name of the Layer we would like to turn off and disable.
enableDisableLayer
is the main function that accepts a enabled
boolean parameter and a name
parameter which will determine which layer to enable/disable and turn off.
You can tweak this to your specifications
function enableDisableLayer(enabled, name) {
return new Promise((resolve, reject) => {
//remove any instance of the interval
clearInterval(layerWatcher);
//cancel the interval if layer not found in 10000 ms (10 sec)
setTimeout(() => {
clearInterval(layerWatcher);
reject();
}, 10000);
layerWatcher = setInterval(() => {
console.log('watching...');
let layer = $('label').filter((l, lab) => {
return lab.innerText.indexOf(name) > -1;
});
if (layer.length > 0) {
console.log('found!');
let checkbox = layer.parent().parent().find('input[type=checkbox]');
if (enabled) {
checkbox[0].disabled = false;
} else {
//if the layer is checked/ticked and on, let's turn it off
if (checkbox[0].checked) checkbox.click();
checkbox[0].disabled = true;
}
clearInterval(layerWatcher);
setTimeout(() => {
resolve();
}, 50);
}
}, 50);
});
}
function enableLayer(name) {
return enableDisableLayer(true, name);
}
function disableAndTurnOffLayer(name) {
return enableDisableLayer(false, name);
}
Now we need to register the appropriate extension function within the maptaskrReady
functional scope. For this, we will use the ZoomChanged event to ensure we fire enableLayer
or disableAndTurnOffLayer
only if the correct zoom threshold has been met. In this case we will use a layer called Single RoadAssets_DataPortal
.
As shown in the highlighted code snippet below, we first manually fire a ZoomChanged
event when the map is ready to ensure that the given layer is enabled/disabled at the very beginning. This is helpful in situations, for example, where the default zoom is set to be quite far out and a given layer needs to be available only when the zoom is closer.
Then below that we listen to ZoomChanged
events and if the zoom is greater or equal to 12, we want to enable our Single RoadAssets_DataPortal
layer. Likewise, when the zoom is beyond this threshold, we want to disable that layer.
if (globalThis && globalThis.top) {
globalThis.top.maptaskrReady = function (pageContext, controlId) {
console.log('Maptaskr Map ID: ' + controlId + ' has Loaded');
let maptaskrControl = globalThis && globalThis.top && globalThis.top.maptaskrCORE && globalThis.top.maptaskrCORE[controlId];
if (maptaskrControl) {
maptaskrControl.clientValidationFunction = clientValidationFunction;
//To prevent users from being able to select the layer when the map loads, trigger a zoom change
maptaskrControl.fire('ZoomChanged', 5, 5);
maptaskrControl.on('ZoomChanged', async function (previousZoom, newZoom) {
console.log('Zoom Changed from ' + previousZoom + ' to ' + newZoom);
if (newZoom >= 12) {
//turn on layer
await enableLayer('Single RoadAssets_DataPortal');
} else {
//turn it off and/or disable
await disableAndTurnOffLayer('Single RoadAssets_DataPortal');
}
});
}
};
}
Let's see this code in action!
When the map initially loads we are expecting Single RoadAssets_DataPortal
to be disabled. Then, when we zoom in close enough the layer checkbox should become clickable and we can switch it on. Finally, when we zoom out beyond the threshold the layer should automatically turn off and the checkbox should be greyed out and not be clickable until we zoom in again.
Below is a gif demonstrating this functionality:
Success! Using the code snippets above we have successfully listened to the ZoomChanged
event and extended it to call a function that will crawl the DOM to find the appropriate layer and enable/disable them.