11import 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" ;
44import { 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 } > <</ button >
125+ < div >
126+ < span >
127+ { page } /{ files . length }
128+ </ span >
129+ </ div >
130+ < button onClick = { pageRight } > ></ 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