reymond-group/smilesDrawer

Bug: PNG drawer does work in version 2.1.7 as a React component

Opened this issue · 5 comments

I am using React in Next.js.

I created a React component to render a chemical structure and I found when using SmilesDrawer.Drawer, the canvas is not updated and no structure is drawn. Using SmilesDrawer.SvgDrawer does work. After a bit of experimentation I found this appears to be a bug with version 2.1.7. Rolling back to earlier 2.1.x versions resulted in an import error. Rolling back to version 2.0.3 the SmilesDrawer.Drawer class does work.

Also, it would be very helpful if the documentation showed how to use smiles-drawer with React as it is not immediately obvious.

Summary of issues:

  • SmilesDrawer.Drawer does not render PNG image in version 2.1.7.
  • SmilesDrawer.SvgDrawer works correctly in 2.1.7.
  • Versions 2.1.1 to 2.1.6 throw SyntaxError: Cannot use import statement outside a module when importing.
  • SmilesDrawer.Drawer works correctly in version 2.0.3.

Example code

This code is for a component to render a structure either as PNG or SVG.

import React, { useRef, useEffect } from "react";
import SmilesDrawer from "smiles-drawer";

const USE_SVG = false;

const SETTINGS = {
  width: 800,
  height: 400,
};

const SmileDrawerContainer = ({ smilesStr }: { smilesStr: string }) => {
  if (USE_SVG) {
    // SVG version (versions: <=2.0.3 and 2.1.7)
    const svgRef = useRef<SVGElement>(null);

    let drawer = new SmilesDrawer.SvgDrawer(SETTINGS);

    useEffect(() => {
      SmilesDrawer.parse(smilesStr, function (tree: any) {
        drawer.draw(tree, "structure-svg", "light");
      });
    }, []);

    return (
      <div>
        <svg id="structure-svg"></svg>
      </div>
    );
  } else {
    // Canvas version (versions: <=2.0.3 only)
    const canvasRef = useRef<HTMLCanvasElement>(null);

    let drawer = new SmilesDrawer.Drawer(SETTINGS);

    useEffect(() => {
      SmilesDrawer.parse(smilesStr, function (tree: any) {
        drawer.draw(tree, "structure-canvas", "light");
      });
    }, []);

    return (
      <div>
        <canvas
          className="relative"
          id="structure-canvas"
          ref={canvasRef}
          width={"800px"}
          height={"400px"}
        />
      </div>
    );
  }
};

export default SmileDrawerContainer;

Thanks for writing this out - I've been so confused.

const source = 'CC(=O)Nc1ccccc1C(=O)O'
const targetImg = container.createEl('img') as HTMLImageElement // container is a HTMLDivElement, decleared previously
const theme = 'dark'

let drawer = new SmilesDrawer.SmiDrawer();
drawer.draw(source, targetImg, theme)

These lines are able to generate a PNG file in v2.1.7.

If that is the case, the documentation really needs to be updated to reflect that a canvas element no longer works

Here's a React example that yields png

const imgRef = useRef<HTMLImageElement>(null);
const drawer = new SmilesDrawer.SmiDrawer(options); // options is a param

useEffect(() => {
  drawer.draw(smilesStr, imgRef.current, 'light');
});

return (
  <div>
    <img ref={imgRef} width={300}></img>
  </div>
);

If that is the case, the documentation really needs to be updated to reflect that a canvas element no longer works

2.1.7 smiles-drawer still works with canvas.
Look at example/next.html file in lib repository and go this way. In case you'll draw a lot of different molecules, create a function which generates unique classname for each of those canvas element

Example: codesandbox link look at the files SmilesDrawer.tsx and App.js