WIP: titik titik mata
This commit is contained in:
parent
3711b59d70
commit
48784beb0e
|
|
@ -8,6 +8,27 @@
|
|||
|
||||
class TobiiReceiverController extends Controller
|
||||
{
|
||||
/**
|
||||
* Fetch eye tracking data from database.
|
||||
*/
|
||||
public function fetchDataTobii($id_test_sessions)
|
||||
{
|
||||
$data_tobii = TobiiDataModel::where('id_test_sessions', $id_test_sessions)->latest()->first();
|
||||
if ($data_tobii) {
|
||||
return response()->json([
|
||||
'status' => true,
|
||||
'msg' => 'Data tobii ditemukan (' . $id_test_sessions . ')',
|
||||
'gaze_x' => $data_tobii->gaze_x,
|
||||
'gaze_y' => $data_tobii->gaze_y,
|
||||
]);
|
||||
} else {
|
||||
return response()->json([
|
||||
'status' => false,
|
||||
'msg' => 'Data tobii tidak ditemukan (' . $id_test_sessions . ')',
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
@section('title', 'Tutorial Test Kecemasan')
|
||||
@extends('user.layouts.test_layout.index')
|
||||
@section('content')
|
||||
<div class="container">
|
||||
<div class="container" id="tutorial_panel">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-8" id="tutorial_1">
|
||||
<div class="card shadow-sm border-0">
|
||||
|
|
@ -41,7 +41,7 @@
|
|||
<button class="btn btn-secondary" onclick="copyLinkApiTobii()">Copy</button>
|
||||
</div>
|
||||
</div>
|
||||
<p class="card-text mt-3" id="status_tobii">Status Tobii: Tidak Terhubung</p>
|
||||
<p class="card-text mt-3" id="status_tobii">Memuat...</p>
|
||||
<button class="btn btn-primary" id="back_btn" onclick="showTutorial(1, 'tutorial_2')">Back</button>
|
||||
<button class="btn btn-primary" id="next_btn_connect_tobii" onclick="showTutorial(3, 'tutorial_2')">Next</button>
|
||||
</div>
|
||||
|
|
@ -51,21 +51,151 @@
|
|||
<div class="card shadow-sm border-0">
|
||||
<div class="card-body">
|
||||
<h3 class="card-title fw-bold mb-4">Tes Keakuratan Mata</h3>
|
||||
<p class="card-text mb-3">Sebelum tes dimulai, cek keakuratan device Tobii anda, jika tidak akurat, lakukan kalibrasi kepada administrator.</p>
|
||||
<button class="btn btn-primary" id="back_btn" onclick="showTutorial(2, 'tutorial_2')">Back</button>
|
||||
<p class="card-text mb-3">Sebelum tes dimulai, cek keakuratan device Tobii anda (disarankan full-screen), jika tidak akurat, lakukan kalibrasi kepada administrator.</p>
|
||||
<button class="btn btn-primary" id="back_btn" onclick="showTutorial(2, 'tutorial_3')">Back</button>
|
||||
<button class="btn btn-secondary" id="fullscreen_btn" onclick="openFullscreen(this)" data-status="fullscreen">Fullscreen</button>
|
||||
<button class="btn btn-secondary" id="hide_btn" onclick="hidePanelTutorial(this)" data-status="hide">Hide</button>
|
||||
<a class="btn btn-primary">Mulai Ujian</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- btn show -->
|
||||
<button type="button" class="btn btn-secondary position-absolute" onclick="showCalibrationPoints()" id="show_calibration" style="z-index: 999">Show</button>
|
||||
<div class="position-absolute bg-white" style="width: 100vw; height: 100vh; z-index: -1;" id="calibration_point">
|
||||
<!-- row 1 -->
|
||||
<div class="rounded-circle bg-primary position-absolute" style="width: 0.5%; aspect-ratio: 1/1; top: 2%; left: 2%"></div>
|
||||
<div class="rounded-circle bg-primary position-absolute" style="width: 0.5%; aspect-ratio: 1/1; top: 2%; left: 19.2%"></div>
|
||||
<div class="rounded-circle bg-primary position-absolute" style="width: 0.5%; aspect-ratio: 1/1; top: 2%; left: 38.4%"></div>
|
||||
<div class="rounded-circle bg-primary position-absolute" style="width: 0.5%; aspect-ratio: 1/1; top: 2%; left: 57.6%"></div>
|
||||
<div class="rounded-circle bg-primary position-absolute" style="width: 0.5%; aspect-ratio: 1/1; top: 2%; left: 76.8%"></div>
|
||||
<div class="rounded-circle bg-primary position-absolute" style="width: 0.5%; aspect-ratio: 1/1; top: 2%; left: 96%"></div>
|
||||
|
||||
<!-- row 2 -->
|
||||
<div class="rounded-circle bg-primary position-absolute" style="width: 0.5%; aspect-ratio: 1/1; top: 19.2%; left: 2%"></div>
|
||||
<div class="rounded-circle bg-primary position-absolute" style="width: 0.5%; aspect-ratio: 1/1; top: 19.2%; left: 19.2%"></div>
|
||||
<div class="rounded-circle bg-primary position-absolute" style="width: 0.5%; aspect-ratio: 1/1; top: 19.2%; left: 38.4%"></div>
|
||||
<div class="rounded-circle bg-primary position-absolute" style="width: 0.5%; aspect-ratio: 1/1; top: 19.2%; left: 57.6%"></div>
|
||||
<div class="rounded-circle bg-primary position-absolute" style="width: 0.5%; aspect-ratio: 1/1; top: 19.2%; left: 76.8%"></div>
|
||||
<div class="rounded-circle bg-primary position-absolute" style="width: 0.5%; aspect-ratio: 1/1; top: 19.2%; left: 96%"></div>
|
||||
|
||||
<!-- row 3 -->
|
||||
<div class="rounded-circle bg-primary position-absolute" style="width: 0.5%; aspect-ratio: 1/1; top: 38.4%; left: 2%"></div>
|
||||
<div class="rounded-circle bg-primary position-absolute" style="width: 0.5%; aspect-ratio: 1/1; top: 38.4%; left: 19.2%"></div>
|
||||
<div class="rounded-circle bg-primary position-absolute" style="width: 0.5%; aspect-ratio: 1/1; top: 38.4%; left: 38.4%"></div>
|
||||
<div class="rounded-circle bg-primary position-absolute" style="width: 0.5%; aspect-ratio: 1/1; top: 38.4%; left: 57.6%"></div>
|
||||
<div class="rounded-circle bg-primary position-absolute" style="width: 0.5%; aspect-ratio: 1/1; top: 38.4%; left: 76.8%"></div>
|
||||
<div class="rounded-circle bg-primary position-absolute" style="width: 0.5%; aspect-ratio: 1/1; top: 38.4%; left: 96%"></div>
|
||||
|
||||
<!-- row 4 -->
|
||||
<div class="rounded-circle bg-primary position-absolute" style="width: 0.5%; aspect-ratio: 1/1; top: 57.6%; left: 2%"></div>
|
||||
<div class="rounded-circle bg-primary position-absolute" style="width: 0.5%; aspect-ratio: 1/1; top: 57.6%; left: 19.2%"></div>
|
||||
<div class="rounded-circle bg-primary position-absolute" style="width: 0.5%; aspect-ratio: 1/1; top: 57.6%; left: 38.4%"></div>
|
||||
<div class="rounded-circle bg-primary position-absolute" style="width: 0.5%; aspect-ratio: 1/1; top: 57.6%; left: 57.6%"></div>
|
||||
<div class="rounded-circle bg-primary position-absolute" style="width: 0.5%; aspect-ratio: 1/1; top: 57.6%; left: 76.8%"></div>
|
||||
<div class="rounded-circle bg-primary position-absolute" style="width: 0.5%; aspect-ratio: 1/1; top: 57.6%; left: 96%"></div>
|
||||
|
||||
<!-- row 5 -->
|
||||
<div class="rounded-circle bg-primary position-absolute" style="width: 0.5%; aspect-ratio: 1/1; top: 76.8%; left: 2%"></div>
|
||||
<div class="rounded-circle bg-primary position-absolute" style="width: 0.5%; aspect-ratio: 1/1; top: 76.8%; left: 19.2%"></div>
|
||||
<div class="rounded-circle bg-primary position-absolute" style="width: 0.5%; aspect-ratio: 1/1; top: 76.8%; left: 38.4%"></div>
|
||||
<div class="rounded-circle bg-primary position-absolute" style="width: 0.5%; aspect-ratio: 1/1; top: 76.8%; left: 57.6%"></div>
|
||||
<div class="rounded-circle bg-primary position-absolute" style="width: 0.5%; aspect-ratio: 1/1; top: 76.8%; left: 76.8%"></div>
|
||||
<div class="rounded-circle bg-primary position-absolute" style="width: 0.5%; aspect-ratio: 1/1; top: 76.8%; left: 96%"></div>
|
||||
|
||||
<!-- row 6 -->
|
||||
<div class="rounded-circle bg-primary position-absolute" style="width: 0.5%; aspect-ratio: 1/1; top: 96%; left: 2%"></div>
|
||||
<div class="rounded-circle bg-primary position-absolute" style="width: 0.5%; aspect-ratio: 1/1; top: 96%; left: 19.2%"></div>
|
||||
<div class="rounded-circle bg-primary position-absolute" style="width: 0.5%; aspect-ratio: 1/1; top: 96%; left: 38.4%"></div>
|
||||
<div class="rounded-circle bg-primary position-absolute" style="width: 0.5%; aspect-ratio: 1/1; top: 96%; left: 57.6%"></div>
|
||||
<div class="rounded-circle bg-primary position-absolute" style="width: 0.5%; aspect-ratio: 1/1; top: 96%; left: 76.8%"></div>
|
||||
<div class="rounded-circle bg-primary position-absolute" style="width: 0.5%; aspect-ratio: 1/1; top: 96%; left: 96%"></div>
|
||||
|
||||
<div id="the_eye" class="rounded-circle bg-danger position-absolute" style="width: 0.5%; aspect-ratio: 1/1;"></div>
|
||||
</div>
|
||||
@endsection
|
||||
|
||||
@section('script')
|
||||
<script>
|
||||
let getDataInterval = false;
|
||||
let checkTobiiInterval = null;
|
||||
|
||||
function showTutorial(step, tutorialId) {
|
||||
$(`#${tutorialId}`).hide();
|
||||
$(`#tutorial_${step}`).show();
|
||||
|
||||
if(step === 2) {
|
||||
checkTobiiInterval = setInterval(() => {
|
||||
checkTobiiConnection();
|
||||
}, 2000);
|
||||
} else {
|
||||
if(checkTobiiInterval) {
|
||||
clearInterval(checkTobiiInterval);
|
||||
}
|
||||
}
|
||||
|
||||
if(step === 3) {
|
||||
$('#calibration_point').show();
|
||||
getDataInterval = true;
|
||||
startPolling();
|
||||
} else {
|
||||
$('#calibration_point').hide();
|
||||
getDataInterval = false;
|
||||
}
|
||||
}
|
||||
|
||||
async function startPolling() {
|
||||
while(getDataInterval) {
|
||||
await fetchDataTobii();
|
||||
await delay(1000);
|
||||
}
|
||||
}
|
||||
|
||||
function delay(ms) {
|
||||
return new Promise(resolve => setTimeout(resolve, ms));
|
||||
}
|
||||
|
||||
function hidePanelTutorial(btn) {
|
||||
const status = $(btn).attr('data-status');
|
||||
if (status === 'hide') {
|
||||
$('#tutorial_panel').hide();
|
||||
$('#show_calibration').show();
|
||||
}
|
||||
}
|
||||
|
||||
function showCalibrationPoints() {
|
||||
$('#show_calibration').toggle();
|
||||
$('#tutorial_panel').toggle();
|
||||
}
|
||||
|
||||
function moveTheEye(x, y) {
|
||||
const eye = $('#the_eye');
|
||||
eye.css({ left: x + 'px', top: y + 'px' });
|
||||
}
|
||||
|
||||
function openFullscreen() {
|
||||
const status = $('#fullscreen_btn').attr('data-status');
|
||||
const elem = document.documentElement;
|
||||
if (status === 'fullscreen') {
|
||||
if (elem.requestFullscreen) {
|
||||
elem.requestFullscreen();
|
||||
} else if (elem.webkitRequestFullscreen) {
|
||||
elem.webkitRequestFullscreen(); // Safari
|
||||
} else if (elem.msRequestFullscreen) {
|
||||
elem.msRequestFullscreen(); // IE
|
||||
}
|
||||
$('#fullscreen_btn').attr('data-status', 'exit-fullscreen');
|
||||
} else if (status === 'exit-fullscreen') {
|
||||
if (document.exitFullscreen) {
|
||||
document.exitFullscreen();
|
||||
} else if (document.webkitExitFullscreen) {
|
||||
document.webkitExitFullscreen(); // Safari
|
||||
} else if (document.msExitFullscreen) {
|
||||
document.msExitFullscreen(); // IE
|
||||
}
|
||||
$('#fullscreen_btn').attr('data-status', 'fullscreen');
|
||||
}
|
||||
}
|
||||
|
||||
function generateLinkApiTobii() {
|
||||
|
|
@ -113,14 +243,26 @@ function checkTobiiConnection() {
|
|||
});
|
||||
}
|
||||
|
||||
async function fetchDataTobii() {
|
||||
try {
|
||||
const response = await fetch('{{ route("tobii-receiver.fetchData", ['id_test_sessions' => $data_session->id_test_sessions]) }}');
|
||||
if (!response.ok) {
|
||||
throw new Error('Network response was not ok');
|
||||
}
|
||||
const data = await response.json();
|
||||
moveTheEye(data.gaze_x, data.gaze_y);
|
||||
} catch (error) {
|
||||
console.error('Error fetching Tobii data:', error);
|
||||
}
|
||||
}
|
||||
|
||||
$(document).ready(function() {
|
||||
$('#tutorial_2').hide();
|
||||
$('#tutorial_3').hide();
|
||||
$('#next_btn_connect_tobii').hide();
|
||||
$('#calibration_point').hide();
|
||||
$('#show_calibration').hide();
|
||||
generateLinkApiTobii();
|
||||
|
||||
setInterval(() => {
|
||||
checkTobiiConnection();
|
||||
}, 2000);
|
||||
});
|
||||
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@
|
|||
Route::resource('tutorial-tes', TutorialTesController::class)->only(['index']);
|
||||
Route::resource('test-sessions', TestSessionsController::class)->only(['store', 'show']);
|
||||
Route::resource('tobii-receiver', TobiiReceiverController::class)->only(['store', 'show']);
|
||||
Route::get('tobii-receiver/fetch/data/{id_test_sessions}', [TobiiReceiverController::class, 'fetchDataTobii'])->name('tobii-receiver.fetchData');
|
||||
Route::middleware(['auth', 'role.auth'])->group(function() {
|
||||
Route::resource('dashboard', DashboardController::class);
|
||||
Route::resource('users', UsersController::class);
|
||||
|
|
|
|||
Loading…
Reference in New Issue