Here is an example of how to integrate Structure Checker web service into Marvin JS editor (Structure Checker license is required). Unlike deprecated JChem Web Services included the structure checker as well, the Marvin JS Micro Services (that bundled in default with JS) does not include it. The Structure Checker service can be found in JChem Micro Services pack. Thus, in this example the JChem Micro Service is called to perform the desired calculations.
This example demonstrate how to listen the molecule changes to send it to the selected Structure Checker(s). If any structure error is detected, it is highlighted on the structure and a detailed error message appears below the editor.In this example, only Bond Length, Bond Angle, and Atom Map checkers are used. The full list of checkers are available here: Checker List
This example requires molchange.js
that defines MolChangeHandler
class to aggregate molecule change events.
First of all, Structure Checkers
checks which services are available. It provides a Promise to notify when the list of the available
services arrived (or notify if services are unreachable).
After that, the following steps will be executed:
add
function of the Checkers
object, selected structure checkers are initialized.onSketchLoaded
function.$(document).ready(function handleDocumentReady (e) {
var config = [
{id: "BondLengthChecker", color: "#ffe211", title: "Bond length"},
{id: "BondAngleChecker", color: "#ef6671", title: "Bond angle"},
{id: "AtomMapChecker", color: "#d26ff1", title: "Atom map"}
];
CheckersWS.then(function(services) {
for(var i = 0; i < config.length; i++) {
if($.inArray(config[i].id, services)) {
Checkers.add(config[i].id, config[i].color, config[i].title);
}
}
MarvinJSUtil.getEditor("#sketch").then(onSketchLoaded, function () {
alert("Cannot retrieve sketcher instance from iframe");
});
}, function(error) {
$('#checkers-panel-result').html('structure checker is not available');
});
});
});
The onSketchLoaded
function instantiates a MolChangeHandler
. Its first parameter is the reference of the editor to which it listens.
The second one is a callback function that is performed at each mol change event.
function onSketchLoaded(sketcherInstance) {
marvinSketcherInstance = sketcherInstance;
// aggregator for molecule change events
new MolChangeHandler(sketcherInstance, onMolChange);
}
If you take a look at the add
function of Checkers
, you can see that it creates a CheckerWidget
object for each checker.
/** Appends a new checker to the document.
* @param id - the name of the checker as referred in JChem WS (see JChem WS documentation)
* @param color - colorizes the result (atoms/bonds) in the editor with this color
* @param title - the short description of the checker that displays in the config panel below.
*/
function add(id, color, title) {
var widget = new CheckerWidget(id, color, title);
$("#checkers-panel-config").append(widget.asWidget());
widgets.push(widget);
}
Returning to the onMolChange
function, you can see that it resets the current highlight on the sketcher, gets the source of the current structure with atom and bond unique IDs and performs a
structure check on it.
function reset() {
// reset current highlight
marvinSketcherInstance.setHighlight({});
$('#checkers-panel-result').empty();
}
var last = null;
function onMolChange(e) {
last = e;
reset();
e.target.exportStructure("mrv", { hasUID: true}).then(function(source) {
if(!e.isDeprecated) { // unless a newer molchange event deprecate this event
e.source = source;
Checkers.check(source);
}
},alert);
}
If you take a closer look at the Checkers.check
function, you can see those CheckerWidget
s are enabled where the checkboxes were previously checked. It creates the input for the Structure Checker web service.
Finally, it calls the send
method with the created object.
/**
* Performs the structure checking on the given molecule source.
* @param source - the molecule source in MRV format.
*/
function check(source) {
function check(source) {
var json = {};
json.filter={};
json.filter.untriggered = true;
json.structure = {};
json.structure.uniqueId = "_mjs::uid";
json.structure.source = source;
json.settings = [];
for(var i = 0; i < widgets.length; i++) {
var widget = widgets[i];
if(widget.isEnabled()) {
json.settings.push({"checkerSettings":{"checkerClass": widget.getId() }});
}
}
if(json.settings.length == 0) {
return;
}
send(json);
}
The send
invokes the web service, then calls onSuccess
function when the response of web service is received or onFail
if any error occurred.
/* Sends an async request to Structure checker web service. */
function send(json) {
// arrange the input for the Structure Checker web service
$.ajax({
"url": + "/jws-checker-fixer/rest-v1/checker-fixer/"
,"type": "POST"
,"dataType": "json"
,"contentType": "application/json"
,"data": JSON.stringify(json)
}).done(function (data, textStatus, jqXHR) {
onSuccess(data);
}).fail(onFail);
}
The onSuccess
function gets the response of the web service as a parameter (data
). Its steps
array contains all the performed checkers.
Each checker result can be referred by its checkerName field.
A checker result can contain many fields but only the following ones are relevant in this case:
checkerName
and the description
are displayed on the current page in the checkers-panel-result
div.
Meanwhile, the affected atoms and bonds are highlighted in the sketcher.
/* Callback to process web service result. */
function onSuccess(data) {
var highlights = [];
for(index in data.steps) {
var checkerResult = data.steps[index];
var widget = getWidget(checkerResult.checkerName);
if(widget) {
// display error message
var message = "("+checkerResult.checkerName+"): "+checkerResult.description;
$('#checkers-panel-result').append(widget.createErrorWidget(message));
// calculate context to highlight
if(typeof checkerResult == 'object') {
var indexes = {};
indexes.atoms = getAtoms(checkerResult.atomIds);
indexes.bonds = getBonds(checkerResult.bondIds);
if(indexes.atoms.length || indexes.bonds.length) { // add highlight unless context is empty
highlights.push({
'style': {
'color': widget.getColor(),
'opacity': 0.25
},
'uids': indexes
});
}
}
}
}
// highlight atoms and bonds
marvinSketcherInstance.setHighlight(highlights);
}
Changing of the configuration (checking or unchecking a checkbox or modifying a checker color) also triggers the checking of the structure
(whose source was already stored in the source
property of the last molchange
event).
function onConfigChange(e) {
// reevaluate last consumed molchange event when congfiguration is changed
if(last && !last.isDeprecated && (typeof last.source == 'string')) {
reset();
Checkers.check(last.source);
}
}