Skip to content
This repository was archived by the owner on May 20, 2025. It is now read-only.

Commit bf1c85d

Browse files
author
James Collier
committed
Prepare a 3.0.0 release
1 parent bf047fd commit bf1c85d

5 files changed

Lines changed: 1724 additions & 1410 deletions

File tree

ChangeLog.md

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10+
## [3.0.0] - 2023-07-20
11+
12+
### Added
13+
14+
- Support for more bond types.
15+
- Adjust input structure in an incompatible way to more easily render bonds that are related.
16+
1017
## [2.0.0] - 2023-06-05
1118

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

3542
Initial release
3643

37-
[unreleased]: https://github.com/vibbits/react-2d-molecule/compare/v2.0.0...HEAD
44+
[unreleased]: https://github.com/vibbits/react-2d-molecule/compare/v3.0.0...HEAD
45+
[3.0.0]: https://github.com/vibbits/react-2d-molecule/compare/v2.0.0...v3.0.0
3846
[2.0.0]: https://github.com/vibbits/react-2d-molecule/compare/v1.0.2...v2.0.0
3947
[1.0.2]: https://github.com/vibbits/react-2d-molecule/compare/v1.0.1...v1.0.2
4048
[1.0.1]: https://github.com/vibbits/react-2d-molecule/compare/v1.0.0...v1.0.1

example/App.tsx

Lines changed: 228 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,181 @@
11
import React, { useState, useRef, useEffect } from "react";
22

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

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

9-
let mol = null;
8+
const parseMol = (text: string): MoleculeData | null => {
109
try {
11-
mol = JSON.parse(json);
12-
} catch (error) {}
10+
return JSON.parse(text);
11+
} catch (error) {
12+
console.error(error);
13+
return null;
14+
}
15+
};
16+
17+
export const App: React.FC<{}> = () => {
18+
const table = useRef(null);
19+
const [mols, setMols] = useState<Array<MoleculeData | null>>([
20+
null,
21+
null,
22+
null,
23+
null,
24+
null,
25+
null,
26+
null,
27+
null,
28+
null,
29+
null,
30+
null,
31+
null,
32+
]);
33+
const [files, setFiles] = useState<File[]>([]);
34+
const [page, setPage] = useState<number>(0);
35+
const [dimensions, setDimensions] = useState<[number, number]>([0, 0]);
36+
const [mol, setMol] = useState<MoleculeData | null>(null);
37+
const [query, setQuery] = useState<string>("");
38+
39+
useEffect(() => {
40+
for (let offset = 0; offset < PAGE_SIZE; offset++) {
41+
if (files[page + offset] !== undefined) {
42+
const reader = new FileReader();
43+
reader.onload = (e) => {
44+
setMols((ms) =>
45+
ms.map((f, i) =>
46+
i === offset ? parseMol(e.target.result as string) : f,
47+
),
48+
);
49+
};
50+
reader.readAsText(files[page + offset]);
51+
}
52+
}
53+
}, [files, page]);
54+
55+
const readTheFiles = (theFiles, thePage) => {
56+
for (let offset = 0; offset < PAGE_SIZE; offset++) {
57+
if (theFiles[thePage + offset] !== undefined) {
58+
const reader = new FileReader();
59+
reader.onload = (e) => {
60+
setMols((ms) =>
61+
ms.map((f, i) =>
62+
i === offset ? parseMol(e.target.result as string) : f,
63+
),
64+
);
65+
};
66+
reader.readAsText(theFiles[thePage + offset]);
67+
}
68+
}
69+
};
70+
71+
const changeTheFiles = (theFiles) => {
72+
setFiles(theFiles);
73+
readTheFiles(theFiles, page);
74+
};
75+
76+
const pageLeft = () => {
77+
const newPage = Math.max(0, page - PAGE_SIZE);
78+
setPage(newPage);
79+
readTheFiles(files, newPage);
80+
};
81+
82+
const pageRight = () => {
83+
const newPage = Math.min(files.length, page + PAGE_SIZE);
84+
setPage(newPage);
85+
readTheFiles(files, newPage);
86+
};
87+
88+
const aspectRatio = (): [number, number] => {
89+
const { width, height } = table.current.getBoundingClientRect();
90+
console.log(width / 3, height / 4);
91+
return [width / 3, height / 4];
92+
};
93+
94+
const updateAspectRatio = () => setDimensions(aspectRatio());
95+
96+
useEffect(() => {
97+
updateAspectRatio();
98+
window.addEventListener("resize", updateAspectRatio);
99+
return () => removeEventListener("resize", updateAspectRatio);
100+
}, []);
13101

14102
return (
15-
<>
103+
<div style={{ display: "flex", flexDirection: "column" }}>
16104
<h1>Render Molecule</h1>
17-
<textarea
18-
value={json}
19-
onChange={(e) => setJson(e.target.value)}
20-
></textarea>
105+
<input
106+
type="file"
107+
// @ts-ignore
108+
webkitdirectory="true"
109+
// @ts-ignore
110+
onChange={(e) => changeTheFiles(e.target.files)}
111+
/>
112+
<input
113+
type="text"
114+
onChange={(e) => setQuery(e.target.value)}
115+
value={query}
116+
/>
117+
<div
118+
style={{
119+
display: "flex",
120+
width: "100%",
121+
justifyContent: "space-between",
122+
}}
123+
>
124+
<button onClick={pageLeft}>&lt;</button>
125+
<div>
126+
<span>
127+
{page}/{files.length}
128+
</span>
129+
</div>
130+
<button onClick={pageRight}>&gt;</button>
131+
</div>
132+
<div
133+
ref={table}
134+
style={{
135+
display: "grid",
136+
gridTemplateColumns: "1fr 1fr 1fr",
137+
gridTemplateRows: "250px 250px 250px 250px",
138+
}}
139+
>
140+
{mols
141+
.filter((mol) => mol !== null)
142+
.map((mol, cell) => {
143+
return (
144+
<div
145+
key={`cell-${cell}`}
146+
style={{
147+
fontSize: "0.65px",
148+
fontFamily: "sans-serif",
149+
border: "1px solid blue",
150+
position: "relative",
151+
}}
152+
>
153+
<Molecule
154+
molecule={mol}
155+
width={dimensions[0]}
156+
height={dimensions[1]}
157+
/>
158+
<div
159+
style={{
160+
position: "absolute",
161+
top: 1,
162+
right: 5,
163+
fontSize: "12px",
164+
}}
165+
>
166+
{files[page + cell].name.replace(".json", "")}
167+
</div>
168+
</div>
169+
);
170+
})}
171+
</div>
172+
<textarea onChange={(e) => setMol(parseMol(e.target.value))}></textarea>
21173
{mol === null ? (
22-
<div>Not valid data</div>
174+
<p>Not a valid molecule</p>
23175
) : (
24176
<DisplayMolecule data={mol} />
25177
)}
26-
</>
178+
</div>
27179
);
28180
};
29181

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

198+
const atomLabel = (atom: Atom, index: number): React.ReactElement => (
199+
<>
200+
{atom.element}
201+
<tspan dy="0.1" style={{ fontSize: "0.3px" }}>
202+
{index}
203+
</tspan>
204+
</>
205+
);
206+
46207
const atomStyle = (element: string, selected: boolean) => {
47208
return {
48209
fill: selected ? "#ffcccc" : element === "C" ? "rgba(1,1,1,0)" : "white",
@@ -72,50 +233,61 @@ const DisplayMolecule: React.FC<{ data: MoleculeData }> = ({ data }) => {
72233
}, []);
73234

74235
return (
75-
<div>
76-
<h3>Interactive</h3>
77-
<div
78-
ref={containerRef}
79-
onPointerMove={(evt) => {
80-
evt.preventDefault();
81-
evt.stopPropagation();
82-
if (mayTranslate) {
83-
window.requestAnimationFrame(() => {
84-
const bbox = containerRef.current.getBoundingClientRect();
85-
setTranslate(([t_x, t_y]) => [
86-
t_x + evt.movementX / bbox.width,
87-
t_y + evt.movementY / bbox.height,
88-
]);
89-
});
90-
}
91-
}}
92-
onPointerDown={() => setMayTranslate(true)}
93-
onPointerUp={() => setMayTranslate(false)}
94-
style={{
95-
fontSize: "0.7px",
96-
fontFamily: "sans-serif",
97-
border: "1px solid red",
98-
}}
99-
>
100-
<Molecule
101-
molecule={mol}
102-
translateX={translateX}
103-
translateY={translateY}
104-
scale={scale}
105-
atomClicked={handleClick}
106-
atomStyle={atomStyle}
107-
atomLabelStyle={atomLabelStyle}
108-
/>
236+
<div
237+
style={{
238+
display: "grid",
239+
gridTemplateColumns: "1fr 1fr",
240+
gridTemplateRows: "450px",
241+
}}
242+
>
243+
<div>
244+
<h3>Interactive</h3>
245+
<div
246+
ref={containerRef}
247+
onPointerMove={(evt) => {
248+
evt.preventDefault();
249+
evt.stopPropagation();
250+
if (mayTranslate) {
251+
window.requestAnimationFrame(() => {
252+
const bbox = containerRef.current.getBoundingClientRect();
253+
setTranslate(([t_x, t_y]) => [
254+
t_x + evt.movementX / bbox.width,
255+
t_y + evt.movementY / bbox.height,
256+
]);
257+
});
258+
}
259+
}}
260+
onPointerDown={() => setMayTranslate(true)}
261+
onPointerUp={() => setMayTranslate(false)}
262+
style={{
263+
fontSize: "0.6px",
264+
fontFamily: "sans-serif",
265+
border: "1px solid red",
266+
}}
267+
>
268+
<Molecule
269+
molecule={mol}
270+
translateX={translateX}
271+
translateY={translateY}
272+
scale={scale}
273+
atomClicked={handleClick}
274+
atomLabel={atomLabel}
275+
atomStyle={atomStyle}
276+
atomLabelStyle={atomLabelStyle}
277+
/>
278+
</div>
109279
</div>
110-
<h3>Non-interactive</h3>
111-
<div
112-
style={{
113-
fontSize: "0.65px",
114-
fontFamily: "sans-serif",
115-
border: "1px solid blue",
116-
}}
117-
>
118-
<Molecule molecule={mol} />
280+
<div>
281+
<h3>Non-interactive</h3>
282+
<div
283+
style={{
284+
fontSize: "0.65px",
285+
fontFamily: "sans-serif",
286+
border: "1px solid blue",
287+
}}
288+
>
289+
<Molecule molecule={mol} />
290+
</div>
119291
</div>
120292
</div>
121293
);

0 commit comments

Comments
 (0)