second commit
This commit is contained in:
@@ -0,0 +1,128 @@
|
||||
{% extends 'base.html' %}
|
||||
{% load i18n home_tags %}
|
||||
{% block header %}
|
||||
<div class="w3-bar w3-dark-light">
|
||||
<a href="#" class="w3-bar-item w3-mobile w3-btn w3-hover-opacity w3-xlarge w3-text-yellow" onclick="toggleSidebar()" title="{% trans 'Barre de côté' %}">
|
||||
<i class="fa-solid fa-right-left"></i>
|
||||
</a>
|
||||
<div class="w3-bar-item w3-btn w3-hover-opacity w3-xlarge">
|
||||
{{ choice_title }}
|
||||
</div>
|
||||
<a href="#" class="w3-bar-item w3-mobile w3-btn w3-hover-opacity w3-right w3-xlarge w3-text-green" onclick="goFullscreen()" title="{% trans 'Ecran plein' %}">
|
||||
<i class="fa-solid fa-maximize"></i>
|
||||
</a>
|
||||
</div>
|
||||
{% endblock %}
|
||||
{% block sidebar %}
|
||||
<div class="w3-dark-xlight w3-border-bottom">
|
||||
<div class="w3-large w3-bold">
|
||||
<a href="/" class="w3-btn w3-hover-opacity w100 w3-left-align">{{ app_title }}<br>
|
||||
<span class="w3-tiny">{{ app_sub_title }}</span>
|
||||
</a>
|
||||
</div>
|
||||
<form method="post" action="{% url 'logout' %}" class="w3-padding-small">
|
||||
{% csrf_token %}
|
||||
<button class="w3-bar-item w3-btn w3-hover-opacity" type="submit" title="{% trans 'Déconnexion' %}">
|
||||
{{ request.user.username }}<i class="fa-solid fa-right-from-bracket w3-right"></i>
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
{% block system %}
|
||||
<div class="w3-light-blue w3-padding-large">
|
||||
<div id="shm-used" class="w3-green w3-round" style="height:0.5em; width: var(--shm-used, 0%);" title="{% trans 'Mémoire partagée' %}"></div>
|
||||
<div id="ramdisk-used" class="w3-purple w3-round" style="height:0.5em;width: var(--ramdisk-used, 0%); margin: 0.35em 0" title="{% trans 'Disque RAM' %}"></div>
|
||||
<div id="mem-used" class="w3-deep-orange w3-round" style="height:0.5em;width: var(--mem-used, 0%); margin: 0.35em 0" title="{% trans 'Mémoire RAM' %}"></div>
|
||||
<div id="cpu-used" class="w3-indigo w3-round" style="height:0.5em;width: var(--cpu-used, 0%); margin: 0.35em 0" title="{% trans 'Charge CPU' %}"></div>
|
||||
<div id="disk-used" class="w3-amber w3-round" style="height:0.5em;width: var(--disk-used, 0%); margin: 0.35em 0" title="{% trans 'Disque /' %}"></div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
{% block columns %}
|
||||
<div class="w3-dark-light">
|
||||
<div class=" w3-padding w3-border-bottom">
|
||||
<div>{% trans "Grille" %}</div>
|
||||
<div style="width:100%">
|
||||
{% x_range 1 13 as cols %}
|
||||
{% for c in cols %}
|
||||
<button id="swap-{{ c }}" class="w3-btn w3-badge w3-padding-small w3-sand w3-tiny" onclick="setGridColumns({{ c }})">{{ c }}</button>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
function updateActiveButton(n) {
|
||||
document.querySelectorAll('[id^="swap-"]').forEach(btn => {
|
||||
btn.classList.remove('w3-blue', 'w3-sand'); btn.classList.add('w3-sand');
|
||||
});
|
||||
const active = sId('swap-'+ n);
|
||||
if (active) { active.classList.remove('w3-sand'); active.classList.add('w3-blue');
|
||||
}
|
||||
}
|
||||
</script>
|
||||
{% endblock %}
|
||||
{% block sidebar_list %}
|
||||
<div class="w3-dark-light w3-padding-small">
|
||||
{% block sidebar_command %}{% endblock %}
|
||||
|
||||
{% if request.user.is_superuser %}
|
||||
<div>
|
||||
<div class="w3-dark-light w3-margin-top-6">
|
||||
<a href="#" class="w3-btn w3-padding-small" onclick="toggleDisplay(sId('_admin'))"><span class="w3-text-orange w3-xlarge">⛶</span>
|
||||
{% trans "Administration" %}
|
||||
</a>
|
||||
</div>
|
||||
<div id="_admin" style="display:none">
|
||||
<a href="{% url 'scanner:admin' %}" class="w3-bar-item w3-btn w3-hover-opacity w3-margin-left">
|
||||
<i class="fa-solid fa-gear w3-text-pink"></i> {% trans "Administration base de données" %}
|
||||
</a>
|
||||
<a href="{% url 'scanner:reductstore' %}" class="w3-bar-item w3-btn w3-hover-opacity w3-margin-left">
|
||||
<img class="w3-no-padding" src="/static/img/reductstore.png" style="width: 24px"> {% trans "Base de données Reductstore" %}
|
||||
</a>
|
||||
<!--a href="{% url 'scanner:adminer' %}" class="w3-bar-item w3-btn w3-hover-opacity w3-margin-left">
|
||||
<img class="w3-no-padding" src="/static/img/adminer.png" style="width: 28px"> {% trans "Base de données mariadb" %}
|
||||
</a-->
|
||||
<!--a href="{% url 'scanner:portainer' %}" class="w3-bar-item w3-btn w3-hover-opacity" w3-margin-left>
|
||||
<img class="w3-no-padding" src="/static/img/portainer.png" style="width: 28px"> {% trans "Portainer" %}
|
||||
</a-->
|
||||
<a href="{% url 'scanner:supervisor' %}" class="w3-bar-item w3-btn w3-hover-opacity w3-margin-left">
|
||||
<i class="fa-solid fa-gears w3-text-purple"></i> {% trans "Supervisor" %}
|
||||
</a>
|
||||
<a href="{% url 'scanner:logs_scheduler' %}" class="w3-bar-item w3-btn w3-hover-opacity w3-margin-left">
|
||||
<i class="fa-regular fa-file-lines w3-text-orange"></i> {% trans "Logs des planifications" %}
|
||||
</a>
|
||||
<a href="{% url 'scanner:logs_worker' %}" class="w3-bar-item w3-btn w3-hover-opacity w3-margin-left">
|
||||
<i class="fa-regular fa-file-lines w3-text-amber"></i> {% trans "Logs des workers" %}
|
||||
</a>
|
||||
<a href="{% url 'scanner:calibration' %}" class="w3-bar-item w3-btn w3-hover-opacity w3-margin-left">
|
||||
<i class="fa-solid fa-wrench w3-text-red"></i> {% trans "Calibration" %}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% block sidebar_smenu %}
|
||||
|
||||
<a href="{% url 'scanner:main' %}" class="w3-bar-item w3-btn w3-hover-opacity">
|
||||
<i class="fa-solid fa-film w3-text-green"></i> {% trans "Balayage multi-puits" %}
|
||||
</a>
|
||||
<a href="{% url 'scanner:images' %}" class="w3-bar-item w3-btn w3-hover-opacity">
|
||||
<i class="fa-regular fa-images w3-text-cyan"></i> {% trans "Gestionnaire d'images" %}
|
||||
</a>
|
||||
<a href="{% url 'scanner:replay' %}" class="w3-bar-item w3-btn w3-hover-opacity">
|
||||
<i class="fa-solid fa-podcast w3-text-amber"></i> {% trans "Redifusion vidéos" %}
|
||||
</a>
|
||||
{% endblock %}
|
||||
|
||||
</div>
|
||||
{% endblock %}
|
||||
{% endblock %}
|
||||
{% block content %}{% endblock %}
|
||||
|
||||
{% block js_footer %}
|
||||
{{ block.super }}
|
||||
<script>
|
||||
const stats_endpoint = "{% url 'scanner:api_stats' %}";
|
||||
</script>
|
||||
<script src="/static/scanner/js/stats.js"></script>
|
||||
{% endblock %}
|
||||
|
||||
|
||||
@@ -0,0 +1,122 @@
|
||||
{% extends 'scanner/base.html' %}
|
||||
{% load i18n home_tags %}
|
||||
|
||||
{% block styles %}
|
||||
{{ block.super }}
|
||||
<link href="/static/scanner/css/calibration.css" rel="stylesheet">
|
||||
{% endblock %}
|
||||
{% block columns %}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="container w3-black">
|
||||
<div class="header">
|
||||
<div class="w3-row w3-row-padding">
|
||||
<div class="w3-col" style="width:30%">
|
||||
{% trans 'Position multi-puit' %}<br>
|
||||
<select id="_well" class="w3-select">
|
||||
{% for w in wells %}
|
||||
<option value="{{ w.position }}" {% if w.position == 'HG' %}selected{% endif %}>{{ w }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
<div class="w3-col" style="width:20%">
|
||||
<div>{% trans 'Vitesse' %}</div>
|
||||
<select id="_feed" class="w3-select">
|
||||
<option value="500">500 mm/mn</option>
|
||||
<option value="750">750 mm/mn</option>
|
||||
<option value="1000" selected>1000 mm/mn</option>
|
||||
<option value="1200">1200 mm/mn</option>
|
||||
<option value="1500">1500 mm/mn</option>
|
||||
<option value="2000">2000 mm/mn</option>
|
||||
<option value="3000">3000 mm/mn</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="w3-col" style="width:20%">
|
||||
<div>{% trans 'Pas' %}</div>
|
||||
<select id="_step" class="w3-select">
|
||||
<option value="0.1">0.1 mm</option>
|
||||
<option value="0.25">0.25 mm</option>
|
||||
<option value="0.5">0.5 mm</option>
|
||||
<option value="1.0" selected>1.0 mm</option>
|
||||
<option value="1.5">1.5 mm</option>
|
||||
<option value="2.0">2.0 mm</option>
|
||||
<option value="2.5">2.5 mm</option>
|
||||
<option value="5.0">5.0 mm</option>
|
||||
<option value="10.0">10.0 mm</option>
|
||||
<option value="20.0">20.0 mm</option>
|
||||
<option value="30.0">30.0 mm</option>
|
||||
<option value="40.0">40.0 mm</option>
|
||||
<option value="50.0">50.0 mm</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="w3-col" style="width:30%">
|
||||
<div class="w3-margin-top w3-padding w3-right">
|
||||
<span id="_ts"></span><br>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="move w3-padding-small w3-center">
|
||||
|
||||
<div class="w3-row">
|
||||
<div class="w3-half">{% trans 'dx' %}<br><input id="_dx" type="number" min="15.0" max="25.0" step="0.01" value=""/></div>
|
||||
<div class="w3-half">{% trans 'dy' %}<br><input id="_dy" type="number" min="15.0" max="25.0" step="0.01" value=""/></div>
|
||||
</div>
|
||||
<button id="_xy-step" class="w3-button w3-warning w3-round-large w3-block w3-large">
|
||||
<i class="fa-solid fa-left-right"></i> {% trans 'Définir (dx, dy)' %}
|
||||
</button>
|
||||
<hr>
|
||||
<div><button id="_up" class="w3-button w3-dark-xlight w3-round-large w3-margin-small w3-block">↑ {% trans 'En haut' %}</button></div>
|
||||
<div><button id="_left" class="w3-button w3-dark-xlight w3-round-large w3-margin-small w3-block">← {% trans 'A gauches' %}</button></div>
|
||||
<div><button id="_right" class="w3-button w3-dark-xlight w3-round-large w3-margin-small w3-block">→ {% trans 'A droite' %}</button></div>
|
||||
<div><button id="_down" class="w3-button w3-dark-xlight w3-round-large w3-margin-small w3-block">↓ {% trans 'En Bas' %}</button></div>
|
||||
<hr>
|
||||
<button id="_xy-base" class="w3-button w3-warning w3-round-large w3-margin-small w3-block">{% trans 'Définir base ' %}</button>
|
||||
</div>
|
||||
<div class="scan w3-center">
|
||||
<div class="w3-row">
|
||||
<div class="w3-half">X<br><span id="_x"></span></div>
|
||||
<div class="w3-half">Y<br><span id="_y"></span></div>
|
||||
</div>
|
||||
|
||||
|
||||
<button id="_goto-0" class="w3-button w3-light-blue w3-round w3-round-large w3-margin-small w3-block">Origine (0, 0)</button>
|
||||
<button id="_goto-xy" class="w3-button w3-light-blue w3-round-large w3-margin-small w3-block w3-margin-bottom">
|
||||
{% trans 'Aller à la base' %}<br>(<span id="_xbase"></span>, <span id="_ybase"></span>)
|
||||
</button>
|
||||
<hr>
|
||||
<button id="_median" class="w3-button w3-teal w3-round-large w3-margin-small w3-block"><i class="fa-solid fa-crosshairs"></i> {% trans 'Axes' %}</button>
|
||||
<button id="_crop" class="w3-button w3-teal w3-round-large w3-margin-small w3-block w3-margin-bottom"><i class="fa-solid fa-crop"></i> {% trans 'Recadrer' %}</button>
|
||||
<span>
|
||||
{% trans 'Rayon' %}: <input id="_crop_radius" type="number" min="100" max="1200" step="1" value="{{ conf.calibration_crop_radius }}" title="{% trans 'Rayon de cadrage' %}"/>
|
||||
</span>
|
||||
<hr>
|
||||
<button id="_test" class="w3-button w3-warning w3-round-large w3-margin-small w3-block">{% trans 'Tester le cirduit' %}</button>
|
||||
<button id="_halt" class="w3-button w3-red w3-round-large w3-margin-small w3-block"><i class="fa-solid fa-hand"></i> {% trans 'ARRET' %}</button>
|
||||
|
||||
</div>
|
||||
<div class="scanner"><img id="scan-img" class="w3-image"></div>
|
||||
</div>
|
||||
<ul id="_debug" class="w3-scroll-y" style="height: 30vh"></ul>
|
||||
{% endblock %}
|
||||
|
||||
{% block js_footer %}
|
||||
{{ block.super }}
|
||||
<script src="/static/scanner/js/calibration.js"></script>
|
||||
<script>
|
||||
const container = sId("scan-img");
|
||||
const ws_route = "{{ ws_route }}";
|
||||
// ---- Point d'entrée ----
|
||||
(async () => {
|
||||
const manager = new ScannerManager(container);
|
||||
const protocol = location.protocol === "https:" ? "wss" : "ws";
|
||||
const wsUrl = `${protocol}://${location.host}/${ws_route}`;
|
||||
const socket = new MetadataSocket(wsUrl);
|
||||
socket.setManager(manager);
|
||||
socket.connect();
|
||||
manager.registerSocket(socket);
|
||||
})();
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
{% extends 'scanner/base.html' %}
|
||||
{% block columns %}{% endblock %}
|
||||
{% block content %}
|
||||
<iframe width="100%" src="{{ link }}" style="border:none; height:90vh;display:block;"></iframe>
|
||||
{% endblock %}
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
<div class="w3-modal" id="imagemodal" style="z-index: 200;">
|
||||
<div class="w3-modal-content w3-border w3-dark-medium" style="max-width: 640px">
|
||||
<button onclick="sId('imagemodal').style.display='none'" class="w3-button w3-round w3-round-xxlarge w3-text-red w3-display-topright w3-xlarge">✖</button>
|
||||
<div class="w3-card-4">
|
||||
<div class="w3-bar w3-dark-xlight" style="padding-right: 4em">
|
||||
<span class="w3-bar-item" id="imagepreview-uuid"></span>
|
||||
<span class="w3-bar-item" id="imagepreview-ts"></span>
|
||||
<span class="w3-bar-item w3-right" id="imagepreview-index"></span>
|
||||
</div>
|
||||
<img id="imagepreview" style="width: 100%">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,114 @@
|
||||
{% extends 'scanner/base.html' %}
|
||||
{% load i18n home_tags scanner_tags %}
|
||||
|
||||
{% block styles %}
|
||||
{{ block.super }}
|
||||
<link href="/static/scanner/css/images.css" rel="stylesheet">
|
||||
{% endblock %}
|
||||
{% block sidebar_list %}
|
||||
<a href="/" class="w3-bar-item w3-btn w3-hover-opacity"><i class="fa-solid fa-house w3-text-orange"></i> {% trans "Retour accueil" %}</a>
|
||||
<form method="post" class="w3-bar-item" action="">
|
||||
{% csrf_token %}
|
||||
<select id="_sid" name="_sid" class="w3-select w3-margin-bottom" onchange="this.form.submit()">
|
||||
<option value="0">---- {% trans "Session d'observations" %}</option>
|
||||
{% for s in sessions %}
|
||||
<option value="{{ s.id }}" {% if s.id == cursid %}selected{% endif %}>{{ s.name }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
{% if cursid %}
|
||||
<div class="multiwell_cards">
|
||||
{% multiwell_cards cursid observations %}
|
||||
</div>
|
||||
{% endif %}
|
||||
</form>
|
||||
{% if cursid %}
|
||||
<a href="#" class="w3-bar-item w3-btn w3-hover-opacity" onclick="download_all_images()">
|
||||
<i class="fa-solid fa-file-export w3-text-red"></i> {% trans "Exporter l'ensemble des images" %}
|
||||
</a>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div id="image-grid">
|
||||
{% if images %}
|
||||
{% for img in images %}
|
||||
<div class="w3-card-4 w3-border">
|
||||
<div class="w3-padding-small w3-dark-xlight w3-tiny">
|
||||
<span>{{ img.uuid }}</span>
|
||||
<span class="w3-right">{{ img.index }}</span>
|
||||
</div>
|
||||
<img class="w3-image" src="{{ img.content }}" onclick="image_preview(this, '{{ img.uuid }}', '{{ img.index }}', '{{ img.ts }}')">
|
||||
<div class="w3-container w3-dark-xlight w3-tiny">
|
||||
<button class="w3-button w3-round w3-warning w3-padding-1"
|
||||
onclick="image_save('{{ img.uuid }}.jpg', '{{ img.content }}')" title="{% trans 'Télécharger' %}"> ⬇
|
||||
</button>
|
||||
<span class="w3-right">{{ img.ts }}</span>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
{% block modal %}
|
||||
{% include "scanner/image-preview.html" %}
|
||||
{% endblock %}
|
||||
{% block js_footer %}
|
||||
{{ block.super }}
|
||||
<script>
|
||||
const container= sId("image-grid");
|
||||
const columns = "{{ conf.default_grid_columns }}";
|
||||
const duration = parseInt("{{ duration }}");
|
||||
const uuid_btn = sId("btn-" + "{{ uuid }}");
|
||||
const image_endpoint = "{% url 'scanner:export_api' %}";
|
||||
const sid = parseInt("{{ cursid }}");
|
||||
|
||||
function setGridColumns(col) { container.style.setProperty("--grid-columns", col); updateActiveButton(col); }
|
||||
function handleMultiwell(b) { b.classList.add('w3-green'); }
|
||||
function image_preview(img, uuid, index, ts) {
|
||||
imagemodal.style.display='block';
|
||||
sId('imagepreview').src = img.src;
|
||||
sId('imagepreview-uuid').textContent = uuid;
|
||||
sId('imagepreview-index').textContent = index;
|
||||
sId('imagepreview-ts').textContent = ts;
|
||||
}
|
||||
|
||||
function image_save(name, img) {
|
||||
const ok = confirm(`Télécharger le fichier ?\n\n${name}`);
|
||||
if (!ok) return false;
|
||||
fetch(img)
|
||||
.then(res => res.blob())
|
||||
.then(blob => {
|
||||
const url = URL.createObjectURL(blob);
|
||||
const a = document.createElement('a');
|
||||
a.href = url;
|
||||
a.download = name;
|
||||
document.body.appendChild(a);
|
||||
a.click();
|
||||
document.body.removeChild(a);
|
||||
URL.revokeObjectURL(url);
|
||||
});
|
||||
}
|
||||
|
||||
function download_all_images() {
|
||||
fetch(image_endpoint, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
action: 'export_images',
|
||||
sid: sid,
|
||||
})
|
||||
}).then(res => {
|
||||
console.log(res);
|
||||
|
||||
}).catch(error => {
|
||||
console.error('Erreur:', error);
|
||||
});
|
||||
}
|
||||
|
||||
setGridColumns(columns);
|
||||
if (uuid_btn)
|
||||
handleMultiwell(uuid_btn);
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
{% extends 'scanner/base.html' %}
|
||||
{% load i18n home_tags %}
|
||||
|
||||
{% block styles %}
|
||||
{{ block.super }}
|
||||
<link href="/static/scanner/css/main.css" rel="stylesheet">
|
||||
{% endblock %}
|
||||
{% block columns %}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="container w3-black">
|
||||
<div class="header">
|
||||
<div class="w3-row w3-row-padding">
|
||||
<div class="w3-half">
|
||||
<div>{% trans "Choix de la session" %}</div>
|
||||
<select id="_session" class="w3-select">
|
||||
{% for s in sessions %}
|
||||
<option value="{{ s.id }}">{{ s.name }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
<div class="w3-half">
|
||||
<div class="w3-margin-top w3-padding w3-right">
|
||||
<span id="_ts"></span><br>
|
||||
(<span id="_x"></span>, <span id="_y"></span>)
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="scan">
|
||||
<button id="_median" class="w3-button w3-teal w3-round-large w3-margin-small w3-block"><i class="fa-solid fa-crosshairs"></i> {% trans 'Axes' %}</button>
|
||||
<button id="_crop" class="w3-button w3-teal w3-round-large w3-margin-small w3-block w3-margin-bottom"><i class="fa-solid fa-crop"></i> {% trans 'Recadrer' %}</button>
|
||||
<hr>
|
||||
<button id="_scan" class="w3-button w3-warning w3-round-large w3-large w3-block">
|
||||
<i class="fa-solid fa-camera"></i><br>{% trans 'Lancer le balayage' %}
|
||||
</button>
|
||||
<button id="_halt" class="w3-button w3-red w3-round-large w3-padding-16 w3-block w3-margin-top"><i class="fa-solid fa-hand"></i><br>{% trans 'ARRET' %}</button>
|
||||
</div>
|
||||
<div class="scanner"><img id="scan-img" class="w3-image"></div>
|
||||
</div>
|
||||
<ul id="_debug" class="w3-scroll-y" style="height: 50vh"></ul>
|
||||
{% endblock %}
|
||||
|
||||
{% block js_footer %}
|
||||
{{ block.super }}
|
||||
<script src="/static/scanner/js/main.js"></script>
|
||||
<script>
|
||||
const container = sId("scan-img");
|
||||
const ws_route = "{{ ws_route }}";
|
||||
|
||||
// ---- Point d'entrée ----
|
||||
(async () => {
|
||||
const manager = new ScannerManager(container);
|
||||
const protocol = location.protocol === "https:" ? "wss" : "ws";
|
||||
const wsUrl = `${protocol}://${location.host}/${ws_route}`;
|
||||
const socket = new MetadataSocket(wsUrl);
|
||||
socket.setManager(manager);
|
||||
socket.connect();
|
||||
manager.registerSocket(socket);
|
||||
})();
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
<div class="slider-container" id="scannerSlider">
|
||||
<div class="display-range w3-small w3-margin-bottom"></div>
|
||||
<div class="range-wrap slider" data-min="1680307200" data-max="1680998400">
|
||||
|
||||
<div class="track"></div>
|
||||
<div class="range-highlight"></div>
|
||||
<input class="min-range" type="range" min="1680307200" max="1680998400" value="1680307200" step="100" aria-label="valeur minimale">
|
||||
<input class="max-range" type="range" min="1680307200" max="1680998400" value="1680998400" step="100" aria-label="valeur maximale">
|
||||
</div>
|
||||
<div class="w3-row w3-margin-top">
|
||||
<div class="w3-half">
|
||||
<span>Min (ms)</span>
|
||||
<input class="min-number" type="number" min="1680307200" max="1680998400" value="1680307200" step="100">
|
||||
</div>
|
||||
<div class="w3-half w3-right-align">
|
||||
<span>Max (ms)</span>
|
||||
<input class="max-number" type="number" min="1680307200" max="1680998400" value="1680998400" step="100">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title></title>
|
||||
<meta http-equiv="refresh" content="0; url={{ link }}" />
|
||||
</head>
|
||||
<body></body>
|
||||
</html>
|
||||
@@ -0,0 +1,134 @@
|
||||
{% extends 'scanner/base.html' %}
|
||||
{% load i18n home_tags scanner_tags %}
|
||||
|
||||
{% block styles %}
|
||||
{{ block.super }}
|
||||
<link href="/static/scanner/css/replay.css" rel="stylesheet">
|
||||
{% endblock %}
|
||||
{% block columns %}{% endblock %}
|
||||
{% block sidebar_list %}
|
||||
<a href="/" class="w3-bar-item w3-btn w3-hover-opacity"><i class="fa-solid fa-house w3-text-orange"></i> {% trans "Retour accueil" %}</a>
|
||||
<form method="post" class="w3-bar-item" action="">
|
||||
{% csrf_token %}
|
||||
<select id="_sid" name="_sid" class="w3-select w3-margin-bottom" onchange="this.form.submit()">
|
||||
<option value="0">---- {% trans "Session d'observations" %}</option>
|
||||
{% for s in sessions %}
|
||||
<option value="{{ s.id }}" {% if s.id == cursid %}selected{% endif %}>{{ s.name }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
{% if cursid %}
|
||||
<div class="multiwell_cards">
|
||||
{% multiwell_cards cursid observations %}
|
||||
</div>
|
||||
{% endif %}
|
||||
</form>
|
||||
{% if cursid %}
|
||||
<a href="#" class="w3-bar-item w3-btn w3-hover-opacity" onclick="download_all_videos()">
|
||||
<i class="fa-solid fa-file-export w3-text-red"></i> {% trans "Exporter l'ensemble des vidéos" %}
|
||||
</a>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div id="replay-grid" class="w3-black">
|
||||
{% if image %}
|
||||
<div class="w3-card-4 w3-border" style="min-width: 640px">
|
||||
<img id="_replay_img" src="{{ image }}" style="width: 100%">
|
||||
<div class="w3-bar w3-padding-small w3-light-grey">
|
||||
<span class="w3-bar-item w3-marging-right w3-dark-xlight" >{{ uuid }}</span>
|
||||
<button id="_replay_play" class="w3-bar-item w3-btn"><i class="fa-solid fa-play"></i></button>
|
||||
<button id="_replay_pause" class="w3-bar-item w3-btn"><i class="fa-solid fa-pause"></i></button>
|
||||
<button id="_replay_stop" class="w3-bar-item w3-btn"><i class="fa-solid fa-stop"></i></button>
|
||||
<button id="_replay_snapshot" class="w3-bar-item w3-btn"><i class="fa-solid fa-image"></i></button>
|
||||
<button id="_replay_videosnap" class="w3-bar-item w3-btn"><i class="fa-solid fa-video"></i></button>
|
||||
|
||||
<div class="replay-speed-control w3-bar-item w3-right w3-padding">
|
||||
<span>x <span id="_speed_label">1</span></span>
|
||||
<input id="_speed_control" type="range" min="0" max="8" step="1" class="w3-range">
|
||||
</div>
|
||||
</div>
|
||||
<div class="w3-dark-light w3-nbsp w3-small w3-padding-small w3-margint-top w3-margin-bottom">
|
||||
<div class="replay-ts-cursor ">
|
||||
<span id="_replay_ts_iso" class="w3-left">2026-04-05T08:13:18.067</span>
|
||||
<span id="_replay_percent" class="w3-right"></span>
|
||||
</div>
|
||||
<div class="replay-slider">
|
||||
<input id="_replay_timeline" type="range" min="0" max="1000" step="0.1" class="replay-timeline" disabled="">
|
||||
</div>
|
||||
<div class="replay-sub-slider">
|
||||
<span id="_replay_dt_left" class="w3-left">2026-04-05T08:13:18.067</span>
|
||||
<span id="_replay_dt_right" class="w3-right">2026-02-20T17:18:44.331</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block js_footer %}
|
||||
{{ block.super }}
|
||||
<script src="/static/scanner/js/replay.js"></script>
|
||||
<script>
|
||||
const ws_route = "{{ ws_route }}";
|
||||
const uuid_btn = sId("btn-" + "{{ uuid }}");
|
||||
const image_endpoint = "{% url 'scanner:export_api' %}";
|
||||
const sid = parseInt("{{ cursid }}");
|
||||
|
||||
function download_all_videos() {
|
||||
fetch(image_endpoint, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
action: 'export_videos',
|
||||
sid: sid,
|
||||
})
|
||||
}).then(res => {
|
||||
console.log(res);
|
||||
}).catch(error => {
|
||||
console.error('Erreur:', error);
|
||||
});
|
||||
}
|
||||
|
||||
function handleMultiwell(b) { b.classList.add('w3-green'); }
|
||||
// ---- Point d'entrée ----
|
||||
(async () => {
|
||||
if (!uuid_btn) return;
|
||||
|
||||
const manager = new ReplayManager({
|
||||
uuid: "{{ uuid }}",
|
||||
dt_start: parseInt("{{ oldest }}"),
|
||||
dt_stop: parseInt("{{ latest }}"),
|
||||
fps: parseFloat("{{ conf.video_frame_rate }}"),
|
||||
video_type: "{{ conf.opencv_video_type }}",
|
||||
video_endpoint: "{% url 'scanner:download_api' %}",
|
||||
img: sId("_replay_img"),
|
||||
play: sId("_replay_play"),
|
||||
pause: sId("_replay_pause"),
|
||||
stop: sId("_replay_stop"),
|
||||
ts: sId("_replay_ts"),
|
||||
snapshot: sId("_replay_snapshot"),
|
||||
videosnap: sId("_replay_videosnap"),
|
||||
speed_control: sId("_speed_control"),
|
||||
speed_label: sId("_speed_label"),
|
||||
timeline: sId("_replay_timeline"),
|
||||
ts_iso: sId("_replay_ts_iso"),
|
||||
percent: sId("_replay_percent"),
|
||||
dt_left: sId("_replay_dt_left"),
|
||||
dt_right: sId("_replay_dt_right")
|
||||
});
|
||||
await manager.start();
|
||||
|
||||
const protocol = location.protocol === "https:" ? "wss" : "ws";
|
||||
const wsUrl = `${protocol}://${location.host}/${ws_route}`;
|
||||
const socket = new MetadataSocket(wsUrl);
|
||||
socket.setManager(manager);
|
||||
socket.connect();
|
||||
manager.registerSocket(socket);
|
||||
|
||||
if (uuid_btn)
|
||||
handleMultiwell(uuid_btn);
|
||||
})();
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user