<?php include "../autoload.php"; ?>
<script src="https://cdn.tailwindcss.com"></script>
<script src="https://unpkg.com/lucide@latest"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/2.5.1/jspdf.umd.min.js"></script>
<style>
@import url('https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;600;700&display=swap');
.gradient-bg {
background: linear-gradient(135deg, #1e40af 0%, #60a5fa 100%);
}
.result-card {
background: linear-gradient(145deg, #ffffff, #f0f7ff);
box-shadow: 0 12px 24px rgba(0, 0, 0, 0.15);
transition: transform 0.3s ease, opacity 0.3s ease;
}
.result-card.hidden {
transform: translateY(20px);
opacity: 0;
}
.result-card:not(.hidden) {
transform: translateY(0);
opacity: 1;
}
.input-container {
background: linear-gradient(145deg, #ffffff, #f9fafb);
transition: all 0.3s ease;
}
.input-container:hover {
transform: translateY(-2px);
box-shadow: 0 6px 12px rgba(0, 0, 0, 0.1);
}
.range-input::-webkit-slider-thumb {
-webkit-appearance: none;
appearance: none;
width: 20px;
height: 20px;
background: #1e40af;
border-radius: 50%;
cursor: pointer;
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.2);
}
.range-input::-moz-range-thumb {
width: 20px;
height: 20px;
background: #1e40af;
border-radius: 50%;
cursor: pointer;
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.2);
}
.btn-primary {
transition: all 0.3s ease;
}
.btn-primary:hover {
transform: translateY(-2px);
box-shadow: 0 6px 12px rgba(0, 0, 0, 0.2);
}
.visual-container {
background: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100" viewBox="0 0 100 100"><rect fill="%23f3f4f6" width="100" height="100"/><circle cx="50" cy="50" r="30" fill="%23dbeafe" opacity="0.5"/></svg>') repeat;
border-radius: 12px;
box-shadow: inset 0 2px 8px rgba(0, 0, 0, 0.05);
}
</style>
<!-- Input Form -->
<div class=" mb-12">
<h2 class="text-3xl font-semibold text-gray-800 mb-6">Enter Your Room Details</h2>
<p class="text-gray-500 mb-8 text-lg">Slide or type to input your viewing distance and room dimensions for a precise TV size recommendation.</p>
<form id="tvSizeForm" class="space-y-8">
<div class="grid grid-cols-1 md:grid-cols-3 gap-6">
<div class="space-y-3">
<label for="distance" class="block text-sm font-medium text-gray-700">Viewing Distance (ft)</label>
<div class="relative flex items-center">
<i data-lucide="ruler" class="absolute left-4 top-1/2 transform -translate-y-1/2 text-gray-400"></i>
<input type="number" id="distance" class="pl-12 pr-4 py-3 block w-full rounded-lg border-gray-300 shadow-sm focus:border-blue-600 focus:ring focus:ring-blue-600 focus:ring-opacity-50 text-lg" placeholder="4.0" step="0.1" min="1" max="20" value="4.0" required>
</div>
<input type="range" id="distanceRange" class="range-input w-full h-2 bg-gray-200 rounded-lg cursor-pointer" min="1" max="20" step="0.1" value="4">
<p id="distanceValue" class="text-sm text-gray-500">4.0 ft</p>
</div>
<div class="space-y-3">
<label for="roomWidth" class="block text-sm font-medium text-gray-700">Room Width (ft)</label>
<div class="relative flex items-center">
<i data-lucide="maximize" class="absolute left-4 top-1/2 transform -translate-y-1/2 text-gray-400"></i>
<input type="number" id="roomWidth" class="pl-12 pr-4 py-3 block w-full rounded-lg border-gray-300 shadow-sm focus:border-blue-600 focus:ring focus:ring-blue-600 focus:ring-opacity-50 text-lg" placeholder="18.0" step="0.1" min="5" max="30" value="18.0" required>
</div>
<input type="range" id="roomWidthRange" class="range-input w-full h-2 bg-gray-200 rounded-lg cursor-pointer" min="5" max="30" step="0.1" value="18">
<p id="roomWidthValue" class="text-sm text-gray-500">18.0 ft</p>
</div>
<div class="space-y-3">
<label for="roomDepth" class="block text-sm font-medium text-gray-700">Room Depth (ft)</label>
<div class="relative flex items-center">
<i data-lucide="expand" class="absolute left-4 top-1/2 transform -translate-y-1/2 text-gray-400"></i>
<input type="number" id="roomDepth" class="pl-12 pr-4 py-3 block w-full rounded-lg border-gray-300 shadow-sm focus:border-blue-600 focus:ring focus:ring-blue-600 focus:ring-opacity-50 text-lg" placeholder="15.0" step="0.1" min="5" max="30" value="15.0" required>
</div>
<input type="range" id="roomDepthRange" class="range-input w-full h-2 bg-gray-200 rounded-lg cursor-pointer" min="5" max="30" step="0.1" value="15">
<p id="roomDepthValue" class="text-sm text-gray-500">15.0 ft</p>
</div>
</div>
<button type="submit" class="btn-primary w-full bg-blue-600 text-white py-4 px-8 rounded-xl hover:bg-blue-700 flex items-center justify-center text-lg">
<i data-lucide="search" class="mr-3 h-5 w-5"></i>
Calculate TV Size
</button>
</form>
</div>
<!-- Result Section -->
<div id="resultSection" class="result-card rounded-2xl p-10 hidden">
<h2 class="text-3xl font-semibold text-gray-800 mb-6 flex items-center">
<i data-lucide="check-circle-2" class="mr-3 text-green-500 h-7 w-7"></i>
Your TV Size Recommendation
</h2>
<div id="resultOutput" class="text-gray-700 space-y-6 text-base">
<!-- Results will be dynamically inserted here -->
</div>
<div class="mt-10 flex flex-col md:flex-row justify-between items-center gap-6">
<div class="flex items-center text-blue-600">
<i data-lucide="info" class="mr-2 h-5 w-5"></i>
<p class="text-sm font-medium">Based on SMPTE (30°) and THX (40°) viewing angle standards for optimal viewing.</p>
</div>
<button id="downloadPdf" class="btn-primary bg-green-600 text-white py-3 px-8 rounded-xl hover:bg-green-700 flex items-center text-base">
<i data-lucide="download" class="mr-2 h-5 w-5"></i>
Download PDF Report
</button>
</div>
<!-- Visual Representation -->
<div class="mt-10 visual-container p-8">
<h3 class="text-xl font-medium text-gray-800 mb-4 flex items-center">
<i data-lucide="monitor" class="mr-3 text-blue-500 h-6 w-6"></i>
Interactive Room & TV Visualization
</h3>
<div class="relative w-full h-96 bg-gray-200 rounded-xl overflow-hidden shadow-lg">
<canvas id="tvCanvas" class="w-full h-full"></canvas>
</div>
<p class="text-sm text-gray-600 mt-4">Interactive visualization showing the recommended TV size scaled to your room width.</p>
</div>
<!-- Expert Insights -->
<div class="mt-10 bg-blue-50 p-8 rounded-xl shadow-sm">
<h3 class="text-xl font-medium text-gray-800 mb-4 flex items-center">
<i data-lucide="lightbulb" class="mr-3 text-yellow-500 h-6 w-6"></i>
Expert Insights for Perfect TV Selection
</h3>
<ul class="list-none space-y-4 text-gray-700 text-sm">
<li class="flex items-start">
<i data-lucide="check" class="mr-2 text-green-500 h-5 w-5"></i>
<span><strong>Optimal Viewing Angle:</strong> SMPTE recommends 30° for standard viewing, while THX suggests 40° for a cinematic experience.</span>
</li>
<li class="flex items-start">
<i data-lucide="check" class="mr-2 text-green-500 h-5 w-5"></i>
<span><strong>4K Resolution:</strong> Sit closer (0.6-1x the TV diagonal) with 4K TVs to enjoy crisp, pixel-free visuals.</span>
</li>
<li class="flex items-start">
<i data-lucide="check" class="mr-2 text-green-500 h-5 w-5"></i>
<span><strong>Room Fit:</strong> Ensure your TV stand or mount is 20% narrower than your room width for balanced aesthetics.</span>
</li>
<li class="flex items-start">
<i data-lucide="check" class="mr-2 text-green-500 h-5 w-5"></i>
<span><strong>Lighting Conditions:</strong> Choose OLED/QLED for darker rooms or LED for brighter environments.</span>
</li>
<li class="flex items-start">
<i data-lucide="check" class="mr-2 text-green-500 h-5 w-5"></i>
<span><strong>Ergonomics:</strong> Position the TV center at eye level (3-4 ft from the floor) to reduce neck strain.</span>
</li>
</ul>
</div>
</div>
<script>
// Initialize Lucid Icons
lucide.createIcons();
// Sync range and number inputs
function syncInputs(numberId, rangeId, valueId) {
const numberInput = document.getElementById(numberId);
const rangeInput = document.getElementById(rangeId);
const valueDisplay = document.getElementById(valueId);
numberInput.addEventListener('input', () => {
rangeInput.value = numberInput.value;
valueDisplay.textContent = `${parseFloat(numberInput.value).toFixed(1)} ft`;
});
rangeInput.addEventListener('input', () => {
numberInput.value = rangeInput.value;
valueDisplay.textContent = `${parseFloat(rangeInput.value).toFixed(1)} ft`;
});
}
syncInputs('distance', 'distanceRange', 'distanceValue');
syncInputs('roomWidth', 'roomWidthRange', 'roomWidthValue');
syncInputs('roomDepth', 'roomDepthRange', 'roomDepthValue');
// Form Submission
document.getElementById('tvSizeForm').addEventListener('submit', function (e) {
e.preventDefault();
calculateTVSize();
});
function calculateTVSize() {
const distance = parseFloat(document.getElementById('distance').value);
const roomWidth = parseFloat(document.getElementById('roomWidth').value);
const roomDepth = parseFloat(document.getElementById('roomDepth').value);
if (!distance || !roomWidth || !roomDepth || distance < 1 || roomWidth < 5 || roomDepth < 5) {
alert('Please enter valid values (Distance ≥ 1 ft, Width/Depth ≥ 5 ft).');
return;
}
// Calculate recommended TV size (SMPTE: 30° field of view, THX: 40°)
const minTvSize = Math.round(distance * 12 / 1.6); // SMPTE
const maxTvSize = Math.round(distance * 12 / 0.6); // THX (4K)
const avgTvSize = Math.round((minTvSize + maxTvSize) / 2);
// Check if TV fits in room
const maxTvWidthInches = roomWidth * 12 * 0.8; // 80% of room width
const tvWidthInches = avgTvSize * 1.78; // 16:9 aspect ratio
const tvFit = tvWidthInches <= maxTvWidthInches ? 'Yes' : 'No';
// Generate output
const output = `
<div class="grid grid-cols-1 md:grid-cols-2 gap-6 bg-white p-6 rounded-xl shadow-sm">
<div>
<p class="font-medium text-gray-700">Recommended TV Size</p>
<p class="text-xl text-blue-600 font-semibold">${minTvSize}" to ${maxTvSize}" <span class="text-base text-gray-600">(Optimal: ~${avgTvSize}")</span></p>
</div>
<div>
<p class="font-medium text-gray-700">Viewing Distance</p>
<p class="text-lg">${distance.toFixed(1)} feet</p>
</div>
<div>
<p class="font-medium text-gray-700">Room Dimensions</p>
<p class="text-lg">${roomWidth.toFixed(1)} ft (width) x ${roomDepth.toFixed(1)} ft (depth)</p>
</div>
<div>
<p class="font-medium text-gray-700">Fit Assessment</p>
<p class="text-lg ${tvFit === 'Yes' ? 'text-green-600' : 'text-red-600'} font-semibold">
${tvFit === 'Yes' ? 'Perfect Fit' : 'May Be Too Large'}
</p>
<p class="text-sm text-gray-600">${tvFit === 'Yes' ? 'The TV fits comfortably within your room.' : 'Consider a smaller TV or adjust your room layout.'}</p>
</div>
</div>
<div class="bg-blue-50 p-4 rounded-lg">
<p class="text-sm"><span class="font-medium">Resolution Tip:</span> For viewing distances under 8 feet, a 4K TV ensures sharp, pixel-free visuals.</p>
</div>
`;
document.getElementById('resultOutput').innerHTML = output;
document.getElementById('resultSection').classList.remove('hidden');
// Draw visualization
drawVisualization(avgTvSize, roomWidth);
// Setup PDF download
setupPdfDownload(distance, roomWidth, roomDepth, minTvSize, maxTvSize, avgTvSize, tvFit);
}
function drawVisualization(tvSize, roomWidth) {
const canvas = document.getElementById('tvCanvas');
const ctx = canvas.getContext('2d');
canvas.width = canvas.offsetWidth;
canvas.height = canvas.offsetHeight;
// Clear canvas
ctx.clearRect(0, 0, canvas.width, canvas.height);
// Scale factors
const scale = canvas.width / (roomWidth * 12); // Pixels per inch
const tvWidth = (tvSize * 1.78) * scale; // 16:9 aspect ratio
const tvHeight = tvWidth / 1.78;
const roomWidthPixels = roomWidth * 12 * scale;
// Draw room background with floor texture
const gradient = ctx.createLinearGradient(0, 0, 0, canvas.height);
gradient.addColorStop(0, '#e5e7eb');
gradient.addColorStop(1, '#d1d5db');
ctx.fillStyle = gradient;
ctx.fillRect(0, 0, roomWidthPixels, canvas.height);
// Draw floor
ctx.fillStyle = 'rgba(120, 113, 108, 0.2)';
ctx.fillRect(0, canvas.height * 0.7, roomWidthPixels, canvas.height * 0.3);
// Draw TV with realistic effects
ctx.shadowColor = 'rgba(0, 0, 0, 0.4)';
ctx.shadowBlur = 15;
ctx.shadowOffsetX = 8;
ctx.shadowOffsetY = 8;
ctx.fillStyle = '#1e3a8a';
const tvX = (roomWidthPixels - tvWidth) / 2;
const tvY = canvas.height * 0.2;
ctx.fillRect(tvX, tvY, tvWidth, tvHeight);
// Draw TV screen with gradient
const screenGradient = ctx.createLinearGradient(tvX, tvY, tvX + tvWidth, tvY + tvHeight);
screenGradient.addColorStop(0, 'rgba(255, 255, 255, 0.15)');
screenGradient.addColorStop(1, 'rgba(255, 255, 255, 0.05)');
ctx.fillStyle = screenGradient;
ctx.fillRect(tvX + 5, tvY + 5, tvWidth - 10, tvHeight - 10);
// Draw TV stand
ctx.fillStyle = '#374151';
ctx.fillRect(tvX + tvWidth * 0.3, tvY + tvHeight, tvWidth * 0.4, 10);
// Draw text
ctx.shadowColor = 'transparent';
ctx.fillStyle = '#ffffff';
ctx.font = 'bold 18px Poppins';
ctx.textAlign = 'center';
ctx.fillText(`${tvSize}" TV`, roomWidthPixels / 2, tvY + tvHeight / 2);
ctx.font = '14px Poppins';
ctx.fillStyle = '#4b5563';
ctx.fillText(`Room Width: ${roomWidth.toFixed(1)} ft`, roomWidthPixels / 2, canvas.height - 30);
}
function setupPdfDownload(distance, roomWidth, roomDepth, minTvSize, maxTvSize, avgTvSize, tvFit) {
document.getElementById('downloadPdf').onclick = function () {
const { jsPDF } = window.jspdf;
const doc = new jsPDF();
// Header
doc.setFont('helvetica', 'bold');
doc.setFontSize(20);
doc.setTextColor(31, 64, 175);
doc.text('<?= $name ?> - TV Size Viewer Report', 20, 20);
doc.setFont('helvetica', 'normal');
doc.setFontSize(10);
doc.setTextColor(100, 100, 100);
doc.text(`Generated on: ${new Date().toLocaleString()}`, 20, 28);
// Results
doc.setFontSize(14);
doc.setTextColor(0, 0, 0);
doc.text('Your TV Size Recommendation', 20, 40);
doc.setFontSize(11);
doc.text(`Recommended TV Size: ${minTvSize}" to ${maxTvSize}" (Optimal: ~${avgTvSize}")`, 20, 50);
doc.text(`Viewing Distance: ${distance.toFixed(1)} feet`, 20, 58);
doc.text(`Room Dimensions: ${roomWidth.toFixed(1)} ft (width) x ${roomDepth.toFixed(1)} ft (depth)`, 20, 66);
doc.text(`Fit Assessment: ${tvFit === 'Yes' ? 'Perfect Fit' : 'May Be Too Large'}`, 20, 74);
doc.text('Resolution Tip: For distances under 8 feet, a 4K TV is recommended.', 20, 82);
// Expert Insights
doc.setFont('helvetica', 'bold');
doc.setFontSize(12);
doc.text('Expert Insights', 20, 94);
doc.setFont('helvetica', 'normal');
doc.setFontSize(10);
doc.text('• Viewing Angle: SMPTE (30°) for standard, THX (40°) for immersive.', 20, 102);
doc.text('• 4K Resolution: Sit closer (0.6-1x diagonal) for crisp visuals.', 20, 110);
doc.text('• Room Fit: TV stand/mount 20% narrower than room width.', 20, 118);
doc.text('• Lighting: OLED/QLED for darker rooms, LED for brighter ones.', 20, 126);
doc.text('• Ergonomics: TV center at eye level (3-4 ft from floor).', 20, 134);
doc.save('HomeFit_TV_Size_Recommendation.pdf');
};
}
</script>