syd 0.2.0__py3-none-any.whl → 1.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- syd/__init__.py +1 -1
- syd/flask_deployment/__init__.py +0 -6
- syd/flask_deployment/deployer.py +446 -460
- syd/flask_deployment/static/css/styles.css +50 -16
- syd/flask_deployment/static/js/viewer.js +154 -67
- syd/flask_deployment/templates/index.html +1 -1
- syd/notebook_deployment/__init__.py +0 -1
- syd/notebook_deployment/deployer.py +119 -218
- syd/notebook_deployment/widgets.py +2 -2
- syd/parameters.py +69 -104
- syd/support.py +27 -0
- syd/viewer.py +10 -6
- syd-1.0.0.dist-info/METADATA +219 -0
- syd-1.0.0.dist-info/RECORD +19 -0
- syd-0.2.0.dist-info/METADATA +0 -126
- syd-0.2.0.dist-info/RECORD +0 -19
- {syd-0.2.0.dist-info → syd-1.0.0.dist-info}/WHEEL +0 -0
- {syd-0.2.0.dist-info → syd-1.0.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -60,16 +60,16 @@ body {
|
|
|
60
60
|
#controls-container {
|
|
61
61
|
display: grid;
|
|
62
62
|
grid-template-columns: 1fr;
|
|
63
|
-
gap:
|
|
63
|
+
gap: 10px;
|
|
64
64
|
}
|
|
65
65
|
|
|
66
66
|
/* Control groups */
|
|
67
67
|
.control-group {
|
|
68
68
|
display: flex;
|
|
69
69
|
flex-direction: column;
|
|
70
|
-
padding:
|
|
70
|
+
padding: 10px;
|
|
71
71
|
border: 1px solid #eee;
|
|
72
|
-
border-radius:
|
|
72
|
+
border-radius: 4px;
|
|
73
73
|
background-color: white;
|
|
74
74
|
box-shadow: 0 2px 4px rgba(0,0,0,0.05);
|
|
75
75
|
}
|
|
@@ -95,7 +95,6 @@ input[type="number"] {
|
|
|
95
95
|
/* Range inputs */
|
|
96
96
|
input[type="range"] {
|
|
97
97
|
width: 100%;
|
|
98
|
-
-webkit-appearance: none;
|
|
99
98
|
height: 6px;
|
|
100
99
|
background: #ddd;
|
|
101
100
|
border-radius: 3px;
|
|
@@ -205,29 +204,71 @@ button.active {
|
|
|
205
204
|
|
|
206
205
|
.range-slider-container {
|
|
207
206
|
position: relative;
|
|
208
|
-
height: 30px;
|
|
209
207
|
margin: 10px 0;
|
|
208
|
+
background: linear-gradient(to right,
|
|
209
|
+
#ddd 0%,
|
|
210
|
+
#ddd var(--min-pos, 0%),
|
|
211
|
+
#3f51b5 var(--min-pos, 0%),
|
|
212
|
+
#3f51b5 var(--max-pos, 100%),
|
|
213
|
+
#ddd var(--max-pos, 100%),
|
|
214
|
+
#ddd 100%);
|
|
215
|
+
border-radius: 3px;
|
|
216
|
+
height: 18px;
|
|
210
217
|
}
|
|
211
218
|
|
|
212
219
|
.range-slider {
|
|
213
220
|
position: absolute;
|
|
214
|
-
top:
|
|
221
|
+
top: 50%;
|
|
222
|
+
transform: translateY(-50%);
|
|
223
|
+
left: 0;
|
|
215
224
|
width: 100%;
|
|
216
225
|
pointer-events: none;
|
|
217
|
-
|
|
226
|
+
-webkit-appearance: none;
|
|
227
|
+
appearance: none;
|
|
228
|
+
background: transparent;
|
|
229
|
+
cursor: pointer;
|
|
230
|
+
margin: 0;
|
|
231
|
+
height: 18px;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
/* Transparent Track for Webkit */
|
|
235
|
+
.range-slider::-webkit-slider-runnable-track {
|
|
236
|
+
background: transparent;
|
|
237
|
+
border: none;
|
|
238
|
+
border-radius: 3px;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/* Transparent Track for Firefox */
|
|
242
|
+
.range-slider::-moz-range-track {
|
|
243
|
+
background: transparent;
|
|
244
|
+
border: none;
|
|
245
|
+
border-radius: 3px;
|
|
218
246
|
}
|
|
219
247
|
|
|
220
248
|
.range-slider.active {
|
|
221
|
-
opacity: 1;
|
|
222
249
|
z-index: 2;
|
|
223
250
|
}
|
|
224
251
|
|
|
225
252
|
.range-slider::-webkit-slider-thumb {
|
|
226
253
|
pointer-events: auto;
|
|
254
|
+
-webkit-appearance: none;
|
|
255
|
+
appearance: none;
|
|
256
|
+
width: 18px;
|
|
257
|
+
height: 18px;
|
|
258
|
+
border-radius: 50%;
|
|
259
|
+
background: #3f51b5;
|
|
260
|
+
cursor: pointer;
|
|
261
|
+
border: 1px solid #2c3e90;
|
|
227
262
|
}
|
|
228
263
|
|
|
229
264
|
.range-slider::-moz-range-thumb {
|
|
230
265
|
pointer-events: auto;
|
|
266
|
+
width: 18px;
|
|
267
|
+
height: 18px;
|
|
268
|
+
border-radius: 50%;
|
|
269
|
+
background: #3f51b5;
|
|
270
|
+
cursor: pointer;
|
|
271
|
+
border: 1px solid #2c3e90;
|
|
231
272
|
}
|
|
232
273
|
|
|
233
274
|
.min-slider {
|
|
@@ -236,11 +277,4 @@ button.active {
|
|
|
236
277
|
|
|
237
278
|
.max-slider {
|
|
238
279
|
z-index: 2;
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
.range-display {
|
|
242
|
-
text-align: center;
|
|
243
|
-
font-size: 13px;
|
|
244
|
-
margin-top: 5px;
|
|
245
|
-
color: #666;
|
|
246
|
-
}
|
|
280
|
+
}
|
|
@@ -1,23 +1,14 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Syd Viewer JavaScript for Flask deployment
|
|
3
|
-
* Handles dynamic creation of UI components and interaction with the Flask backend
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
// State object to store current values
|
|
7
1
|
let state = {};
|
|
8
2
|
let paramInfo = {};
|
|
3
|
+
let paramOrder = [];
|
|
4
|
+
let isUpdating = false;
|
|
9
5
|
|
|
10
6
|
// Config object parsed from HTML data attributes
|
|
11
7
|
const config = {
|
|
12
|
-
figureWidth: parseFloat(document.getElementById('viewer-config').dataset.figureWidth || 8.0),
|
|
13
|
-
figureHeight: parseFloat(document.getElementById('viewer-config').dataset.figureHeight || 6.0),
|
|
14
8
|
controlsPosition: document.getElementById('viewer-config').dataset.controlsPosition || 'left',
|
|
15
|
-
controlsWidthPercent: parseInt(document.getElementById('viewer-config').dataset.controlsWidthPercent ||
|
|
9
|
+
controlsWidthPercent: parseInt(document.getElementById('viewer-config').dataset.controlsWidthPercent || 20)
|
|
16
10
|
};
|
|
17
11
|
|
|
18
|
-
// Track whether we're currently in an update operation
|
|
19
|
-
let isUpdating = false;
|
|
20
|
-
|
|
21
12
|
// Initialize the viewer
|
|
22
13
|
document.addEventListener('DOMContentLoaded', function() {
|
|
23
14
|
// Fetch initial parameter information from server
|
|
@@ -25,6 +16,7 @@ document.addEventListener('DOMContentLoaded', function() {
|
|
|
25
16
|
.then(response => response.json())
|
|
26
17
|
.then(data => {
|
|
27
18
|
paramInfo = data.params;
|
|
19
|
+
paramOrder = data.param_order;
|
|
28
20
|
|
|
29
21
|
// Initialize state from parameter info
|
|
30
22
|
for (const [name, param] of Object.entries(paramInfo)) {
|
|
@@ -51,8 +43,14 @@ function createControls() {
|
|
|
51
43
|
// Clear any existing controls
|
|
52
44
|
controlsContainer.innerHTML = '';
|
|
53
45
|
|
|
54
|
-
// Create controls for each parameter
|
|
55
|
-
|
|
46
|
+
// Create controls for each parameter in the order specified by the viewer
|
|
47
|
+
paramOrder.forEach(name => {
|
|
48
|
+
const param = paramInfo[name];
|
|
49
|
+
if (!param) {
|
|
50
|
+
console.warn(`Parameter info not found for ${name} during control creation.`);
|
|
51
|
+
return; // Skip if param info is missing for some reason
|
|
52
|
+
}
|
|
53
|
+
|
|
56
54
|
// Create control group
|
|
57
55
|
const controlGroup = createControlGroup(name, param);
|
|
58
56
|
|
|
@@ -60,7 +58,7 @@ function createControls() {
|
|
|
60
58
|
if (controlGroup) {
|
|
61
59
|
controlsContainer.appendChild(controlGroup);
|
|
62
60
|
}
|
|
63
|
-
}
|
|
61
|
+
});
|
|
64
62
|
}
|
|
65
63
|
|
|
66
64
|
/**
|
|
@@ -188,7 +186,7 @@ function createIntegerControl(name, param) {
|
|
|
188
186
|
input.value = param.value;
|
|
189
187
|
|
|
190
188
|
// Add event listeners
|
|
191
|
-
slider.addEventListener('
|
|
189
|
+
slider.addEventListener('change', function() {
|
|
192
190
|
const value = parseInt(this.value, 10);
|
|
193
191
|
input.value = value;
|
|
194
192
|
updateParameter(name, value);
|
|
@@ -235,7 +233,7 @@ function createFloatControl(name, param) {
|
|
|
235
233
|
input.value = param.value;
|
|
236
234
|
|
|
237
235
|
// Add event listeners
|
|
238
|
-
slider.addEventListener('
|
|
236
|
+
slider.addEventListener('change', function() {
|
|
239
237
|
const value = parseFloat(this.value);
|
|
240
238
|
input.value = value;
|
|
241
239
|
updateParameter(name, value);
|
|
@@ -378,7 +376,7 @@ function createRangeControl(name, param, converter) {
|
|
|
378
376
|
minInput.className = 'range-input';
|
|
379
377
|
minInput.min = param.min;
|
|
380
378
|
minInput.max = param.max;
|
|
381
|
-
minInput.step = param.step || 1;
|
|
379
|
+
minInput.step = param.step || (converter === parseInt ? 1 : 0.01); // Default step
|
|
382
380
|
minInput.value = param.value[0];
|
|
383
381
|
|
|
384
382
|
// Create slider container
|
|
@@ -392,7 +390,7 @@ function createRangeControl(name, param, converter) {
|
|
|
392
390
|
minSlider.className = 'range-slider min-slider';
|
|
393
391
|
minSlider.min = param.min;
|
|
394
392
|
minSlider.max = param.max;
|
|
395
|
-
minSlider.step = param.step || 1;
|
|
393
|
+
minSlider.step = param.step || (converter === parseInt ? 1 : 0.01); // Default step
|
|
396
394
|
minSlider.value = param.value[0];
|
|
397
395
|
|
|
398
396
|
// Create max slider
|
|
@@ -402,7 +400,7 @@ function createRangeControl(name, param, converter) {
|
|
|
402
400
|
maxSlider.className = 'range-slider max-slider';
|
|
403
401
|
maxSlider.min = param.min;
|
|
404
402
|
maxSlider.max = param.max;
|
|
405
|
-
maxSlider.step = param.step || 1;
|
|
403
|
+
maxSlider.step = param.step || (converter === parseInt ? 1 : 0.01); // Default step
|
|
406
404
|
maxSlider.value = param.value[1];
|
|
407
405
|
|
|
408
406
|
// Create max input
|
|
@@ -412,41 +410,39 @@ function createRangeControl(name, param, converter) {
|
|
|
412
410
|
maxInput.className = 'range-input';
|
|
413
411
|
maxInput.min = param.min;
|
|
414
412
|
maxInput.max = param.max;
|
|
415
|
-
maxInput.step = param.step || 1;
|
|
413
|
+
maxInput.step = param.step || (converter === parseInt ? 1 : 0.01); // Default step
|
|
416
414
|
maxInput.value = param.value[1];
|
|
417
415
|
|
|
418
|
-
// Range display
|
|
419
|
-
const rangeDisplay = document.createElement('div');
|
|
420
|
-
rangeDisplay.className = 'range-display';
|
|
421
|
-
rangeDisplay.id = `${name}-range-display`;
|
|
422
|
-
rangeDisplay.textContent = `Range: ${param.value[0]} - ${param.value[1]}`;
|
|
423
|
-
|
|
424
416
|
// Add event listeners
|
|
425
|
-
minSlider.addEventListener('
|
|
417
|
+
minSlider.addEventListener('change', function() {
|
|
426
418
|
const minVal = converter(this.value);
|
|
427
419
|
const maxVal = converter(maxSlider.value);
|
|
428
420
|
|
|
429
421
|
if (minVal <= maxVal) {
|
|
430
422
|
state[name] = [minVal, maxVal];
|
|
431
423
|
minInput.value = minVal;
|
|
432
|
-
|
|
424
|
+
updateSliderGradient(minSlider, maxSlider, sliderContainer); // Update gradient
|
|
433
425
|
updateParameter(name, [minVal, maxVal]);
|
|
434
426
|
} else {
|
|
435
|
-
this.value = maxVal;
|
|
427
|
+
this.value = maxVal; // Snap to maxVal if crossing
|
|
428
|
+
minInput.value = maxVal; // Also update input
|
|
429
|
+
updateSliderGradient(minSlider, maxSlider, sliderContainer); // Update gradient
|
|
436
430
|
}
|
|
437
431
|
});
|
|
438
432
|
|
|
439
|
-
maxSlider.addEventListener('
|
|
433
|
+
maxSlider.addEventListener('change', function() {
|
|
440
434
|
const minVal = converter(minSlider.value);
|
|
441
435
|
const maxVal = converter(this.value);
|
|
442
436
|
|
|
443
437
|
if (maxVal >= minVal) {
|
|
444
438
|
state[name] = [minVal, maxVal];
|
|
445
439
|
maxInput.value = maxVal;
|
|
446
|
-
|
|
440
|
+
updateSliderGradient(minSlider, maxSlider, sliderContainer); // Update gradient
|
|
447
441
|
updateParameter(name, [minVal, maxVal]);
|
|
448
442
|
} else {
|
|
449
|
-
this.value = minVal;
|
|
443
|
+
this.value = minVal; // Snap to minVal if crossing
|
|
444
|
+
maxInput.value = minVal; // Also update input
|
|
445
|
+
updateSliderGradient(minSlider, maxSlider, sliderContainer); // Update gradient
|
|
450
446
|
}
|
|
451
447
|
});
|
|
452
448
|
|
|
@@ -457,10 +453,13 @@ function createRangeControl(name, param, converter) {
|
|
|
457
453
|
if (!isNaN(minVal) && minVal >= param.min && minVal <= maxVal) {
|
|
458
454
|
state[name] = [minVal, maxVal];
|
|
459
455
|
minSlider.value = minVal;
|
|
460
|
-
|
|
456
|
+
updateSliderGradient(minSlider, maxSlider, sliderContainer); // Update gradient
|
|
461
457
|
updateParameter(name, [minVal, maxVal]);
|
|
462
458
|
} else {
|
|
463
|
-
|
|
459
|
+
// Revert input value and ensure gradient matches state
|
|
460
|
+
this.value = state[name][0];
|
|
461
|
+
minSlider.value = state[name][0];
|
|
462
|
+
updateSliderGradient(minSlider, maxSlider, sliderContainer);
|
|
464
463
|
}
|
|
465
464
|
});
|
|
466
465
|
|
|
@@ -471,10 +470,13 @@ function createRangeControl(name, param, converter) {
|
|
|
471
470
|
if (!isNaN(maxVal) && maxVal <= param.max && maxVal >= minVal) {
|
|
472
471
|
state[name] = [minVal, maxVal];
|
|
473
472
|
maxSlider.value = maxVal;
|
|
474
|
-
|
|
473
|
+
updateSliderGradient(minSlider, maxSlider, sliderContainer); // Update gradient
|
|
475
474
|
updateParameter(name, [minVal, maxVal]);
|
|
476
475
|
} else {
|
|
476
|
+
// Revert input value and ensure gradient matches state
|
|
477
477
|
this.value = state[name][1];
|
|
478
|
+
maxSlider.value = state[name][1];
|
|
479
|
+
updateSliderGradient(minSlider, maxSlider, sliderContainer);
|
|
478
480
|
}
|
|
479
481
|
});
|
|
480
482
|
|
|
@@ -487,18 +489,13 @@ function createRangeControl(name, param, converter) {
|
|
|
487
489
|
|
|
488
490
|
container.appendChild(inputsContainer);
|
|
489
491
|
container.appendChild(sliderContainer);
|
|
490
|
-
|
|
492
|
+
|
|
493
|
+
// Set initial gradient state
|
|
494
|
+
updateSliderGradient(minSlider, maxSlider, sliderContainer);
|
|
491
495
|
|
|
492
496
|
return container;
|
|
493
497
|
}
|
|
494
498
|
|
|
495
|
-
/**
|
|
496
|
-
* Update range display text
|
|
497
|
-
*/
|
|
498
|
-
function updateRangeDisplay(displayElement, min, max) {
|
|
499
|
-
displayElement.textContent = `Range: ${min} - ${max}`;
|
|
500
|
-
}
|
|
501
|
-
|
|
502
499
|
/**
|
|
503
500
|
* Create unbounded integer control
|
|
504
501
|
*/
|
|
@@ -576,7 +573,7 @@ function createButtonControl(name, param) {
|
|
|
576
573
|
console.error('Error:', data.error);
|
|
577
574
|
} else {
|
|
578
575
|
// Update state with any changes from callbacks
|
|
579
|
-
updateStateFromServer(data.state);
|
|
576
|
+
updateStateFromServer(data.state, data.params);
|
|
580
577
|
// Update plot if needed
|
|
581
578
|
updatePlot();
|
|
582
579
|
}
|
|
@@ -611,7 +608,8 @@ function updateParameter(name, value) {
|
|
|
611
608
|
},
|
|
612
609
|
body: JSON.stringify({
|
|
613
610
|
name: name,
|
|
614
|
-
value: value
|
|
611
|
+
value: value,
|
|
612
|
+
action: false
|
|
615
613
|
}),
|
|
616
614
|
})
|
|
617
615
|
.then(response => response.json())
|
|
@@ -620,7 +618,7 @@ function updateParameter(name, value) {
|
|
|
620
618
|
console.error('Error:', data.error);
|
|
621
619
|
} else {
|
|
622
620
|
// Update state with any changes from callbacks
|
|
623
|
-
updateStateFromServer(data.state);
|
|
621
|
+
updateStateFromServer(data.state, data.params);
|
|
624
622
|
// Update plot
|
|
625
623
|
updatePlot();
|
|
626
624
|
}
|
|
@@ -633,16 +631,16 @@ function updateParameter(name, value) {
|
|
|
633
631
|
/**
|
|
634
632
|
* Update local state from server response
|
|
635
633
|
*/
|
|
636
|
-
function updateStateFromServer(serverState) {
|
|
634
|
+
function updateStateFromServer(serverState, serverParamInfo) {
|
|
637
635
|
// Set updating flag to prevent recursive updates
|
|
638
636
|
isUpdating = true;
|
|
639
637
|
|
|
640
638
|
try {
|
|
641
639
|
// Update any parameters that changed due to callbacks
|
|
642
640
|
for (const [name, value] of Object.entries(serverState)) {
|
|
643
|
-
if (JSON.stringify(state[name]) !== JSON.stringify(value)) {
|
|
641
|
+
if (JSON.stringify(state[name]) !== JSON.stringify(value) || JSON.stringify(paramInfo[name]) !== JSON.stringify(serverParamInfo[name])) {
|
|
644
642
|
state[name] = value;
|
|
645
|
-
updateControlValue(name, value);
|
|
643
|
+
updateControlValue(name, value, serverParamInfo[name]);
|
|
646
644
|
}
|
|
647
645
|
}
|
|
648
646
|
} finally {
|
|
@@ -654,11 +652,9 @@ function updateStateFromServer(serverState) {
|
|
|
654
652
|
/**
|
|
655
653
|
* Update a control's value in the UI
|
|
656
654
|
*/
|
|
657
|
-
function updateControlValue(name, value) {
|
|
655
|
+
function updateControlValue(name, value, param) {
|
|
658
656
|
if (!paramInfo[name]) return;
|
|
659
|
-
|
|
660
|
-
const param = paramInfo[name];
|
|
661
|
-
|
|
657
|
+
|
|
662
658
|
switch (param.type) {
|
|
663
659
|
case 'text':
|
|
664
660
|
document.getElementById(`${name}-input`).value = value;
|
|
@@ -668,29 +664,97 @@ function updateControlValue(name, value) {
|
|
|
668
664
|
break;
|
|
669
665
|
case 'integer':
|
|
670
666
|
case 'float':
|
|
671
|
-
document.getElementById(`${name}-slider`)
|
|
672
|
-
|
|
667
|
+
const slider = document.getElementById(`${name}-slider`);
|
|
668
|
+
slider.value = value;
|
|
669
|
+
slider.min = param.min;
|
|
670
|
+
slider.max = param.max;
|
|
671
|
+
slider.step = param.step;
|
|
672
|
+
const input = document.getElementById(`${name}-input`);
|
|
673
|
+
input.value = value;
|
|
674
|
+
input.min = param.min;
|
|
675
|
+
input.max = param.max;
|
|
676
|
+
input.step = param.step;
|
|
673
677
|
break;
|
|
674
678
|
case 'selection':
|
|
675
|
-
document.getElementById(`${name}-select`)
|
|
679
|
+
const selectElement = document.getElementById(`${name}-select`);
|
|
680
|
+
if (selectElement) {
|
|
681
|
+
// 1. Clear existing options
|
|
682
|
+
selectElement.innerHTML = '';
|
|
683
|
+
|
|
684
|
+
// 2. Add new options from the updated param info
|
|
685
|
+
if (param.options && Array.isArray(param.options)) {
|
|
686
|
+
param.options.forEach(option => {
|
|
687
|
+
const optionElement = document.createElement('option');
|
|
688
|
+
optionElement.value = option;
|
|
689
|
+
optionElement.textContent = formatLabel(String(option));
|
|
690
|
+
// Store original type/value info
|
|
691
|
+
optionElement.dataset.originalType = typeof option;
|
|
692
|
+
if (typeof option === 'number') {
|
|
693
|
+
optionElement.dataset.originalValue = option;
|
|
694
|
+
}
|
|
695
|
+
selectElement.appendChild(optionElement);
|
|
696
|
+
});
|
|
697
|
+
} else {
|
|
698
|
+
console.warn(`No options found or options is not an array for parameter: ${name}`);
|
|
699
|
+
}
|
|
700
|
+
|
|
701
|
+
selectElement.value = value;
|
|
702
|
+
} else {
|
|
703
|
+
console.warn(`No select element found for parameter: ${name}`);
|
|
704
|
+
}
|
|
676
705
|
break;
|
|
677
706
|
case 'multiple-selection':
|
|
678
|
-
const
|
|
679
|
-
if (
|
|
680
|
-
|
|
707
|
+
const multiSelect = document.getElementById(`${name}-select`);
|
|
708
|
+
if (multiSelect) {
|
|
709
|
+
multiSelect.innerHTML = '';
|
|
710
|
+
|
|
711
|
+
if (param.options && Array.isArray(param.options)) {
|
|
712
|
+
param.options.forEach(option => {
|
|
713
|
+
const optionElement = document.createElement('option');
|
|
714
|
+
optionElement.value = option;
|
|
715
|
+
optionElement.textContent = formatLabel(String(option));
|
|
716
|
+
multiSelect.appendChild(optionElement);
|
|
717
|
+
});
|
|
718
|
+
} else {
|
|
719
|
+
console.warn(`No options found or options is not an array for parameter: ${name}`);
|
|
720
|
+
}
|
|
721
|
+
|
|
722
|
+
Array.from(multiSelect.options).forEach(option => {
|
|
681
723
|
option.selected = value.includes(option.value);
|
|
682
724
|
});
|
|
683
725
|
}
|
|
684
726
|
break;
|
|
685
727
|
case 'integer-range':
|
|
686
728
|
case 'float-range':
|
|
687
|
-
document.getElementById(`${name}-min-slider`)
|
|
688
|
-
document.getElementById(`${name}-max-slider`)
|
|
689
|
-
document.getElementById(`${name}-min-input`)
|
|
690
|
-
document.getElementById(`${name}-max-input`)
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
729
|
+
const minSlider = document.getElementById(`${name}-min-slider`);
|
|
730
|
+
const maxSlider = document.getElementById(`${name}-max-slider`);
|
|
731
|
+
const minInput = document.getElementById(`${name}-min-input`);
|
|
732
|
+
const maxInput = document.getElementById(`${name}-max-input`);
|
|
733
|
+
|
|
734
|
+
minSlider.min = param.min;
|
|
735
|
+
minSlider.max = param.max;
|
|
736
|
+
minSlider.step = param.step;
|
|
737
|
+
maxSlider.min = param.min;
|
|
738
|
+
maxSlider.max = param.max;
|
|
739
|
+
maxSlider.step = param.step;
|
|
740
|
+
minInput.min = param.min;
|
|
741
|
+
minInput.max = param.max;
|
|
742
|
+
minInput.step = param.step;
|
|
743
|
+
maxInput.min = param.min;
|
|
744
|
+
maxInput.max = param.max;
|
|
745
|
+
maxInput.step = param.step;
|
|
746
|
+
|
|
747
|
+
minSlider.value = value[0];
|
|
748
|
+
maxSlider.value = value[1];
|
|
749
|
+
minInput.value = value[0];
|
|
750
|
+
maxInput.value = value[1];
|
|
751
|
+
|
|
752
|
+
// Update the gradient background
|
|
753
|
+
const sliderContainer = minSlider ? minSlider.closest('.range-slider-container') : null;
|
|
754
|
+
if (sliderContainer) {
|
|
755
|
+
updateSliderGradient(minSlider, maxSlider, sliderContainer);
|
|
756
|
+
} else {
|
|
757
|
+
console.warn(`Could not find slider container for range control: ${name}`);
|
|
694
758
|
}
|
|
695
759
|
break;
|
|
696
760
|
case 'unbounded-integer':
|
|
@@ -700,6 +764,29 @@ function updateControlValue(name, value) {
|
|
|
700
764
|
}
|
|
701
765
|
}
|
|
702
766
|
|
|
767
|
+
/**
|
|
768
|
+
* Updates the background gradient for the dual range slider.
|
|
769
|
+
* @param {HTMLInputElement} minSlider - The minimum value slider element.
|
|
770
|
+
* @param {HTMLInputElement} maxSlider - The maximum value slider element.
|
|
771
|
+
* @param {HTMLElement} container - The container element holding the sliders.
|
|
772
|
+
*/
|
|
773
|
+
function updateSliderGradient(minSlider, maxSlider, container) {
|
|
774
|
+
const rangeMin = parseFloat(minSlider.min);
|
|
775
|
+
const rangeMax = parseFloat(minSlider.max);
|
|
776
|
+
const minVal = parseFloat(minSlider.value);
|
|
777
|
+
const maxVal = parseFloat(maxSlider.value);
|
|
778
|
+
|
|
779
|
+
// Calculate percentages
|
|
780
|
+
const range = rangeMax - rangeMin;
|
|
781
|
+
// Prevent division by zero if min === max
|
|
782
|
+
const minPercent = range === 0 ? 0 : ((minVal - rangeMin) / range) * 100;
|
|
783
|
+
const maxPercent = range === 0 ? 100 : ((maxVal - rangeMin) / range) * 100;
|
|
784
|
+
|
|
785
|
+
// Update CSS custom properties
|
|
786
|
+
container.style.setProperty('--min-pos', `${minPercent}%`);
|
|
787
|
+
container.style.setProperty('--max-pos', `${maxPercent}%`);
|
|
788
|
+
}
|
|
789
|
+
|
|
703
790
|
/**
|
|
704
791
|
* Format parameter name as a label (capitalize each word)
|
|
705
792
|
*/
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<!DOCTYPE html>
|
|
2
2
|
<html>
|
|
3
3
|
<head>
|
|
4
|
-
<title>
|
|
4
|
+
<title>{{ title }}</title>
|
|
5
5
|
<meta charset="UTF-8">
|
|
6
6
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
7
7
|
<link rel="stylesheet" href="{{ url_for('static', filename='css/styles.css') }}">
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
from .deployer import NotebookDeployer
|