halaman-psikolog #1

Merged
Mahayoga merged 52 commits from halaman-psikolog into master 2026-07-06 12:37:30 +07:00
3 changed files with 172 additions and 8 deletions
Showing only changes of commit 48784beb0e - Show all commits

View File

@ -8,6 +8,27 @@
class TobiiReceiverController extends Controller 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. * Display a listing of the resource.
*/ */

View File

@ -1,7 +1,7 @@
@section('title', 'Tutorial Test Kecemasan') @section('title', 'Tutorial Test Kecemasan')
@extends('user.layouts.test_layout.index') @extends('user.layouts.test_layout.index')
@section('content') @section('content')
<div class="container"> <div class="container" id="tutorial_panel">
<div class="row justify-content-center"> <div class="row justify-content-center">
<div class="col-md-8" id="tutorial_1"> <div class="col-md-8" id="tutorial_1">
<div class="card shadow-sm border-0"> <div class="card shadow-sm border-0">
@ -41,7 +41,7 @@
<button class="btn btn-secondary" onclick="copyLinkApiTobii()">Copy</button> <button class="btn btn-secondary" onclick="copyLinkApiTobii()">Copy</button>
</div> </div>
</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="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> <button class="btn btn-primary" id="next_btn_connect_tobii" onclick="showTutorial(3, 'tutorial_2')">Next</button>
</div> </div>
@ -51,21 +51,151 @@
<div class="card shadow-sm border-0"> <div class="card shadow-sm border-0">
<div class="card-body"> <div class="card-body">
<h3 class="card-title fw-bold mb-4">Tes Keakuratan Mata</h3> <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> <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_2')">Back</button> <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> <a class="btn btn-primary">Mulai Ujian</a>
</div> </div>
</div> </div>
</div> </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 @endsection
@section('script') @section('script')
<script> <script>
let getDataInterval = false;
let checkTobiiInterval = null;
function showTutorial(step, tutorialId) { function showTutorial(step, tutorialId) {
$(`#${tutorialId}`).hide(); $(`#${tutorialId}`).hide();
$(`#tutorial_${step}`).show(); $(`#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() { 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() { $(document).ready(function() {
$('#tutorial_2').hide(); $('#tutorial_2').hide();
$('#tutorial_3').hide();
$('#next_btn_connect_tobii').hide(); $('#next_btn_connect_tobii').hide();
$('#calibration_point').hide();
$('#show_calibration').hide();
generateLinkApiTobii(); generateLinkApiTobii();
setInterval(() => {
checkTobiiConnection();
}, 2000);
}); });
</script> </script>

View File

@ -35,6 +35,7 @@
Route::resource('tutorial-tes', TutorialTesController::class)->only(['index']); Route::resource('tutorial-tes', TutorialTesController::class)->only(['index']);
Route::resource('test-sessions', TestSessionsController::class)->only(['store', 'show']); Route::resource('test-sessions', TestSessionsController::class)->only(['store', 'show']);
Route::resource('tobii-receiver', TobiiReceiverController::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::middleware(['auth', 'role.auth'])->group(function() {
Route::resource('dashboard', DashboardController::class); Route::resource('dashboard', DashboardController::class);
Route::resource('users', UsersController::class); Route::resource('users', UsersController::class);