MIF_E31231392/resources/views/user/pages/finish_ujian/index.blade.php

380 lines
12 KiB
PHP

@section('title', 'Hasil Tes')
@extends('user.layouts.index')
@section('content')
<style>
.stats-grid {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 16px;
}
.stat-card {
padding: 20px;
border-radius: 12px;
background: #f5f5f5;
}
.bg-custom {
background: #f5f5f5;
}
</style>
<!-- Page Title -->
<div class="page-title">
<div class="heading">
<div class="container">
<div class="row d-flex justify-content-center text-center">
<div class="col-lg-8">
<h1 class="heading-title">Hasil Tes Anda</h1>
<p class="mb-0">
Cek hasil tes kamu dari sini ya, jika kamu sudah mendapatkan kode dari email setelah melakukan booking, kamu bisa melihat hasil tes disini dengan kode tadi.
</p>
</div>
</div>
</div>
</div>
<nav class="breadcrumbs">
<div class="container">
<ol>
<li><a href="index.html">Home</a></li>
<li class="current">Hasil Tes</li>
</ol>
</div>
</nav>
</div><!-- End Page Title -->
<!-- About Section -->
<section id="about" class="about section">
<div class="container">
<div class="row">
<div class="col-md-12">
<h2 class="title text-center">Detail Tes/Ujian kamu</h2>
<div class="row">
<div class="col-md-4 col-6 rounded p-3">
<div class="container border border-primary rounded h-100 p-2 bg-custom">
<h3>Informasi Pribadi</h3>
<ul class="list-unstyled">
<li><strong>Nama:</strong> {{ $data_information['nama'] }}</li>
<li><strong>Email:</strong> {{ $data_information['email'] }}</li>
<li><strong>Nomor Handphone:</strong> {{ $data_information['no_hp'] }}</li>
</ul>
</div>
</div>
<div class="col-md-4 col-6 rounded p-3">
<div class="container border border-primary rounded h-100 p-2 bg-custom">
<h3>Informasi Ujian</h3>
<ul class="list-unstyled">
<li><strong>Durasi Ujian:</strong> {{ $difference }}</li>
<li><strong>Resolusi Layar (saat ujian):</strong> {{ $screen_dim['width'] }} x {{ $screen_dim['height'] }}</li>
<li><strong>Jumlah Pergerakan Mata:</strong> <span id="total_movement">0</span></li>
</ul>
</div>
</div>
<div class="col-md-4 col-6 primary p-3">
<div class="container border border-success rounded h-100 p-2 bg-custom">
<h3>Hasil Ujian (STAI-T)</h3>
<ul class="list-unstyled">
<li><strong>Total Skor:</strong> {{ $data_aswered['totalScore'] }}</li>
<li><strong>Soal terjawab:</strong> {{ $data_aswered['answered'] }}</li>
<li><strong>Soal tidak terjawab:</strong> {{ $data_aswered['unanswered'] }}</li>
</ul>
</div>
</div>
</div>
<div class="row">
<div class="stats-grid">
<div class="stat-card">
<h3>Avg Velocity</h3>
<p id="avgVelocity"></p>
</div>
<div class="stat-card">
<h3>Fixation Ratio</h3>
<p id="fixationRatio"></p>
</div>
<div class="stat-card">
<h3>Total Eye Distance</h3>
<p id="totalDistance"></p>
</div>
<div class="stat-card">
<h3>Most Viewed Area</h3>
<p id="mostViewedArea"></p>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="container" data-aos="fade-up" data-aos-delay="100">
<table class="table" id="table-data-hasil-ujian">
<thead>
<tr>
<th>No</th>
<th>Pertanyaan</th>
<th>Jawaban</th>
<th>Skor</th>
</tr>
</thead>
<tbody></tbody>
</table>
</div>
<div class="container">
<div class="row">
<div class="col-lg-12">
<h2 class="title">Grafik Kecepatan Mata</h2>
<canvas id="velocityChart"></canvas>
</div>
<div class="col-lg-12 mt-5">
<h2 class="title">Heatmap Pergerakan Mata</h2>
<div style="position: relative; aspect-ratio: 16/9;">
<img src="{{ asset('assets/users/assets/img/overlay/overlay.png') }}" style="width:100%; height:100%; object-fit: cover;">
<div id="heatmapChart" style="aspect-ratio: 16/9;"></div>
</div>
</div>
</div>
</div>
</section><!-- /About Section -->
<div class="toast-container position-fixed bottom-0 end-0 p-3">
<div id="liveToast" class="toast" role="alert" aria-live="assertive" aria-atomic="true">
<div class="toast-header">
<strong class="me-auto"><i class="bi bi-exclamation-triangle"></i> Kesalahan</strong>
<button type="button" class="btn-close" data-bs-dismiss="toast" aria-label="Close"></button>
</div>
<div class="toast-body">
{{ session('error') }}
</div>
</div>
</div>
@endsection
@section('script')
<script>
const ws = new WebSocket('{{ env("WEBSOCKET_URL") }}');
let table = null;
let data_tobii = null;
let heatmapContainer = null;
let clientWidth = null;
let clientHeight = null;
let recordedScreenWidth = null
let recordedScreenHeight = null
let mappedHeatmapData = null;
let scaleX = null;
let scaleY = null;
let heatmapInstance = null;
let score = null;
let totalScore = null;
let soalTerjawab = 0;
function renderVelocityChart(timeseries) {
const base = timeseries.timestamp[0];
const labels = timeseries.timestamp.map(t => (t - base) / 1000);
const ctx = document.getElementById('velocityChart').getContext('2d');
new Chart(ctx, {
type: 'line',
data: {
labels: labels,
datasets: [{
label: 'Velocity',
data: timeseries.velocity,
borderWidth: 2,
tension: 0.3
}]
},
options: {
responsive: true,
plugins: {
tooltip: {
callbacks: {
label: function(context) {
return "Velocity: " + context.raw.toFixed(4);
}
}
}
},
scales: {
x: {
display: false
}
}
}
});
}
async function loadData(data) {
const res = await fetch("{{ env('PYTHON_API_URL') }}/extract", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(data)
});
const result = await res.json();
if(result != null) {
renderVelocityChart(result.timeseries);
mappedHeatmapData = result.heatmap.map(point => ({
x: point.x * scaleX,
y: point.y * scaleY,
value: point.value
}));
heatmapInstance.setData({
max: 10,
data: mappedHeatmapData
});
heatmapContainer.style.removeProperty('position');
renderStats(result.statistics);
Swal.close();
}
}
function renderStats(stats) {
document.getElementById("avgVelocity")
.innerText = stats.avg_velocity.toFixed(4);
document.getElementById("fixationRatio")
.innerText = stats.fixation_ratio.toFixed(2) + "%";
document.getElementById("totalDistance")
.innerText = stats.total_distance.toFixed(2);
document.getElementById("mostViewedArea")
.innerText = stats.most_viewed_area;
}
$(document).ready(function() {
table = new DataTable("#table-data-hasil-ujian", {
searching: false,
paging: false,
ajax: {
url: '{{ route('hasil-tes.getAllAnswer', ['id_test_sessions' => $id_session]) }}',
dataSrc: 'data' // Specify the key containing the data array
},
columns: [
{
data: null,
render: function(data, type, row, meta) {
return meta.row + 1;
}
},
{
data: 'soal'
},
{
data: null,
render: function(data, type, row) {
let renderedJawaban = null;
if(row.jawaban_key == 'a') {
renderedJawaban = `<span class="badge text-bg-primary">${row.jawaban}</span>`;
score = 1;
} else if(row.jawaban_key == 'b') {
renderedJawaban = `<span class="badge" style="background-color: #fc7938; color: white;">${row.jawaban}</span>`;
score = 2;
} else if(row.jawaban_key == 'c') {
renderedJawaban = `<span class="badge text-bg-danger">${row.jawaban}</span>`;
score = 3;
} else if(row.jawaban_key == 'd') {
renderedJawaban = `<span class="badge text-bg-warning">${row.jawaban}</span>`;
score = 4;
} else if(row.jawaban_key == 'e') {
renderedJawaban = `<span class="badge text-bg-success">${row.jawaban}</span>`;
score = 5;
} else {
renderedJawaban = `<span class="badge text-bg-secondary">${row.jawaban}</span>`;
}
return renderedJawaban;
}
},
{
data: null,
render: function(data, type, row) {
return `<span>${score}</span>`;
}
}
]
});
ws.onopen = () => {
console.log("Connected to WebSocket");
Swal.fire({
title: 'Status',
text: 'Memuat data...',
icon: 'info',
showConfirmButton: false,
allowOutsideClick: false,
allowEscapeKey: false
});
ws.send(JSON.stringify({
type: 'get_json_file',
session_id: '{{ $id_session }}'
}));
ws.onmessage = (event) => {
const data = JSON.parse(event.data);
if(data.type === 'json_file_data') {
if(data.data != null) {
data_tobii = null;
let xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if(this.readyState == 4 && this.status == 200) {
let data_ = JSON.parse(this.responseText);
$('#total_movement').html(data.data.length + " (1 detik = 3 pergerakan)");
if(data_.status) {
heatmapContainer = document.getElementById('heatmapChart');
clientWidth = heatmapContainer.clientWidth;
clientHeight = heatmapContainer.clientHeight;
recordedScreenWidth = data_.screen_w;
recordedScreenHeight = data_.screen_h;
scaleX = clientWidth / recordedScreenWidth;
scaleY = clientHeight / recordedScreenHeight;
data_tobii = {
data: data.data,
screen_w: recordedScreenWidth,
screen_h: recordedScreenHeight
};
heatmapInstance = h337.create({
container: heatmapContainer,
radius: 40,
maxOpacity: 0.6,
blur: 0.85
});
loadData(data_tobii);
} else {
Swal.fire({
title: 'Error',
text: 'Gagal mencari data, silahkan coba lagi nanti',
icon: 'error',
showConfirmButton: true,
allowOutsideClick: false,
allowEscapeKey: false
});
}
}
};
xhttp.open('GET', '{{ route('test-sessions.getScreen', ['id_test_sessions' => $id_session]) }}', true);
xhttp.send();
}
}
};
};
});
</script>
@if (session('error'))
<script>
$(document).ready(function() {
var toast = new bootstrap.Toast(document.getElementById('liveToast'));
toast.show();
});
</script>
@endif
@endsection