This commit is contained in:
Jack Parrot
2025-03-23 07:16:40 +01:00
parent 4a764beb9b
commit de2ab090d7
8 changed files with 879 additions and 46 deletions
+23
View File
@@ -12119,3 +12119,26 @@ input:checked + .slider:before {
.slider.round:before {
border-radius: 50%;
}
#map {
max-width: 100%;
max-height: 100%;
}
.pico canvas {
display: inline-block;
}
.pico :where(audio, canvas, iframe, img, svg, video) {
vertical-align: middle;
}
*, ::after, ::before {
box-sizing: border-box;
background-repeat: no-repeat;
}
canvas {
overflow-clip-margin: content-box;
overflow: clip;
}
+95 -30
View File
@@ -4473,25 +4473,38 @@
* --------------------------------------------------------------------------
*/
const index_umd = {
Alert,
Button,
Carousel,
Collapse,
Dropdown,
Modal,
Offcanvas,
Popover,
ScrollSpy,
Tab,
Toast,
Tooltip
const motors_buf = new Float32Array(2);
const motors_ml = document.getElementById("motors_ml")
const motors_mr = document.getElementById("motors_mr")
const motors_stop = document.getElementById("motors_stop")
const motors_joystick = document.getElementById('motors_joystick');
const motors_canvas = document.getElementById('motors_canvas');
let motors_ws = null;
const send_motors = (vl, vr) => {
/*if (motors_ws && motors_ws.readyState == WebSocket.OPEN) {
const lim = v => Math.max(-1, Math.min(v, 1));
motors_buf[0] = lim(vl);
motors_buf[1] = lim(vr);
motors_ml.value = vl * 100;
motors_mr.value = vr * 100;
motors_ws.send(motors_buf);
} else if (!motors_ws || motors_ws.readyState != WebSocket.CONNECTING) {
motors_ws = new WebSocket('ws://' + document.location.host + '/motors.ws');
motors_ws.addEventListener("open", () => send_motors(vl, vr));
}*/
};
document.getElementById("colorLed").onchange=function(){
// do whatever you want with value
console.log(this.value);
};
const update_motors = () => {
const vl = motors_ml.value / 100;
const vr = motors_mr.value / 100;
send_motors(vl, vr);
}
const btnsz = 40;
let positionX = 0, positionY = 0;
@@ -4503,20 +4516,19 @@
const h = motors_joystick.height;
ctx.clearRect(0, 0, w, h);
ctx.fillStyle = "#00aa0040";
ctx.fillStyle = "#00aaff40";
ctx.beginPath();
ctx.arc(w/2, h/2, w/2-btnsz, 0, 2 * Math.PI);
ctx.fill();
ctx.lineWidth = 2;
ctx.strokeStyle = "#009900";
ctx.fillStyle = "#00aa00";
ctx.strokeStyle = "#0099ee";
ctx.fillStyle = "#00aaff";
ctx.beginPath();
ctx.arc(w/2 + positionX, h/2 + positionY, btnsz, 0, 2 * Math.PI);
ctx.fill();
ctx.stroke();
}
const updatePosition = e => {
const clientX = e.clientX || e.touches[0].clientX;
const clientY = e.clientY || e.touches[0].clientY;
@@ -4531,11 +4543,9 @@
}
positionX = vx * kw;
positionY = vy * kw;
console.log("PositionX : "+ Math.round(positionX))
console.log("PositionY : "+ Math.round(positionY))
vy *= -1;
if (performance.now() - lastsend > 250) {
//send_motors(vy+vx, vy-vx);
send_motors(vy+vx, vy-vx);
lastsend = performance.now();
}
joystick_draw();
@@ -4552,7 +4562,7 @@
};
const onup = () => {
if (clicked) {
//send_motors(0, 0);
send_motors(0, 0);
motors_joystick.style.cursor = ''
clicked = false;
positionX = positionY = 0;
@@ -4569,14 +4579,69 @@
motors_joystick.addEventListener('touchend', onup);
motors_joystick.addEventListener('touchcancel', onup);
function onclick(){
send_motors(vy+vx, vy-vx);
//const text_color = getComputedStyle(motors_canvas).color;
document.body.addEventListener('h:infos:motors', e => {
const ctx = motors_canvas.getContext("2d");
const w = motors_canvas.width;
const h = motors_canvas.height;
const m = 5;
const ml = e.detail[0];
const mr = e.detail[1];
ctx.clearRect(0, 0, w, h);
ctx.lineWidth = 3;
ctx.strokeStyle = "#808080"
ctx.fillStyle = "#008000"
}
ctx.beginPath();
ctx.rect(m, m, w-2*m, (h/2-m));
ctx.stroke();
ctx.beginPath();
ctx.rect(m, (h/2-m)+m, w-2*m, (h/2-m));
ctx.stroke();
ctx.beginPath();
if (ml > 0)
ctx.rect(w/2, m+1, ml*(w/2-m), (h/2-m)-2);
else
ctx.rect(w/2+ml*(w/2-m), m+1, -ml*(w/2-m), (h/2-m)-2);
ctx.fill();
ctx.beginPath();
if (ml > 0)
ctx.rect(w/2, (h/2-m)+m+1, mr*(w/2-m), (h/2-m)-2);
else
ctx.rect(w/2+mr*(w/2-m), (h/2-m)+m+1, -mr*(w/2-m), (h/2-m)-2);
ctx.fill();
});
/*document.body.addEventListener('h:section:statechanged', e => {
infos_mask(INFOS_MOTORS, e.detail['on']);
});
infos_mask(INFOS_MOTORS, true);*/
document.getElementById("colorLed").value = "#ffffff"
document.getElementById("colorLed").onchange=function(){
// do whatever you want with value
console.log(this.value);
};
const index_umd = {
Alert,
Button,
Carousel,
Collapse,
Dropdown,
Modal,
Offcanvas,
Popover,
ScrollSpy,
Tab,
Toast,
Tooltip
};
return index_umd;
}));
//# sourceMappingURL=bootstrap.js.map
+1
View File
@@ -0,0 +1 @@
+482
View File
@@ -0,0 +1,482 @@
//Infos
const INFOS_POSITION = 0x01;
const INFOS_LED = 0x02;
const INFOS_MOTORS = 0x04;
const INFOS_WHEELS = 0x08;
const INFOS_SPEED = 0x10;
const INFOS_RANGEFINDER = 0x20;
let infos_ws = null;
let period_ms = 500;
let mask = 0;
function on_msg(e) {
const view = new DataView(e.data);
let pos = 0;
const mask = view.getUint8(pos);
pos++;
if (mask & INFOS_POSITION) {
const position_x = view.getFloat32(pos + 0);
const position_y = view.getFloat32(pos + 4);
const position_a = view.getFloat32(pos + 8);
pos += 3*4;
document.body.dispatchEvent(new CustomEvent('h:infos:position', {
'detail': [position_x, position_y, position_a]
}));
}
if (mask & INFOS_LED) {
const led_r = view.getUint8(pos + 0);
const led_g = view.getUint8(pos + 1);
const led_b = view.getUint8(pos + 2);
pos += 3;
document.body.dispatchEvent(new CustomEvent('h:infos:led', {
'detail': [led_r, led_g, led_b]
}));
}
if (mask & INFOS_MOTORS) {
const ml = view.getFloat32(pos + 0);
const mr = view.getFloat32(pos + 4);
pos += 2*4;
document.body.dispatchEvent(new CustomEvent('h:infos:motors', {
'detail': [ml, mr]
}));
}
if (mask & INFOS_WHEELS) {
const wl = view.getInt16(pos + 0);
const wr = view.getInt16(pos + 2);
const tl = view.getInt16(pos + 4);
const tr = view.getInt16(pos + 6);
pos += 4*2;
document.body.dispatchEvent(new CustomEvent('h:infos:wheels', {
'detail': [wl, wr, tl, tr]
}));
}
if (mask & INFOS_SPEED) {
const w = view.getFloat32(pos + 0);
const v = view.getFloat32(pos + 4);
pos += 4*2;
document.body.dispatchEvent(new CustomEvent('h:infos:speed', {
'detail': [w, v]
}));
}
if (mask & INFOS_RANGEFINDER) {
const d = view.getUint16(pos + 0);
pos += 2;
console.log(d);
document.body.dispatchEvent(new CustomEvent('h:infos:rangefinder', {
'detail': [d]
}));
}
}
function send_mask() {
/*if (mask == 0) {
if (infos_ws) {
infos_ws.close();
infos_ws = null;
}
} else {
if (infos_ws) {
if (infos_ws.readyState == WebSocket.OPEN) {
const buf = new Uint8Array(2);
buf[0] = period_ms / 10;
buf[1] = mask;
infos_ws.send(buf);
}
} else {
infos_ws = new WebSocket('ws://' + document.location.host + '/infos.ws');
infos_ws.binaryType = "arraybuffer";
infos_ws.addEventListener("open", send_mask);
infos_ws.addEventListener("message", on_msg);
}
}*/
}
function infos_mask(v, on) {
if (on)
mask |= v;
else
mask &= ~v;
send_mask();
}
//--------------------------------
//main
document.body.innerHTML = `
<header class="pico">
<details class="dropdown">
<summary>Sections…</summary>
<ul id="ul_header_menu"></ul>
</details>
<h1>MinHAUMtaure</h1>
</header>
`;
const sections_opened = new Set();
if (sessionStorage.getItem('sections_opened')) {
for (const s of sessionStorage.getItem('sections_opened').split('\n'))
sections_opened.add(s);
}
const sections = [
{ 'id': 'led', 'title': 'Led' },
{ 'id': 'motors', 'title': 'Moteurs' },
{ 'id': 'wheels', 'title': 'Retour roues' },
{ 'id': 'position', 'title': 'Position' },
{ 'id': 'turtle', 'title': 'Turtle' },
{ 'id': 'rangefinder', 'title': 'Télémètre' },
{ 'id': 'config', 'title': 'Config' },
{ 'id': 'wlan', 'title': 'Wifi' },
];
const ul_header_menu = document.getElementById('ul_header_menu');
for (const d of sections) {
const s = document.createElement('section');
const id = d['id'];
const title = d['title'];
s.id = 'section_' + id;
document.body.append(s);
const li = document.createElement('li');
ul_header_menu.append(li);
const label = document.createElement('label');
li.append(label);type="module"
const checkbox = document.createElement('input');
checkbox.type = 'checkbox';
checkbox.checked = false;
label.append(checkbox, title);
const h2 = document.createElement('h2');
const b_spans = document.createElement('b');
const span_fs = document.createElement('span');
span_fs.innerText = "⛶";
const span_close = document.createElement('span');
span_close.innerText = "×";
b_spans.append(span_fs, span_close);
h2.append(title, b_spans);
s.insertBefore(h2, s.firstChild);
s.classList.add('pico');
span_close.addEventListener('click', () => {
if (document.fullscreenElement != null)
document.exitFullscreen();
toggle(false);
});
span_fs.addEventListener('click', () => {
if (document.fullscreenElement == null)
s.requestFullscreen();
else
document.exitFullscreen();
});
const toggle = on => {
s.classList.toggle('opened', on);
checkbox.checked = on;
if (on)
sections_opened.add(id);
else
sections_opened.delete(id);
sessionStorage.setItem('sections_opened', Array.from(sections_opened).join('\n'));
if (on)
import('./' + id + '.js');
document.body.dispatchEvent(new CustomEvent('h:section:statechanged', {
'detail': {
'id': id,
'on': on,
'section': s
}
}));
}
checkbox.addEventListener('click', e => toggle(e.target.checked));
if (sections_opened.has(id)) toggle(true);
}
async function form_post(form) {
const data = new URLSearchParams();
for (const pair of new FormData(form)) {
data.append(pair[0], pair[1]);
}
return await fetch(form.action, {
method: 'post',
headers: { "Content-Type": "application/x-www-form-urlencoded" },
body: data
});
}
//--------------------------------
//motors
const section = document.getElementById('section_motors');
section.insertAdjacentHTML('beforeend', `
<div class="grid">
<p><canvas id="motors_joystick" width="400" height="400"></canvas></p>
<p>
<input type="range" min="-100" max="100" value="0" id="motors_ml" /><br/>
<input type="range" min="-100" max="100" value="0" id="motors_mr" /><br/>
<input type="button" id="motors_stop" value="Stop" />
<canvas id="motors_canvas" width="350" height="40"></canvas>
</p>
</div>
`);
const motors_buf = new Float32Array(2);
const motors_ml = document.getElementById("motors_ml")
const motors_mr = document.getElementById("motors_mr")
const motors_stop = document.getElementById("motors_stop")
const motors_joystick = document.getElementById('motors_joystick');
const motors_canvas = document.getElementById('motors_canvas');
let motors_ws = null;
const send_motors = (vl, vr) => {
/*if (motors_ws && motors_ws.readyState == WebSocket.OPEN) {
const lim = v => Math.max(-1, Math.min(v, 1));
motors_buf[0] = lim(vl);
motors_buf[1] = lim(vr);
motors_ml.value = vl * 100;
motors_mr.value = vr * 100;
motors_ws.send(motors_buf);
} else if (!motors_ws || motors_ws.readyState != WebSocket.CONNECTING) {
motors_ws = new WebSocket('ws://' + document.location.host + '/motors.ws');
motors_ws.addEventListener("open", () => send_motors(vl, vr));
}*/
};
const update_motors = () => {
const vl = motors_ml.value / 100;
const vr = motors_mr.value / 100;
send_motors(vl, vr);
}
motors_ml.addEventListener('change', update_motors);
motors_mr.addEventListener('change', update_motors);
motors_stop.addEventListener('click', e => {
e.preventDefault();
motors_ml.value = 0;
motors_mr.value = 0;
update_motors();
});
const btnsz = 40;
let positionX = 0, positionY = 0;
let clicked = false;
let lastsend = performance.now();
const joystick_draw = () => {
const ctx = motors_joystick.getContext("2d");
const w = motors_joystick.width;
const h = motors_joystick.height;
ctx.clearRect(0, 0, w, h);
ctx.fillStyle = "#00aaff40";
ctx.beginPath();
ctx.arc(w/2, h/2, w/2-btnsz, 0, 2 * Math.PI);
ctx.fill();
ctx.lineWidth = 2;
ctx.strokeStyle = "#0099ee";
ctx.fillStyle = "#00aaff";
ctx.beginPath();
ctx.arc(w/2 + positionX, h/2 + positionY, btnsz, 0, 2 * Math.PI);
ctx.fill();
ctx.stroke();
}
const updatePosition = e => {
const clientX = e.clientX || e.touches[0].clientX;
const clientY = e.clientY || e.touches[0].clientY;
const r = motors_joystick.getBoundingClientRect();
const kw = r.width/2 - btnsz;
let vx = Math.max(-1, Math.min((clientX - r.left - r.width/2) / kw, 1));
let vy = Math.max(-1, Math.min((clientY - r.top - r.height/2) / kw, 1));
if (vx*vx + vy*vy > 1) {
const a = Math.atan2(vy, vx);
vx = Math.cos(a);
vy = Math.sin(a);
}
positionX = vx * kw;
positionY = vy * kw;
vy *= -1;
if (performance.now() - lastsend > 250) {
send_motors(vy+vx, vy-vx);
lastsend = performance.now();
}
joystick_draw();
}
const ondown = e => {
clicked = true;
motors_joystick.style.cursor = 'none'
updatePosition(e);
};
const onmove = e => {
if (clicked) {
updatePosition(e);
}
};
const onup = () => {
if (clicked) {
send_motors(0, 0);
motors_joystick.style.cursor = ''
clicked = false;
positionX = positionY = 0;
joystick_draw();
}
};
joystick_draw();
motors_joystick.addEventListener('mousedown', ondown);
motors_joystick.addEventListener('mousemove', onmove);
motors_joystick.addEventListener('mouseup', onup);
motors_joystick.addEventListener('mouseleave', onup);
motors_joystick.addEventListener('touchstart', ondown);
motors_joystick.addEventListener('touchmove', onmove);
motors_joystick.addEventListener('touchend', onup);
motors_joystick.addEventListener('touchcancel', onup);
const text_color = getComputedStyle(motors_canvas).color;
document.body.addEventListener('h:infos:motors', e => {
const ctx = motors_canvas.getContext("2d");
const w = motors_canvas.width;
const h = motors_canvas.height;
const m = 5;
const ml = e.detail[0];
const mr = e.detail[1];
ctx.clearRect(0, 0, w, h);
ctx.lineWidth = 3;
ctx.strokeStyle = "#808080"
ctx.fillStyle = "#008000"
ctx.beginPath();
ctx.rect(m, m, w-2*m, (h/2-m));
ctx.stroke();
ctx.beginPath();
ctx.rect(m, (h/2-m)+m, w-2*m, (h/2-m));
ctx.stroke();
ctx.beginPath();
if (ml > 0)
ctx.rect(w/2, m+1, ml*(w/2-m), (h/2-m)-2);
else
ctx.rect(w/2+ml*(w/2-m), m+1, -ml*(w/2-m), (h/2-m)-2);
ctx.fill();
ctx.beginPath();
if (ml > 0)
ctx.rect(w/2, (h/2-m)+m+1, mr*(w/2-m), (h/2-m)-2);
else
ctx.rect(w/2+mr*(w/2-m), (h/2-m)+m+1, -mr*(w/2-m), (h/2-m)-2);
ctx.fill();
});
document.body.addEventListener('h:section:statechanged', e => {
infos_mask(INFOS_MOTORS, e.detail['on']);
});
infos_mask(INFOS_MOTORS, true);
//--------------------------------------------------
//position
const section2 = document.getElementById('section_position');
section2.insertAdjacentHTML('beforeend', `
<p>
<input type="range" min="190" max="1000" value="1000" id="map_scale" /><br/>
<input type="button" value="RàZ position" id="position_reset" /><br/>
<canvas id="map" width="800" height="800"></canvas>
</p>
`);
const position_reset = document.getElementById('position_reset');
position_reset.addEventListener('click', async () => {
position_reset.disabled = true;
await fetch('/position/reset')
position_reset.disabled = false;
});
const map_canvas = document.getElementById('map');
const map_scale_range = document.getElementById('map_scale');
const pos_hist = [];
const text_color2 = getComputedStyle(map_canvas).color;
const map_draw = (x, y, a) => {
const ctx = map_canvas.getContext("2d");
const w = map_canvas.width;
const h = map_canvas.height;
const map_scale = Number(map_scale_range.value);
ctx.clearRect(0, 0, w, h);
pos_hist.unshift([x, y]);
if (pos_hist.length > 10) pos_hist.pop();
ctx.font = '30px sans-serif';
ctx.fillStyle = text_color2;
ctx.textAlign = 'right';
ctx.fillText(Math.round(x*1000) + ' mm <X>', w-5, 30);
ctx.fillText(Math.round(y*1000) + ' mm <Y>', w-5, 60);
ctx.fillText(Math.round(a*180/Math.PI) + ' deg <A>', w-5, 90);
ctx.save();
ctx.translate(w/2, h/2);
ctx.scale(map_scale/1000, map_scale/1000);
ctx.lineWidth = Math.round(2*1000/map_scale);
ctx.beginPath();
for (let i = -10; i <= 11; i++) {
ctx.moveTo(-95+190*i, -95-2090);
ctx.lineTo(-95+190*i, -95+2090+190);
ctx.moveTo(-95-2090, -95+190*i);
ctx.lineTo(-95+2090+190, -95+190*i);
}
ctx.strokeStyle = 'rgba(180, 180, 180, 50%)';
ctx.stroke();
const hl = pos_hist.length;
for (let i = 1; i < hl; i++) {
ctx.beginPath();
ctx.moveTo(1000*pos_hist[i-1][0], -1000*pos_hist[i-1][1]);
ctx.lineTo(1000*pos_hist[i][0], -1000*pos_hist[i][1]);
const v = Math.round((hl-i)/(hl-1)*100);
ctx.strokeStyle = 'rgba(180, 200, 0, ' + v + '%)';
ctx.stroke();
}
ctx.translate(x*1000, -y*1000);
ctx.rotate(-a);
ctx.beginPath();
ctx.moveTo(40, 0);
ctx.lineTo(35, 77/4);
ctx.lineTo(24, 77/2);
ctx.lineTo(-68, 77/2);
ctx.lineTo(-68, -77/2);
ctx.lineTo(24, -77/2);
ctx.lineTo(35, -77/4);
ctx.lineTo(40, 0);
ctx.strokeStyle = '#008000'
ctx.stroke();
ctx.restore();
};
document.body.addEventListener('h:infos:position', e => {
map_draw(...e.detail);
});
document.body.addEventListener('h:section:statechanged', e => {
infos_mask(INFOS_POSITION, e.detail['on']);
});
infos_mask(INFOS_POSITION, true);
+166
View File
@@ -0,0 +1,166 @@
import { infos_mask, INFOS_MOTORS } from "./infos.js";
const section = document.getElementById('section_motors');
section.insertAdjacentHTML('beforeend', `
<div class="grid">
<p><canvas id="motors_joystick" width="400" height="400"></canvas></p>
<p>
<input type="range" min="-100" max="100" value="0" id="motors_ml" /><br/>
<input type="range" min="-100" max="100" value="0" id="motors_mr" /><br/>
<input type="button" id="motors_stop" value="Stop" />
<canvas id="motors_canvas" width="350" height="40"></canvas>
</p>
</div>
`);
const motors_buf = new Float32Array(2);
const motors_ml = document.getElementById("motors_ml")
const motors_mr = document.getElementById("motors_mr")
const motors_stop = document.getElementById("motors_stop")
const motors_joystick = document.getElementById('motors_joystick');
const motors_canvas = document.getElementById('motors_canvas');
let motors_ws = null;
const send_motors = (vl, vr) => {
if (motors_ws && motors_ws.readyState == WebSocket.OPEN) {
const lim = v => Math.max(-1, Math.min(v, 1));
motors_buf[0] = lim(vl);
motors_buf[1] = lim(vr);
motors_ml.value = vl * 100;
motors_mr.value = vr * 100;
motors_ws.send(motors_buf);
} else if (!motors_ws || motors_ws.readyState != WebSocket.CONNECTING) {
motors_ws = new WebSocket('ws://' + document.location.host + '/motors.ws');
motors_ws.addEventListener("open", () => send_motors(vl, vr));
}
};
const update_motors = () => {
const vl = motors_ml.value / 100;
const vr = motors_mr.value / 100;
send_motors(vl, vr);
}
motors_ml.addEventListener('change', update_motors);
motors_mr.addEventListener('change', update_motors);
motors_stop.addEventListener('click', e => {
e.preventDefault();
motors_ml.value = 0;
motors_mr.value = 0;
update_motors();
});
const btnsz = 40;
let positionX = 0, positionY = 0;
let clicked = false;
let lastsend = performance.now();
const joystick_draw = () => {
const ctx = motors_joystick.getContext("2d");
const w = motors_joystick.width;
const h = motors_joystick.height;
ctx.clearRect(0, 0, w, h);
ctx.fillStyle = "#00aaff40";
ctx.beginPath();
ctx.arc(w/2, h/2, w/2-btnsz, 0, 2 * Math.PI);
ctx.fill();
ctx.lineWidth = 2;
ctx.strokeStyle = "#0099ee";
ctx.fillStyle = "#00aaff";
ctx.beginPath();
ctx.arc(w/2 + positionX, h/2 + positionY, btnsz, 0, 2 * Math.PI);
ctx.fill();
ctx.stroke();
}
const updatePosition = e => {
const clientX = e.clientX || e.touches[0].clientX;
const clientY = e.clientY || e.touches[0].clientY;
const r = motors_joystick.getBoundingClientRect();
const kw = r.width/2 - btnsz;
let vx = Math.max(-1, Math.min((clientX - r.left - r.width/2) / kw, 1));
let vy = Math.max(-1, Math.min((clientY - r.top - r.height/2) / kw, 1));
if (vx*vx + vy*vy > 1) {
const a = Math.atan2(vy, vx);
vx = Math.cos(a);
vy = Math.sin(a);
}
positionX = vx * kw;
positionY = vy * kw;
vy *= -1;
if (performance.now() - lastsend > 250) {
send_motors(vy+vx, vy-vx);
lastsend = performance.now();
}
joystick_draw();
}
const ondown = e => {
clicked = true;
motors_joystick.style.cursor = 'none'
updatePosition(e);
};
const onmove = e => {
if (clicked) {
updatePosition(e);
}
};
const onup = () => {
if (clicked) {
send_motors(0, 0);
motors_joystick.style.cursor = ''
clicked = false;
positionX = positionY = 0;
joystick_draw();
}
};
joystick_draw();
motors_joystick.addEventListener('mousedown', ondown);
motors_joystick.addEventListener('mousemove', onmove);
motors_joystick.addEventListener('mouseup', onup);
motors_joystick.addEventListener('mouseleave', onup);
motors_joystick.addEventListener('touchstart', ondown);
motors_joystick.addEventListener('touchmove', onmove);
motors_joystick.addEventListener('touchend', onup);
motors_joystick.addEventListener('touchcancel', onup);
const text_color = getComputedStyle(motors_canvas).color;
document.body.addEventListener('h:infos:motors', e => {
const ctx = motors_canvas.getContext("2d");
const w = motors_canvas.width;
const h = motors_canvas.height;
const m = 5;
const ml = e.detail[0];
const mr = e.detail[1];
ctx.clearRect(0, 0, w, h);
ctx.lineWidth = 3;
ctx.strokeStyle = "#808080"
ctx.fillStyle = "#008000"
ctx.beginPath();
ctx.rect(m, m, w-2*m, (h/2-m));
ctx.stroke();
ctx.beginPath();
ctx.rect(m, (h/2-m)+m, w-2*m, (h/2-m));
ctx.stroke();
ctx.beginPath();
if (ml > 0)
ctx.rect(w/2, m+1, ml*(w/2-m), (h/2-m)-2);
else
ctx.rect(w/2+ml*(w/2-m), m+1, -ml*(w/2-m), (h/2-m)-2);
ctx.fill();
ctx.beginPath();
if (ml > 0)
ctx.rect(w/2, (h/2-m)+m+1, mr*(w/2-m), (h/2-m)-2);
else
ctx.rect(w/2+mr*(w/2-m), (h/2-m)+m+1, -mr*(w/2-m), (h/2-m)-2);
ctx.fill();
});
document.body.addEventListener('h:section:statechanged', e => {
infos_mask(INFOS_MOTORS, e.detail['on']);
});
infos_mask(INFOS_MOTORS, true);
+89
View File
@@ -0,0 +1,89 @@
import { infos_mask, INFOS_POSITION } from "./infos.js";
const section = document.getElementById('section_position');
section.insertAdjacentHTML('beforeend', `
<p>
<input type="range" min="190" max="1000" value="1000" id="map_scale" /><br/>
<input type="button" value="RàZ position" id="position_reset" /><br/>
<canvas id="map" width="800" height="800"></canvas>
</p>
`);
const position_reset = document.getElementById('position_reset');
position_reset.addEventListener('click', async () => {
position_reset.disabled = true;
await fetch('/position/reset')
position_reset.disabled = false;
});
const map_canvas = document.getElementById('map');
const map_scale_range = document.getElementById('map_scale');
const pos_hist = [];
const text_color = getComputedStyle(map_canvas).color;
const map_draw = (x, y, a) => {
const ctx = map_canvas.getContext("2d");
const w = map_canvas.width;
const h = map_canvas.height;
const map_scale = Number(map_scale_range.value);
ctx.clearRect(0, 0, w, h);
pos_hist.unshift([x, y]);
if (pos_hist.length > 10) pos_hist.pop();
ctx.font = '30px sans-serif';
ctx.fillStyle = text_color;
ctx.textAlign = 'right';
ctx.fillText(Math.round(x*1000) + ' mm <X>', w-5, 30);
ctx.fillText(Math.round(y*1000) + ' mm <Y>', w-5, 60);
ctx.fillText(Math.round(a*180/Math.PI) + ' deg <A>', w-5, 90);
ctx.save();
ctx.translate(w/2, h/2);
ctx.scale(map_scale/1000, map_scale/1000);
ctx.lineWidth = Math.round(2*1000/map_scale);
ctx.beginPath();
for (let i = -10; i <= 11; i++) {
ctx.moveTo(-95+190*i, -95-2090);
ctx.lineTo(-95+190*i, -95+2090+190);
ctx.moveTo(-95-2090, -95+190*i);
ctx.lineTo(-95+2090+190, -95+190*i);
}
ctx.strokeStyle = 'rgba(180, 180, 180, 50%)';
ctx.stroke();
const hl = pos_hist.length;
for (let i = 1; i < hl; i++) {
ctx.beginPath();
ctx.moveTo(1000*pos_hist[i-1][0], -1000*pos_hist[i-1][1]);
ctx.lineTo(1000*pos_hist[i][0], -1000*pos_hist[i][1]);
const v = Math.round((hl-i)/(hl-1)*100);
ctx.strokeStyle = 'rgba(180, 200, 0, ' + v + '%)';
ctx.stroke();
}
ctx.translate(x*1000, -y*1000);
ctx.rotate(-a);
ctx.beginPath();
ctx.moveTo(40, 0);
ctx.lineTo(35, 77/4);
ctx.lineTo(24, 77/2);
ctx.lineTo(-68, 77/2);
ctx.lineTo(-68, -77/2);
ctx.lineTo(24, -77/2);
ctx.lineTo(35, -77/4);
ctx.lineTo(40, 0);
ctx.strokeStyle = '#008000'
ctx.stroke();
ctx.restore();
};
document.body.addEventListener('h:infos:position', e => {
map_draw(...e.detail);
});
document.body.addEventListener('h:section:statechanged', e => {
infos_mask(INFOS_POSITION, e.detail['on']);
});
infos_mask(INFOS_POSITION, true);
Binary file not shown.

After

Width:  |  Height:  |  Size: 169 KiB

+17 -10
View File
@@ -6,27 +6,30 @@
<link rel="stylesheet" href="./bootstrap-5.3.3-dist/css/bootstrap.css">
<title>MinHAUMTaure</title>
</header>
<body>
<body background="./images/labyrinth-1080p-wallpaper-1920x1080.jpg">
<div class="container-fluid">
<div class="container-fluid text-white">
<div class="row mb-5 mt-5">
<div class="col">
<h1 class="text-center">Bienvenue sur MinHAUMTaure</h1>
</div>
</div>
<div class="row">
<div class="col mt-5">
<div class="row flex-nowrap">
<div class="row justify-content-around">
<div class="col-5 mt-5">
<div class="row mb-3">
<h2 class="text-center">Fonctionnalités</h2>
</div>
<div class="row flex-nowrap align-items-center bg-dark bg-opacity-75 rounded-5">
<div class="col ">
<h2 class="text-center">Directions</h2>
<canvas id="motors_joystick"width="400"height="400"></canvas>
<h2 class="text-center pt-4">Directions</h2>
<canvas id="motors_joystick"width="400"height="400">
</div>
<div class="col">
<h2 class="text-center"> Fonctionnalités</h2>
<h2 >Changement de couleur LED</h2>
<p>Sélection de la couleur</p>
<input type="color" id="colorLed">
<h2 class="text-center">Automatique</h2>
<h2>Automatique</h2>
<div class="form-check-inline form-switch">
<input class="form-check-input" type="checkbox" role="switch" id="flexSwitchCheckDefault">
<label class="form-check-label" for="flexSwitchCheckDefault">Mode Auto</label>
@@ -34,12 +37,16 @@
</div>
</div>
</div>
<div class="col mt-5">
<div class="col-5 mt-5">
<div class="row mb-3">
<h2 class="text-center">Repère Spatial</h2>
</div>
<div class="row flex-nowrap align-items-center bg-dark bg-opacity-75 rounded-5">
</div>
</div>
</div>
</div>
</body>
<script src="./bootstrap-5.3.3-dist/js/bootstrap.js"></script>