Skip to main content

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 subsubLayerWatcher;

Next, we need to add a new function at the bottom of the file that will be responsible for matching a given sub-layer name against what's available in the DOM and clicking the check-box to toggle the layer on.

This function accepts a name parameter which is the name of the sub-layer we would like to toggle on. Then it waits 10 seconds for the parent layer to load, if the layer doesn't load within 10 seconds it cancels the function.

note

You can tweak this to your specifications

Next, there's a 100ms interval that will watch the DOM to find a label that matches the sub-layer name provided. Once the sub-layer has been found, it finds the respective checkbox element and executes click() on it to toggle the layer. Finally, it clears the interval and completes the execution.

function turnOnLayerByName(name) {
return new Promise((resolve, reject) => {
//wait for layer to load...
clearInterval(subsubLayerWatcher);

//cancel the interval if layernot found in 10000 ms (10 sec)
setTimeout(() => {
clearInterval(subsubLayerWatcher);
reject();
}, 10000);

//enable the sub (or sub sub layer of choice)
subsubLayerWatcher = setInterval(() => {
console.log('watching...');
let subSubLayer = $('label').filter((l, lab) => {
return lab.innerText.indexOf(name) > -1;
});
if (subSubLayer.length > 0) {
console.log('found!');
subSubLayer.parent().parent().find('input[type=checkbox]').click();
clearInterval(subsubLayerWatcher);
setTimeout(() => {
resolve();
}, 500);
}
}, 100);
});
}

Now we need to register the appropriate extension function within the maptaskrReady functional scope. For this, we will use the LayerSelected event to ensure we fire turnOnLayerByName only if the correct parent layer has been turned on. In this case we will use a parent layer called SLIP_Public_Services.

As shown in the highlighted code snippet below, we check that the parent layer's name is SLIP_Public_Services. If this is the case, we call our function turnOnLayerByName with the desired sub-layer names. In this scenario we are turning on a layer that is 3 sub-layers deep. We achieve this by enabling each subsequent layer down the layer tree. THe code below will wait for the parent layer SLIP_Public_Services to be enabled and then turn on the sub-layer named Juvenile Period for Slow-Maturing Serotinous Obligate-Seeder Plant Species - SW of WA. Then we turn on the sub-sub-layer called Juvenile Period in Slow-Maturing Plants (2090 RCP 8.5) - SW of WA (DBCA-076) and finally toggling on the sub-sub-sub-layer called 2x Juvenile period in years which contains data that can be rendered on the map.

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;
maptaskrControl.on('LayerSelected', async function (layerGroupID, layerID, checked) {
if (checked && layerID == 'SLIP_Public_Services') {
//turn on sub layer
await turnOnLayerByName('Juvenile Period for Slow-Maturing Serotinous Obligate-Seeder Plant Species - SW of WA');
//turn on sub sub layer
await turnOnLayerByName('Juvenile Period in Slow-Maturing Plants (2090 RCP 8.5) - SW of WA (DBCA-076)');
//turn on sub sub sub layer
await turnOnLayerByName('2x Juvenile period in years');
}
});
}
};
}

Let's see this code in action!

First we turn on the SLIP_Public_Services parent layer and wait for it to load. When this parent layer is toggled you should notice in the developer console a number of outputs informing you that the function is watching for the sub-layer name and a found! output when it finds the given sub-layer name.

As you can see below we're getting three instances of found! which is what we are expecting.

Below is a gif demonstrating this functionality:

Success! Using the code snippets above we have successfully listened to the LayerSelected event and extended it to call a function that will crawl the DOM to find the appropriate sub-layers and toggle them on.