partridgejiang / Kekule.js

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

making the molecules to be in focus #305

Closed joeolu14 closed 1 year ago

joeolu14 commented 1 year ago

When I load the molecule to the editor, I load in mol format. This is what my editor looks like image

I will have to scroll to where the molecules are, is there a way to scroll or autofocus on the molecule loaded like this image

Also is there a way to reduce the zoom as the zoom is way bigger than expected.

This is my setup

const MolEditor: FC<MolEditorProps> = ({ molecule, id, width, height }) => {
  useEffect(() => {
    if (molecule && id) {
      setTimeout(() => {
        const composer = Kekule.Widget.getWidgetById(id);
        composer.setCommonToolButtons([
          // "newDoc",
          "copy",
          "undo",
          "redo",
          "cut",
          "paste",
          "zoomIn",
          "zoomOut",
          "objInspector",
        ]);
        const myMolecule = new Kekule.IO.loadFormatData(molecule, "mol");

        composer.setChemObj(myMolecule);
      }, 200);
    }
  }, [molecule, id]);

  return (
    <Container key={id}>
      <div
        id={id}
        style={{
          width,
          height,
          textAlign: "center",
        }}
        data-widget="Kekule.Editor.Composer"
      ></div>
    </Container>
  );
};
partridgejiang commented 1 year ago

Hi @joeolu14, the method scrollClientToObject can be used to scroll to object inside editor:

// ...
composer.setChemObj(myMolecule);
composer.getEditor().scrollClientToObject(myMolecule);

The zoomTo method can be used to change the current zoom level of editor:

composer.zoomTo(0.75);

And the initialZoom controls the initial zoom level when loading or creating new object in editor:

composer.setInitialZoom(1);  // The default initial zoom level is 1.5 for some historical reason
joeolu14 commented 1 year ago

Hi @joeolu14, the method scrollClientToObject can be used to scroll to object inside editor:

// ...
composer.setChemObj(myMolecule);
composer.getEditor().scrollClientToObject(myMolecule);

The zoomTo method can be used to change the current zoom level of editor:

composer.zoomTo(0.75);

And the initialZoom controls the initial zoom level when loading or creating new object in editor:

composer.setInitialZoom(1);  // The default initial zoom level is 1.5 for some historical reason

Just tried and the scrollClientToObject seem to work but scrolls to the starting point of the molecule, I am trying to get the molecule in the middle of the canvas. image

Also the setInitialZoom and zoomTo functions do now exist, it throws an error when I try to use them.

partridgejiang commented 1 year ago

Sorry I have made a mistake about the zoom related properties and methods, these properties/methods are located in editor object rather than the composer, so the code should be:

composer.getEditor().zoomTo(0.75);
composer.getEditor().setInitialZoom(1);

And for the scrolling, you may also try the extra option param of scrollClientToObject:

composer.getEditor().scrollClientToObject(myMolecule, {scrollToCenter: true, coverMostObjs: true});
joeolu14 commented 1 year ago

Thanks @partridgejiang, I will like to know how to save the molecule as svg? is there a function for this?

partridgejiang commented 1 year ago

Hi @joeolu14, there is an online demo for exporting to SVG ( http://partridgejiang.github.io/Kekule.js/demos/items/chemEditor/exportSVG.html ). In brief, a special hidden viewer with SVG renderer need to be created and used to output the SVG code for chem objects.

joeolu14 commented 1 year ago

@partridgejiang yes I saw the implementation but I could not reproduce same for a simple react application

joeolu14 commented 1 year ago

@partridgejiang In the root of my component I made this declaration

  Kekule.ChemWidget.Viewer2DSvg = Object.assign(Kekule.ChemWidget.Viewer2D, {
    CLASS_NAME: "Kekule.ChemWidget.Viewer2DSvg",
    // @ts-ignore
    createDrawBridge: function ($super, slient) {
      if (Kekule.Render.RaphaelRendererBridge) { 
        return new Kekule.Render.RaphaelRendererBridge();
      } else { 
        return $super(slient);
      }
    },
  });

And this is function to generate the SVG image

  const generateImage = () => {
    const composer = Kekule.Widget.getWidgetById("composer");  

    const chemViewer = Kekule.Widget.getWidgetById("chemViewer");
    var chemObj = composer.getSavingTargetObj();

    if (chemObj) { 
      chemViewer.setChemObj(chemObj); 
      var context = chemViewer.getDrawContext();  
      if (context && context.toSVG) {
        var svg = context.toSVG();
        console.log("SVG: ", svg);
        alert(svg);
      }
    }  
  };

But context does not seem to have the .toSVG function This is where I load the viewer to the page

   <div style={{ marginTop: "50px", textAlign: "center" }}>
        <div
          id="chemViewer"
          style={{
            width: "800px",
            height: "400px",
          }}
          data-widget="Kekule.ChemWidget.Viewer2DSvg" 
        ></div>
      </div>
partridgejiang commented 1 year ago

Hi @joeolu14, there may be some problems in the first line of your codes: ( Kekule.ChemWidget.Viewer2DSvg = Object.assign(Kekule.ChemWidget.Viewer2D, {...})). Object.assign can be used to copy object but is not designed to extend class. In Kekule.js, a special Class.create (or Kekule.Class.create) method should be used instead:

Kekule.ChemWidget.Viewer2DSvg = Kekule.Class.create(Kekule.ChemWidget.Viewer2D,
    {
      /** @private */
      CLASS_NAME: 'Kekule.ChemWidget.Viewer2DSvg',
        /** @ignore */
        createDrawBridge: function($super, slient)
      {
            if (Kekule.Render.RaphaelRendererBridge)
            return new Kekule.Render.RaphaelRendererBridge();
        else
            return $super(slient);
        }
    });

By the way, to export SVG, both Raphael.js and Raphael.export libs should also be included in your page. For example, there are two related Githubissues.

  • Githubissues is a development platform for aggregating issues.