Skip to content

Commit

Permalink
Prepare a 3.0.0 release
Browse files Browse the repository at this point in the history
  • Loading branch information
MaybeJustJames committed Jul 20, 2023
1 parent bf047fd commit bf1c85d
Show file tree
Hide file tree
Showing 5 changed files with 1,724 additions and 1,410 deletions.
10 changes: 9 additions & 1 deletion ChangeLog.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

## [3.0.0] - 2023-07-20

### Added

- Support for more bond types.
- Adjust input structure in an incompatible way to more easily render bonds that are related.

## [2.0.0] - 2023-06-05

### Added
Expand Down Expand Up @@ -34,7 +41,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

Initial release

[unreleased]: https://github.com/vibbits/react-2d-molecule/compare/v2.0.0...HEAD
[unreleased]: https://github.com/vibbits/react-2d-molecule/compare/v3.0.0...HEAD
[3.0.0]: https://github.com/vibbits/react-2d-molecule/compare/v2.0.0...v3.0.0
[2.0.0]: https://github.com/vibbits/react-2d-molecule/compare/v1.0.2...v2.0.0
[1.0.2]: https://github.com/vibbits/react-2d-molecule/compare/v1.0.1...v1.0.2
[1.0.1]: https://github.com/vibbits/react-2d-molecule/compare/v1.0.0...v1.0.1
Expand Down
284 changes: 228 additions & 56 deletions example/App.tsx
Original file line number Diff line number Diff line change
@@ -1,29 +1,181 @@
import React, { useState, useRef, useEffect } from "react";

import type { MoleculeData } from "@vibbioinfocore/react-2d-molecule";
import type { Atom, MoleculeData } from "@vibbioinfocore/react-2d-molecule";
import { Molecule } from "@vibbioinfocore/react-2d-molecule";

export const App: React.FC<{}> = () => {
const [json, setJson] = useState<string>("");
const PAGE_SIZE = 12;

let mol = null;
const parseMol = (text: string): MoleculeData | null => {
try {
mol = JSON.parse(json);
} catch (error) {}
return JSON.parse(text);
} catch (error) {
console.error(error);
return null;
}
};

export const App: React.FC<{}> = () => {
const table = useRef(null);
const [mols, setMols] = useState<Array<MoleculeData | null>>([
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
]);
const [files, setFiles] = useState<File[]>([]);
const [page, setPage] = useState<number>(0);
const [dimensions, setDimensions] = useState<[number, number]>([0, 0]);
const [mol, setMol] = useState<MoleculeData | null>(null);
const [query, setQuery] = useState<string>("");

useEffect(() => {
for (let offset = 0; offset < PAGE_SIZE; offset++) {
if (files[page + offset] !== undefined) {
const reader = new FileReader();
reader.onload = (e) => {
setMols((ms) =>
ms.map((f, i) =>
i === offset ? parseMol(e.target.result as string) : f,
),
);
};
reader.readAsText(files[page + offset]);
}
}
}, [files, page]);

const readTheFiles = (theFiles, thePage) => {
for (let offset = 0; offset < PAGE_SIZE; offset++) {
if (theFiles[thePage + offset] !== undefined) {
const reader = new FileReader();
reader.onload = (e) => {
setMols((ms) =>
ms.map((f, i) =>
i === offset ? parseMol(e.target.result as string) : f,
),
);
};
reader.readAsText(theFiles[thePage + offset]);
}
}
};

const changeTheFiles = (theFiles) => {
setFiles(theFiles);
readTheFiles(theFiles, page);
};

const pageLeft = () => {
const newPage = Math.max(0, page - PAGE_SIZE);
setPage(newPage);
readTheFiles(files, newPage);
};

const pageRight = () => {
const newPage = Math.min(files.length, page + PAGE_SIZE);
setPage(newPage);
readTheFiles(files, newPage);
};

const aspectRatio = (): [number, number] => {
const { width, height } = table.current.getBoundingClientRect();
console.log(width / 3, height / 4);
return [width / 3, height / 4];
};

const updateAspectRatio = () => setDimensions(aspectRatio());

useEffect(() => {
updateAspectRatio();
window.addEventListener("resize", updateAspectRatio);
return () => removeEventListener("resize", updateAspectRatio);
}, []);

return (
<>
<div style={{ display: "flex", flexDirection: "column" }}>
<h1>Render Molecule</h1>
<textarea
value={json}
onChange={(e) => setJson(e.target.value)}
></textarea>
<input
type="file"
// @ts-ignore
webkitdirectory="true"
// @ts-ignore
onChange={(e) => changeTheFiles(e.target.files)}
/>
<input
type="text"
onChange={(e) => setQuery(e.target.value)}
value={query}
/>
<div
style={{
display: "flex",
width: "100%",
justifyContent: "space-between",
}}
>
<button onClick={pageLeft}>&lt;</button>
<div>
<span>
{page}/{files.length}
</span>
</div>
<button onClick={pageRight}>&gt;</button>
</div>
<div
ref={table}
style={{
display: "grid",
gridTemplateColumns: "1fr 1fr 1fr",
gridTemplateRows: "250px 250px 250px 250px",
}}
>
{mols
.filter((mol) => mol !== null)
.map((mol, cell) => {
return (
<div
key={`cell-${cell}`}
style={{
fontSize: "0.65px",
fontFamily: "sans-serif",
border: "1px solid blue",
position: "relative",
}}
>
<Molecule
molecule={mol}
width={dimensions[0]}
height={dimensions[1]}
/>
<div
style={{
position: "absolute",
top: 1,
right: 5,
fontSize: "12px",
}}
>
{files[page + cell].name.replace(".json", "")}
</div>
</div>
);
})}
</div>
<textarea onChange={(e) => setMol(parseMol(e.target.value))}></textarea>
{mol === null ? (
<div>Not valid data</div>
<p>Not a valid molecule</p>
) : (
<DisplayMolecule data={mol} />
)}
</>
</div>
);
};

Expand All @@ -43,6 +195,15 @@ const DisplayMolecule: React.FC<{ data: MoleculeData }> = ({ data }) => {
});
};

const atomLabel = (atom: Atom, index: number): React.ReactElement => (
<>
{atom.element}
<tspan dy="0.1" style={{ fontSize: "0.3px" }}>
{index}
</tspan>
</>
);

const atomStyle = (element: string, selected: boolean) => {
return {
fill: selected ? "#ffcccc" : element === "C" ? "rgba(1,1,1,0)" : "white",
Expand Down Expand Up @@ -72,50 +233,61 @@ const DisplayMolecule: React.FC<{ data: MoleculeData }> = ({ data }) => {
}, []);

return (
<div>
<h3>Interactive</h3>
<div
ref={containerRef}
onPointerMove={(evt) => {
evt.preventDefault();
evt.stopPropagation();
if (mayTranslate) {
window.requestAnimationFrame(() => {
const bbox = containerRef.current.getBoundingClientRect();
setTranslate(([t_x, t_y]) => [
t_x + evt.movementX / bbox.width,
t_y + evt.movementY / bbox.height,
]);
});
}
}}
onPointerDown={() => setMayTranslate(true)}
onPointerUp={() => setMayTranslate(false)}
style={{
fontSize: "0.7px",
fontFamily: "sans-serif",
border: "1px solid red",
}}
>
<Molecule
molecule={mol}
translateX={translateX}
translateY={translateY}
scale={scale}
atomClicked={handleClick}
atomStyle={atomStyle}
atomLabelStyle={atomLabelStyle}
/>
<div
style={{
display: "grid",
gridTemplateColumns: "1fr 1fr",
gridTemplateRows: "450px",
}}
>
<div>
<h3>Interactive</h3>
<div
ref={containerRef}
onPointerMove={(evt) => {
evt.preventDefault();
evt.stopPropagation();
if (mayTranslate) {
window.requestAnimationFrame(() => {
const bbox = containerRef.current.getBoundingClientRect();
setTranslate(([t_x, t_y]) => [
t_x + evt.movementX / bbox.width,
t_y + evt.movementY / bbox.height,
]);
});
}
}}
onPointerDown={() => setMayTranslate(true)}
onPointerUp={() => setMayTranslate(false)}
style={{
fontSize: "0.6px",
fontFamily: "sans-serif",
border: "1px solid red",
}}
>
<Molecule
molecule={mol}
translateX={translateX}
translateY={translateY}
scale={scale}
atomClicked={handleClick}
atomLabel={atomLabel}
atomStyle={atomStyle}
atomLabelStyle={atomLabelStyle}
/>
</div>
</div>
<h3>Non-interactive</h3>
<div
style={{
fontSize: "0.65px",
fontFamily: "sans-serif",
border: "1px solid blue",
}}
>
<Molecule molecule={mol} />
<div>
<h3>Non-interactive</h3>
<div
style={{
fontSize: "0.65px",
fontFamily: "sans-serif",
border: "1px solid blue",
}}
>
<Molecule molecule={mol} />
</div>
</div>
</div>
);
Expand Down
Loading

0 comments on commit bf1c85d

Please sign in to comment.