Rezolvarea primelor de pe razele spiralei numerelor naturale
<html lang="ro">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Harta Numerică - Tabel Fractal Parascan-Margoș</title>
<script src="https://cdn.tailwindcss.com"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/html2canvas/1.4.1/html2canvas.min.js"></script>
<style>
body {
background-color: #020617;
color: #e2e8f0;
overflow-y: auto;
overflow-x: hidden;
font-family: 'JetBrains Mono', monospace;
}
.main-wrapper {
min-height: 100vh;
display: flex;
flex-direction: column;
padding: 20px;
}
.dot-map-container {
flex-grow: 1;
position: relative;
background: #020617;
border-radius: 24px;
border: 1px solid #1e293b;
overflow-x: auto;
overflow-y: auto;
max-height: 75vh;
padding: 20px;
scroll-behavior: smooth;
}
/* Layout-ul pentru coloane (raze) */
.dot-layout {
display: flex;
gap: 40px;
min-width: fit-content;
}
.dot-column {
display: flex;
flex-direction: column;
gap: 2px;
position: relative;
}
.ray-header {
position: sticky;
top: 0;
background: #020617;
padding: 10px 0;
z-index: 50;
border-bottom: 1px solid #1e293b;
text-align: center;
}
/* Containerul pentru un rând (Număr + Scara Divizorilor) */
.number-row {
display: flex;
align-items: center;
height: 12px;
position: relative;
border-bottom: 1px solid rgba(30, 41, 59, 0.2);
}
/* Punctul central (Numărul de pe rază) */
.main-node {
width: 10px;
height: 10px;
border-radius: 50%;
flex-shrink: 0;
z-index: 20;
cursor: help;
}
/* Scara numerică a divizorilor */
.divisor-scale {
position: relative;
height: 100%;
/* Lățimea axei X este proporțională cu valoarea numărului sau fixă pentru aliniere */
width: 300px;
margin-left: 10px;
background: rgba(15, 23, 42, 0.5);
}
.divisor-mark {
position: absolute;
width: 2px;
height: 6px;
top: 50%;
transform: translateY(-50%);
border-radius: 1px;
}
/* Culori conform logicii anterioare */
.node-prime { background-color: #f59e0b; box-shadow: 0 0 8px rgba(245, 158, 11, 0.5); }
.node-normal { background-color: #334155; }
.node-cancelled { background-color: #ef4444; }
.div-prime { background-color: #6366f1; width: 3px; height: 8px; }
.div-composite { background-color: #1e293b; }
.control-panel {
background: rgba(15, 23, 42, 0.9);
backdrop-filter: blur(12px);
padding: 15px;
border-radius: 20px;
border: 1px solid #334155;
margin-bottom: 20px;
display: flex;
flex-wrap: wrap;
justify-content: center;
gap: 20px;
align-items: center;
position: sticky;
top: 0;
z-index: 100;
}
#export-loading {
display: none;
position: fixed;
top: 0; left: 0; width: 100%; height: 100%;
background: rgba(2, 6, 23, 0.95);
z-index: 9999;
justify-content: center;
align-items: center;
flex-direction: column;
}
.label-text {
font-size: 8px;
color: #64748b;
text-transform: uppercase;
letter-spacing: 0.1em;
}
</style>
</head>
<body>
<div id="export-loading">
<div class="animate-spin rounded-full h-16 w-16 border-t-4 border-amber-500 mb-4"></div>
<p class="text-white font-black text-xs uppercase tracking-widest">Generare Tabel Fractal...</p>
</div>
<div class="main-wrapper">
<header class="text-center mb-6">
<h1 class="text-3xl font-black text-white tracking-tighter uppercase italic">
Tabel Fractal <span class="text-amber-500">Parascan-Margoș</span>
</h1>
<p class="text-slate-500 text-[10px] mt-1 uppercase tracking-[0.3em]">Distribuția Divizorilor pe Scara Reală a Numerelor</p>
</header>
<div class="control-panel">
<div class="flex flex-col gap-1">
<div class="flex items-center gap-4 bg-slate-900 px-4 py-2 rounded-xl border border-slate-800">
<label class="text-[9px] font-bold text-slate-400 uppercase">Raze (1-50):</label>
<input type="range" id="ray-slider" min="1" max="50" value="6" oninput="updateUI()" class="h-1.5 bg-slate-700 rounded-lg appearance-none cursor-pointer w-40">
<span id="ray-val" class="text-amber-500 font-bold text-sm w-6">6</span>
</div>
</div>
<div class="flex gap-2">
<button onclick="renderGrid(100)" class="bg-slate-800 hover:bg-slate-700 text-white px-4 py-2 rounded-lg text-[10px] font-bold uppercase transition-all">Scurt (600)</button>
<button onclick="renderGrid(1667)" class="bg-amber-600 hover:bg-amber-500 text-white px-5 py-2 rounded-lg text-[10px] font-black uppercase shadow-lg transition-all">Proiectează 10.000</button>
</div>
<div class="h-8 w-[1px] bg-slate-800 mx-2"></div>
<button onclick="downloadJPG()" class="bg-indigo-700 hover:bg-indigo-600 text-white px-6 py-2 rounded-lg text-[10px] font-bold uppercase transition-all">Exportă JPG</button>
</div>
<div class="dot-map-container" id="scroll-container">
<div id="fractal-layout" class="dot-layout"></div>
</div>
</div>
<script>
let currentRows = 100;
function isPrime(n) {
if (n <= 1) return false;
if (n <= 3) return true;
if (n % 2 === 0 || n % 3 === 0) return false;
for (let i = 5; i * i <= n; i += 6) {
if (n % i === 0 || n % (i + 2) === 0) return false;
}
return true;
}
function getDivisors(n) {
const divs = [];
if (n < 2) return divs;
for (let i = 2; i <= Math.sqrt(n); i++) {
if (n % i === 0) {
divs.push(i);
if (i*i !== n) divs.push(n/i);
}
}
return divs.sort((a, b) => a - b);
}
function createRow(num) {
const row = document.createElement('div');
row.className = 'number-row';
const prime = isPrime(num);
const baseC = (num - 1) % 6;
const isPrimeRay = (baseC === 0 || baseC === 4);
const cancelled = isPrimeRay && !prime && num > 1;
// Nodul principal
const node = document.createElement('div');
node.className = `main-node ${prime ? 'node-prime' : (cancelled ? 'node-cancelled' : 'node-normal')}`;
node.title = `N: ${num}`;
row.appendChild(node);
// Scara Divizorilor (Tabel Fractal)
const scale = document.createElement('div');
scale.className = 'divisor-scale';
const divisors = getDivisors(num);
divisors.forEach(d => {
const mark = document.createElement('div');
const isDivPrime = isPrime(d);
mark.className = `divisor-mark ${isDivPrime ? 'div-prime' : 'div-composite'}`;
// Poziționare pe scara reală: (valoare divizor / valoare număr) * 100%
// Pentru vizualizare fractală optimă, folosim o scară logaritmică sau fixă.
// Aici folosim scara liniară raportată la un maxim local pentru a vedea densitatea.
const position = (d / num) * 100;
mark.style.left = `${position}%`;
mark.title = `Divizor: ${d}`;
scale.appendChild(mark);
});
row.appendChild(scale);
return row;
}
function renderGrid(rows) {
currentRows = rows;
const colsCount = parseInt(document.getElementById('ray-slider').value);
const layout = document.getElementById('fractal-layout');
layout.innerHTML = '';
const fragment = document.createDocumentFragment();
for (let c = 0; c < colsCount; c++) {
const col = document.createElement('div');
col.className = 'dot-column';
const header = document.createElement('div');
header.className = 'ray-header';
header.innerHTML = `<span class="label-text">Raza</span><br><span class="text-amber-500 font-bold">${c+1}</span>`;
col.appendChild(header);
for (let r = 0; r < rows; r++) {
const num = 1 + (r * colsCount) + c;
if (num > 10000) break;
col.appendChild(createRow(num));
}
fragment.appendChild(col);
}
layout.appendChild(fragment);
}
function updateUI() {
const val = document.getElementById('ray-slider').value;
document.getElementById('ray-val').innerText = val;
renderGrid(currentRows);
}
async function downloadJPG() {
const loading = document.getElementById('export-loading');
const target = document.getElementById('fractal-layout');
loading.style.display = 'flex';
setTimeout(async () => {
try {
const canvas = await html2canvas(target, {
backgroundColor: '#020617',
scale: 1,
logging: false,
useCORS: true
});
const imgData = canvas.toDataURL('image/jpeg', 0.85);
const link = document.createElement('a');
link.href = imgData;
link.download = `Tabel_Fractal_Parascan_Margos_${new Date().getTime()}.jpg`;
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
} catch (e) {
console.error(e);
alert("Imaginea este prea mare pentru memoria browserului la 10.000 de puncte. Încercați o setare mai scurtă.");
} finally {
loading.style.display = 'none';
}
}, 100);
}
window.onload = () => renderGrid(100);
</script>
</body>
</html>
Niciun comentariu:
Trimiteți un comentariu