392 lines
17 KiB
PHP
392 lines
17 KiB
PHP
<link rel="stylesheet" href="{{asset('/public/frontend/css/game.css?version=2.4')}}" />
|
|
<div class="row chart_containter">
|
|
<div class="col-lg-6 col-md-6 ribbon">
|
|
<div class="wrap">
|
|
<span class="ribbon6" id="game_rule" data-toggle="modal" data-target="#ruleModal">Thể lệ tham dự</span>
|
|
</div>
|
|
@if(Session::has('success'))
|
|
<div class="alert alert-success">
|
|
{{ Session::get('success') }}
|
|
@php
|
|
Session::forget('success');
|
|
@endphp
|
|
</div>
|
|
@endif
|
|
@if(Session::has('error'))
|
|
<div class="alert alert-danger">
|
|
{{ Session::get('error') }}
|
|
@php
|
|
Session::forget('error');
|
|
@endphp
|
|
</div>
|
|
@endif
|
|
@if(Session::has('errors'))
|
|
<div class="alert alert-danger">
|
|
{{ 'Có lỗi xảy ra (' . implode(', ', $errors->all(':message')) . ')'}}
|
|
@php
|
|
Session::forget('errors');
|
|
@endphp
|
|
</div>
|
|
@endif
|
|
<div id="luckywheel_container">
|
|
<div class="luckywheel_inner" style="margin-top: 1rem;">
|
|
<div class="luckywheel_inner" style="background-color: #950000;
|
|
box-shadow: inset 6px -6px 20px #000;">
|
|
<div class="wheel-section">
|
|
<div class="wheel-container">
|
|
<div class="wheel-border-lights">
|
|
<canvas id="wheelCanvas" width="600" height="600"></canvas>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="cylinder_container">
|
|
<div class="cylinder2"></div>
|
|
<div class="cylinder"></div>
|
|
</div>
|
|
<button id="spinButton" style="display: block;"
|
|
data-check="{{ Auth::check() && $spined == 0 ? 'true' : 'false' }}"
|
|
data-auth="{{ Auth::check() ? 'true' : 'false' }}"
|
|
data-spined="{{ $spined ?? 0 }}">BẮT ĐẦU
|
|
QUAY
|
|
</button>
|
|
<!-- Debug: Auth={{ Auth::check() ? 'YES' : 'NO' }} Spined={{ $spined ?? 0 }} -->
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-lg-6 col-md-6 slogan">
|
|
<div class="custom_title text-center" style="{{ !Auth::check() || $spined == 1 ? 'position: absolute;' : '' }};">
|
|
<span>VÒNG QUAY MAY MẮN</span>
|
|
</div>
|
|
<div class="logo-container">
|
|
<img class="logo" src="{{asset('/public/frontend/imgs/LogoSIS.png')}}" alt="Your Company Logo">
|
|
</div>
|
|
<div class="demonstration_img">
|
|
@if (isset($parameter_data['banner_image']) && $parameter_data['banner_image'] != '')
|
|
<img src="{{asset('/public/images/' . $parameter_data['banner_image'])}}" alt="Demonstration img">
|
|
@else
|
|
<img src="{{asset('/public/frontend/imgs/luckywheel_winner.avif')}}" alt="Demonstration img">
|
|
@endif
|
|
</div>
|
|
</div>
|
|
@if (!$is_login || $spined == 1)
|
|
<section class="alert_wheel_spin">
|
|
<div class="alert fade alert-simple alert-danger alert-dismissible text-left font__family-montserrat font__size-16 font__weight-light brk-library-rendered rendered show"
|
|
role="alert" data-brk-library="component__alert">
|
|
<button type="button" class="close font__size-18" data-dismiss="alert">
|
|
<span aria-hidden="true">
|
|
<i class="fa fa-times danger "></i>
|
|
</span>
|
|
<span class="sr-only">Close</span>
|
|
</button>
|
|
<i class="start-icon far fa-times-circle faa-pulse animated"></i>
|
|
<strong class="font__weight-semibold">Thông báo: </strong>
|
|
@if (!$is_login)
|
|
<div class="alert alert-danger text-center" style="width: 100%; margin: auto;">
|
|
Vui lòng <a class="btn btn-danger custom_btn" href="{{ route('login') }}">Nhập thông tin</a> để có thể
|
|
quay số
|
|
trúng giải
|
|
</div>
|
|
@endif
|
|
@if ($spined == 1)
|
|
<div class="alert alert-danger text-center prize_alert">
|
|
Bạn chỉ được phép quay 1 lần,
|
|
giải thưởng gần nhất <b>
|
|
<h2>{{ $lasted_prize_name ?? '' }}</h2>
|
|
</b>
|
|
</div>
|
|
@endif
|
|
</div>
|
|
</section>
|
|
@endif
|
|
<div id="result"></div>
|
|
</div>
|
|
@include('frontend.game.customprize_popup')
|
|
@include('frontend.game.rule')
|
|
<script>
|
|
$('#game_rule').on('click', function () {
|
|
$('#gamerule').html('');
|
|
$.ajaxSetup({
|
|
headers: {
|
|
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
|
|
}
|
|
});
|
|
var url = "{{route('game/rule')}}";
|
|
$.ajax({
|
|
// dataType: 'json',
|
|
url: url,
|
|
type: 'GET',
|
|
contentType: false,
|
|
processData: false,
|
|
success: function (result) {
|
|
$('#gamerule').html(result);
|
|
}
|
|
});
|
|
});
|
|
|
|
const canvas = document.getElementById("wheelCanvas");
|
|
const ctx = canvas.getContext("2d");
|
|
const spinButton = document.getElementById("spinButton");
|
|
const segmentsInput = document.getElementById("segments");
|
|
const resultDiv = document.getElementById("result");
|
|
let game_data = "{{json_encode($game_data)}}";
|
|
var data = JSON.parse(game_data.replace(/"/g, '"'));
|
|
let segments = [];
|
|
let prize_ids = [];
|
|
const images = [];
|
|
data.forEach(item => {
|
|
segments.push(item.detail);
|
|
prize_ids.push(item.id);
|
|
const img = new Image();
|
|
img.src = item.image; // Đảm bảo 'item' chứa URL của ảnh
|
|
images.push(img);
|
|
});
|
|
// Tableau de couleurs avec leurs configurations
|
|
const colorSchemes = [{
|
|
bg: "#e30a00",
|
|
text: "#fff"
|
|
}, // Bleu foncé
|
|
{
|
|
bg: "#fff",
|
|
text: "#e30a00"
|
|
}, {
|
|
bg: "#e30a00",
|
|
text: "#fff"
|
|
}, // Bleu foncé
|
|
{
|
|
bg: "#fff",
|
|
text: "#e30a00"
|
|
}, {
|
|
bg: "#e30a00",
|
|
text: "#fff"
|
|
}, // Bleu foncé
|
|
{
|
|
bg: "#fff",
|
|
text: "#e30a00"
|
|
}, {
|
|
bg: "#e30a00",
|
|
text: "#fff"
|
|
}, // Bleu foncé
|
|
{
|
|
bg: "#fff",
|
|
text: "#e30a00"
|
|
}, {
|
|
bg: "#e30a00",
|
|
text: "#fff"
|
|
}, // Bleu foncé
|
|
{
|
|
bg: "#fff",
|
|
text: "#e30a00"
|
|
}
|
|
];
|
|
// Dimensions du canvas
|
|
const width = 600; // Tăng chiều rộng
|
|
const height = 600;
|
|
canvas.width = width; // Cập nhật kích thước canvas
|
|
canvas.height = height;
|
|
// Variables pour l'animation
|
|
let currentAngle = 0; // angle de départ
|
|
let spinVelocity = 0; // vitesse de rotation
|
|
let isSpinning = false; // indicateur d'animation en cours
|
|
// Fonction pour dessiner la roue
|
|
function drawWheel(segmentsArray) {
|
|
ctx.clearRect(0, 0, width, height);
|
|
const numSegments = segmentsArray.length;
|
|
const anglePerSegment = (2 * Math.PI) / numSegments;
|
|
const centerX = width / 2;
|
|
const centerY = height / 2;
|
|
const radius = Math.min(width, height) / 2;
|
|
|
|
for (let i = 0; i < numSegments; i++) {
|
|
const startAngle = currentAngle + i * anglePerSegment - Math.PI / 2;
|
|
const endAngle = startAngle + anglePerSegment;
|
|
const colorScheme = colorSchemes[i % colorSchemes.length];
|
|
|
|
// Vẽ nền của phân đoạn
|
|
ctx.beginPath();
|
|
ctx.moveTo(centerX, centerY);
|
|
ctx.arc(centerX, centerY, radius, startAngle, endAngle);
|
|
ctx.fillStyle = colorScheme.bg;
|
|
ctx.fill();
|
|
ctx.closePath();
|
|
|
|
// BẮT ĐẦU: Vẽ ảnh TRƯỚC chữ để chữ nằm trên ảnh
|
|
if (images[i] && images[i].complete && images[i].naturalWidth > 0 && images[i].naturalHeight > 0) { // Kiểm tra ảnh đã tải xong và không bị lỗi
|
|
ctx.save(); // Lưu trạng thái hiện tại của canvas
|
|
|
|
const imageSize = 100; // Kích thước ảnh
|
|
const distanceFromCenter = radius * 0.65; // Khoảng cách từ tâm vòng quay ra vị trí ảnh
|
|
|
|
// Tính toán góc chính giữa của phân đoạn hiện tại
|
|
const angleOfSegmentCenter = startAngle + anglePerSegment / 2;
|
|
|
|
// Tính toán vị trí tâm của ảnh trên vòng quay (nếu không xoay)
|
|
const imageCenterX = centerX + Math.cos(angleOfSegmentCenter) * distanceFromCenter;
|
|
const imageCenterY = centerY + Math.sin(angleOfSegmentCenter) * distanceFromCenter;
|
|
|
|
// Di chuyển gốc tọa độ về tâm của ảnh
|
|
ctx.translate(imageCenterX, imageCenterY);
|
|
|
|
// Xoay ngữ cảnh vẽ để "chân" ảnh hướng về tâm vòng tròn.
|
|
ctx.rotate(angleOfSegmentCenter + Math.PI / 2);
|
|
|
|
// Vẽ ảnh. Vì gốc tọa độ đã ở tâm ảnh, ta vẽ ảnh tại (-imageSize / 2, -imageSize / 2)
|
|
// để căn giữa ảnh.
|
|
ctx.drawImage(images[i], -imageSize / 2, -imageSize / 2, imageSize, imageSize);
|
|
|
|
ctx.restore(); // Khôi phục trạng thái canvas về ban đầu
|
|
} else if (images[i] && !images[i].complete) {
|
|
// Nếu ảnh chưa tải xong, gán sự kiện onload để vẽ lại khi ảnh đã sẵn sàng
|
|
images[i].onload = () => {
|
|
drawWheel(segments);
|
|
};
|
|
}
|
|
// KẾT THÚC: Vẽ ảnh
|
|
|
|
// BẮT ĐẦU: Vẽ chữ SAU ảnh để chữ nằm trên ảnh
|
|
ctx.save();
|
|
ctx.fillStyle = colorScheme.text;
|
|
ctx.font = "bold 24px Arial"; // Đã TĂNG kích thước chữ lên 24px
|
|
ctx.translate(
|
|
centerX + Math.cos(startAngle + anglePerSegment / 2) * (radius * 0.85),
|
|
centerY + Math.sin(startAngle + anglePerSegment / 2) * (radius * 0.85)
|
|
);
|
|
ctx.rotate(startAngle + anglePerSegment / 2 + Math.PI / 2);
|
|
const text = segmentsArray[i];
|
|
ctx.fillText(text, -ctx.measureText(text).width / 2, 0);
|
|
ctx.restore();
|
|
// KẾT THÚC: Vẽ chữ
|
|
}
|
|
|
|
// Vẽ mũi tên chỉ thị
|
|
const oscillationAmount = 8; // Tăng độ lớn dao động để mũi tên "rung" mạnh hơn
|
|
const oscillationSpeed = 0.05; // Giảm tốc độ dao động để nó mượt mà hơn
|
|
const time = Date.now() * 0.005; // Sử dụng thời gian để tạo dao động độc lập với vòng quay
|
|
const offsetX_oscillation = Math.sin(time * oscillationSpeed) * oscillationAmount;
|
|
const offsetY_oscillation = Math.cos(time * oscillationSpeed) * oscillationAmount;
|
|
|
|
// Dời mũi tên sang phải 15px cố định
|
|
const fixedOffsetX = 0;
|
|
|
|
ctx.beginPath();
|
|
// Điều chỉnh vị trí mũi tên để nó nằm gần viền ngoài của canvas và dời sang phải
|
|
// Thêm fixedOffsetX vào các tọa độ X để dịch chuyển sang phải
|
|
ctx.moveTo(centerX + 100, centerY);
|
|
ctx.lineTo(centerX, centerY - 60);
|
|
ctx.lineTo(centerX, centerY + 60);
|
|
ctx.closePath(); // Đóng đường dẫn để đảm bảo hình tam giác được vẽ đúng
|
|
|
|
// Định dạng màu sắc và đổ bóng cho mũi tên
|
|
ctx.fillStyle = "#db0202"; // Màu cam nổi bật (Material Design Orange A700)
|
|
ctx.shadowColor = "rgb(0, 0, 0)"; // Màu đổ bóng
|
|
ctx.shadowBlur = 30; // Độ mờ đổ bóng
|
|
ctx.shadowOffsetX = 5; // Độ lệch đổ bóng theo X
|
|
ctx.shadowOffsetY = 5; // Độ lệch đổ bóng theo Y
|
|
ctx.fill();
|
|
|
|
// Đảm bảo reset shadow sau khi vẽ mũi tên để không ảnh hưởng các phần tử khác
|
|
ctx.shadowColor = "transparent";
|
|
ctx.shadowBlur = 0;
|
|
ctx.shadowOffsetX = 0;
|
|
ctx.shadowOffsetY = 0;
|
|
|
|
// --- Bắt đầu phần vẽ HÌNH TRÒN tại TÂM ---
|
|
ctx.beginPath();
|
|
const centerCircleRadius = radius * 0.18; // Kích thước hình tròn tại tâm, 18% bán kính vòng quay
|
|
ctx.arc(centerX, centerY, centerCircleRadius, 0, Math.PI * 2, false);
|
|
ctx.fillStyle = "#fff"; // Màu vàng gold cho hình tròn tâm
|
|
ctx.shadowColor = "rgba(0, 0, 0, 0.4)"; // Đổ bóng nhẹ cho hình tròn tâm
|
|
ctx.shadowBlur = 10;
|
|
ctx.shadowOffsetX = 3;
|
|
ctx.shadowOffsetY = 3;
|
|
ctx.fill();
|
|
ctx.strokeStyle = "#db0202"; // Viền màu đồng cho hình tròn tâm
|
|
ctx.lineWidth = 10;
|
|
ctx.stroke();
|
|
|
|
// Đảm bảo reset shadow sau khi vẽ hình tròn để không ảnh hưởng mũi tên
|
|
ctx.shadowColor = "transparent";
|
|
ctx.shadowBlur = 0;
|
|
ctx.shadowOffsetX = 0;
|
|
ctx.shadowOffsetY = 0;
|
|
|
|
// Vẽ chữ lên hình tròn tại tâm
|
|
ctx.save(); // Lưu trạng thái canvas để không ảnh hưởng các phần tử khác
|
|
ctx.fillStyle = "#db0202"; // Màu chữ
|
|
ctx.font = `bold ${Math.min(centerCircleRadius * 0.6, 32)}px Arial`; // Kích thước chữ responsive, tối đa 28px
|
|
ctx.textAlign = 'center';
|
|
ctx.textBaseline = 'middle'; // Căn giữa chữ theo chiều dọc
|
|
const centerText = "S.I.S"; // Văn bản muốn hiển thị
|
|
ctx.fillText(centerText, centerX, centerY); // Vẽ chữ tại tâm
|
|
ctx.restore(); // Khôi phục trạng thái canvas
|
|
// --- Kết thúc phần vẽ HÌNH TRÒN tại TÂM ---
|
|
}
|
|
// Animation de la roue
|
|
function spinWheel() {
|
|
if (!isSpinning) return;
|
|
// Mise à jour de l'angle et réduction de la vitesse
|
|
currentAngle += spinVelocity;
|
|
spinVelocity *= 0.995; // friction
|
|
// Condition d'arrêt
|
|
if (spinVelocity < 0.01) {
|
|
spinVelocity = 0;
|
|
isSpinning = false;
|
|
findWinner();
|
|
}
|
|
// Redessiner la roue à chaque frame
|
|
drawWheel(segments);
|
|
requestAnimationFrame(spinWheel);
|
|
}
|
|
// Déterminer le segment gagnant en fonction de l'angle final
|
|
function findWinner() {
|
|
const numSegments = segments.length;
|
|
const anglePerSegment = (2 * Math.PI) / numSegments;
|
|
let normalizedAngle = currentAngle % (2 * Math.PI);
|
|
if (normalizedAngle < 0) normalizedAngle += 2 * Math.PI;
|
|
normalizedAngle = (normalizedAngle - Math.PI / 2 + 2 * Math.PI) % (2 * Math.PI);
|
|
const winningIndex = (numSegments - Math.floor(normalizedAngle / anglePerSegment) - 1) % numSegments;
|
|
const winner = segments[winningIndex];
|
|
const resultDiv = document.getElementById('result');
|
|
resultDiv.classList.remove('show');
|
|
// Utiliser le schéma de couleur du segment gagnant
|
|
const colorScheme = colorSchemes[winningIndex % colorSchemes.length];
|
|
setTimeout(() => {
|
|
// cong bo giai thuong
|
|
let prize_id = prize_ids[winningIndex];
|
|
var csrfToken = $('meta[name="csrf-token"]').attr('content');
|
|
$.ajax({
|
|
url: "{{ route('updateprizeuser') }}",
|
|
type: 'POST',
|
|
data: {
|
|
prize_id: prize_id,
|
|
_token: csrfToken // Bao gồm CSRF token
|
|
},
|
|
success: function (response) {
|
|
resultDiv.innerHTML = response;
|
|
},
|
|
error: function (xhr, status, error) {
|
|
alert('Có lỗi xảy ra');
|
|
}
|
|
});
|
|
resultDiv.classList.add('show');
|
|
}, 300);
|
|
}
|
|
// Bouton "Tourner la roue"
|
|
spinButton.addEventListener("click", (event) => {
|
|
if ($(event.currentTarget).data('check') == false) {
|
|
alert('Chưa đăng nhập hoặc đã quay số rồi');
|
|
return;
|
|
}
|
|
if (!isSpinning) {
|
|
// Réinitialiser l'affichage du résultat
|
|
const resultDiv = document.getElementById('result');
|
|
resultDiv.classList.remove('show');
|
|
// Donner une vitesse initiale aléatoire
|
|
spinVelocity = Math.random() * 0.5 + 0.4;
|
|
isSpinning = true;
|
|
spinWheel();
|
|
}
|
|
});
|
|
drawWheel(segments);
|
|
</script>
|
|
<script src="{{asset('/public/frontend/js/game.js')}}"></script> |