partridgejiang / Kekule.js

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

composer.exportObjs not working #304

Closed joeolu14 closed 1 year ago

joeolu14 commented 1 year ago

Hi,

This is my setup of the Composer widget, using ReactJs. I want a situation where the user clicks on the generate Button, I console.log the exported molecule. The issue is, when I click on the button, I only get an empty array and not the molecule.

const Draw = () => {
  var composer = new Kekule.Editor.Composer(document);
  composer.setDimension("600px", "400px");

  const generateMe = () => { 
    var mols = composer.exportObjs(Kekule.Molecule); 
    var msg = "Molecule count: " + mols.length + "\n";
    for (var i = 0, l = mols.length; i < l; ++i) {
      var mol = mols[i];
      msg +=
        "--------------------\n" + Kekule.IO.saveFormatData(mol, "cml") + "\n";
    }
    console.log(msg); 
  };

  return (
    <div>
      <div
        id="composer"
        style={{ width: "600px", height: "400px" }}
        data-widget="Kekule.Editor.Composer"
        // data-chem-obj="url(#molecule)"
      ></div>
      <button onClick={generateMe}> generate </button>
    </div>
  );
};

export default Draw;

image

partridgejiang commented 1 year ago

Hi @joeolu14, the composer widget displayed in page is created by <div data-widget="Kekule.Editor.Composer"> automatically, and has nothing to do with the manually created one in var composer = new Kekule.Editor.Composer(document);. Actually, the composer widget stored in composer variable is a hidden since you never insert it to any HTML element and is always empty.

You may try the following code instead:

const Draw = () => {
  const generateMe = () => { 
    var composer = Kekule.Widget.getWidgetById('composer');
    var mols = composer.exportObjs(Kekule.Molecule); 
    var msg = "Molecule count: " + mols.length + "\n";
    for (var i = 0, l = mols.length; i < l; ++i) {
      var mol = mols[i];
      msg +=
        "--------------------\n" + Kekule.IO.saveFormatData(mol, "cml") + "\n";
    }
    console.log(msg); 
  };

  return (
    <div>
      <div
        id="composer"
        style={{ width: "600px", height: "400px" }}
        data-widget="Kekule.Editor.Composer"
        // data-chem-obj="url(#molecule)"
      ></div>
      <button onClick={generateMe}> generate </button>
    </div>
  );
};
joeolu14 commented 1 year ago

Hi @partridgejiang, Thank you, it worked, is there a function to save/export the molecule(s) as jpeg or base64 image string?

partridgejiang commented 1 year ago

The exportToDataUri method of editor can be utilized to export the whole canvas of editor area inside a composer:

let base64str = composer.getEditor().exportToDataUri();

However, since the whole editor area is exported, the exported image will be exactly the same size as the editor and often containing a lot of blank spaces.

So it is recommended to use an additional auto-sized viewer widget to export image containing the chem object itself:

let viewer = new Kekule.ChemWidget.Viewer2D(document);  // create a viewer but not appended to any HTML element, just a hidden one
viewer.autoSize = true;
viewer.chemObj = composer.getSavingTargetObj();
let base64str = viewer.exportToDataUri();
joeolu14 commented 1 year ago

Thank you so much @partridgejiang, my last question: How do we get the molecular weight of each of the molecules?

partridgejiang commented 1 year ago

The molecular weight can be easily calculated by sum up the natural mass of each atom in molecule, e.g.:

let flattenMol = molecule.getFlattenedShadowFragment();   // get the flatten structure of the molecule, otherwise the may be nested sub groups inside it
let weight = 0;
for (let i = 0, l = flattenMol.getNodeCount(); i < l; ++i)
{
  weight += flattenMol.getNodeAt(i).getIsotope().getNaturalMass();
}
console.log(weight);
joeolu14 commented 1 year ago

Thank you