mqtnl
Version:
Familiar socket API over MQTT with smart packet prioritization and IoT-friendly features
128 lines (109 loc) • 3.38 kB
HTML
<html>
<head>
<title>Serial Transmisi Partikel</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/5.3.0/fabric.min.js"></script>
<style>
canvas {
border: 1px solid #ccc;
}
button {
margin-top: 10px;
}
label {
margin-left: 10px;
}
</style>
</head>
<body>
<canvas id="canvas" width="1000" height="500"></canvas>
<br>
<button id="btnTransmit">Transmit</button>
<label>Durasi tiap partikel (ms):
<input type="number" id="durationInput" value="500" min="100" max="5000">
</label>
<script>
const canvas = new fabric.Canvas('canvas');
const boxSize = 5;
const rows = 15;
const cols = 10;
const spacing = boxSize + 1;
const startX = 20;
const startY = 75;
const groupYgap = 125;
const targetX0 = 800;
const colors = ['red', 'orange', 'green'];
const particles = [];
// Inisiasi semua kotak dan simpan posisi awal
colors.forEach((color, gi) => {
for (let r = 0; r < rows; r++) {
for (let c = 0; c < cols; c++) {
const left = startX + c * spacing;
const top = startY + gi * groupYgap + r * spacing;
const rect = new fabric.Rect({
left, top, width: boxSize, height: boxSize,
stroke: "grey", strokeWidth: .5,
fill: color, selectable: false
});
canvas.add(rect);
particles.push({ rect, sx: left, sy: top, r, c, gi });
}
}
});
// Fisher–Yates shuffle
function shuffle(arr) {
for (let i = arr.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[arr[i], arr[j]] = [arr[j], arr[i]];
}
return arr;
}
document.getElementById('btnTransmit').onclick = () => {
const duration = +document.getElementById('durationInput').value;
// Reset semua kotak ke posisi awal
particles.forEach(p => {
p.rect.set({ left: p.sx, top: p.sy });
p.rect.setCoords();
});
canvas.renderAll();
// Susun urutan per grup secara acak
const byGroup = [[], [], []];
particles.forEach((p, idx) => byGroup[p.gi].push(idx));
const order = []
.concat(shuffle(byGroup[0]))
.concat(shuffle(byGroup[1]))
.concat(shuffle(byGroup[2]));
// Hitung target untuk setiap kotak
order.forEach(idx => {
const p = particles[idx];
p.tx = targetX0 + p.c * spacing;
p.ty = startY + p.gi * groupYgap + p.r * spacing;
});
// Animasi serial satu per satu
let ptr = 0;
function nextParticle() {
if (ptr >= order.length) return;
const p = particles[order[ptr++]];
const t0 = performance.now();
function step(now) {
const elapsed = now - t0;
const t = Math.min(elapsed / duration, 1);
const x = p.sx + (p.tx - p.sx) * t;
const curve = Math.sin(t * Math.PI) * -100;
const y = p.sy + (p.ty - p.sy) * t + curve;
p.rect.set({ left: x, top: y });
p.rect.setCoords();
canvas.renderAll();
if (t < 1) {
requestAnimationFrame(step);
} else {
nextParticle();
}
}
requestAnimationFrame(step);
}
nextParticle();
};
</script>
</body>
</html>