@@ -12,20 +12,23 @@ def plot_wave():
1212
1313 - Read the user input
1414 - Check the breaking criteria
15- - Generate the wave,
16- - Plots the wave using SVG
15+ - Generate the wave
16+ - Show the wave profile using SVG
1717 - Show the wave properties in output text area
1818 - Show warnings and errors in the info area
1919
2020 """
21+ global current_raschii_wave
22+ current_raschii_wave = None
23+
2124 page .find ("#raschii p.info" ).textContent = "Generating wave..."
2225 page .find ("#raschii p.warning" ).textContent = ""
2326 page .find ("#raschii p.error" ).textContent = ""
2427 page .find ("#raschii_out" ).textContent = ""
25- SvgWavePlot .current_wave = None
2628
2729 # Read the user input
2830 wave_input = WaveInput ()
31+ wave_input .load_from_page ()
2932 if not wave_input .is_ok :
3033 page .find ("#raschii p.error" ).textContent = wave_input .error_message
3134 return
@@ -71,20 +74,25 @@ def plot_wave():
7174 f" Wave period = { wave .T :.2f} " ,
7275 f" Phase speed = { wave .c :.3f} " ,
7376 "" ,
74- "Details :" ,
77+ "Numerical details :" ,
7578 * [f" { key } : { value } " for key , value in wave .data .items ()],
7679 ]
7780 page .find ("#raschii_out" ).textContent = "\n " .join (outputs )
78- SvgWavePlot (wave = wave , x = x , eta = eta )
81+ current_raschii_wave = wave
82+ page .find ("#raschii_plot" ).innerHTML = wave_profile_to_svg (x , eta )
7983
8084
8185@pyscript .when ("click" , "#raschii_plot" )
8286def show_info_when_clicking_plot (mouse_event ):
8387 """
84- This is called when the user clicks on the SVG plot.
88+ This is called when the user clicks on the SVG wave profile.
89+
90+ - Get the coordinates of the clicked point in the wave coordinate system
91+ - Show information about the clicked point, including particle velocities
92+
8593 """
86- wave = SvgWavePlot . current_wave
87- if wave is None :
94+ global current_raschii_wave
95+ if current_raschii_wave is None :
8896 page .find ("#raschii p.info" ).textContent = "No wave data available."
8997 return
9098
@@ -93,12 +101,12 @@ def show_info_when_clicking_plot(mouse_event):
93101
94102 # Show the information about the clicked point
95103 info = f"You clicked on x = { x :.3f} m, z = { z :.3f} m (from the bottom)"
96- eta = wave .surface_elevation (x = [x ], t = 0.0 )[0 ]
104+ eta = current_raschii_wave .surface_elevation (x = [x ], t = 0.0 )[0 ]
97105 if z > eta :
98106 info += "<br>(Air)"
99107 else :
100108 info += "<br>(Water)"
101- vel = wave .velocity (x , z , all_points_wet = True )
109+ vel = current_raschii_wave .velocity (x , z , all_points_wet = True )
102110 info += f"<br>Horizontal particle velocity: { vel [0 , 0 ]:.3f} "
103111 info += f"<br>Vertical particle velocity: { vel [0 , 1 ]:.3f} "
104112
@@ -107,37 +115,25 @@ def show_info_when_clicking_plot(mouse_event):
107115
108116class WaveInput :
109117 def __init__ (self ):
118+ self .wave_model_name : str
119+ self .height : float
120+ self .depth : float
121+ self .length : float
122+ self .order : float
123+
110124 self .is_ok : bool = True
111125 self .warning_message : str = ""
112126 self .error_message : str = ""
113127
114- def get_input_value (name : str , converter ):
115- try :
116- element = page .find (f"#raschii_{ name } " )
117- except Exception :
118- self .is_ok = False
119- self .error_message += f"Input element '{ name } ' not found.\n "
120- return None
121-
122- try :
123- value = element [0 ].value
124- except IndexError :
125- self .is_ok = False
126- self .error_message += f"Input element '{ name } ' is empty!\n "
127- return None
128-
129- try :
130- return converter (value )
131- except ValueError :
132- self .is_ok = False
133- self .error_message += f"Invalid value for '{ name } ': { value !r} is not a number!\n "
134- return None
135-
136- self .wave_model_name : str = get_input_value ("wave_model" , str )
137- self .height : float = get_input_value ("height" , float )
138- self .depth : float = get_input_value ("depth" , float )
139- self .length : float = get_input_value ("length" , float )
140- self .order : float = get_input_value ("order" , int )
128+ def load_from_page (self ):
129+ """
130+ Load the wave input parameters from the user input on the web page
131+ """
132+ self .wave_model_name = self ._get_page_input_value ("wave_model" , str )
133+ self .height = self ._get_page_input_value ("height" , float )
134+ self .depth = self ._get_page_input_value ("depth" , float )
135+ self .length = self ._get_page_input_value ("length" , float )
136+ self .order = self ._get_page_input_value ("order" , int )
141137
142138 if self .height < 0 :
143139 self .is_ok = False
@@ -149,50 +145,64 @@ def get_input_value(name: str, converter):
149145 self .is_ok = False
150146 self .error_message += "Wave length must be positive!\n "
151147
148+ def _get_page_input_value (self , name : str , converter ):
149+ try :
150+ element = page .find (f"#raschii_{ name } " )
151+ except Exception :
152+ self .is_ok = False
153+ self .error_message += f"Input element '{ name } ' not found.\n "
154+ return None
152155
153- class SvgWavePlot :
154- current_wave = None
156+ try :
157+ value = element [0 ].value
158+ except IndexError :
159+ self .is_ok = False
160+ self .error_message += f"Input element '{ name } ' is empty!\n "
161+ return None
155162
156- def __init__ (self , wave , x : list [float ], eta : list [float ]):
157- SvgWavePlot .current_wave = wave
163+ try :
164+ return converter (value )
165+ except ValueError :
166+ self .is_ok = False
167+ self .error_message += f"Invalid value for '{ name } ': { value !r} is not a number!\n "
168+ return None
158169
159- # Plot extents
160- self .xmin = min (x )
161- self .xmax = max (x )
162- eta_min = min (eta )
163- eta_max = max (eta )
164- self .ymin = max (eta_min - (eta_max - eta_min ) * 0.4 , 0.0 )
165- self .ymax = eta_max + (eta_max - eta_min ) * 0.4
166170
167- self .x = [0.0 , * x , x [- 1 ]]
168- self .y = [0.0 , * eta , 0.0 ]
169- self .eta = eta
170- self .create_svg ()
171+ def wave_profile_to_svg (x : list [float ], eta : list [float ]) -> str :
172+ """
173+ Convert the wave profile to SVG format and returns it as string
171174
172- def create_svg (self ):
173- """
174- Create the SVG tags to plot the wave.
175+ We need to handle the fact that SVG y-coordinates are inverted compared to
176+ the wave coordinate system. The SVG origin is at the top-left corner and is
177+ positive downwards, while the wave coordinate system has the origin at the
178+ still water surface and is positive upwards.
179+ """
180+ # Plot extents
181+ xmin = min (x )
182+ xmax = max (x )
183+ eta_min = min (eta )
184+ eta_max = max (eta )
185+ ymin = max (eta_min - (eta_max - eta_min ) * 0.4 , 0.0 )
186+ ymax = eta_max + (eta_max - eta_min ) * 0.4
187+
188+ x_plot = [0.0 , * x , x [- 1 ]]
189+ y_plot = [0.0 , * eta , 0.0 ]
190+ coords = " " .join (f"{ x } ,{ y } " for x , y in zip (x_plot , y_plot ))
191+
192+ dx = xmax - xmin
193+ dy = ymax - ymin
194+ svg_contents = [
195+ '<svg version="1.1" preserveAspectRatio="none"' ,
196+ f'viewBox="{ xmin } { - ymax } { dx } { dy } ">' ,
197+ '<g transform="scale(1,-1)">' ,
198+ f'<path d="M{ coords } z" fill="#687dc1"></path>' ,
199+ "</g>" ,
200+ "</svg>" ,
201+ ]
202+ return "\n " .join (svg_contents )
175203
176- We need to handle the fact that SVG y-coordinates are inverted compared to
177- the wave coordinate system. The SVG origin is at the top-left corner and is
178- positive downwards, while the wave coordinate system has the origin at the
179- still water surface and is positive upwards.
180- """
181- dx = self .xmax - self .xmin
182- dy = self .ymax - self .ymin
183- coords = " " .join (f"{ x } ,{ y } " for x , y in zip (self .x , self .y ))
184- svg_contents = [
185- '<svg version="1.1" preserveAspectRatio="none"' ,
186- f'viewBox="{ self .xmin } { - self .ymax } { dx } { dy } ">' ,
187- '<g transform="scale(1,-1)">' ,
188- f'<path d="M{ coords } z" fill="#687dc1"></path>' ,
189- "</g>" ,
190- "</svg>" ,
191- ]
192- page .find ("#raschii_plot" ).innerHTML = "\n " .join (svg_contents )
193-
194-
195- def get_physical_coordinates (mouse_event ):
204+
205+ def get_physical_coordinates (mouse_event ) -> tuple [float , float ]:
196206 """
197207 Convert the mouse click coordinates from the SVG element to the physical
198208 coordinates used when creating the SVG.
0 commit comments