Skip to content

Commit 0c0cd65

Browse files
author
Unai Lería Fortea
committed
Merge branch 'webagg-backend'
2 parents d0850ff + 5cc4c76 commit 0c0cd65

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

74 files changed

+6434
-125
lines changed

.gitmodules

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
[submodule "phaseportrait"]
2-
path = phaseportrait
3-
url = git@github.com:phaseportrait/phaseportrait.git
1+
[submodule "phaseportrait_local"]
2+
path = phaseportrait_local
3+
url = https://github.com/phaseportrait/phaseportrait
44
branch = develop

index.html

Lines changed: 66 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
12
<!DOCTYPE html>
23
<html>
34

@@ -8,7 +9,13 @@
89
<link rel="stylesheet" href="css/style.css">
910
<link rel="stylesheet" href="node_modules/codemirror/lib/codemirror.css">
1011
<link rel="stylesheet" href="node_modules/codemirror/theme/material.css">
12+
<link rel="stylesheet" href="web_backend/css/page.css">
13+
<link rel="stylesheet" href="web_backend/css/boilerplate.css">
14+
<link rel="stylesheet" href="web_backend/css/fbm.css">
15+
<link rel="stylesheet" href="web_backend/css/mpl.css">
1116
<script src="renderer.js"></script>
17+
<script src="web_backend/js/mpl.js"></script>
18+
<!-- <script src="web_backend/js/nbagg_mpl.js"></script> -->
1219
</head>
1320

1421
<body class="dark:bg-gray-600">
@@ -85,6 +92,13 @@
8592
</div>
8693

8794
<!-- Args container -->
95+
<!-- TODO: poner bonito. Imagino que habrá que ponérselo al primero de los dF_args. -->
96+
<div class="field w-full flex gap-2 items-center ">
97+
<!-- <label class="label">name</label> -->
98+
<label class="label w-full" style="margin-left: 6%; ">min</label>
99+
<label class="label w-full">value</label>
100+
<label class="label w-full">max</label>
101+
</div>
88102
<div id="dF_args_container" class="container flex flex-col items-center gap-2">
89103
</div>
90104

@@ -108,6 +122,10 @@
108122
<label class="label">max</label>
109123
<input id="x_max" type="number" placeholder="1" class="input">
110124
</div>
125+
<div>
126+
<label class="label">scale</label>
127+
<input id="xScale" type="text" placeholder="" class="input">
128+
</div>
111129

112130
</div>
113131
<div class="field w-full flex gap-2 items-center">
@@ -118,6 +136,22 @@
118136
<div>
119137
<input id="y_max" type="number" placeholder="1" class="input">
120138
</div>
139+
<div>
140+
<input id="yScale" type="text" placeholder="" class="input">
141+
</div>
142+
143+
</div>
144+
<div id="z_range_div" class="field w-full flex gap-2 items-center" style="display: none">
145+
<div class="label">z</div>
146+
<div>
147+
<input id="z_min" type="number" placeholder="0" class="input">
148+
</div>
149+
<div>
150+
<input id="z_max" type="number" placeholder="1" class="input">
151+
</div>
152+
<div>
153+
<input id="zScale" type="text" placeholder="" class="input">
154+
</div>
121155

122156
</div>
123157
</div>
@@ -160,8 +194,10 @@
160194

161195
<!-- color -->
162196
<div class="field w-full">
197+
<!-- TODO: mejorar la presentación de esta parte -->
163198
<div class="flex justify-between items-center">
164199
<label for="color" class="label">Color</label>
200+
165201
<a target="_blank" class="dark:text-gray-300 hover:text-blue-600 dark:hover:text-blue-400"
166202
href="https://matplotlib.org/stable/tutorials/colors/colormaps.html">
167203
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 mt-[-0.5rem]" fill="none"
@@ -171,8 +207,22 @@
171207
d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"/>
172208
</svg>
173209
</a>
210+
211+
<input class="
212+
h-4 w-4
213+
m-0 mr-1
214+
border border-gray-300 rounded-sm bg-white
215+
checked:bg-blue-600 checked:border-blue-600
216+
focus:outline-none
217+
transition duration-200 align-top
218+
bg-no-repeat bg-center bg-contain float-left
219+
cursor-pointer"
220+
type="checkbox" id="Colorbar">
221+
<label class="inline-block text-gray-800 dark:text-white text-sm select-none" for="Colorbar">
222+
Colorbar
223+
</label>
174224
</div>
175-
<input id="color" type="text" placeholder="viridis" class="input">
225+
<input id="color" type="text" placeholder="rainbow" class="input">
176226
</div>
177227

178228
</div>
@@ -246,7 +296,7 @@
246296
<div class="image-area__container relative">
247297

248298
<div id="loader" class="container flex justify-center items-center py-12 select-none"
249-
style="display: none">
299+
style="display: null">
250300
<img src="./icons/phaseportrait_icon.ico" alt="">
251301
</div>
252302

@@ -255,12 +305,21 @@
255305
<img src="./icons/phaseportrait_sadicon.png" alt="">
256306
</div>
257307

258-
<img id="img" src="svg/default.svg" class="
259-
max-h-full
260-
flex-1
308+
<!-- <iframe id="img" src="svg/default.svg" class="
309+
max-w-full
261310
bg-gray-100
262-
dark:rounded-xl
263-
">
311+
dark:rounded-xl"
312+
style="display: flex; border: none;"
313+
frameborder="0"
314+
marginheight="0"
315+
marginwidth="0"
316+
width="100%"
317+
height="650px">
318+
</iframe> -->
319+
320+
<div id="figure" class="rounded-md">
321+
</div>
322+
264323

265324
<!-- Code display -->
266325
<div id="code_div" style="display: none;" class="

main.js

Lines changed: 133 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,24 @@
11
'use strict';
22

3+
const { spawn } = require('child_process');
34
const electron = require('electron');
45
const {app, BrowserWindow, ipcMain} = electron;
56
const fs = require('fs');
67

7-
let {PythonShell} = require('python-shell')
8+
const WebSocket = require('ws');
9+
10+
11+
const DEBUG = false;
12+
const DEBUG_RENDER = false;
813

9-
const logger = new console.Console(fs.createWriteStream(`${__dirname}/log.txt`));
10-
const python_options = fs.createReadStream(`${__dirname}/python_settings.json`)
1114

1215
// Keep a global reference of the mainWindowdow object to avoid garbage collector
1316
let mainWindow = null;
17+
let python_server_process = null;
18+
let phaseportrait_socket = null;
19+
// let mpl_websocket = null;
20+
let FigId = null;
21+
let ws_uri = "ws://127.0.0.1:8080/";
1422

1523
function createMainWindow() {
1624
// Create the browser mainWindow
@@ -22,13 +30,15 @@ function createMainWindow() {
2230
webPreferences: {
2331
nodeIntegration: true,
2432
contextIsolation: false,
25-
}
33+
},
34+
slashes: true
2635
});
2736

2837
// Load the index page
2938
mainWindow.loadFile('index.html');
3039

31-
// mainWindow.openDevTools()
40+
if (DEBUG||DEBUG_RENDER)
41+
mainWindow.openDevTools();
3242

3343
// Link handler
3444
mainWindow.webContents.setWindowOpenHandler(({url}) => {
@@ -40,30 +50,62 @@ function createMainWindow() {
4050
mainWindow.on('closed', () => {
4151
mainWindow = null;
4252
});
43-
}
44-
45-
function emptySVGDir() {
46-
fs.readdir(`${__dirname}/svg`, (err, files) => {
47-
if (err) throw err;
48-
for (const file of files) {
49-
if (file === 'default.svg') continue;
50-
fs.unlinkSync(`${__dirname}/svg/${file}`, err => {
51-
if (err) throw err;
52-
});
53-
}
54-
});
55-
}
53+
};
54+
55+
// function emptySVGDir() {
56+
// fs.readdir(`${__dirname}/svg`, (err, files) => {
57+
// if (err) throw err;
58+
// for (const file of files) {
59+
// if (file === 'default.svg') continue;
60+
// fs.unlinkSync(`${__dirname}/svg/${file}`, err => {
61+
// if (err) throw err;
62+
// });
63+
// }
64+
// });
65+
// };
66+
67+
5668

5769
app.on('ready', () => {
58-
emptySVGDir();
70+
// emptySVGDir();
5971
createMainWindow();
6072

73+
if (!DEBUG){
74+
python_server_process = spawn('python',[`${__dirname}/phaseportrait-launcher.py`])
75+
python_server_process.stdout.on('data', (data) => {
76+
if (DEBUG || DEBUG_RENDER) console.log(String(data));
77+
FigId = String(data).split(',')[1];
78+
setupMPLWebSocket();
79+
80+
if (phaseportrait_socket === null){
81+
setupPPWebSocket();
82+
};
83+
84+
updatePlot();
85+
});
86+
}
87+
else{
88+
setupPPWebSocket();
89+
setupMPLWebSocket();
90+
updatePlot();
91+
}
92+
6193
ipcMain.on('request-plot', (event, plotParams) => {
6294
plot(plotParams);
6395
})
6496
ipcMain.on('request-code', (event, plotParams) => {
6597
generateCode(plotParams);
6698
})
99+
ipcMain.on('save-configuration', (event, settings) => {
100+
fs.writeFileSync("settings.json", JSON.stringify(settings), 'utf-8')
101+
})
102+
ipcMain.on('request-configuration', (e) => {
103+
fs.readFile("settings.json", (err, data) => {
104+
let settings = JSON.parse(data);
105+
if (DEBUG || DEBUG_RENDER) console.log(settings);
106+
mainWindow.webContents.send('load-configuration', settings);
107+
});
108+
})
67109
});
68110

69111
// disable menu
@@ -81,53 +123,79 @@ app.on('quit', () => {
81123
// do some additional cleanup
82124
});
83125

84-
function runPythonScript(plot = true, plotParams = []) {
85-
return new Promise(function (success, nosuccess) {
86-
let options = {
87-
args: [plot ? '--plot' : '--code',
88-
JSON.stringify(plotParams)]
89-
}
90-
PythonShell.run(`${__dirname}/phaseportrait-launcher.py`, options, (err, results) => {
91-
if (err) nosuccess(err);
92-
success(results)
93-
});
94-
});
95-
}
96-
126+
app.on('window-all-closed', () => {
127+
// For MacOs
128+
if (process.platform !== 'darwin') {
129+
app.quit()
130+
}
131+
});
97132

98-
function updatePlotSVG(filename) {
99-
mainWindow.webContents.send('load-svg', filename)
100-
}
133+
function updatePlot() {
134+
mainWindow.webContents.send('load-plot', FigId);
135+
};
136+
137+
function get_websocket_type() {
138+
if (typeof WebSocket !== 'undefined') {
139+
return WebSocket;
140+
} else if (typeof MozWebSocket !== 'undefined') {
141+
return MozWebSocket;
142+
} else {
143+
alert(
144+
'Your browser does not have WebSocket support. ' +
145+
'Please try Chrome, Safari or Firefox ≥ 6. ' +
146+
'Firefox 4 and 5 are also supported but you ' +
147+
'have to enable WebSockets in about:config.'
148+
);
149+
}
150+
};
151+
152+
function setupMPLWebSocket() {
153+
let mpl_websocket_type = get_websocket_type();
154+
// mpl_websocket = new mpl_websocket_type(`${ws_uri}ws`);
155+
};
156+
157+
function setupPPWebSocket(){
158+
let web_socket_type = get_websocket_type();
159+
phaseportrait_socket = new web_socket_type(`${ws_uri}pp`);
160+
// phaseportrait_socket.onerror = ...;
161+
// phaseportrait_socket.onopen = ...;
162+
// phaseportrait_socket.onmessage = ...;
163+
phaseportrait_socket.onclose = function(){
164+
setTimeout(setupPPWebSocket, 2000);
165+
166+
};
167+
phaseportrait_socket.on("error", (err) => {
168+
// logger.log('error', error);
169+
showError(err);
170+
});
171+
};
101172

102-
function showPythonCode(filename) {
103-
mainWindow.webContents.send('show-code', filename)
104-
}
173+
function showPythonCode(message) {
174+
mainWindow.webContents.send('show-code', message);
175+
};
105176

106177
function showError(message) {
107-
mainWindow.webContents.send('show-error', message)
108-
}
109-
110-
function plot(params) {
111-
runPythonScript(true, params)
112-
.then((data) => {
113-
if (data == 0) {
114-
throw Error('Error: Invalid function');
115-
}
116-
updatePlotSVG(data);
117-
})
118-
.catch((error) => {
119-
logger.log('error', error);
120-
showError(error);
121-
});
122-
}
123-
124-
function generateCode(params) {
125-
runPythonScript(false, params)
126-
.then((data) => {
127-
showPythonCode(data.join('\n'))
128-
})
129-
.catch((error) => {
130-
logger.log('error', error);
131-
showError(error);
132-
});
133-
}
178+
mainWindow.webContents.send('show-error', message);
179+
};
180+
181+
function sendParamsToPython(plot = true, plotParams = []) {
182+
plotParams["phaseportrait_request"] = plot ? '--plot' : '--code';
183+
phaseportrait_socket.send(JSON.stringify(plotParams))
184+
};
185+
186+
function plot(plotParams) {
187+
phaseportrait_socket.removeAllListeners("message");
188+
phaseportrait_socket.on("message", (data) => {
189+
if (DEBUG || DEBUG_RENDER) console.log(String(data));
190+
updatePlot(data.toString());
191+
});
192+
sendParamsToPython(true, plotParams);
193+
};
194+
195+
function generateCode(codeParams) {
196+
phaseportrait_socket.removeAllListeners("message");
197+
phaseportrait_socket.on("message", (data) => {
198+
showPythonCode(data.toString());
199+
});
200+
sendParamsToPython(false, codeParams);
201+
};

0 commit comments

Comments
 (0)