feat: Added ElectronJS app to display the app
feat: Removed fullscreen dialogs to display them in popup window
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,5 +1,4 @@
|
||||
/3d-app/
|
||||
/electron-3d-app/
|
||||
/express-app/
|
||||
/react-app/
|
||||
/.vscode/
|
||||
|
8
.hintrc
Normal file
8
.hintrc
Normal file
@ -0,0 +1,8 @@
|
||||
{
|
||||
"extends": [
|
||||
"development"
|
||||
],
|
||||
"hints": {
|
||||
"no-inline-styles": "off"
|
||||
}
|
||||
}
|
BIN
3D_app/assets/settings.png
Normal file
BIN
3D_app/assets/settings.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 219 KiB |
@ -1,4 +1,5 @@
|
||||
from dash import State, Output, Input, callback
|
||||
from tkinter import NONE
|
||||
from dash import State, Output, Input, callback, clientside_callback
|
||||
import dash
|
||||
import numpy as np
|
||||
import plotly.graph_objects as go
|
||||
@ -74,50 +75,19 @@ def get_callbacks():
|
||||
)
|
||||
return [fig, True]
|
||||
|
||||
# callback pour le plot 3D en plein écran
|
||||
@callback(
|
||||
Output("3dplot-fullscreen", "figure"),
|
||||
[
|
||||
Input("iso-slider-fullscreen", "value"),
|
||||
Input("y-slider-fullscreen", "value"),
|
||||
],
|
||||
# callback pour le plein écran du plot 3D
|
||||
clientside_callback(
|
||||
"""
|
||||
function toggle_fullscreen_3dplot(n1) {
|
||||
if (n1) {
|
||||
window.open("fullscreen/3dplot", "", "width=800,height=600,popup=true");
|
||||
}
|
||||
}
|
||||
""",
|
||||
Output("js", "children", allow_duplicate=True),
|
||||
[Input("fullscreen-button-3dplot", "n_clicks")],
|
||||
prevent_initial_call=True,
|
||||
)
|
||||
def update_3dplot_fullscreen(iso_value, y_values):
|
||||
y_min, y_max = y_values
|
||||
selected_volume = volume[0:dim_x, int(y_min) : int(y_max), 0:dim_z]
|
||||
X, Y, Z = np.mgrid[
|
||||
0 : selected_volume.shape[0],
|
||||
0 : selected_volume.shape[1],
|
||||
0 : selected_volume.shape[2],
|
||||
]
|
||||
|
||||
fig = go.Figure(
|
||||
data=go.Volume(
|
||||
x=X.flatten(),
|
||||
y=Y.flatten(),
|
||||
z=Z.flatten(),
|
||||
value=selected_volume.flatten(),
|
||||
isomin=iso_value,
|
||||
isomax=selected_volume.max(),
|
||||
opacity=0.1,
|
||||
surface_count=20,
|
||||
colorscale="Jet",
|
||||
)
|
||||
)
|
||||
|
||||
return fig
|
||||
|
||||
# callback pour le plein écran du plot 3D
|
||||
@callback(
|
||||
Output("modal-3dplot", "is_open"),
|
||||
[Input("fullscreen-button-3dplot", "n_clicks")],
|
||||
[dash.dependencies.State("modal-3dplot", "is_open")],
|
||||
)
|
||||
def toggle_fullscreen_3dplot(n1, is_open):
|
||||
if n1:
|
||||
return not is_open
|
||||
return is_open
|
||||
|
||||
# callback pour les paramètres du plot 3D
|
||||
@callback(
|
||||
@ -152,8 +122,6 @@ def get_callbacks():
|
||||
[
|
||||
Output("iso-slider-container", "children"),
|
||||
Output("y-slider-container", "children"),
|
||||
Output("iso-slider-fullscreen-container", "children"),
|
||||
Output("y-slider-fullscreen-container", "children"),
|
||||
],
|
||||
Input("3dplot-settings", "data"),
|
||||
)
|
||||
@ -197,47 +165,8 @@ def get_callbacks():
|
||||
),
|
||||
]
|
||||
)
|
||||
iso_slider_fullscreen = dbc.Row(
|
||||
[
|
||||
dbc.Col(html.Span("Iso value: "), width="auto"),
|
||||
dbc.Col(
|
||||
dcc.Slider(
|
||||
id="iso-slider-fullscreen",
|
||||
min=0,
|
||||
max=volume.max() / 2,
|
||||
value=0,
|
||||
step=1,
|
||||
marks={
|
||||
str(i): str(i)
|
||||
for i in range(
|
||||
0,
|
||||
int(volume.max() / 2) + 1,
|
||||
int((volume.max() / 2) / 20),
|
||||
)
|
||||
},
|
||||
)
|
||||
),
|
||||
]
|
||||
)
|
||||
y_slider_fullscreen = dbc.Row(
|
||||
[
|
||||
dbc.Col(html.Span("Y crop: "), width="auto"),
|
||||
dbc.Col(
|
||||
dcc.RangeSlider(
|
||||
id="y-slider-fullscreen",
|
||||
min=0,
|
||||
max=dim_y,
|
||||
value=[0, dim_y],
|
||||
marks={
|
||||
str(i): str(i)
|
||||
for i in range(0, dim_y + 1, max(1, int(dim_y / 20)))
|
||||
},
|
||||
)
|
||||
),
|
||||
]
|
||||
)
|
||||
if data is None:
|
||||
return [None, None, None, None]
|
||||
return [None, None]
|
||||
else:
|
||||
if (
|
||||
data["card_settings"] is None
|
||||
@ -246,22 +175,10 @@ def get_callbacks():
|
||||
iso_slider = None
|
||||
if data["card_settings"] is None or "y_slider" not in data["card_settings"]:
|
||||
y_slider = None
|
||||
if (
|
||||
data["fullscreen_settings"] is None
|
||||
or "iso_slider" not in data["fullscreen_settings"]
|
||||
):
|
||||
iso_slider_fullscreen = None
|
||||
if (
|
||||
data["fullscreen_settings"] is None
|
||||
or "y_slider" not in data["fullscreen_settings"]
|
||||
):
|
||||
y_slider_fullscreen = None
|
||||
|
||||
return [
|
||||
iso_slider,
|
||||
y_slider,
|
||||
iso_slider_fullscreen,
|
||||
y_slider_fullscreen,
|
||||
]
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
@ -295,40 +212,19 @@ def get_callbacks():
|
||||
|
||||
return [fig, True]
|
||||
|
||||
# callback pour le A-scan en plein écran
|
||||
@callback(
|
||||
Output("heatmap-ascan-fullscreen", "figure"),
|
||||
[
|
||||
Input("layer-slider-x-ascan-fullscreen", "value"),
|
||||
Input("layer-slider-z-ascan-fullscreen", "value"),
|
||||
Input("crop-slider-fullscreen", "value"),
|
||||
],
|
||||
State("store-settings", "data"),
|
||||
)
|
||||
def update_heatmap_ascan_fullscreen(layer_x, layer_z, crop, settings):
|
||||
y_min, y_max = crop or [0, dim_y]
|
||||
layer_x = layer_x or 0
|
||||
layer_z = layer_z or 0
|
||||
if settings["apply_sampling_everywhere"]:
|
||||
data = volume
|
||||
else:
|
||||
data = pre_volume
|
||||
|
||||
fig = px.line(
|
||||
y=data[layer_x - 1, int(y_min) : int(y_max), layer_z], title="A-scan"
|
||||
)
|
||||
return fig
|
||||
|
||||
# callback pour le plein écran du A-scan
|
||||
@callback(
|
||||
Output("modal-ascan", "is_open"),
|
||||
# callback pour le plein écran du plot 3D
|
||||
clientside_callback(
|
||||
"""
|
||||
function toggle_fullscreen_ascant(n1) {
|
||||
if (n1) {
|
||||
window.open("fullscreen/ascan", "", "width=800,height=600,popup=true");
|
||||
}
|
||||
}
|
||||
""",
|
||||
Output("js", "children", allow_duplicate=True),
|
||||
[Input("fullscreen-button-ascan", "n_clicks")],
|
||||
[dash.dependencies.State("modal-ascan", "is_open")],
|
||||
prevent_initial_call=True,
|
||||
)
|
||||
def toggle_fullscreen_ascan(n1, is_open):
|
||||
if n1:
|
||||
return not is_open
|
||||
return is_open
|
||||
|
||||
# callback pour les paramètres du A-scan
|
||||
@callback(
|
||||
@ -362,9 +258,6 @@ def get_callbacks():
|
||||
@callback(
|
||||
[
|
||||
Output("crop-slider-container", "children"),
|
||||
Output("layer-slider-x-ascan-fullscreen-container", "children"),
|
||||
Output("layer-slider-z-ascan-fullscreen-container", "children"),
|
||||
Output("crop-slider-fullscreen-container", "children"),
|
||||
],
|
||||
Input("ascan-settings", "data"),
|
||||
)
|
||||
@ -390,92 +283,16 @@ def get_callbacks():
|
||||
),
|
||||
]
|
||||
)
|
||||
slider_x_fullscreen = dbc.Row(
|
||||
[
|
||||
dbc.Col(html.Span("Layer X: "), width="auto"),
|
||||
dbc.Col(
|
||||
dcc.Slider(
|
||||
id="layer-slider-x-ascan-fullscreen",
|
||||
min=0,
|
||||
max=dim_x,
|
||||
value=0,
|
||||
step=1,
|
||||
marks={
|
||||
str(i): str(i)
|
||||
for i in range(0, dim_x, max(1, int(dim_x / 50)))
|
||||
},
|
||||
)
|
||||
),
|
||||
]
|
||||
)
|
||||
slider_z_fullscreen = dbc.Row(
|
||||
[
|
||||
dbc.Col(html.Span("Layer Z: "), width="auto"),
|
||||
dbc.Col(
|
||||
dcc.Slider(
|
||||
id="layer-slider-z-ascan-fullscreen",
|
||||
min=1,
|
||||
max=dim_z - 1,
|
||||
value=1,
|
||||
marks={
|
||||
str(i): str(i)
|
||||
for i in range(1, dim_z - 1, max(1, int(dim_z / 20)))
|
||||
},
|
||||
step=1,
|
||||
)
|
||||
),
|
||||
]
|
||||
)
|
||||
crop_slider_fullscreen = dbc.Row(
|
||||
[
|
||||
dbc.Col(html.Span("Crop: "), width="auto"),
|
||||
dbc.Col(
|
||||
dcc.RangeSlider(
|
||||
id="crop-slider-fullscreen",
|
||||
min=0,
|
||||
max=dim_y,
|
||||
value=[0, dim_y],
|
||||
marks={
|
||||
str(i): str(i)
|
||||
for i in range(
|
||||
0,
|
||||
dim_y + 1,
|
||||
max(1, int(dim_y / 20)),
|
||||
)
|
||||
},
|
||||
step=1,
|
||||
)
|
||||
),
|
||||
]
|
||||
)
|
||||
if data is None:
|
||||
return [None, None, None, None]
|
||||
return [None]
|
||||
else:
|
||||
if (
|
||||
data["card_settings"] is None
|
||||
or "crop_slider" not in data["card_settings"]
|
||||
):
|
||||
crop_slider = None
|
||||
if (
|
||||
data["fullscreen_settings"] is None
|
||||
or "layer_slider_x" not in data["fullscreen_settings"]
|
||||
):
|
||||
slider_x_fullscreen = None
|
||||
if (
|
||||
data["fullscreen_settings"] is None
|
||||
or "layer_slider_z" not in data["fullscreen_settings"]
|
||||
):
|
||||
slider_z_fullscreen = None
|
||||
if (
|
||||
data["fullscreen_settings"] is None
|
||||
or "crop_slider" not in data["fullscreen_settings"]
|
||||
):
|
||||
crop_slider_fullscreen = None
|
||||
return [
|
||||
crop_slider,
|
||||
slider_x_fullscreen,
|
||||
slider_z_fullscreen,
|
||||
crop_slider_fullscreen,
|
||||
]
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
@ -512,37 +329,19 @@ def get_callbacks():
|
||||
|
||||
return [fig, layer, True]
|
||||
|
||||
# callback pour les B-scan ZX en plein écran
|
||||
@callback(
|
||||
Output("heatmap-bscan-zx-fullscreen", "figure"),
|
||||
Input("layer-slider-bscan-zx-fullscreen", "value"),
|
||||
State("store-settings", "data"),
|
||||
)
|
||||
def update_heatmap_bscan_zx_fullscreen(layer, settings):
|
||||
if settings["apply_sampling_everywhere"]:
|
||||
data = volume
|
||||
else:
|
||||
data = pre_volume
|
||||
|
||||
fig = px.imshow(
|
||||
data[layer - 1, :, :],
|
||||
color_continuous_scale="Jet",
|
||||
aspect="auto",
|
||||
title="B-scan ZX",
|
||||
)
|
||||
|
||||
return fig
|
||||
|
||||
# callback pour le plein écran du B-scan ZX
|
||||
@callback(
|
||||
Output("modal-bscan-zx", "is_open"),
|
||||
clientside_callback(
|
||||
"""
|
||||
function toggle_fullscreen_bscan_zx(n1) {
|
||||
if (n1) {
|
||||
window.open("fullscreen/bscan-zx", "", "width=800,height=600,popup=true");
|
||||
}
|
||||
}
|
||||
""",
|
||||
Output("js", "children", allow_duplicate=True),
|
||||
[Input("fullscreen-button-bscan-zx", "n_clicks")],
|
||||
[dash.dependencies.State("modal-bscan-zx", "is_open")],
|
||||
prevent_initial_call=True,
|
||||
)
|
||||
def toggle_fullscreen_bscan_zx(n1, is_open):
|
||||
if n1:
|
||||
return not is_open
|
||||
return is_open
|
||||
|
||||
# callback pour les paramètres du B-scan ZX
|
||||
@callback(
|
||||
@ -576,7 +375,6 @@ def get_callbacks():
|
||||
@callback(
|
||||
[
|
||||
Output("layer-slider-bscan-zx-container", "children"),
|
||||
Output("layer-slider-bscan-zx-fullscreen-container", "children"),
|
||||
],
|
||||
Input("bscan-zx-settings", "data"),
|
||||
)
|
||||
@ -599,56 +397,14 @@ def get_callbacks():
|
||||
),
|
||||
]
|
||||
)
|
||||
x_slider_fullscreen = dbc.Row(
|
||||
[
|
||||
dbc.Col(html.Span("X layer: "), width="auto"),
|
||||
dbc.Col(
|
||||
dcc.Slider(
|
||||
id="layer-slider-bscan-zx-fullscreen",
|
||||
min=0,
|
||||
max=dim_z,
|
||||
value=0,
|
||||
step=1,
|
||||
marks={
|
||||
str(i): str(i)
|
||||
for i in range(0, dim_z, max(1, int(dim_z / 50)))
|
||||
},
|
||||
)
|
||||
),
|
||||
]
|
||||
)
|
||||
y_slider_fullscreen = dbc.Row(
|
||||
[
|
||||
dbc.Col(html.Span("Y layer: "), width="auto"),
|
||||
dbc.Col(
|
||||
dcc.Slider(
|
||||
id="layer-slider-bscan-xy-fullscreen",
|
||||
min=0,
|
||||
max=dim_z,
|
||||
value=0,
|
||||
step=1,
|
||||
marks={
|
||||
str(i): str(i)
|
||||
for i in range(0, dim_z, max(1, int(dim_z / 50)))
|
||||
},
|
||||
)
|
||||
),
|
||||
]
|
||||
)
|
||||
if data is None:
|
||||
return [None, None]
|
||||
return [None]
|
||||
else:
|
||||
if data["card_settings"] is None or "x_slider" not in data["card_settings"]:
|
||||
slider = None
|
||||
if (
|
||||
data["fullscreen_settings"] is None
|
||||
or "layer_slider" not in data["fullscreen_settings"]
|
||||
):
|
||||
slider_fullscreen = None
|
||||
|
||||
return [
|
||||
slider,
|
||||
slider_fullscreen,
|
||||
]
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
@ -682,34 +438,20 @@ def get_callbacks():
|
||||
fig.update_layout(title="B-scan XY")
|
||||
|
||||
return [fig, layer, True]
|
||||
|
||||
# callback pour les B-scan ZX en plein écran
|
||||
@callback(
|
||||
Output("heatmap-bscan-xy-fullscreen", "figure"),
|
||||
Input("layer-slider-bscan-xy-fullscreen", "value"),
|
||||
State("store-settings", "data"),
|
||||
)
|
||||
def update_heatmap_bscan_xy_fullscreen(layer, settings):
|
||||
if settings["apply_sampling_everywhere"]:
|
||||
data = volume
|
||||
else:
|
||||
data = pre_volume
|
||||
|
||||
fig = go.Figure(data=go.Heatmap(z=data[:, :, layer], colorscale="Jet"))
|
||||
fig.update_layout(title="B-scan XY")
|
||||
|
||||
return fig
|
||||
|
||||
|
||||
# callback pour le plein écran du B-scan XY
|
||||
@callback(
|
||||
Output("modal-bscan-xy", "is_open"),
|
||||
clientside_callback(
|
||||
"""
|
||||
function toggle_fullscreen_bscan_xy(n1) {
|
||||
if (n1) {
|
||||
window.open("fullscreen/bscan-xy", "", "width=800,height=600,popup=true");
|
||||
}
|
||||
}
|
||||
""",
|
||||
Output("js", "children", allow_duplicate=True),
|
||||
[Input("fullscreen-button-bscan-xy", "n_clicks")],
|
||||
[dash.dependencies.State("modal-bscan-xy", "is_open")],
|
||||
prevent_initial_call=True,
|
||||
)
|
||||
def toggle_fullscreen_bscan_xy(n1, is_open):
|
||||
if n1:
|
||||
return not is_open
|
||||
return is_open
|
||||
|
||||
@callback(
|
||||
[
|
||||
@ -758,7 +500,6 @@ def get_callbacks():
|
||||
@callback(
|
||||
[
|
||||
Output("layer-slider-bscan-xy-container", "children"),
|
||||
Output("layer-slider-bscan-xy-fullscreen-container", "children"),
|
||||
],
|
||||
Input("bscan-xy-settings", "data"),
|
||||
)
|
||||
@ -781,56 +522,14 @@ def get_callbacks():
|
||||
),
|
||||
]
|
||||
)
|
||||
x_slider_fullscreen = dbc.Row(
|
||||
[
|
||||
dbc.Col(html.Span("X layer: "), width="auto"),
|
||||
dbc.Col(
|
||||
dcc.Slider(
|
||||
id="layer-slider-bscan-xy-fullscreen",
|
||||
min=0,
|
||||
max=dim_x,
|
||||
value=0,
|
||||
step=1,
|
||||
marks={
|
||||
str(i): str(i)
|
||||
for i in range(0, dim_x, max(1, int(dim_x / 50)))
|
||||
},
|
||||
)
|
||||
),
|
||||
]
|
||||
)
|
||||
y_slider_fullscreen = dbc.Row(
|
||||
[
|
||||
dbc.Col(html.Span("Y layer: "), width="auto"),
|
||||
dbc.Col(
|
||||
dcc.Slider(
|
||||
id="layer-slider-bscan-zx-fullscreen",
|
||||
min=0,
|
||||
max=dim_x,
|
||||
value=0,
|
||||
step=1,
|
||||
marks={
|
||||
str(i): str(i)
|
||||
for i in range(0, dim_x, max(1, int(dim_x / 50)))
|
||||
},
|
||||
)
|
||||
),
|
||||
]
|
||||
)
|
||||
if data is None:
|
||||
return [None, None]
|
||||
return [None]
|
||||
else:
|
||||
if data["card_settings"] is None or "x_slider" not in data["card_settings"]:
|
||||
slider = None
|
||||
if (
|
||||
data["fullscreen_settings"] is None
|
||||
or "layer_slider" not in data["fullscreen_settings"]
|
||||
):
|
||||
slider_fullscreen = None
|
||||
|
||||
return [
|
||||
slider,
|
||||
slider_fullscreen,
|
||||
]
|
||||
|
||||
# ---------------------------------------------------------------------------------
|
||||
@ -1107,9 +806,9 @@ def get_callbacks():
|
||||
|
||||
# Mettre à jour les graphiques
|
||||
update_3dplot(0, [0, dim_y // 2], settings, False)
|
||||
update_heatmap_ascan(0, 0, False, settings)
|
||||
update_heatmap_bscan_zx(0, False, settings)
|
||||
update_heatmap_bscan_xy(0, False, settings)
|
||||
update_heatmap_ascan(0, 0, False, settings) # type: ignore
|
||||
update_heatmap_bscan_zx(0, False, settings) # type: ignore
|
||||
update_heatmap_bscan_xy(0, False, settings) # type: ignore
|
||||
|
||||
return None
|
||||
|
||||
|
@ -4,6 +4,7 @@ from os import listdir
|
||||
from os.path import isfile, join
|
||||
import dash_bootstrap_components as dbc
|
||||
|
||||
|
||||
def get_callbacks():
|
||||
# callback pour le modal
|
||||
@callback(
|
||||
@ -16,7 +17,6 @@ def get_callbacks():
|
||||
return not is_open
|
||||
return is_open
|
||||
|
||||
|
||||
@callback(
|
||||
Output("settings-modal", "is_open"),
|
||||
[Input("settings-open", "n_clicks"), Input("settings-close", "n_clicks")],
|
||||
@ -27,7 +27,6 @@ def get_callbacks():
|
||||
return not is_open
|
||||
return is_open
|
||||
|
||||
|
||||
# callback pour le navmenu
|
||||
@callback(
|
||||
Output("offcanvas-menu", "is_open"),
|
||||
@ -39,10 +38,13 @@ def get_callbacks():
|
||||
return not is_open
|
||||
return is_open
|
||||
|
||||
|
||||
@callback(
|
||||
Output("open-modal", "is_open"),
|
||||
[Input("open-button", "n_clicks"), Input("open-close", "n_clicks"), Input("open-refresh", "n_clicks")],
|
||||
[
|
||||
Input("open-button", "n_clicks"),
|
||||
Input("open-close", "n_clicks"),
|
||||
Input("open-refresh", "n_clicks"),
|
||||
],
|
||||
[dash.dependencies.State("open-modal", "is_open")],
|
||||
)
|
||||
def toggle_open(n1, n2, n3, is_open):
|
||||
@ -52,7 +54,6 @@ def get_callbacks():
|
||||
return True
|
||||
return is_open
|
||||
|
||||
|
||||
@callback(
|
||||
Output("save-modal", "is_open"),
|
||||
[
|
||||
@ -67,7 +68,6 @@ def get_callbacks():
|
||||
return not is_open
|
||||
return is_open
|
||||
|
||||
|
||||
@callback(
|
||||
Output("file-list", "children"),
|
||||
[Input("open-refresh", "n_clicks")],
|
||||
@ -85,7 +85,6 @@ def get_callbacks():
|
||||
if isfile(join("Dataset/saves", file))
|
||||
]
|
||||
|
||||
|
||||
@callback(
|
||||
[
|
||||
Output("open-modal", "is_open", allow_duplicate=True),
|
||||
@ -105,7 +104,6 @@ def get_callbacks():
|
||||
filename = filenames[file_index["index"]]
|
||||
return [False, filename, f"Opened file: {filename}"]
|
||||
|
||||
|
||||
@callback(
|
||||
Output("save-format", "options"),
|
||||
[Input("store-filters", "data")],
|
||||
@ -121,3 +119,11 @@ def get_callbacks():
|
||||
{"label": "Save filtered dataset", "value": "filt", "disabled": True},
|
||||
]
|
||||
|
||||
@callback(
|
||||
Output("navbar", "style"),
|
||||
Input("loc", "pathname"),
|
||||
)
|
||||
def hide_navbar(pathname):
|
||||
if not str.startswith(pathname, "/fullscreen"):
|
||||
return {"display": "block"}
|
||||
return {"display": "none"}
|
||||
|
@ -1,7 +1,7 @@
|
||||
import dash
|
||||
from dash import dcc, html, ALL, DiskcacheManager
|
||||
import dash_bootstrap_components as dbc
|
||||
from os import listdir, mkdir, path
|
||||
from os import listdir, mkdir
|
||||
from os.path import isfile, join
|
||||
import diskcache
|
||||
from json import load
|
||||
@ -69,7 +69,7 @@ modal_overlay = dbc.Modal(
|
||||
|
||||
modal_settings = dbc.Modal(
|
||||
[
|
||||
dbc.ModalHeader("Settings"),
|
||||
dbc.ModalHeader(dbc.ModalTitle("Settings")),
|
||||
dbc.ModalBody(
|
||||
[
|
||||
dbc.Switch(
|
||||
@ -146,7 +146,7 @@ modal_settings = dbc.Modal(
|
||||
|
||||
modal_open = dbc.Modal(
|
||||
[
|
||||
dbc.ModalHeader("Open a file"),
|
||||
dbc.ModalHeader(dbc.ModalTitle("Open a file")),
|
||||
dbc.ModalBody(
|
||||
[
|
||||
dbc.ListGroup(
|
||||
@ -177,7 +177,7 @@ modal_open = dbc.Modal(
|
||||
|
||||
modal_save = dbc.Modal(
|
||||
[
|
||||
dbc.ModalHeader("Save a file"),
|
||||
dbc.ModalHeader(dbc.ModalTitle("Save a file")),
|
||||
dbc.ModalBody(
|
||||
[
|
||||
dbc.Input(id="save-input", placeholder="Filename"),
|
||||
@ -383,6 +383,8 @@ nav_bar = dbc.Navbar(
|
||||
style={"--bs-gutter-x": "0"},
|
||||
),
|
||||
dark=True,
|
||||
style={"display": "none"},
|
||||
id="navbar",
|
||||
)
|
||||
|
||||
# on défini le layout de l'application
|
||||
@ -408,8 +410,10 @@ app.layout = dbc.Container(
|
||||
dcc.Store(id="3dplot-settings"),
|
||||
dcc.Store(id="bscan-zx-settings"),
|
||||
dcc.Store(id="bscan-xy-settings"),
|
||||
html.Div(id="js", hidden=True),
|
||||
],
|
||||
id="app-container",
|
||||
style={"paddingLeft": "0 !important", "paddingRight": "0 !important"},
|
||||
fluid=True,
|
||||
)
|
||||
|
||||
@ -418,5 +422,5 @@ get_callbacks()
|
||||
# on lance l'application
|
||||
if __name__ == "__main__":
|
||||
app.run(
|
||||
debug=config["debug"] or False, port=config["port"] or "8051", threaded=True
|
||||
debug=config["debug"] or False, dev_tools_ui=config['debug'] or False, port=config["port"] or "8051", threaded=True
|
||||
)
|
||||
|
194
3D_app/pages/fullscreen/3dplot.py
Normal file
194
3D_app/pages/fullscreen/3dplot.py
Normal file
@ -0,0 +1,194 @@
|
||||
from dash import html, dcc, callback, Output, Input, clientside_callback
|
||||
import dash_bootstrap_components as dbc
|
||||
import numpy as np
|
||||
import plotly.graph_objects as go
|
||||
import plotly.io as pio
|
||||
import dash
|
||||
from callbacks.home import pre_volume, volume, dim_x, dim_y, dim_z, X, Y, Z
|
||||
|
||||
dash.register_page(
|
||||
__name__,
|
||||
path="/fullscreen/3dplot",
|
||||
title="3D Plot",
|
||||
)
|
||||
|
||||
# on défini le thème de l'application
|
||||
pio.templates.default = "plotly_dark"
|
||||
|
||||
# on crée le plot 3D
|
||||
fig = go.Figure(
|
||||
data=go.Volume(
|
||||
x=X.flatten(),
|
||||
y=Y.flatten(),
|
||||
z=Z.flatten(),
|
||||
value=volume.flatten(),
|
||||
isomin=5000,
|
||||
isomax=volume.max(),
|
||||
opacity=0.1, # needs to be small to see through all surfaces
|
||||
surface_count=20, # needs to be a large number for good volume rendering
|
||||
colorscale="Jet",
|
||||
)
|
||||
)
|
||||
|
||||
# on défini les configurations des plots
|
||||
config3DPlot = {
|
||||
"toImageButtonOptions": {
|
||||
"format": "svg", # one of png, svg, jpeg, webp
|
||||
"filename": "3D-Plot",
|
||||
"height": 1000,
|
||||
"width": 1400,
|
||||
"scale": 1, # Multiply title/legend/axis/canvas sizes by this factor
|
||||
},
|
||||
"displaylogo": False,
|
||||
}
|
||||
|
||||
layout = html.Div(
|
||||
[
|
||||
html.Div(id="3dplot-js", hidden=True),
|
||||
dbc.Spinner(id="loading-3dplot", color="primary", fullscreen=True, fullscreen_style={"backgroundColor": "var(--bs-body-bg)"}),
|
||||
dcc.Graph(
|
||||
id="3dplot-fullscreen",
|
||||
figure=fig,
|
||||
config=config3DPlot,
|
||||
style={"marginBottom": "15px", "height": "85vh"},
|
||||
), # 'fig' is your 3D plotly figure
|
||||
html.Div(
|
||||
dcc.Slider(
|
||||
id="iso-slider-fullscreen",
|
||||
min=volume.min(),
|
||||
max=volume.max() / 2,
|
||||
value=volume.min(),
|
||||
marks={
|
||||
str(i): str(i)
|
||||
for i in range(
|
||||
int(volume.min()),
|
||||
int(volume.max() / 2) + 1,
|
||||
int((volume.max() / 2 - volume.min()) / 20),
|
||||
)
|
||||
},
|
||||
step=1,
|
||||
),
|
||||
id="iso-slider-fullscreen-container",
|
||||
),
|
||||
html.Div(
|
||||
dcc.RangeSlider(
|
||||
id="y-slider-fullscreen",
|
||||
min=0,
|
||||
max=dim_y,
|
||||
value=[0, dim_y / 2],
|
||||
marks={
|
||||
str(i): str(i)
|
||||
for i in range(
|
||||
0,
|
||||
int(dim_y) + 1,
|
||||
max(1, int(dim_y / 50)),
|
||||
)
|
||||
},
|
||||
step=1,
|
||||
),
|
||||
id="y-slider-fullscreen-container",
|
||||
),
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
# callback pour le plot 3D en plein écran
|
||||
@callback(
|
||||
[Output("3dplot-fullscreen", "figure"), Output("loading-3dplot", "children")],
|
||||
[
|
||||
Input("iso-slider-fullscreen", "value"),
|
||||
Input("y-slider-fullscreen", "value"),
|
||||
],
|
||||
)
|
||||
def update_3dplot_fullscreen(iso_value, y_values):
|
||||
y_min, y_max = y_values
|
||||
selected_volume = volume[0:dim_x, int(y_min) : int(y_max), 0:dim_z]
|
||||
X, Y, Z = np.mgrid[
|
||||
0 : selected_volume.shape[0],
|
||||
0 : selected_volume.shape[1],
|
||||
0 : selected_volume.shape[2],
|
||||
]
|
||||
|
||||
fig = go.Figure(
|
||||
data=go.Volume(
|
||||
x=X.flatten(),
|
||||
y=Y.flatten(),
|
||||
z=Z.flatten(),
|
||||
value=selected_volume.flatten(),
|
||||
isomin=iso_value,
|
||||
isomax=selected_volume.max(),
|
||||
opacity=0.1,
|
||||
surface_count=20,
|
||||
colorscale="Jet",
|
||||
)
|
||||
)
|
||||
|
||||
return [fig, html.Div()]
|
||||
|
||||
|
||||
@callback(
|
||||
[
|
||||
Output("iso-slider-fullscreen-container", "children"),
|
||||
Output("y-slider-fullscreen-container", "children"),
|
||||
],
|
||||
Input("3dplot-settings", "data"),
|
||||
)
|
||||
def update_3dplot_sliders(data):
|
||||
print(data)
|
||||
iso_slider = dbc.Row(
|
||||
[
|
||||
dbc.Col(html.Span("Iso value: "), width="auto"),
|
||||
dbc.Col(
|
||||
dcc.Slider(
|
||||
id="iso-slider-fullscreen",
|
||||
min=0,
|
||||
max=volume.max() / 2,
|
||||
value=0,
|
||||
step=1,
|
||||
marks={
|
||||
str(i): str(i)
|
||||
for i in range(
|
||||
0,
|
||||
int(volume.max() / 2) + 1,
|
||||
int((volume.max() / 2) / 20),
|
||||
)
|
||||
},
|
||||
)
|
||||
),
|
||||
]
|
||||
)
|
||||
y_slider = dbc.Row(
|
||||
[
|
||||
dbc.Col(html.Span("Y crop: "), width="auto"),
|
||||
dbc.Col(
|
||||
dcc.RangeSlider(
|
||||
id="y-slider-fullscreen",
|
||||
min=0,
|
||||
max=dim_y,
|
||||
value=[0, dim_y],
|
||||
marks={
|
||||
str(i): str(i)
|
||||
for i in range(0, dim_y + 1, max(1, int(dim_y / 20)))
|
||||
},
|
||||
)
|
||||
),
|
||||
]
|
||||
)
|
||||
if data is None:
|
||||
return [None, None]
|
||||
else:
|
||||
if (
|
||||
data["fullscreen_settings"] is None
|
||||
or "iso_slider" not in data["fullscreen_settings"]
|
||||
):
|
||||
iso_slider = None
|
||||
if (
|
||||
data["fullscreen_settings"] is None
|
||||
or "y_slider" not in data["fullscreen_settings"]
|
||||
):
|
||||
y_slider = None
|
||||
|
||||
return [
|
||||
iso_slider,
|
||||
y_slider,
|
||||
]
|
199
3D_app/pages/fullscreen/ascan.py
Normal file
199
3D_app/pages/fullscreen/ascan.py
Normal file
@ -0,0 +1,199 @@
|
||||
import dash
|
||||
from dash import dcc, html, Input, Output, State, callback
|
||||
import dash_bootstrap_components as dbc
|
||||
import plotly.express as px
|
||||
from callbacks.home import pre_volume, volume, dim_x, dim_y, dim_z, X, Y, Z
|
||||
|
||||
dash.register_page(__name__, path="/fullscreen/ascan", title="A-Scan")
|
||||
|
||||
configAScan = {
|
||||
"toImageButtonOptions": {
|
||||
"format": "svg", # one of png, svg, jpeg, webp
|
||||
"filename": "A-Scan",
|
||||
"height": 1000,
|
||||
"width": 1400,
|
||||
"scale": 1, # Multiply title/legend/axis/canvas sizes by this factor
|
||||
},
|
||||
"displaylogo": False,
|
||||
}
|
||||
|
||||
layout = html.Div(
|
||||
[
|
||||
dbc.Spinner(
|
||||
id="loading-ascan",
|
||||
color="primary",
|
||||
fullscreen=True,
|
||||
fullscreen_style={"backgroundColor": "var(--bs-body-bg)"},
|
||||
),
|
||||
dcc.Graph(
|
||||
id="heatmap-ascan-fullscreen",
|
||||
config=configAScan,
|
||||
style={"marginBottom": "15px", "height": "85vh"},
|
||||
), # 'fig' is your 2D plotly figure
|
||||
html.Div(
|
||||
dcc.Slider(
|
||||
id="layer-slider-x-ascan-fullscreen",
|
||||
min=0,
|
||||
max=dim_x,
|
||||
value=0,
|
||||
step=1,
|
||||
marks={
|
||||
str(i): str(i)
|
||||
for i in range(
|
||||
0,
|
||||
dim_x,
|
||||
max(1, int(dim_x / 50)),
|
||||
)
|
||||
},
|
||||
),
|
||||
id="layer-slider-x-ascan-fullscreen-container",
|
||||
),
|
||||
html.Div(
|
||||
dcc.Slider(
|
||||
id="layer-slider-z-ascan-fullscreen",
|
||||
min=1,
|
||||
max=dim_z,
|
||||
value=1,
|
||||
step=1,
|
||||
marks={
|
||||
str(i): str(i)
|
||||
for i in range(
|
||||
1,
|
||||
dim_z,
|
||||
max(1, int(dim_z / 20)),
|
||||
)
|
||||
},
|
||||
),
|
||||
id="layer-slider-z-ascan-fullscreen-container",
|
||||
),
|
||||
html.Div(
|
||||
dcc.RangeSlider(
|
||||
id="crop-slider-fullscreen",
|
||||
min=0,
|
||||
max=dim_y,
|
||||
value=[0, dim_y],
|
||||
marks={
|
||||
str(i): str(i)
|
||||
for i in range(
|
||||
0,
|
||||
dim_y + 1,
|
||||
max(1, int(dim_y / 20)),
|
||||
)
|
||||
},
|
||||
step=1,
|
||||
),
|
||||
id="crop-slider-fullscreen-container",
|
||||
),
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
# callback pour le A-scan en plein écran
|
||||
@callback(
|
||||
[Output("heatmap-ascan-fullscreen", "figure"), Output("loading-ascan", "children")],
|
||||
[
|
||||
Input("layer-slider-x-ascan-fullscreen", "value"),
|
||||
Input("layer-slider-z-ascan-fullscreen", "value"),
|
||||
Input("crop-slider-fullscreen", "value"),
|
||||
],
|
||||
State("store-settings", "data"),
|
||||
)
|
||||
def update_heatmap_ascan_fullscreen(layer_x, layer_z, crop, settings):
|
||||
y_min, y_max = crop or [0, dim_y]
|
||||
layer_x = layer_x or 0
|
||||
layer_z = layer_z or 0
|
||||
if settings["apply_sampling_everywhere"]:
|
||||
data = volume
|
||||
else:
|
||||
data = pre_volume
|
||||
|
||||
fig = px.line(y=data[layer_x - 1, int(y_min) : int(y_max), layer_z], title="A-scan")
|
||||
|
||||
return [fig, html.Div()]
|
||||
|
||||
|
||||
@callback(
|
||||
[
|
||||
Output("layer-slider-x-ascan-fullscreen-container", "children"),
|
||||
Output("layer-slider-z-ascan-fullscreen-container", "children"),
|
||||
Output("crop-slider-fullscreen-container", "children"),
|
||||
],
|
||||
Input("ascan-settings", "data"),
|
||||
)
|
||||
def update_sliders(data):
|
||||
slider_x_fullscreen = dbc.Row(
|
||||
[
|
||||
dbc.Col(html.Span("Layer X: "), width="auto"),
|
||||
dbc.Col(
|
||||
dcc.Slider(
|
||||
id="layer-slider-x-ascan-fullscreen",
|
||||
min=0,
|
||||
max=dim_x,
|
||||
value=0,
|
||||
step=1,
|
||||
marks={
|
||||
str(i): str(i) for i in range(0, dim_x, max(1, int(dim_x / 50)))
|
||||
},
|
||||
)
|
||||
),
|
||||
]
|
||||
)
|
||||
slider_z_fullscreen = dbc.Row(
|
||||
[
|
||||
dbc.Col(html.Span("Layer Z: "), width="auto"),
|
||||
dbc.Col(
|
||||
dcc.Slider(
|
||||
id="layer-slider-z-ascan-fullscreen",
|
||||
min=1,
|
||||
max=dim_z - 1,
|
||||
value=1,
|
||||
marks={
|
||||
str(i): str(i)
|
||||
for i in range(1, dim_z - 1, max(1, int(dim_z / 20)))
|
||||
},
|
||||
step=1,
|
||||
)
|
||||
),
|
||||
]
|
||||
)
|
||||
crop_slider_fullscreen = dbc.Row(
|
||||
[
|
||||
dbc.Col(html.Span("Crop: "), width="auto"),
|
||||
dbc.Col(
|
||||
dcc.RangeSlider(
|
||||
id="crop-slider-fullscreen",
|
||||
min=0,
|
||||
max=dim_y,
|
||||
value=[0, dim_y],
|
||||
marks={
|
||||
str(i): str(i)
|
||||
for i in range(
|
||||
0,
|
||||
dim_y + 1,
|
||||
max(1, int(dim_y / 20)),
|
||||
)
|
||||
},
|
||||
step=1,
|
||||
)
|
||||
),
|
||||
]
|
||||
)
|
||||
if data is None:
|
||||
return [None, None, None]
|
||||
else:
|
||||
if (
|
||||
data["fullscreen_settings"] is None
|
||||
or "layer_slider_x" not in data["fullscreen_settings"]
|
||||
):
|
||||
slider_x_fullscreen = None
|
||||
if (
|
||||
data["fullscreen_settings"] is None
|
||||
or "layer_slider_z" not in data["fullscreen_settings"]
|
||||
):
|
||||
slider_z_fullscreen = None
|
||||
if (
|
||||
data["fullscreen_settings"] is None
|
||||
or "crop_slider" not in data["fullscreen_settings"]
|
||||
):
|
||||
crop_slider_fullscreen = None
|
||||
return [slider_x_fullscreen, slider_z_fullscreen, crop_slider_fullscreen]
|
104
3D_app/pages/fullscreen/bscan-xy.py
Normal file
104
3D_app/pages/fullscreen/bscan-xy.py
Normal file
@ -0,0 +1,104 @@
|
||||
import re
|
||||
import dash
|
||||
from dash import html, dcc, Input, Output, State, callback
|
||||
import plotly.graph_objects as go
|
||||
import dash_bootstrap_components as dbc
|
||||
from callbacks.home import pre_volume, volume, dim_x, dim_y, dim_z, X, Y, Z
|
||||
|
||||
dash.register_page(__name__, path="/fullscreen/bscan-xy", title="B-Scan XY")
|
||||
|
||||
configBScanXY = {
|
||||
"toImageButtonOptions": {
|
||||
"format": "svg", # one of png, svg, jpeg, webp
|
||||
"filename": "B-Scan XY",
|
||||
"height": 1000,
|
||||
"width": 1400,
|
||||
"scale": 1, # Multiply title/legend/axis/canvas sizes by this factor
|
||||
},
|
||||
"displaylogo": False,
|
||||
}
|
||||
|
||||
layout = html.Div(
|
||||
[
|
||||
dbc.Spinner(
|
||||
id="loading-bscan-xy",
|
||||
color="primary",
|
||||
fullscreen=True,
|
||||
fullscreen_style={"backgroundColor": "var(--bs-body-bg)"},
|
||||
),
|
||||
dcc.Graph(
|
||||
id="heatmap-bscan-xy-fullscreen",
|
||||
config=configBScanXY,
|
||||
style={"marginBottom": "15px", "height": "85vh"},
|
||||
), # 'fig' is your 2D plotly figure
|
||||
html.Div(
|
||||
dcc.Slider(
|
||||
id="layer-slider-bscan-xy-fullscreen",
|
||||
min=1,
|
||||
max=dim_z - 1,
|
||||
value=1,
|
||||
step=1,
|
||||
marks={
|
||||
str(i): str(i)
|
||||
for i in range(
|
||||
1,
|
||||
dim_z + 1,
|
||||
max(1, int(dim_z / 50)),
|
||||
)
|
||||
},
|
||||
),
|
||||
id="layer-slider-bscan-xy-fullscreen-container",
|
||||
),
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
# callback pour les B-scan ZX en plein écran
|
||||
@callback(
|
||||
[Output("heatmap-bscan-xy-fullscreen", "figure"), Output("loading-bscan-xy", "children")],
|
||||
Input("layer-slider-bscan-xy-fullscreen", "value"),
|
||||
State("store-settings", "data"),
|
||||
)
|
||||
def update_heatmap_bscan_xy_fullscreen(layer, settings):
|
||||
if settings["apply_sampling_everywhere"]:
|
||||
data = volume
|
||||
else:
|
||||
data = pre_volume
|
||||
|
||||
fig = go.Figure(data=go.Heatmap(z=data[:, :, layer], colorscale="Jet"))
|
||||
fig.update_layout(title="B-scan XY")
|
||||
|
||||
return [fig, html.Div()]
|
||||
|
||||
|
||||
@callback(
|
||||
Output("layer-slider-bscan-xy-fullscreen-container", "children"),
|
||||
Input("bscan-xy-settings", "data"),
|
||||
)
|
||||
def update_sliders(data):
|
||||
slider_fullscreen = dbc.Row(
|
||||
[
|
||||
dbc.Col(html.Span("X layer: "), width="auto"),
|
||||
dbc.Col(
|
||||
dcc.Slider(
|
||||
id="layer-slider-bscan-xy-fullscreen",
|
||||
min=0,
|
||||
max=dim_x,
|
||||
value=0,
|
||||
step=1,
|
||||
marks={
|
||||
str(i): str(i) for i in range(0, dim_x, max(1, int(dim_x / 50)))
|
||||
},
|
||||
)
|
||||
),
|
||||
]
|
||||
)
|
||||
if data is None:
|
||||
return [None]
|
||||
else:
|
||||
if (
|
||||
data["fullscreen_settings"] is None
|
||||
or "layer_slider" not in data["fullscreen_settings"]
|
||||
):
|
||||
slider_fullscreen = None
|
||||
return [slider_fullscreen]
|
107
3D_app/pages/fullscreen/bscan-zx.py
Normal file
107
3D_app/pages/fullscreen/bscan-zx.py
Normal file
@ -0,0 +1,107 @@
|
||||
import dash
|
||||
from dash import html, dcc, Input, Output, State, callback
|
||||
import plotly.express as px
|
||||
import dash_bootstrap_components as dbc
|
||||
from callbacks.home import pre_volume, volume, dim_x, dim_y, dim_z, X, Y, Z
|
||||
|
||||
dash.register_page(__name__, path="/fullscreen/bscan-zx", title="B-Scan ZX")
|
||||
|
||||
configBScanXY = {
|
||||
"toImageButtonOptions": {
|
||||
"format": "svg", # one of png, svg, jpeg, webp
|
||||
"filename": "B-Scan ZX",
|
||||
"height": 1000,
|
||||
"width": 1400,
|
||||
"scale": 1, # Multiply title/legend/axis/canvas sizes by this factor
|
||||
},
|
||||
"displaylogo": False,
|
||||
}
|
||||
|
||||
layout = html.Div(
|
||||
[
|
||||
dbc.Spinner(
|
||||
id="loading-bscan-zx",
|
||||
color="primary",
|
||||
fullscreen=True,
|
||||
fullscreen_style={"backgroundColor": "var(--bs-body-bg)"},
|
||||
),
|
||||
dcc.Graph(
|
||||
id="heatmap-bscan-zx-fullscreen",
|
||||
config=configBScanXY,
|
||||
style={"marginBottom": "15px", "height": "85vh"},
|
||||
), # 'fig' is your 2D plotly figure
|
||||
html.Div(
|
||||
dcc.Slider(
|
||||
id="layer-slider-bscan-zx-fullscreen",
|
||||
min=0,
|
||||
max=dim_x,
|
||||
value=0,
|
||||
step=1,
|
||||
marks={
|
||||
str(i): str(i)
|
||||
for i in range(
|
||||
0,
|
||||
dim_x + 1,
|
||||
max(1, int(dim_x / 50)),
|
||||
)
|
||||
},
|
||||
),
|
||||
id="layer-slider-bscan-zx-fullscreen-container",
|
||||
),
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
# callback pour les B-scan ZX en plein écran
|
||||
@callback(
|
||||
[Output("heatmap-bscan-zx-fullscreen", "figure"), Output("loading-bscan-zx", "children")],
|
||||
Input("layer-slider-bscan-zx-fullscreen", "value"),
|
||||
State("store-settings", "data"),
|
||||
)
|
||||
def update_heatmap_bscan_zx_fullscreen(layer, settings):
|
||||
if settings["apply_sampling_everywhere"]:
|
||||
data = volume
|
||||
else:
|
||||
data = pre_volume
|
||||
|
||||
fig = px.imshow(
|
||||
data[layer - 1, :, :],
|
||||
color_continuous_scale="Jet",
|
||||
aspect="auto",
|
||||
title="B-scan ZX",
|
||||
)
|
||||
|
||||
return [fig, html.Div()]
|
||||
|
||||
@callback(
|
||||
Output("layer-slider-bscan-zx-fullscreen-container", "children"),
|
||||
Input("bscan-zx-settings", "data"),
|
||||
)
|
||||
def update_sliders(data):
|
||||
slider_fullscreen = dbc.Row(
|
||||
[
|
||||
dbc.Col(html.Span("X layer: "), width="auto"),
|
||||
dbc.Col(
|
||||
dcc.Slider(
|
||||
id="layer-slider-bscan-zx-fullscreen",
|
||||
min=0,
|
||||
max=dim_x,
|
||||
value=0,
|
||||
step=1,
|
||||
marks={
|
||||
str(i): str(i)
|
||||
for i in range(0, dim_x, max(1, int(dim_x / 50)))
|
||||
},
|
||||
)
|
||||
),
|
||||
]
|
||||
)
|
||||
if data is None:
|
||||
return None
|
||||
else:
|
||||
if (
|
||||
data["fullscreen_settings"] is None
|
||||
or "layer_slider" not in data["fullscreen_settings"]
|
||||
):
|
||||
slider_fullscreen = None
|
||||
return slider_fullscreen
|
@ -1,5 +1,5 @@
|
||||
import dash
|
||||
from dash import html, dcc, DiskcacheManager
|
||||
from dash import html, dcc, DiskcacheManager, get_asset_url
|
||||
import dash_bootstrap_components as dbc
|
||||
import plotly.graph_objects as go
|
||||
import numpy as np
|
||||
@ -178,66 +178,7 @@ mesh_card = dbc.Fade(
|
||||
),
|
||||
dbc.Modal(
|
||||
[
|
||||
dbc.ModalHeader(dbc.ModalTitle("3D Plot")),
|
||||
dbc.ModalBody(
|
||||
[
|
||||
dcc.Graph(
|
||||
id="3dplot-fullscreen",
|
||||
figure=fig,
|
||||
config=config3DPlot,
|
||||
style={"marginBottom": "15px", "height": "90%"},
|
||||
), # 'fig' is your 3D plotly figure
|
||||
html.Div(
|
||||
dcc.Slider(
|
||||
id="iso-slider-fullscreen",
|
||||
min=volume.min(),
|
||||
max=volume.max() / 2,
|
||||
value=volume.min(),
|
||||
marks={
|
||||
str(i): str(i)
|
||||
for i in range(
|
||||
int(volume.min()),
|
||||
int(volume.max() / 2) + 1,
|
||||
int(
|
||||
(
|
||||
volume.max() / 2
|
||||
- volume.min()
|
||||
)
|
||||
/ 20
|
||||
),
|
||||
)
|
||||
},
|
||||
step=1,
|
||||
),
|
||||
id="iso-slider-fullscreen-container",
|
||||
),
|
||||
html.Div(
|
||||
dcc.RangeSlider(
|
||||
id="y-slider-fullscreen",
|
||||
min=0,
|
||||
max=dim_y,
|
||||
value=[0, dim_y / 2],
|
||||
marks={
|
||||
str(i): str(i)
|
||||
for i in range(
|
||||
0,
|
||||
int(dim_y) + 1,
|
||||
max(1, int(dim_y / 50)),
|
||||
)
|
||||
},
|
||||
step=1,
|
||||
),
|
||||
id="y-slider-fullscreen-container",
|
||||
),
|
||||
]
|
||||
),
|
||||
],
|
||||
id="modal-3dplot",
|
||||
fullscreen=True,
|
||||
),
|
||||
dbc.Modal(
|
||||
[
|
||||
dbc.ModalHeader(dbc.ModalTitle("3D plot settings")),
|
||||
dbc.ModalHeader([html.Img(src=get_asset_url("settings.png"), height="32px", style={"marginRight": "5px"}), dbc.ModalTitle("3D plot settings")]),
|
||||
dbc.ModalBody(
|
||||
[
|
||||
html.Span("Card display: "),
|
||||
@ -352,77 +293,7 @@ Ascan_card = dbc.Fade(
|
||||
),
|
||||
dbc.Modal(
|
||||
[
|
||||
dbc.ModalHeader(dbc.ModalTitle("A-Scan")),
|
||||
dbc.ModalBody(
|
||||
[
|
||||
dcc.Graph(
|
||||
id="heatmap-ascan-fullscreen",
|
||||
config=configAScan,
|
||||
style={"marginBottom": "15px"},
|
||||
), # 'fig' is your 2D plotly figure
|
||||
html.Div(
|
||||
dcc.Slider(
|
||||
id="layer-slider-x-ascan-fullscreen",
|
||||
min=0,
|
||||
max=dim_x,
|
||||
value=0,
|
||||
step=1,
|
||||
marks={
|
||||
str(i): str(i)
|
||||
for i in range(
|
||||
0,
|
||||
dim_x,
|
||||
max(1, int(dim_x / 50)),
|
||||
)
|
||||
},
|
||||
),
|
||||
id="layer-slider-x-ascan-fullscreen-container",
|
||||
),
|
||||
html.Div(
|
||||
dcc.Slider(
|
||||
id="layer-slider-z-ascan-fullscreen",
|
||||
min=1,
|
||||
max=dim_z,
|
||||
value=1,
|
||||
step=1,
|
||||
marks={
|
||||
str(i): str(i)
|
||||
for i in range(
|
||||
1,
|
||||
dim_z,
|
||||
max(1, int(dim_z / 20)),
|
||||
)
|
||||
},
|
||||
),
|
||||
id="layer-slider-z-ascan-fullscreen-container",
|
||||
),
|
||||
html.Div(
|
||||
dcc.RangeSlider(
|
||||
id="crop-slider-fullscreen",
|
||||
min=0,
|
||||
max=dim_y,
|
||||
value=[0, dim_y],
|
||||
marks={
|
||||
str(i): str(i)
|
||||
for i in range(
|
||||
0,
|
||||
dim_y + 1,
|
||||
max(1, int(dim_y / 20)),
|
||||
)
|
||||
},
|
||||
step=1,
|
||||
),
|
||||
id="crop-slider-fullscreen-container",
|
||||
),
|
||||
]
|
||||
),
|
||||
],
|
||||
id="modal-ascan",
|
||||
fullscreen=True,
|
||||
),
|
||||
dbc.Modal(
|
||||
[
|
||||
dbc.ModalHeader(dbc.ModalTitle("A-Scan settings")),
|
||||
dbc.ModalHeader([html.Img(src=get_asset_url("settings.png"), height="32px", style={"marginRight": "5px"}), dbc.ModalTitle("A-Scan settings")]),
|
||||
dbc.ModalBody(
|
||||
[
|
||||
html.Span("Card display: "),
|
||||
@ -537,41 +408,7 @@ Bscan_card_xy = dbc.Fade(
|
||||
),
|
||||
dbc.Modal(
|
||||
[
|
||||
dbc.ModalHeader(dbc.ModalTitle("B-Scan ZX")),
|
||||
dbc.ModalBody(
|
||||
[
|
||||
dcc.Graph(
|
||||
id="heatmap-bscan-zx-fullscreen",
|
||||
config=configBScanXY,
|
||||
style={"marginBottom": "15px", "height": "90%"},
|
||||
), # 'fig' is your 2D plotly figure
|
||||
html.Div(
|
||||
dcc.Slider(
|
||||
id="layer-slider-bscan-zx-fullscreen",
|
||||
min=0,
|
||||
max=dim_x,
|
||||
value=0,
|
||||
step=1,
|
||||
marks={
|
||||
str(i): str(i)
|
||||
for i in range(
|
||||
0,
|
||||
dim_x + 1,
|
||||
max(1, int(dim_x / 50)),
|
||||
)
|
||||
},
|
||||
),
|
||||
id="layer-slider-bscan-zx-fullscreen-container",
|
||||
),
|
||||
]
|
||||
),
|
||||
],
|
||||
id="modal-bscan-zx",
|
||||
fullscreen=True,
|
||||
),
|
||||
dbc.Modal(
|
||||
[
|
||||
dbc.ModalHeader(dbc.ModalTitle("B-Scan ZX settings")),
|
||||
dbc.ModalHeader([html.Img(src=get_asset_url("settings.png"), height="32px", style={"marginRight": "5px"}), dbc.ModalTitle("B-Scan ZX settings")]),
|
||||
dbc.ModalBody(
|
||||
[
|
||||
html.Span("Card display: "),
|
||||
@ -689,41 +526,7 @@ Bscan_card_zx = dbc.Fade(
|
||||
),
|
||||
dbc.Modal(
|
||||
[
|
||||
dbc.ModalHeader(dbc.ModalTitle("B-Scan XY")),
|
||||
dbc.ModalBody(
|
||||
[
|
||||
dcc.Graph(
|
||||
id="heatmap-bscan-xy-fullscreen",
|
||||
config=configBScanXY,
|
||||
style={"marginBottom": "15px", "height": "90%"},
|
||||
), # 'fig' is your 2D plotly figure
|
||||
html.Div(
|
||||
dcc.Slider(
|
||||
id="layer-slider-bscan-xy-fullscreen",
|
||||
min=1,
|
||||
max=dim_z - 1,
|
||||
value=1,
|
||||
step=1,
|
||||
marks={
|
||||
str(i): str(i)
|
||||
for i in range(
|
||||
1,
|
||||
dim_z + 1,
|
||||
max(1, int(dim_z / 50)),
|
||||
)
|
||||
},
|
||||
),
|
||||
id="layer-slider-bscan-xy-fullscreen-container",
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
id="modal-bscan-xy",
|
||||
fullscreen=True,
|
||||
),
|
||||
dbc.Modal(
|
||||
[
|
||||
dbc.ModalHeader(dbc.ModalTitle("B-Scan XY settings")),
|
||||
dbc.ModalHeader([html.Img(src=get_asset_url("settings.png"), height="32px", style={"marginRight": "5px"}), dbc.ModalTitle("B-Scan XY settings")]),
|
||||
dbc.ModalBody(
|
||||
[
|
||||
html.Span("Card display: "),
|
||||
|
@ -1,5 +1,6 @@
|
||||
dash==2.17.0
|
||||
dash_bootstrap_components==1.6.0
|
||||
dash_extensions==1.0.16
|
||||
diskcache==5.6.3
|
||||
matplotlib==3.8.4
|
||||
numpy==2.0.0
|
||||
@ -7,5 +8,5 @@ pandas==2.2.2
|
||||
plotly==5.22.0
|
||||
progress==1.6
|
||||
python_igraph==0.11.5
|
||||
scipy==1.13.1
|
||||
scipy==1.14.0
|
||||
tqdm==4.66.4
|
||||
|
92
electron-3d-app/.gitignore
vendored
Normal file
92
electron-3d-app/.gitignore
vendored
Normal file
@ -0,0 +1,92 @@
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
lerna-debug.log*
|
||||
|
||||
# Diagnostic reports (https://nodejs.org/api/report.html)
|
||||
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
|
||||
|
||||
# Runtime data
|
||||
pids
|
||||
*.pid
|
||||
*.seed
|
||||
*.pid.lock
|
||||
.DS_Store
|
||||
|
||||
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||
lib-cov
|
||||
|
||||
# Coverage directory used by tools like istanbul
|
||||
coverage
|
||||
*.lcov
|
||||
|
||||
# nyc test coverage
|
||||
.nyc_output
|
||||
|
||||
# node-waf configuration
|
||||
.lock-wscript
|
||||
|
||||
# Compiled binary addons (https://nodejs.org/api/addons.html)
|
||||
build/Release
|
||||
|
||||
# Dependency directories
|
||||
node_modules/
|
||||
jspm_packages/
|
||||
|
||||
# TypeScript v1 declaration files
|
||||
typings/
|
||||
|
||||
# TypeScript cache
|
||||
*.tsbuildinfo
|
||||
|
||||
# Optional npm cache directory
|
||||
.npm
|
||||
|
||||
# Optional eslint cache
|
||||
.eslintcache
|
||||
|
||||
# Optional REPL history
|
||||
.node_repl_history
|
||||
|
||||
# Output of 'npm pack'
|
||||
*.tgz
|
||||
|
||||
# Yarn Integrity file
|
||||
.yarn-integrity
|
||||
|
||||
# dotenv environment variables file
|
||||
.env
|
||||
.env.test
|
||||
|
||||
# parcel-bundler cache (https://parceljs.org/)
|
||||
.cache
|
||||
|
||||
# next.js build output
|
||||
.next
|
||||
|
||||
# nuxt.js build output
|
||||
.nuxt
|
||||
|
||||
# vuepress build output
|
||||
.vuepress/dist
|
||||
|
||||
# Serverless directories
|
||||
.serverless/
|
||||
|
||||
# FuseBox cache
|
||||
.fusebox/
|
||||
|
||||
# DynamoDB Local files
|
||||
.dynamodb/
|
||||
|
||||
# Webpack
|
||||
.webpack/
|
||||
|
||||
# Vite
|
||||
.vite/
|
||||
|
||||
# Electron-Forge
|
||||
out/
|
34
electron-3d-app/README.md
Normal file
34
electron-3d-app/README.md
Normal file
@ -0,0 +1,34 @@
|
||||
# Electron app
|
||||
|
||||
## Run or build from source
|
||||
|
||||
### Requirements:
|
||||
|
||||
- Node.JS LTS (tested with 20.14.0)
|
||||
- NPM (tested with 10.8.1)
|
||||
|
||||
### Run
|
||||
|
||||
1. Navigate to this folder
|
||||
2. Run `npm install` to install dependencies
|
||||
3. Run `npm start` to start the application
|
||||
|
||||
### Build
|
||||
|
||||
1. Navigate to this folder
|
||||
2. Run `npm install` to install dependencies
|
||||
3. Run `npm run make` to build the application and package it in an installer
|
||||
4. Run `npm run package` to build the application binaries
|
||||
|
||||
Once this is done, you will find the installer in `/path/to/electron/app/out/make/your_arch/` and the binaries in `/path/to/electron/app/out/your_arch`
|
||||
|
||||
## Use the app
|
||||
|
||||
At first run, the app will ask you to enter the URL of the server
|
||||
|
||||

|
||||
|
||||
|
||||
If the server is unavailable, a message will be displayed to tell you the app cannot contact the server. You have two buttons: Reload and Change config. The second button is to modify the server URL in the config, if your server have new IP.
|
||||
|
||||

|
54
electron-3d-app/forge.config.js
Normal file
54
electron-3d-app/forge.config.js
Normal file
@ -0,0 +1,54 @@
|
||||
const { FusesPlugin } = require('@electron-forge/plugin-fuses');
|
||||
const { FuseV1Options, FuseVersion } = require('@electron/fuses');
|
||||
|
||||
module.exports = {
|
||||
packagerConfig: {
|
||||
asar: true,
|
||||
},
|
||||
rebuildConfig: {},
|
||||
makers: [
|
||||
{
|
||||
name: '@electron-forge/maker-squirrel',
|
||||
config: {
|
||||
options: {
|
||||
author: "Florian Goussot",
|
||||
description: "Stage IJL",
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
name: '@electron-forge/maker-zip',
|
||||
platforms: ['darwin', 'linux', 'windows'],
|
||||
},
|
||||
{
|
||||
name: '@electron-forge/maker-deb',
|
||||
config: {
|
||||
options: {
|
||||
maintainer: 'Florian Goussot',
|
||||
homepage: 'https://github.com/mathur04/stage_IJL'
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
name: '@electron-forge/maker-dmg',
|
||||
config: {},
|
||||
},
|
||||
],
|
||||
plugins: [
|
||||
{
|
||||
name: '@electron-forge/plugin-auto-unpack-natives',
|
||||
config: {},
|
||||
},
|
||||
// Fuses are used to enable/disable various Electron functionality
|
||||
// at package time, before code signing the application
|
||||
new FusesPlugin({
|
||||
version: FuseVersion.V1,
|
||||
[FuseV1Options.RunAsNode]: false,
|
||||
[FuseV1Options.EnableCookieEncryption]: true,
|
||||
[FuseV1Options.EnableNodeOptionsEnvironmentVariable]: false,
|
||||
[FuseV1Options.EnableNodeCliInspectArguments]: false,
|
||||
[FuseV1Options.EnableEmbeddedAsarIntegrityValidation]: true,
|
||||
[FuseV1Options.OnlyLoadAppFromAsar]: true,
|
||||
}),
|
||||
],
|
||||
};
|
BIN
electron-3d-app/image/README/1719573286190.png
Normal file
BIN
electron-3d-app/image/README/1719573286190.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 6.7 KiB |
BIN
electron-3d-app/image/README/1719573426594.png
Normal file
BIN
electron-3d-app/image/README/1719573426594.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 48 KiB |
6424
electron-3d-app/package-lock.json
generated
Normal file
6424
electron-3d-app/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
38
electron-3d-app/package.json
Normal file
38
electron-3d-app/package.json
Normal file
@ -0,0 +1,38 @@
|
||||
{
|
||||
"name": "electron-3d-app",
|
||||
"productName": "electron-3d-app",
|
||||
"version": "1.0.0",
|
||||
"description": "My Electron application description",
|
||||
"main": "src/index.js",
|
||||
"scripts": {
|
||||
"start": "electron-forge start",
|
||||
"package": "electron-forge package",
|
||||
"make": "electron-forge make",
|
||||
"publish": "electron-forge publish",
|
||||
"lint": "echo \"No linting configured\""
|
||||
},
|
||||
"devDependencies": {
|
||||
"@electron-forge/cli": "^7.4.0",
|
||||
"@electron-forge/maker-deb": "^7.4.0",
|
||||
"@electron-forge/maker-rpm": "^7.4.0",
|
||||
"@electron-forge/maker-squirrel": "^7.4.0",
|
||||
"@electron-forge/maker-zip": "^7.4.0",
|
||||
"@electron-forge/plugin-auto-unpack-natives": "^7.4.0",
|
||||
"@electron-forge/plugin-fuses": "^7.4.0",
|
||||
"@electron/fuses": "^1.8.0",
|
||||
"electron": "30.0.6"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": {
|
||||
"name": "Le Stagiaire",
|
||||
"email": "florian.goussot@ac-nancy-metz.fr"
|
||||
},
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@electron-forge/maker-dmg": "^7.4.0",
|
||||
"custom-electron-prompt": "^1.5.7",
|
||||
"electron-squirrel-startup": "^1.0.1",
|
||||
"jspython-interpreter": "^2.1.15",
|
||||
"python-shell": "^5.0.0"
|
||||
}
|
||||
}
|
BIN
electron-3d-app/src/connection_error.png
Normal file
BIN
electron-3d-app/src/connection_error.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 444 KiB |
27
electron-3d-app/src/error.html
Normal file
27
electron-3d-app/src/error.html
Normal file
@ -0,0 +1,27 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous">
|
||||
<title>ERROR!</title>
|
||||
</head>
|
||||
<body style="padding: 8px;">
|
||||
<img src="connection_error.png" alt="Error" height="128"/>
|
||||
<h1>Cannot connect to the server</h1>
|
||||
<p>Cannot access URL <span id="url"></span><br>
|
||||
Please be sure the server is running and the URL is correct!</p>
|
||||
<button id="reload" class="btn btn-primary">Reload</button> <button id="chg_conf" class="btn btn-secondary">Change config</button>
|
||||
<script>
|
||||
document.getElementById('url').innerText = location.search.substring(1);
|
||||
document.getElementById('reload').onclick = () => {
|
||||
document.getElementById('reload').innerHTML = `<span class="spinner-border spinner-border-sm" arria-hidden=true></span>`;
|
||||
window.electronApi.reloadServer();
|
||||
}
|
||||
document.getElementById('chg_conf').onclick = () => {
|
||||
document.getElementById('chg_conf').innerHTML = `<span class="spinner-border spinner-border-sm" arria-hidden=true></span>`;
|
||||
window.electronApi.changeConfig();
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
7
electron-3d-app/src/index.css
Normal file
7
electron-3d-app/src/index.css
Normal file
@ -0,0 +1,7 @@
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica,
|
||||
Arial, sans-serif;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
padding: 2rem;
|
||||
}
|
22
electron-3d-app/src/index.html
Normal file
22
electron-3d-app/src/index.html
Normal file
@ -0,0 +1,22 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>Hello World!</title>
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" />
|
||||
<link rel="stylesheet" href="index.css" />
|
||||
<script type="module" src="renderer.js"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<button id="open-files">Ouvrir</button>
|
||||
<div class="card" style="width: 50%;">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">Card title</h5>
|
||||
<div id="plot1"></div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
</html>
|
111
electron-3d-app/src/index.js
Normal file
111
electron-3d-app/src/index.js
Normal file
@ -0,0 +1,111 @@
|
||||
const { app, BrowserWindow, nativeTheme, Menu, dialog, ipcMain } = require('electron/main');
|
||||
const path = require('node:path');
|
||||
const fs = require('node:fs')
|
||||
const prompt = require('custom-electron-prompt');
|
||||
|
||||
const configPath = app.getPath('userData');
|
||||
const configFile = path.join(configPath, 'config.json');
|
||||
|
||||
if (!fs.existsSync(configFile)) {
|
||||
fs.writeFileSync(configFile, JSON.stringify({}), 'utf8');
|
||||
}
|
||||
|
||||
const config = JSON.parse(fs.readFileSync(configFile, 'utf8'));
|
||||
|
||||
// Handle creating/removing shortcuts on Windows when installing/uninstalling.
|
||||
if (require('electron-squirrel-startup')) {
|
||||
app.quit();
|
||||
}
|
||||
|
||||
const createWindow = () => {
|
||||
// Create the browser window.
|
||||
const mainWindow = new BrowserWindow({
|
||||
width: 1280,
|
||||
height: 720,
|
||||
webPreferences: {
|
||||
preload: path.join(__dirname, 'preload.js'),
|
||||
},
|
||||
nodeIntegration: true
|
||||
});
|
||||
|
||||
mainWindow.setMenu(null);
|
||||
mainWindow.loadURL(config.serverUrl);
|
||||
nativeTheme.themeSource = 'dark';
|
||||
|
||||
mainWindow.webContents.on('before-input-event', (event, input) => {
|
||||
if (input.control && input.key.toLocaleLowerCase() === 'r') {
|
||||
mainWindow.reload();
|
||||
console.log("Reloading window...");
|
||||
}
|
||||
if (input.key.toLocaleLowerCase() === 'f11') {
|
||||
mainWindow.setFullScreen(!mainWindow.isFullScreen());
|
||||
}
|
||||
})
|
||||
|
||||
ipcMain.on("config-change", (event) => {
|
||||
prompt({ title: "Configuration", label: "Please provide the server URL and port:", inputAttrs: { type: 'url' }, type: "input", value: config.serverUrl }).then((value) => {
|
||||
if (value !== null) {
|
||||
config.serverUrl = value;
|
||||
fs.writeFileSync(configFile, JSON.stringify(config));
|
||||
mainWindow.loadURL(config.serverUrl);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
ipcMain.on("get-server", () => {
|
||||
mainWindow.loadURL(config.serverUrl);
|
||||
});
|
||||
|
||||
mainWindow.webContents.on('did-fail-load', (evt, errorCode, errorDescription, validatedURL, isMainFrame, frameProcessIdn, frameRoutingId) => {
|
||||
if (errorCode === -102) {
|
||||
dialog.showErrorBox("ERROR!", `Could not find the server at ${validatedURL}!\nPlease be sure the server is running and the URL is correct!`);
|
||||
mainWindow.loadFile("src/error.html", { search: encodeURI(validatedURL) });
|
||||
} else {
|
||||
dialog.showErrorBox("ERROR!", errorDescription);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// This method will be called when Electron has finished
|
||||
// initialization and is ready to create browser windows.
|
||||
// Some APIs can only be used after this event occurs.
|
||||
|
||||
Menu.setApplicationMenu(null);
|
||||
|
||||
app.whenReady().then(() => {
|
||||
if (!config.serverUrl) {
|
||||
// Open a dialog to select the python executable
|
||||
prompt({ title: "Configuration", label: "Please provide the server URL and port:", inputAttrs: { type: 'url' }, type: "input" }).then((value) => {
|
||||
if (value !== null) {
|
||||
config.serverUrl = value;
|
||||
fs.writeFileSync(configFile, JSON.stringify(config));
|
||||
createWindow();
|
||||
} else {
|
||||
dialog.showErrorBox("ERROR!", "You must specify a server URL!\nThe application will exit!");
|
||||
app.quit();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
createWindow();
|
||||
}
|
||||
|
||||
// On OS X it's common to re-create a window in the app when the
|
||||
// dock icon is clicked and there are no other windows open.
|
||||
app.on('activate', () => {
|
||||
if (BrowserWindow.getAllWindows().length === 0) {
|
||||
createWindow();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Quit when all windows are closed, except on macOS. There, it's common
|
||||
// for applications and their menu bar to stay active until the user quits
|
||||
// explicitly with Cmd + Q.
|
||||
app.on('window-all-closed', () => {
|
||||
if (process.platform !== 'darwin') {
|
||||
app.quit();
|
||||
}
|
||||
});
|
||||
|
||||
// In this file you can include the rest of your app's specific main process
|
||||
// code. You can also put them in separate files and import them here.
|
9
electron-3d-app/src/preload.js
Normal file
9
electron-3d-app/src/preload.js
Normal file
@ -0,0 +1,9 @@
|
||||
// See the Electron documentation for details on how to use preload scripts:
|
||||
// https://www.electronjs.org/docs/latest/tutorial/process-model#preload-scripts
|
||||
|
||||
const { contextBridge, ipcRenderer } = require("electron/renderer");
|
||||
|
||||
contextBridge.exposeInMainWorld("electronApi", {
|
||||
changeConfig: () => ipcRenderer.send('config-change'),
|
||||
reloadServer: () => ipcRenderer.send('get-server'),
|
||||
})
|
0
electron-3d-app/src/renderer.js
Normal file
0
electron-3d-app/src/renderer.js
Normal file
Reference in New Issue
Block a user