faronespace / index.html
farone11's picture
Update index.html
b8a031b verified
Raw
History Blame Contribute Delete
47.1 kB
<!DOCTYPE html>
<html lang="id">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>FarOneSquare Calculator - Square of 9 Level</title>
<script src="https://cdn.tailwindcss.com"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css">
<style>
@import url('https://fonts.googleapis.com/css2?family=Orbitron:wght@400;500;600;700;900&family=Rajdhani:wght@300;400;500;600;700&display=swap');
* {
font-family: 'Rajdhani', sans-serif;
}
h1, h2, h3, .font-orbitron {
font-family: 'Orbitron', sans-serif;
}
body {
background: #030712;
background-image:
radial-gradient(circle at 15% 50%, rgba(0, 150, 255, 0.25) 0%, transparent 40%),
radial-gradient(circle at 85% 50%, rgba(0, 150, 255, 0.25) 0%, transparent 40%),
radial-gradient(circle at 50% 20%, rgba(0, 200, 255, 0.15) 0%, transparent 50%),
linear-gradient(180deg, #000814 0%, #001d3d 50%, #000814 100%);
background-attachment: fixed;
min-height: 100vh;
overflow-x: hidden;
}
body::before {
content: '';
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-image:
linear-gradient(rgba(0, 150, 255, 0.03) 1px, transparent 1px),
linear-gradient(90deg, rgba(0, 150, 255, 0.03) 1px, transparent 1px);
background-size: 50px 50px;
pointer-events: none;
z-index: 0;
}
body::after {
content: '';
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-image:
radial-gradient(circle at 10% 30%, rgba(0, 200, 255, 0.08) 0%, transparent 25%),
radial-gradient(circle at 90% 70%, rgba(0, 200, 255, 0.08) 0%, transparent 25%);
pointer-events: none;
z-index: 0;
animation: pulseGlow 8s ease-in-out infinite;
}
@keyframes pulseGlow {
0%, 100% { opacity: 0.5; }
50% { opacity: 1; }
}
.cyber-frame {
position: relative;
border: 1px solid rgba(0, 150, 255, 0.3);
box-shadow:
0 0 40px rgba(0, 150, 255, 0.2),
inset 0 0 30px rgba(0, 150, 255, 0.05);
animation: borderPulse 4s ease-in-out infinite;
}
@keyframes borderPulse {
0%, 100% {
box-shadow: 0 0 40px rgba(0, 150, 255, 0.2), inset 0 0 30px rgba(0, 150, 255, 0.05);
}
50% {
box-shadow: 0 0 60px rgba(0, 150, 255, 0.4), inset 0 0 40px rgba(0, 150, 255, 0.1);
}
}
.cyber-frame::before,
.cyber-frame::after {
content: '';
position: absolute;
width: 40px;
height: 40px;
border: 2px solid #00d9ff;
filter: drop-shadow(0 0 10px rgba(0, 217, 255, 0.8));
pointer-events: none;
}
.cyber-frame::before {
top: -2px;
left: -2px;
border-right: none;
border-bottom: none;
}
.cyber-frame::after {
bottom: -2px;
right: -2px;
border-left: none;
border-top: none;
}
.corner-tech::before,
.corner-tech::after {
content: '';
position: absolute;
width: 40px;
height: 40px;
border: 2px solid #00d9ff;
filter: drop-shadow(0 0 10px rgba(0, 217, 255, 0.8));
pointer-events: none;
}
.corner-tech::before {
top: -2px;
right: -2px;
border-left: none;
border-bottom: none;
}
.corner-tech::after {
bottom: -2px;
left: -2px;
border-right: none;
border-top: none;
}
.glass-card {
background: rgba(3, 7, 18, 0.6);
backdrop-filter: blur(20px);
-webkit-backdrop-filter: blur(20px);
border: 1px solid rgba(0, 150, 255, 0.2);
box-shadow: 0 8px 32px 0 rgba(0, 0, 0, 0.5);
}
.glass-card-light {
background: rgba(3, 7, 18, 0.4);
backdrop-filter: blur(12px);
-webkit-backdrop-filter: blur(12px);
border: 1px solid rgba(0, 150, 255, 0.15);
}
.neon-text {
text-shadow:
0 0 10px rgba(0, 217, 255, 0.8),
0 0 20px rgba(0, 217, 255, 0.5),
0 0 30px rgba(0, 217, 255, 0.3);
}
.neon-blue {
color: #00d9ff;
text-shadow: 0 0 20px rgba(0, 217, 255, 0.6);
}
.info-card {
background: rgba(3, 7, 18, 0.7);
backdrop-filter: blur(16px);
-webkit-backdrop-filter: blur(16px);
border: 1px solid rgba(0, 150, 255, 0.3);
box-shadow:
0 0 20px rgba(0, 150, 255, 0.15),
inset 0 1px 0 rgba(255, 255, 255, 0.1);
transition: all 0.3s ease;
}
.info-card:hover {
border-color: rgba(0, 217, 255, 0.5);
box-shadow:
0 0 30px rgba(0, 150, 255, 0.3),
inset 0 1px 0 rgba(255, 255, 255, 0.2);
transform: translateY(-2px);
}
.cardinal-badge {
width: 28px;
height: 28px;
border-radius: 8px;
display: flex;
align-items: center;
justify-content: center;
font-size: 11px;
font-weight: 700;
font-family: 'Orbitron', sans-serif;
box-shadow: 0 0 15px currentColor;
position: relative;
}
.cardinal-badge::after {
content: '';
position: absolute;
inset: -2px;
border-radius: 10px;
padding: 2px;
background: linear-gradient(135deg, currentColor, transparent);
-webkit-mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
-webkit-mask-composite: xor;
mask-composite: exclude;
opacity: 0.5;
}
.cardinal-badge.r-green {
background: rgba(0, 255, 150, 0.2);
border: 1px solid rgba(0, 255, 150, 0.5);
color: #00ff96;
}
.cardinal-badge.s-red {
background: rgba(255, 50, 100, 0.2);
border: 1px solid rgba(255, 50, 100, 0.5);
color: #ff3264;
}
.cardinal-badge.r-purple {
background: rgba(168, 85, 247, 0.2);
border: 1px solid rgba(168, 85, 247, 0.5);
color: #a855f7;
}
.cardinal-badge.r-blue {
background: rgba(0, 217, 255, 0.2);
border: 1px solid rgba(0, 217, 255, 0.5);
color: #00d9ff;
}
.btn-primary {
background: linear-gradient(135deg, #0077ff 0%, #00d9ff 100%);
border: 1px solid rgba(0, 217, 255, 0.5);
box-shadow:
0 0 20px rgba(0, 150, 255, 0.4),
inset 0 1px 0 rgba(255, 255, 255, 0.2);
transition: all 0.3s ease;
}
.btn-primary:hover {
box-shadow:
0 0 30px rgba(0, 150, 255, 0.6),
inset 0 1px 0 rgba(255, 255, 255, 0.3);
transform: translateY(-2px);
}
.btn-primary:active {
transform: translateY(0px);
}
.btn-secondary {
background: rgba(0, 150, 255, 0.1);
border: 1px solid rgba(0, 150, 255, 0.3);
backdrop-filter: blur(10px);
transition: all 0.3s ease;
}
.btn-secondary:hover {
background: rgba(0, 150, 255, 0.2);
box-shadow: 0 0 20px rgba(0, 150, 255, 0.3);
}
input[type="number"], select {
background: rgba(3, 7, 18, 0.7);
border: 1px solid rgba(0, 150, 255, 0.3);
color: #00d9ff;
transition: all 0.3s ease;
}
input[type="number"]:focus, select:focus {
outline: none;
border-color: #00d9ff;
box-shadow: 0 0 15px rgba(0, 217, 255, 0.4);
background: rgba(3, 7, 18, 0.9);
}
.level-buy {
background: linear-gradient(90deg, rgba(255, 50, 100, 0.15) 0%, rgba(255, 50, 100, 0.05) 100%);
border-left: 3px solid #ff3264;
}
.level-sell {
background: linear-gradient(90deg, rgba(0, 255, 150, 0.15) 0%, rgba(0, 255, 150, 0.05) 100%);
border-left: 3px solid #00ff96;
}
.level-neutral {
background: linear-gradient(90deg, rgba(0, 217, 255, 0.1) 0%, rgba(0, 217, 255, 0.05) 100%);
border-left: 3px solid #00d9ff;
}
.cube-wrapper {
perspective: 1000px;
}
.cube-3d {
transform-style: preserve-3d;
animation: rotateCube 15s linear infinite;
}
@keyframes rotateCube {
0% { transform: rotateX(15deg) rotateY(0deg); }
100% { transform: rotateX(15deg) rotateY(360deg); }
}
.toast {
animation: slideInRight 0.3s ease, fadeOut 0.3s ease 2.7s;
}
@keyframes slideInRight {
from { transform: translateX(400px); opacity: 0; }
to { transform: translateX(0); opacity: 1; }
}
@keyframes fadeOut {
to { opacity: 0; }
}
.table-row {
transition: all 0.2s ease;
}
.table-row:hover {
background: rgba(0, 150, 255, 0.08);
transform: scale(1.01);
}
.degree-highlight {
background: linear-gradient(90deg, rgba(0, 217, 255, 0.2) 0%, rgba(0, 217, 255, 0.05) 100%);
box-shadow: inset 0 0 20px rgba(0, 217, 255, 0.1);
}
.stat-number {
background: linear-gradient(135deg, #00d9ff, #0077ff);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
.toggle-switch {
position: relative;
width: 54px;
height: 28px;
}
.toggle-switch input {
opacity: 0;
width: 0;
height: 0;
}
.toggle-slider {
position: absolute;
cursor: pointer;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(0, 150, 255, 0.2);
border: 1px solid rgba(0, 150, 255, 0.3);
transition: 0.4s;
border-radius: 28px;
}
.toggle-slider:before {
position: absolute;
content: "";
height: 20px;
width: 20px;
left: 3px;
bottom: 3px;
background: linear-gradient(135deg, #0077ff 0%, #00d9ff 100%);
transition: 0.4s;
border-radius: 50%;
box-shadow: 0 0 10px rgba(0, 217, 255, 0.6);
}
input:checked + .toggle-slider {
background-color: rgba(0, 217, 255, 0.3);
border-color: #00d9ff;
box-shadow: 0 0 15px rgba(0, 217, 255, 0.4);
}
input:checked + .toggle-slider:before {
transform: translateX(26px);
}
@keyframes pulse-realtime {
0%, 100% { opacity: 1; }
50% { opacity: 0.5; }
}
.realtime-active {
animation: pulse-realtime 2s ease-in-out infinite;
}
.author-footnote {
font-weight: 700;
text-align: center;
font-size: 0.95rem;
color: #00d9ff;
text-shadow:
0 0 5px rgba(0, 217, 255, 0.8),
0 0 10px rgba(0, 217, 255, 0.6),
0 0 20px rgba(0, 150, 255, 0.4),
0 0 30px rgba(0, 100, 255, 0.2);
letter-spacing: 1px;
animation: authorGlow 3s ease-in-out infinite;
}
@keyframes authorGlow {
0%, 100% {
text-shadow:
0 0 5px rgba(0, 217, 255, 0.8),
0 0 10px rgba(0, 217, 255, 0.6),
0 0 20px rgba(0, 150, 255, 0.4);
}
50% {
text-shadow:
0 0 10px rgba(0, 217, 255, 1),
0 0 20px rgba(0, 217, 255, 0.8),
0 0 30px rgba(0, 150, 255, 0.6),
0 0 40px rgba(0, 100, 255, 0.4);
}
}
@media (max-width: 390px) {
.cyber-frame::before,
.cyber-frame::after,
.corner-tech::before,
.corner-tech::after {
width: 25px;
height: 25px;
}
h1 { font-size: 1.5rem; }
.info-card { padding: 0.875rem; }
th, td { font-size: 0.7rem; padding: 0.5rem 0.15rem !important; }
.cardinal-badge { width: 24px; height: 24px; font-size: 9px; }
.author-footnote { font-size: 0.85rem; }
}
</style>
</head>
<body class="text-gray-200 p-4 md:p-8">
<div class="max-w-7xl mx-auto relative z-10">
<!-- Main Container with Cyber Frame -->
<div class="cyber-frame corner-tech rounded-2xl p-6 md:p-10 relative">
<!-- Header -->
<header class="mb-8 md:mb-10">
<div class="flex flex-col lg:flex-row lg:items-start lg:justify-between gap-6 mb-6">
<div class="flex-1">
<div class="flex items-center gap-3 mb-3">
<div class="w-12 h-12 rounded-xl bg-gradient-to-br from-cyan-500 to-blue-600 flex items-center justify-center shadow-lg shadow-cyan-500/50">
<i class="fas fa-calculator text-2xl text-white"></i>
</div>
<h1 class="text-3xl md:text-5xl font-bold neon-text font-orbitron">
FarOneSquare Calculator
</h1>
</div>
<p class="text-base md:text-lg text-cyan-300 opacity-90">
Square of 9 Level - Support & Resistance 360°
</p>
<div class="mt-4 flex flex-wrap gap-2">
<div class="inline-flex items-center gap-2 px-4 py-2 glass-card-light rounded-full">
<i class="fas fa-calculator neon-blue text-sm"></i>
<span class="text-xs md:text-sm text-cyan-400">Rumus: (√Price ± Factor)²</span>
</div>
<div id="modeIndicator" class="inline-flex items-center gap-2 px-4 py-2 glass-card-light rounded-full transition-all">
<i id="modeIcon" class="fas fa-sync-alt neon-blue text-sm"></i>
<span id="modeText" class="text-xs md:text-sm text-cyan-400">Real-time Calculation: ON</span>
</div>
</div>
</div>
<!-- Quick Inputs -->
<div class="flex flex-col gap-4 lg:w-auto">
<!-- Toggle Real-time -->
<div class="glass-card-light rounded-lg px-4 py-3 flex items-center justify-between gap-4">
<div class="flex items-center gap-2">
<i class="fas fa-bolt text-cyan-400"></i>
<span class="text-sm font-semibold text-cyan-300">Real-time Mode</span>
</div>
<label class="toggle-switch">
<input type="checkbox" id="realtimeToggle" checked>
<span class="toggle-slider"></span>
</label>
</div>
<div class="flex flex-col sm:flex-row gap-4">
<div>
<label class="block text-xs font-medium text-cyan-300 mb-1.5 uppercase tracking-wider">
<i class="fas fa-dollar-sign mr-1"></i>Harga Dasar
</label>
<input type="number" id="basePrice" value="4370" step="1"
class="w-full sm:w-44 px-4 py-2.5 rounded-lg text-base font-semibold font-orbitron">
</div>
<div>
<label class="block text-xs font-medium text-cyan-300 mb-1.5 uppercase tracking-wider">
<i class="fas fa-ruler mr-1"></i>Tick Size
</label>
<input type="number" id="tickSize" value="5" min="1" step="1"
class="w-full sm:w-36 px-4 py-2.5 rounded-lg text-base font-semibold font-orbitron">
</div>
<div class="flex items-end">
<button id="calcBtn" onclick="manualCalculate()" class="btn-primary px-6 py-2.5 rounded-lg font-semibold text-white flex items-center gap-2 w-full sm:w-auto">
<i class="fas fa-play"></i>
<span>Hitung</span>
</button>
</div>
</div>
</div>
</div>
<!-- 4 Info Cards Row -->
<div class="grid grid-cols-2 lg:grid-cols-4 gap-3 md:gap-4">
<!-- Card 1: Square Root -->
<div class="info-card rounded-xl p-4 md:p-5">
<div class="text-[10px] md:text-xs uppercase text-gray-400 mb-2 tracking-wider font-semibold flex items-center gap-1">
<i class="fas fa-square-root-alt"></i>
Square Root
</div>
<div id="squareRootValue" class="text-2xl md:text-4xl font-bold stat-number font-orbitron">
66.106
</div>
<div class="text-[10px] text-gray-500 mt-1">√Harga Dasar</div>
</div>
<!-- Card 2: Cardinal -->
<div class="info-card rounded-xl p-4 md:p-5">
<div class="text-[10px] md:text-xs uppercase text-gray-400 mb-2 tracking-wider font-semibold flex items-center gap-1">
<i class="fas fa-compass"></i>
Cardinal 90° 180° 270° 360°
</div>
<div class="flex items-center gap-2 md:gap-2.5">
<div class="cardinal-badge r-green" title="Resistance">R</div>
<div class="cardinal-badge s-red" title="Support">S</div>
<div class="cardinal-badge r-purple" title="Resistance">R</div>
<div class="cardinal-badge r-blue" title="Resistance">R</div>
</div>
<div class="text-[10px] text-gray-500 mt-1">R/S Pattern</div>
</div>
<!-- Card 3: Prev 360 Support -->
<div class="info-card rounded-xl p-4 md:p-5">
<div class="text-[10px] md:text-xs uppercase text-gray-400 mb-2 tracking-wider font-semibold flex items-center gap-1">
<i class="fas fa-arrow-down text-red-400"></i>
Prev 360° Support
</div>
<div id="prevSupportValue" class="text-2xl md:text-4xl font-bold text-red-400 font-orbitron">
4,110
</div>
<div class="text-[10px] text-gray-500 mt-1">Support Utama</div>
</div>
<!-- Card 4: Next 360 Resist -->
<div class="info-card rounded-xl p-4 md:p-5">
<div class="text-[10px] md:text-xs uppercase text-gray-400 mb-2 tracking-wider font-semibold flex items-center gap-1">
<i class="fas fa-arrow-up text-green-400"></i>
Next 360° Resist
</div>
<div id="nextResistValue" class="text-2xl md:text-4xl font-bold text-green-400 font-orbitron">
4,640
</div>
<div class="text-[10px] text-gray-500 mt-1">Resistance Utama</div>
</div>
</div>
</header>
<!-- Results Table -->
<div class="glass-card rounded-xl p-6 md:p-8 mb-6 md:mb-8">
<div class="flex flex-col sm:flex-row sm:items-center sm:justify-between gap-4 mb-6">
<h2 class="text-xl md:text-2xl font-semibold neon-blue font-orbitron flex items-center gap-3">
<i class="fas fa-table"></i>
Level Square of 9
</h2>
<div class="flex gap-3 flex-wrap">
<button onclick="toggleFilter()" class="btn-secondary px-4 py-2 rounded-lg font-semibold text-cyan-300 flex items-center gap-2 text-sm">
<i class="fas fa-filter"></i>
<span id="filterText">Show All</span>
</button>
<button onclick="copyResults()" class="btn-secondary px-4 py-2 rounded-lg font-semibold text-cyan-300 flex items-center gap-2 text-sm">
<i class="fas fa-copy"></i>
Copy
</button>
<button onclick="exportCSV()" class="btn-secondary px-4 py-2 rounded-lg font-semibold text-cyan-300 flex items-center gap-2 text-sm">
<i class="fas fa-file-export"></i>
CSV
</button>
<button onclick="exportJSON()" class="btn-secondary px-4 py-2 rounded-lg font-semibold text-cyan-300 flex items-center gap-2 text-sm">
<i class="fas fa-code"></i>
JSON
</button>
</div>
</div>
<div class="overflow-x-auto rounded-lg">
<table class="w-full text-sm md:text-base">
<thead>
<tr class="border-b-2 border-cyan-900 bg-cyan-950/30">
<th class="text-left py-3 px-3 text-cyan-300 font-semibold font-orbitron">DERAJAT</th>
<th class="text-right py-3 px-3 text-cyan-300 font-semibold font-orbitron">RESISTANCE</th>
<th class="text-right py-3 px-3 text-cyan-300 font-semibold font-orbitron">JARAK R</th>
<th class="text-right py-3 px-3 text-cyan-300 font-semibold font-orbitron">SUPPORT</th>
<th class="text-right py-3 px-3 text-cyan-300 font-semibold font-orbitron">JARAK S</th>
<th class="text-center py-3 px-3 text-cyan-300 font-semibold font-orbitron">TYPE</th>
</tr>
</thead>
<tbody id="resultsBody">
<!-- Results will be inserted here -->
</tbody>
</table>
</div>
</div>
<!-- Info Sections -->
<div class="grid grid-cols-1 lg:grid-cols-2 gap-6 md:gap-8">
<!-- Cara Baca Level -->
<div class="glass-card rounded-xl p-6 md:p-8">
<h2 class="text-xl md:text-2xl font-semibold mb-6 neon-blue font-orbitron flex items-center gap-3">
<i class="fas fa-book-open"></i>
Cara Baca Level
</h2>
<div class="space-y-4">
<div class="glass-card-light rounded-lg p-4 level-sell">
<h3 class="font-semibold text-green-400 mb-2 flex items-center gap-2">
<i class="fas fa-arrow-up"></i>Resistance (Hijau)
</h3>
<p class="text-sm text-gray-300">Level di atas harga dasar. Area supply kuat, berpotensi tertahan/reversal turun. Semakin tinggi derajat, semakin kuat resistance.</p>
</div>
<div class="glass-card-light rounded-lg p-4 level-buy">
<h3 class="font-semibold text-red-400 mb-2 flex items-center gap-2">
<i class="fas fa-arrow-down"></i>Support (Merah)
</h3>
<p class="text-sm text-gray-300">Level di bawah harga dasar. Area demand kuat, berpotensi memantul naik. Semakin rendah derajat, semakin kuat support.</p>
</div>
<div class="glass-card-light rounded-lg p-4">
<h3 class="font-semibold text-cyan-400 mb-2 flex items-center gap-2">
<i class="fas fa-compass"></i>Type Level
</h3>
<div class="text-sm text-gray-300 space-y-2">
<div class="flex items-center gap-2"><span class="w-20 text-blue-400 font-semibold">Full (360°)</span> <span class="text-xs">- Level paling kuat</span></div>
<div class="flex items-center gap-2"><span class="w-20 text-purple-400 font-semibold">3Q (270°)</span> <span class="text-xs">- Three Quarter</span></div>
<div class="flex items-center gap-2"><span class="w-20 text-orange-400 font-semibold">Mid (180°)</span> <span class="text-xs">- Midpoint</span></div>
<div class="flex items-center gap-2"><span class="w-20 text-green-400 font-semibold">Quarter (90°)</span> <span class="text-xs">- Level penting</span></div>
<div class="flex items-center gap-2"><span class="w-20 text-gray-400 font-semibold">Minor</span> <span class="text-xs">- Level tambahan</span></div>
</div>
</div>
</div>
</div>
<!-- Rumus -->
<div class="glass-card rounded-xl p-6 md:p-8">
<h2 class="text-xl md:text-2xl font-semibold mb-6 neon-blue font-orbitron flex items-center gap-3">
<i class="fas fa-square-root-alt"></i>
Rumus Square of 9
</h2>
<div class="flex flex-col items-center">
<div class="mb-6 cube-wrapper">
<div class="cube-3d relative w-32 h-32">
<div class="absolute inset-0 bg-gradient-to-br from-cyan-500 to-blue-600 rounded-lg opacity-80" style="box-shadow: 0 0 40px rgba(0, 217, 255, 0.8);"></div>
<div class="absolute inset-0 flex items-center justify-center">
<span class="text-white font-bold font-orbitron text-2xl">9</span>
</div>
</div>
</div>
<div class="w-full space-y-3">
<div class="glass-card-light rounded-lg p-4">
<div class="text-cyan-400 font-semibold mb-2 flex items-center gap-2">
<i class="fas fa-calculator"></i>Formula Utama
</div>
<div class="space-y-1">
<code class="text-cyan-400 font-mono text-sm block">Factor = Derajat / 180</code>
<code class="text-green-400 font-mono text-sm block">Resistance = (√Price + Factor)²</code>
<code class="text-red-400 font-mono text-sm block">Support = (√Price - Factor)²</code>
</div>
</div>
<div class="glass-card-light rounded-lg p-4">
<div class="text-cyan-400 font-semibold mb-2 flex items-center gap-2">
<i class="fas fa-ruler"></i>Tick Size
</div>
<p class="text-sm text-gray-300">Hasil dibulatkan ke kelipatan Tick Size terdekat. Default: 5 untuk saham Indonesia.</p>
</div>
<div class="glass-card-light rounded-lg p-4">
<div class="text-cyan-400 font-semibold mb-2 flex items-center gap-2">
<i class="fas fa-chart-line"></i>Contoh Harga <span id="examplePrice" class="text-white">4370</span>
</div>
<div id="exampleCalc" class="text-xs text-gray-300 space-y-1 font-mono">
<div>√4370 = 66.106</div>
<div class="text-green-400">360° R: (66.106 + 2.0)² = 4,640</div>
<div class="text-red-400">360° S: (66.106 - 2.0)² = 4,110</div>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Footer -->
<footer class="mt-8 md:mt-12 text-center">
<div class="glass-card-light rounded-xl p-6">
<p class="text-sm text-gray-400 mb-2">
<i class="fas fa-info-circle mr-2 neon-blue"></i>
FarOneSquare Calculator menggunakan rumus Square of 9 untuk memproyeksikan level support & resistance
</p>
<p class="text-xs text-gray-500">
Hasil perhitungan bukan saran finansial. Gunakan sebagai referensi analisis teknikal. DYOR - Do Your Own Research.
</p>
<div class="mt-4 flex justify-center gap-4 text-xs text-gray-600 mb-4">
<span><i class="fas fa-code mr-1"></i>v2.1</span>
<span><i class="fas fa-palette mr-1"></i>Cyberpunk UI</span>
<span><i class="fas fa-bolt mr-1"></i>Real-time Mode</span>
</div>
<div class="pt-4 border-t border-cyan-900/30">
<p class="author-footnote font-orbitron">
<i class="fas fa-users mr-2"></i>Authors Setiawan F | Selviana R
</p>
</div>
</div>
</footer>
</div>
</div>
<!-- Toast Container -->
<div id="toastContainer" class="fixed top-4 right-4 z-50 space-y-2 max-w-sm"></div>
<script>
// Data derajat & type Square of 9
const squareLevels = [
{ degree: 45, type: 'Minor', color: 'text-gray-400', bgColor: 'bg-gray-500/20' },
{ degree: 90, type: 'Quarter', color: 'text-green-400', bgColor: 'bg-green-500/20' },
{ degree: 135, type: 'Minor', color: 'text-gray-400', bgColor: 'bg-gray-500/20' },
{ degree: 180, type: 'Mid', color: 'text-orange-400', bgColor: 'bg-orange-500/20' },
{ degree: 225, type: 'Minor', color: 'text-gray-400', bgColor: 'bg-gray-500/20' },
{ degree: 270, type: '3Q', color: 'text-purple-400', bgColor: 'bg-purple-500/20' },
{ degree: 315, type: 'Minor', color: 'text-gray-400', bgColor: 'bg-gray-500/20' },
{ degree: 360, type: 'Full', color: 'text-blue-400', bgColor: 'bg-blue-500/20' }
];
let currentData = [];
let showOnlyMajor = false;
let realtimeMode = true;
let debounceTimer;
// Round to nearest tick size
function roundToTick(value, tickSize) {
return Math.round(value / tickSize) * tickSize;
}
// Format number with thousand separator
function formatNumber(num) {
return num.toLocaleString('id-ID');
}
// Update mode indicator UI
function updateModeIndicator() {
const indicator = document.getElementById('modeIndicator');
const icon = document.getElementById('modeIcon');
const text = document.getElementById('modeText');
const calcBtn = document.getElementById('calcBtn');
if (realtimeMode) {
icon.className = 'fas fa-bolt neon-blue text-sm realtime-active';
text.textContent = 'Real-time Calculation: ON';
indicator.style.borderColor = 'rgba(0, 217, 255, 0.5)';
calcBtn.style.opacity = '0.5';
calcBtn.style.cursor = 'not-allowed';
} else {
icon.className = 'fas fa-pause neon-blue text-sm';
text.textContent = 'Manual Mode: OFF';
indicator.style.borderColor = 'rgba(255, 100, 0.3)';
calcBtn.style.opacity = '1';
calcBtn.style.cursor = 'pointer';
}
}
// Main calculation function - Rumus Square of 9
function calculateLevels(isManual = false) {
const basePrice = parseFloat(document.getElementById('basePrice').value) || 0;
const tickSize = parseFloat(document.getElementById('tickSize').value) || 1;
if (basePrice <= 0) {
if (isManual) showToast('Harga dasar harus lebih dari 0', 'error');
return;
}
// Step 1: Akar kuadrat harga dasar
const sqrtBase = Math.sqrt(basePrice);
// Update Square Root card with animation
const sqrtEl = document.getElementById('squareRootValue');
sqrtEl.style.transform = 'scale(1.05)';
sqrtEl.textContent = sqrtBase.toFixed(3);
setTimeout(() => sqrtEl.style.transform = 'scale(1)', 150);
currentData = squareLevels.map(level => {
// Step 2: Factor = Derajat / 180
const factor = level.degree / 180;
// Step 3: Resistance = (√Price + Factor)²
// Step 4: Support = (√Price - Factor)²
const resistanceRaw = Math.pow(sqrtBase + factor, 2);
const supportRaw = Math.pow(sqrtBase - factor, 2);
// Step 5: Bulatkan ke tick size terdekat
const resistance = roundToTick(resistanceRaw, tickSize);
const support = roundToTick(supportRaw, tickSize);
// Jarak dari harga dasar
const jarakR = resistance - basePrice;
const jarakS = basePrice - support;
return {
degree: level.degree,
type: level.type,
typeColor: level.color,
bgColor: level.bgColor,
resistance: resistance,
support: support,
jarakR: jarakR,
jarakS: jarakS
};
});
// Update 360° cards with animation
const level360 = currentData.find(d => d.degree === 360);
if (level360) {
const prevEl = document.getElementById('prevSupportValue');
const nextEl = document.getElementById('nextResistValue');
prevEl.style.transform = 'scale(1.05)';
nextEl.style.transform = 'scale(1.05)';
setTimeout(() => {
prevEl.textContent = formatNumber(level360.support);
nextEl.textContent = formatNumber(level360.resistance);
prevEl.style.transform = 'scale(1)';
nextEl.style.transform = 'scale(1)';
}, 100);
}
// Update example calculation
document.getElementById('examplePrice').textContent = basePrice;
document.getElementById('exampleCalc').innerHTML = `
<div>√${basePrice} = ${sqrtBase.toFixed(3)}</div>
<div class="text-green-400">360° R: (${sqrtBase.toFixed(3)} + 2.0)² = ${formatNumber(level360.resistance)}</div>
<div class="text-red-400">360° S: (${sqrtBase.toFixed(3)} - 2.0)² = ${formatNumber(level360.support)}</div>
`;
renderTable();
if (isManual) showToast('Kalkulasi berhasil!', 'success');
}
// Manual calculate with button
function manualCalculate() {
if (!realtimeMode) {
calculateLevels(true);
} else {
showToast('Real-time mode aktif, kalkulasi otomatis', 'info');
}
}
// Render table
function renderTable() {
const tbody = document.getElementById('resultsBody');
tbody.innerHTML = '';
let displayData = currentData;
if (showOnlyMajor) {
displayData = currentData.filter(row => row.type !== 'Minor');
}
displayData.forEach((row, index) => {
const tr = document.createElement('tr');
const isHighlight = [90, 180, 270, 360].includes(row.degree);
tr.className = `table-row border-b border-cyan-900/30 ${isHighlight ? 'degree-highlight' : ''}`;
tr.style.animationDelay = `${index * 30}ms`;
tr.innerHTML = `
<td class="py-3 px-3 font-semibold font-orbitron ${isHighlight ? 'text-cyan-300' : ''}">${row.degree}°</td>
<td class="py-3 px-3 text-right font-semibold text-green-400 font-orbitron">${formatNumber(row.resistance)}</td>
<td class="py-3 px-3 text-right text-sm ${row.jarakR >= 0 ? 'text-green-400' : 'text-red-400'}">+${formatNumber(row.jarakR)}</td>
<td class="py-3 px-3 text-right font-semibold text-red-400 font-orbitron">${formatNumber(row.support)}</td>
<td class="py-3 px-3 text-right text-sm ${row.jarakS >= 0 ? 'text-red-400' : 'text-green-400'}">-${formatNumber(row.jarakS)}</td>
<td class="py-3 px-3 text-center">
<span class="inline-block px-3 py-1 rounded-full text-xs font-semibold ${row.typeColor} ${row.bgColor} border border-current">${row.type}</span>
</td>
`;
tbody.appendChild(tr);
});
}
// Toggle filter
function toggleFilter() {
showOnlyMajor = !showOnlyMajor;
document.getElementById('filterText').textContent = showOnlyMajor ? 'Show All' : 'Major Only';
renderTable();
showToast(showOnlyMajor ? 'Menampilkan level major saja' : 'Menampilkan semua level', 'info');
}
// Copy results
function copyResults() {
const basePrice = document.getElementById('basePrice').value;
const tickSize = document.getElementById('tickSize').value;
let text = `FarOneSquare Calculator - Square of 9 Level\n`;
text += `Harga Dasar: ${basePrice} | Tick Size: ${tickSize}\n`;
text += `Mode: ${realtimeMode ? 'Real-time' : 'Manual'}\n`;
text += `Generated: ${new Date().toLocaleString('id-ID')}\n\n`;
text += `DERAJAT\tRESISTANCE\tJARAK R\tSUPPORT\tJARAK S\tTYPE\n`;
text += `${'='.repeat(70)}\n`;
currentData.forEach(row => {
text += `${row.degree}°\t${row.resistance}\t+${row.jarakR}\t${row.support}\t-${row.jarakS}\t${row.type}\n`;
});
navigator.clipboard.writeText(text).then(() => {
showToast('Data berhasil dicopy ke clipboard!', 'success');
}).catch(() => {
showToast('Gagal copy data', 'error');
});
}
// Export CSV
function exportCSV() {
const basePrice = document.getElementById('basePrice').value;
const tickSize = document.getElementById('tickSize').value;
let csv = `FarOneSquare Calculator - Square of 9 Level\n`;
csv += `Harga Dasar,${basePrice}\n`;
csv += `Tick Size,${tickSize}\n`;
csv += `Mode,${realtimeMode ? 'Real-time' : 'Manual'}\n`;
csv += `Generated,${new Date().toLocaleString('id-ID')}\n\n`;
csv += `DERAJAT,RESISTANCE,JARAK R,SUPPORT,JARAK S,TYPE\n`;
currentData.forEach(row => {
csv += `${row.degree},${row.resistance},${row.jarakR},${row.support},${row.jarakS},${row.type}\n`;
});
const blob = new Blob([csv], { type: 'text/csv;charset=utf-8;' });
const url = window.URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = `faronesquare_${basePrice}_${Date.now()}.csv`;
a.click();
window.URL.revokeObjectURL(url);
showToast('CSV berhasil didownload!', 'success');
}
// Export JSON
function exportJSON() {
const basePrice = document.getElementById('basePrice').value;
const tickSize = document.getElementById('tickSize').value;
const sqrtBase = Math.sqrt(basePrice);
const jsonData = {
app: 'FarOneSquare Calculator',
version: '2.1',
timestamp: new Date().toISOString(),
mode: realtimeMode ? 'realtime' : 'manual',
input: {
basePrice: basePrice,
tickSize: tickSize,
sqrtPrice: sqrtBase.toFixed(3)
},
summary: {
level360: currentData.find(d => d.degree === 360)
},
levels: currentData
};
const blob = new Blob([JSON.stringify(jsonData, null, 2)], { type: 'application/json' });
const url = window.URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = `faronesquare_${basePrice}_${Date.now()}.json`;
a.click();
window.URL.revokeObjectURL(url);
showToast('JSON berhasil didownload!', 'success');
}
// Toast notification
function showToast(message, type = 'info') {
const container = document.getElementById('toastContainer');
const toast = document.createElement('div');
const icons = {
success: 'fa-check-circle text-green-400',
error: 'fa-times-circle text-red-400',
info: 'fa-info-circle text-cyan-400'
};
const borders = {
success: 'border-green-400',
error: 'border-red-400',
info: 'border-cyan-400'
};
toast.className = `toast glass-card px-5 py-3 rounded-lg shadow-xl flex items-center gap-3 border-l-4 ${borders[type]}`;
toast.innerHTML = `
<i class="fas ${icons[type]}"></i>
<span class="text-white font-semibold text-sm">${message}</span>
`;
container.appendChild(toast);
setTimeout(() => {
toast.style.opacity = '0';
setTimeout(() => toast.remove(), 300);
}, 2700);
}
// Debounced auto-calculation for real-time mode
function debounceCalculate() {
if (!realtimeMode) return;
clearTimeout(debounceTimer);
debounceTimer = setTimeout(() => calculateLevels(false), 400);
}
// Toggle real-time mode
document.getElementById('realtimeToggle').addEventListener('change', function(e) {
realtimeMode = e.target.checked;
updateModeIndicator();
if (realtimeMode) {
showToast('Real-time mode ON - Update otomatis saat input berubah', 'success');
calculateLevels(false); // Calculate immediately
} else {
showToast('Manual mode ON - Klik Hitung untuk update', 'info');
}
});
// Input listeners
document.getElementById('basePrice').addEventListener('input', debounceCalculate);
document.getElementById('tickSize').addEventListener('input', debounceCalculate);
// Initial setup
updateModeIndicator();
calculateLevels();
// Keyboard shortcuts
document.addEventListener('keydown', (e) => {
if (e.ctrlKey || e.metaKey) {
if (e.key === 'c' && e.target.tagName !== 'INPUT') {
e.preventDefault();
copyResults();
}
if (e.key === 's') {
e.preventDefault();
exportCSV();
}
}
if (e.key === 'Enter' && !realtimeMode) {
calculateLevels(true);
}
});
</script>
<script>(function(){document.addEventListener("click",function(e){var a=e.target.closest("[data-product-id]");if(!a)return;e.preventDefault();var pid=a.getAttribute("data-product-id");if(pid)parent.postMessage({type:"ecto-artifact-link-click",productId:pid},"*")})})();</script>
</body>
</html>