calibration
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
** custom.js
|
** custom.js
|
||||||
** GNU GENERAL PUBLIC LICENSE: (c) DD miraceti.net return document.querySelectorAll(id);
|
** GNU GENERAL PUBLIC LICENSE: (c) DD miraceti.net
|
||||||
*/
|
*/
|
||||||
let s = function(sel) { return document.querySelector(sel); };
|
let s = function(sel) { return document.querySelector(sel); };
|
||||||
let ss = function(sel) { return document.querySelectorAll(sel); };
|
let ss = function(sel) { return document.querySelectorAll(sel); };
|
||||||
|
|||||||
@@ -66,14 +66,15 @@ class WellPositionAdmin(admin.ModelAdmin):
|
|||||||
list_display = ('multiwell__position', 'well__name', 'order', 'x', 'y', 'px_per_mm', 'author',)
|
list_display = ('multiwell__position', 'well__name', 'order', 'x', 'y', 'px_per_mm', 'author',)
|
||||||
|
|
||||||
|
|
||||||
#class ExperimentConfigInline(admin.TabularInline):
|
class ExperimentWellInline(admin.TabularInline):
|
||||||
# model = models.ExperimentConfig
|
model = models.ExperimentWell
|
||||||
# extra = 0
|
extra = 0
|
||||||
|
|
||||||
|
|
||||||
class ExperimentAdmin(admin.ModelAdmin):
|
class ExperimentAdmin(admin.ModelAdmin):
|
||||||
#inlines = (ExperimenConfigInline,)
|
inlines = (ExperimentWellInline, )
|
||||||
list_filter = ('session_experiments__session', 'author', )
|
list_filter = ('session_experiments__session', 'author', )
|
||||||
list_display = ('title', 'author', 'identifier', 'multiwell', 'created', 'started', 'finished')
|
list_display = ('title', 'author', 'identifier', 'duration', 'multiwell', 'created', 'started', 'finished')
|
||||||
readonly_fields = ('created', 'identifier', 'started', 'finished', )
|
readonly_fields = ('created', 'identifier', 'started', 'finished', )
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -238,6 +238,7 @@ class Experiment(models.Model):
|
|||||||
author = models.ForeignKey(User, on_delete=models.CASCADE, verbose_name="Auteur", null=True, blank=True)
|
author = models.ForeignKey(User, on_delete=models.CASCADE, verbose_name="Auteur", null=True, blank=True)
|
||||||
multiwell = models.ForeignKey(MultiWell, verbose_name=_("Multi-puits"), on_delete=models.SET_NULL, null=True, blank=True)
|
multiwell = models.ForeignKey(MultiWell, verbose_name=_("Multi-puits"), on_delete=models.SET_NULL, null=True, blank=True)
|
||||||
duration = models.PositiveIntegerField(_("Durée"), help_text=_('Durée de la prise de vue en secondes'), blank=False, default=120)
|
duration = models.PositiveIntegerField(_("Durée"), help_text=_('Durée de la prise de vue en secondes'), blank=False, default=120)
|
||||||
|
|
||||||
created = models.DateTimeField(_("Date de création"), default=timezone.now)
|
created = models.DateTimeField(_("Date de création"), default=timezone.now)
|
||||||
started = models.DateTimeField (_("Date de début"), null=True, blank=True)
|
started = models.DateTimeField (_("Date de début"), null=True, blank=True)
|
||||||
finished = models.DateTimeField (_("Date de fin"), null=True, blank=True)
|
finished = models.DateTimeField (_("Date de fin"), null=True, blank=True)
|
||||||
@@ -400,3 +401,29 @@ class SessionExperiment(models.Model):
|
|||||||
return f'{self.session.name}'
|
return f'{self.session.name}'
|
||||||
|
|
||||||
|
|
||||||
|
class ExperimentWell(models.Model):
|
||||||
|
author = models.ForeignKey(User, on_delete=models.CASCADE, verbose_name="Auteur", null=True, blank=True)
|
||||||
|
experiment = models.ForeignKey(Experiment, verbose_name=_("Expérience"), on_delete=models.SET_NULL, null=True, blank=True, related_name="experimentwell")
|
||||||
|
well = models.ForeignKey(Well, verbose_name=_("Puit"), on_delete=models.SET_NULL, null=True, blank=True, related_name="wellexperiment")
|
||||||
|
active = models.BooleanField(_("Active"), default=True)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def wellname_by_experiment(cls, experiment_id):
|
||||||
|
return [ ew.well.name for ew in ExperimentWell.objects.filter(experiment__id=experiment_id, active=True).order_by('well__order') ]
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
ordering = ['experiment',]
|
||||||
|
unique_together = ["experiment", "well", ]
|
||||||
|
verbose_name = _("Expérience puit")
|
||||||
|
verbose_name_plural = _("Expériences puitd")
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return f'{self.experiment.title}'
|
||||||
|
|
||||||
|
|
||||||
|
@receiver(post_save, sender=Experiment)
|
||||||
|
def create_experiment_well(sender, instance, created, **kwargs):
|
||||||
|
wells = Well.objects.all()
|
||||||
|
for well in wells:
|
||||||
|
ExperimentWell.objects.get_or_create(experiment=instance, well=well, author=instance.author, defaults={'active':True})
|
||||||
|
|
||||||
|
|||||||
@@ -137,11 +137,11 @@ class MultiWellManager:
|
|||||||
return self.multiwell.config()
|
return self.multiwell.config()
|
||||||
|
|
||||||
|
|
||||||
def multiwell_buttons(self):
|
def multiwell_buttons(self, btn_class="w3-button", onclick=''' onclick="goto_well(this)"'''):
|
||||||
multiwells = []
|
multiwells = []
|
||||||
multiwells.append('''<div class="w3-border well-btn">''')
|
multiwells.append('''<div class="w3-border well-btn">''')
|
||||||
for wl in self.well_iterator:
|
for wl in self.well_iterator:
|
||||||
multiwells.append(f"""<button class="w3-button well" value="{wl.order}" onclick="goto_well(this)">{wl.well.name}</button>""")
|
multiwells.append(f"""<button class="{btn_class} well" value="{wl.order}"{onclick}>{wl.well.name}</button>""")
|
||||||
multiwells.append('''</div>''')
|
multiwells.append('''</div>''')
|
||||||
self.well_iterator.reset()
|
self.well_iterator.reset()
|
||||||
return mark_safe("\n".join(multiwells))
|
return mark_safe("\n".join(multiwells))
|
||||||
@@ -152,6 +152,7 @@ class MultiWellManager:
|
|||||||
try:
|
try:
|
||||||
well = well_position.well
|
well = well_position.well
|
||||||
multiwell = experiment.multiwell
|
multiwell = experiment.multiwell
|
||||||
|
|
||||||
if self.process.use_tracking:
|
if self.process.use_tracking:
|
||||||
cfg = ExperimentConfig.objects.filter(experiment_id=experiment.id, well_id=well.id).first()
|
cfg = ExperimentConfig.objects.filter(experiment_id=experiment.id, well_id=well.id).first()
|
||||||
if not cfg:
|
if not cfg:
|
||||||
@@ -159,15 +160,19 @@ class MultiWellManager:
|
|||||||
# reset PlanarianTracker => on_well_change
|
# reset PlanarianTracker => on_well_change
|
||||||
self.process.cam.on_well_change(cfg, draw_contours=False)
|
self.process.cam.on_well_change(cfg, draw_contours=False)
|
||||||
|
|
||||||
|
## create uuid for this capture
|
||||||
uuid = f'{self.process.data.session}-{multiwell.position}-{well.name}'
|
uuid = f'{self.process.data.session}-{multiwell.position}-{well.name}'
|
||||||
|
|
||||||
## start recording
|
## start recording
|
||||||
self.process.data.uuid = uuid
|
self.process.data.uuid = uuid
|
||||||
if not simulate:
|
if not simulate:
|
||||||
self.process.data.record = True
|
self.process.data.record = True
|
||||||
|
self.process._send(current=well_position.order)
|
||||||
|
|
||||||
start = time.monotonic()
|
start = time.monotonic()
|
||||||
while not self.stop_playing.is_set():
|
while not self.stop_playing.is_set():
|
||||||
if time.monotonic() - start > multiwell.duration:
|
## stop after duration in experiemnt now
|
||||||
|
if time.monotonic() - start > experiment.duration:
|
||||||
break
|
break
|
||||||
self.cnc_controller.wait_for(0.1)
|
self.cnc_controller.wait_for(0.1)
|
||||||
|
|
||||||
@@ -191,19 +196,26 @@ class MultiWellManager:
|
|||||||
logger.info(f"Simulating capture with file {vf}")
|
logger.info(f"Simulating capture with file {vf}")
|
||||||
|
|
||||||
|
|
||||||
|
def _is_well_valid(self, welposition):
|
||||||
|
names = models.ExperimentWell.wellname_by_experiment(welposition.experiment.id)
|
||||||
|
if welposition.well.name not in names:
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
def _grid_scanning(self, experiment, xnext=0, ynext=0, simulate=False):
|
def _grid_scanning(self, experiment, xnext=0, ynext=0, simulate=False):
|
||||||
try:
|
try:
|
||||||
multiwell = experiment.multiwell
|
multiwell = experiment.multiwell
|
||||||
wells = models.WellPosition.objects.filter(multiwell_id=multiwell.id).order_by('order').all()
|
wellpositions = models.WellPosition.objects.filter(multiwell_id=multiwell.id).order_by('order').all()
|
||||||
cam = self.process.cam
|
cam = self.process.cam
|
||||||
cam._aligner.set_tube_diameter(multiwell.diameter)
|
cam._aligner.set_tube_diameter(multiwell.diameter)
|
||||||
|
|
||||||
for wl in wells:
|
for wl in wellpositions:
|
||||||
if self.stop_playing.is_set():
|
if self.stop_playing.is_set():
|
||||||
break
|
break
|
||||||
self.cnc_controller.move_to(wl.x, wl.y, feed=wl.multiwell.feed)
|
if not self._is_well_valid(wl):
|
||||||
|
continue
|
||||||
|
|
||||||
## change file
|
self.cnc_controller.move_to(wl.x, wl.y, feed=wl.multiwell.feed)
|
||||||
if self.process.conf.capture_type == 'file':
|
if self.process.conf.capture_type == 'file':
|
||||||
self._capture_file_simulation(wl.well.name)
|
self._capture_file_simulation(wl.well.name)
|
||||||
|
|
||||||
@@ -308,6 +320,18 @@ class MultiWellManager:
|
|||||||
return {"state": "goto", "msg": f">>> {wl.well.name}: ({wl.x}, {wl.y})"}
|
return {"state": "goto", "msg": f">>> {wl.well.name}: ({wl.x}, {wl.y})"}
|
||||||
|
|
||||||
|
|
||||||
|
def goto_xy(self):
|
||||||
|
wl = self.well_iterator.seek(0)
|
||||||
|
if self.process.conf.capture_type == 'file':
|
||||||
|
self._capture_file_simulation(wl.well.name)
|
||||||
|
self.cnc_controller.move_to(self.xbase, self.ybase, feed=self.feed)
|
||||||
|
|
||||||
|
def goto_0(self):
|
||||||
|
self.well_iterator.reset()
|
||||||
|
if self.process.conf.capture_type == 'file':
|
||||||
|
self._capture_file_simulation('zero')
|
||||||
|
self.cnc_controller.move_to(0, 0, feed=self.feed*2)
|
||||||
|
|
||||||
def set_well_position(self):
|
def set_well_position(self):
|
||||||
wl = self.well_iterator.get_current()
|
wl = self.well_iterator.get_current()
|
||||||
if wl:
|
if wl:
|
||||||
@@ -329,8 +353,12 @@ class MultiWellManager:
|
|||||||
for wl in self.well_iterator:
|
for wl in self.well_iterator:
|
||||||
if self.stop_playing.is_set():
|
if self.stop_playing.is_set():
|
||||||
break
|
break
|
||||||
|
|
||||||
self.cnc_controller.wait_for(2.0)
|
self.cnc_controller.wait_for(2.0)
|
||||||
self.cnc_controller.move_to(wl.x, wl.y, feed=wl.multiwell.feed)
|
self.cnc_controller.move_to(wl.x, wl.y, feed=wl.multiwell.feed)
|
||||||
|
## change file
|
||||||
|
if self.process.conf.capture_type == 'file':
|
||||||
|
self._capture_file_simulation(wl.well.name)
|
||||||
self.process._send(current=wl.order)
|
self.process._send(current=wl.order)
|
||||||
|
|
||||||
start = time.monotonic()
|
start = time.monotonic()
|
||||||
@@ -374,8 +402,8 @@ class MultiWellManager:
|
|||||||
self.process.cam._aligner.debug = False
|
self.process.cam._aligner.debug = False
|
||||||
|
|
||||||
logger.info(f"Scan terminé — retour à l'origine (X=0, Y=0) en {int(time.monotonic()-start_test)} s")
|
logger.info(f"Scan terminé — retour à l'origine (X=0, Y=0) en {int(time.monotonic()-start_test)} s")
|
||||||
self.cnc_controller.move_to(0, 0, feed=self.multiwell.feed*2)
|
self.goto_0()
|
||||||
|
self.process._send(current=self.get_well_order())
|
||||||
|
|
||||||
def scan_test(self, auto=False):
|
def scan_test(self, auto=False):
|
||||||
if self.test_thread:
|
if self.test_thread:
|
||||||
@@ -467,12 +495,12 @@ class MultiWellManager:
|
|||||||
""" Active / désactive le mode debug sur le stream."""
|
""" Active / désactive le mode debug sur le stream."""
|
||||||
aligner = self.process.cam._aligner
|
aligner = self.process.cam._aligner
|
||||||
aligner.debug = not aligner.debug
|
aligner.debug = not aligner.debug
|
||||||
return {"state": "debug", "msg": f"Debug: {aligner.debug}"}
|
return {"state": "debug", "value": aligner.debug, "msg": f"Debug: {aligner.debug}"}
|
||||||
|
|
||||||
def set_calib_debug(self, value=True):
|
def set_calib_debug(self, value=True):
|
||||||
""" Active / désactive le mode debug sur le stream."""
|
""" Active / désactive le mode debug sur le stream."""
|
||||||
aligner = self.process.cam._aligner
|
aligner = self.process.cam._aligner
|
||||||
aligner.debug = value
|
aligner.debug = value
|
||||||
return {"state": "debug", "msg": f"Debug: {aligner.debug}"}
|
return {"state": "debug", "value": aligner.debug, "msg": f"Debug: {aligner.debug}"}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -373,6 +373,8 @@ class ScannerProcess(Task):
|
|||||||
self.cam._active_median = False
|
self.cam._active_median = False
|
||||||
self.grbl.go_origin(feed=self.manager.feed)
|
self.grbl.go_origin(feed=self.manager.feed)
|
||||||
self.cam.set_draw_contours(False)
|
self.cam.set_draw_contours(False)
|
||||||
|
buttons = self.manager.multiwell_buttons(btn_class="w3-btn", onclick="")
|
||||||
|
self._send(buttons=buttons)
|
||||||
|
|
||||||
elif topic == 'scan' or topic == 'simulate':
|
elif topic == 'scan' or topic == 'simulate':
|
||||||
logger.info(f"==== Scan {cmd}")
|
logger.info(f"==== Scan {cmd}")
|
||||||
@@ -390,9 +392,12 @@ class ScannerProcess(Task):
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"Scan error: {e}")
|
logger.error(f"Scan error: {e}")
|
||||||
self._send(state='error', msg=str(_('Erreur lors du démarrage du balayage...')))
|
self._send(state='error', msg=str(_('Erreur lors du démarrage du balayage...')))
|
||||||
|
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
self._send(
|
||||||
|
buttons=buttons,
|
||||||
|
current=self.manager.get_well_order(),
|
||||||
|
)
|
||||||
elif cmd["type"]=="calibrate":
|
elif cmd["type"]=="calibrate":
|
||||||
topic = cmd.get("topic")
|
topic = cmd.get("topic")
|
||||||
value = cmd.get("value")
|
value = cmd.get("value")
|
||||||
@@ -424,11 +429,13 @@ class ScannerProcess(Task):
|
|||||||
|
|
||||||
elif topic == 'median':
|
elif topic == 'median':
|
||||||
self.cam._active_median = not self.cam._active_median
|
self.cam._active_median = not self.cam._active_median
|
||||||
|
self._send(state="median", value=self.cam._active_median, msg=f"Median: {self.cam._active_median}")
|
||||||
continue
|
continue
|
||||||
|
|
||||||
elif topic == 'crop':
|
elif topic == 'crop':
|
||||||
self.cam._active_crop = not self.cam._active_crop
|
self.cam._active_crop = not self.cam._active_crop
|
||||||
self.cam.set_circular_crop(self.crop) if self.cam._active_crop else self.cam.set_circular_crop(None)
|
self.cam.set_circular_crop(self.crop) if self.cam._active_crop else self.cam.set_circular_crop(None)
|
||||||
|
self._send(state="crop", value=self.cam._active_crop, msg=f"Crop: {self.cam._active_crop}")
|
||||||
continue
|
continue
|
||||||
|
|
||||||
elif topic == 'crop_radius':
|
elif topic == 'crop_radius':
|
||||||
@@ -452,17 +459,10 @@ class ScannerProcess(Task):
|
|||||||
self.manager.duration = float(value)
|
self.manager.duration = float(value)
|
||||||
|
|
||||||
elif topic == 'goto_0':
|
elif topic == 'goto_0':
|
||||||
self.grbl.go_origin(feed=self.manager.feed)
|
self.manager.goto_0()
|
||||||
self.manager.well_iterator.reset()
|
|
||||||
self.manager.well_iterator.seek(0)
|
|
||||||
if self.conf.capture_type == 'file':
|
|
||||||
self.manager._capture_file_simulation('zero')
|
|
||||||
|
|
||||||
elif topic == 'goto_xy':
|
elif topic == 'goto_xy':
|
||||||
self.grbl.move_to(self.manager.xbase, self.manager.ybase, feed=self.manager.feed)
|
self.manager.goto_xy()
|
||||||
wl = self.manager.well_iterator.seek(0)
|
|
||||||
if self.conf.capture_type == 'file':
|
|
||||||
self.manager._capture_file_simulation(wl.well.name)
|
|
||||||
|
|
||||||
elif topic == 'xy_base':
|
elif topic == 'xy_base':
|
||||||
self.manager.set_position()
|
self.manager.set_position()
|
||||||
@@ -488,7 +488,6 @@ class ScannerProcess(Task):
|
|||||||
elif topic == 'halt':
|
elif topic == 'halt':
|
||||||
self.manager.halt_scanning()
|
self.manager.halt_scanning()
|
||||||
|
|
||||||
|
|
||||||
elif topic == 'calib_debug':
|
elif topic == 'calib_debug':
|
||||||
msg = self.manager.calib_toggle_debug()
|
msg = self.manager.calib_toggle_debug()
|
||||||
self._send(**msg)
|
self._send(**msg)
|
||||||
|
|||||||
@@ -1 +1,11 @@
|
|||||||
|
|
||||||
|
.well {
|
||||||
|
padding: 0.2em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.well-btn {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(6, 1fr);
|
||||||
|
justify-items: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|||||||
@@ -101,7 +101,16 @@ class ScannerManager {
|
|||||||
if (payload.jpeg) { this.container.src = `data:image/jpeg;base64,${payload.jpeg}`; }
|
if (payload.jpeg) { this.container.src = `data:image/jpeg;base64,${payload.jpeg}`; }
|
||||||
if (payload.xbase) { this.xbase.textContent = payload.xbase; this.ybase.textContent = payload.ybase; }
|
if (payload.xbase) { this.xbase.textContent = payload.xbase; this.ybase.textContent = payload.ybase; }
|
||||||
if (payload.xy) { this.x.textContent=payload.x.toFixed(2); this.y.textContent=payload.y.toFixed(2); }
|
if (payload.xy) { this.x.textContent=payload.x.toFixed(2); this.y.textContent=payload.y.toFixed(2); }
|
||||||
if (payload.state) { this.debug.insertAdjacentHTML('afterbegin', `<li>[ ${++this.debug_count} - ${payload.state} ]: ${payload.msg}</li>`); }
|
if (payload.state) {
|
||||||
|
if (payload.state == 'debug') {
|
||||||
|
const span = this.calib_debug.querySelector("span.debug"); span.style.color = payload.value ? '#f0f': '#fff';
|
||||||
|
} else if (payload.state == 'median') {
|
||||||
|
const span = this.median.querySelector("span.median"); span.style.color = payload.value ? '#f0f' : '#fff';
|
||||||
|
} else if (payload.state == 'crop') {
|
||||||
|
const span = this.crop.querySelector("span.crop"); span.style.color = payload.value ? '#f0f' : '#fff';
|
||||||
|
}
|
||||||
|
this.debug.insertAdjacentHTML('afterbegin', `<li>[ ${++this.debug_count} - ${payload.state} ]: ${payload.msg}</li>`);
|
||||||
|
}
|
||||||
if (payload.ts) { this.ts.textContent = timestampToLocalISOString(payload.ts); }
|
if (payload.ts) { this.ts.textContent = timestampToLocalISOString(payload.ts); }
|
||||||
|
|
||||||
if (payload.buttons) { this.well_btn.innerHTML = payload.buttons; }
|
if (payload.buttons) { this.well_btn.innerHTML = payload.buttons; }
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ class ScannerManager {
|
|||||||
this.frame_count = options.frame_count;
|
this.frame_count = options.frame_count;
|
||||||
this.scan_state = options.scan_state;
|
this.scan_state = options.scan_state;
|
||||||
this.sim_bt = options.simulate;
|
this.sim_bt = options.simulate;
|
||||||
|
this.well_btn = options.well_btn;
|
||||||
}
|
}
|
||||||
|
|
||||||
init_controls() {
|
init_controls() {
|
||||||
@@ -47,14 +48,14 @@ class ScannerManager {
|
|||||||
if (payload.ts) { this.ts.textContent = timestampToLocalISOString(payload.ts); }
|
if (payload.ts) { this.ts.textContent = timestampToLocalISOString(payload.ts); }
|
||||||
if (payload.scan_state) { this.scan_state.textContent=payload.scan_state;}
|
if (payload.scan_state) { this.scan_state.textContent=payload.scan_state;}
|
||||||
|
|
||||||
if (payload.detected && use_tracking) {
|
if (payload.buttons) { this.well_btn.innerHTML = payload.buttons; }
|
||||||
this.cx.textContent = payload.cx; this.cy.textContent = payload.cy;
|
if (payload.current >= 0) {
|
||||||
this.speed_px_s.textContent = payload.speed_px_s;
|
document.querySelectorAll('button.w3-button.well').forEach(btn => {
|
||||||
this.axial_speed.textContent = payload.axial_speed;
|
if (btn.value==payload.current) { btn.classList.add('w3-green'); return; }
|
||||||
this.axial_pos.textContent = payload.axial_pos;
|
btn.classList.remove('w3-green');
|
||||||
this.area_px.textContent = payload.area_px;
|
});
|
||||||
this.frame_count.textContent = payload.count;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch(e) { console.log(e); }
|
} catch(e) { console.log(e); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -86,6 +86,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="w3-row w3-row-padding">
|
<div class="w3-row w3-row-padding">
|
||||||
<div id="_well_btn" class="w3-col w3-margin-bottom"></div>
|
<div id="_well_btn" class="w3-col w3-margin-bottom"></div>
|
||||||
|
|
||||||
<div class="w3-third">
|
<div class="w3-third">
|
||||||
<button id="_previous" class="w3-button w3-dark-xlight w3-round-large w3-padding-small">
|
<button id="_previous" class="w3-button w3-dark-xlight w3-round-large w3-padding-small">
|
||||||
<span class="w3-small">{% trans 'Précéd.' %}</span><br><i class="fa-solid fa-circle-left w3-xlarge"></i>
|
<span class="w3-small">{% trans 'Précéd.' %}</span><br><i class="fa-solid fa-circle-left w3-xlarge"></i>
|
||||||
@@ -134,17 +135,17 @@
|
|||||||
<div class="w3-row w3-row-padding">
|
<div class="w3-row w3-row-padding">
|
||||||
<div class="w3-half">
|
<div class="w3-half">
|
||||||
<button id="_calib_debug" class="w3-button w3-dark-xlight w3-round-large w3-padding-1 w3-block" title="{% trans 'Ce mode permet les réglages graphiques' %}">
|
<button id="_calib_debug" class="w3-button w3-dark-xlight w3-round-large w3-padding-1 w3-block" title="{% trans 'Ce mode permet les réglages graphiques' %}">
|
||||||
{% trans 'Debug' %}<br><i class="fa-solid fa-triangle-exclamation w3-text-amber w3-xlarge"></i>
|
<span class="debug">{% trans 'Debug' %}</span><br><i class="fa-solid fa-triangle-exclamation w3-text-amber w3-xlarge"></i>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="w3-half">
|
<div class="w3-half">
|
||||||
<button id="_median" class="w3-button w3-dark-xlight w3-round-large w3-padding-1 w3-block">
|
<button id="_median" class="w3-button w3-dark-xlight w3-round-large w3-padding-1 w3-block">
|
||||||
{% trans 'Axes' %}<br><i class="fa-solid fa-crosshairs w3-text-amber w3-xlarge"></i>
|
<span class="median">{% trans 'Axes' %}</span><br><i class="fa-solid fa-crosshairs w3-text-amber w3-xlarge"></i>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="w3-col">
|
<div class="w3-col">
|
||||||
<button id="_crop" class="w3-button w3-dark-xlight w3-round-large w3-padding-small w3-margin-top w3-block" title="{% trans 'Ce mode actionne le pointage graphique' %}">
|
<button id="_crop" class="w3-button w3-dark-xlight w3-round-large w3-padding-small w3-margin-top w3-block" title="{% trans 'Ce mode actionne le pointage graphique' %}">
|
||||||
{% trans 'Recadrer' %}<br><i class="fa-solid fa-crop w3-text-amber w3-xlarge"></i>
|
<span class="crop">{% trans 'Recadrer pour calibrer / suivre' %}</span><br><i class="fa-solid fa-crop w3-text-amber w3-xlarge"></i>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -48,6 +48,9 @@
|
|||||||
{% trans 'Simuler' %}<br>{% trans 'le balayage' %}<br><i class="fa-solid fa-triangle-exclamation w3-text-orange w3-xlarge"></i>
|
{% trans 'Simuler' %}<br>{% trans 'le balayage' %}<br><i class="fa-solid fa-triangle-exclamation w3-text-orange w3-xlarge"></i>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="w3-col">
|
||||||
|
<div id="_well_btn" class="w3-margin-top"></div>
|
||||||
|
</div>
|
||||||
<div class="w3-col">
|
<div class="w3-col">
|
||||||
<button id="_halt" class="w3-button w3-red w3-round-large w3-margin-top w3-block">
|
<button id="_halt" class="w3-button w3-red w3-round-large w3-margin-top w3-block">
|
||||||
{% trans 'ARRET' %}<br><i class="fa-solid fa-hand w3-xlarge"></i>
|
{% trans 'ARRET' %}<br><i class="fa-solid fa-hand w3-xlarge"></i>
|
||||||
@@ -94,7 +97,8 @@
|
|||||||
area_px : sId("_area_px"),
|
area_px : sId("_area_px"),
|
||||||
frame_count : sId("_count"),
|
frame_count : sId("_count"),
|
||||||
scan_state : sId("_scan_state"),
|
scan_state : sId("_scan_state"),
|
||||||
simulate : sId("_simulate")
|
simulate : sId("_simulate"),
|
||||||
|
well_btn : sId("_well_btn")
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
<script src="/static/scanner/js/scanning.js"></script>
|
<script src="/static/scanner/js/scanning.js"></script>
|
||||||
|
|||||||
Reference in New Issue
Block a user