partridgejiang / Kekule.js

A Javascript cheminformatics toolkit.
http://partridgejiang.github.io/Kekule.js
MIT License
248 stars 61 forks source link

Add a select list of atoms to the bottom of the composer #209

Closed Benjaki2 closed 3 years ago

Benjaki2 commented 3 years ago

@partridgejiang First off, I am huge fan of the project. Thanks for all the work!

I was trying to edit the chem composer to display specific atoms at the bottom of the composer so that it might be easier for a new user to find how to change the atom of a node. Is there a good way to go about doing this? Thanks again!

Screen Shot 2021-02-12 at 11 45 47 PM
partridgejiang commented 3 years ago

Hi @Benjaki2, please the the small demo below: SpecificAtomIaController.zip

In general, since there is no existing chem tool to change the atom element to a specified one in the package, you have to create a custom one your self. First of all, create a new interaction controller class, implementing the behavior when clicking on an atom in editor:

Kekule.Editor.MolSpecifiedAtomIaController = Class.create(Kekule.Editor.BaseEditorIaController,
{
    // ...
    changeNode: function(node)
    {
        var newNodeClass = Kekule.Atom;
        var modifiedProps = {
            'isotopeId': this.getSpecifiedAtomSymbol(),
            'explicitHydrogenCount': null
        };
        this.applyModification(node, null, newNodeClass, modifiedProps);
    },
    react_pointerup: function(e)
    {
        if (e.getButton() === Kekule.X.Event.MOUSE_BTN_LEFT)
        {
            this.getEditor().setSelection(null);
            var coord = this._getEventMouseCoord(e);
            {
                var obj = this.getTopmostInteractableObjAtScreenCoord(coord);
                if (obj && this.isValidNode(obj))  // can modify atom of this object
                {
                    this.changeNode(obj);
                    e.preventDefault();
                    e.stopPropagation();
                }
                return true;
            }
        }
    }
});

Then create new action classes associated with this controller. The util function Kekule.Editor.createComposerIaControllerActionClass is used in the demo:

Kekule.Editor.ActionComposerMolSpecifiedAtomController_C = Kekule.Editor.createComposerIaControllerActionClass(
    'Kekule.Editor.ActionComposerMolSpecifiedAtomController_C',
    'C', //caption
    'Carbon atom', //hint
    'MolSpecifiedAtomIaController',   // the controller name
    'MolSpecifiedAtomIaController-C',  // html class name for the button
    { 'specifiedAtomSymbol': 'C' }  // initial property values of the interaction controller
);

Afterward, register the iteraction controller and action to editor class:

Kekule.Editor.IaControllerManager.register(Kekule.Editor.MolSpecifiedAtomIaController, Kekule.Editor.ChemSpaceEditor);
Kekule.ActionManager.registerNamedActionClass('specifiedAtomC', Kekule.Editor.ActionComposerMolSpecifiedAtomController_C, Kekule.Editor.ChemSpaceEditor);

At last, customize the editor UI:

var BNS = Kekule.ChemWidget.ComponentWidgetNames;
composer.setChemToolButtons([
    // ...
    //BNS.molAtomAndFormula,
    // replace the default atom and formula tool with this new one
    {
        "name": BNS.molAtomAndFormula,
        "attached": [
            BNS.molFormula,
            BNS.molRepMethane,
            BNS.molAtom,
            'specifiedAtomC',  // the name of custom action
            'specifiedAtomN',
            'specifiedAtomO',
        ]
    },
    // ...
]);

Of course, do not forget to assign the icon image of action button:

<style>
        /** custom IA controller and action styles **/
        .K-Chem-Composer-Assoc-Toolbar .K-Chem-MolSpecifiedAtomIaController-C > .K-Pri-Glyph-Content
        {
            background-image: url("./icons/atomC.png");
        }
</style>

After all those changes, the specified atom button should be visible in editor. image When clicking on the button, the custom action (e.g. ActionComposerMolSpecifiedAtomController_C) will be executed and MolSpecifiedAtomIaController will be activated.

Benjaki2 commented 3 years ago

@partridgejiang That worked great! thanks so much for the code demo!