|
|
import * as d3 from 'd3'; |
|
|
|
|
|
document.addEventListener('DOMContentLoaded', function() { |
|
|
|
|
|
const navLinks = document.querySelectorAll('nav a'); |
|
|
const sections = document.querySelectorAll('.dashboard-section'); |
|
|
|
|
|
navLinks.forEach(link => { |
|
|
link.addEventListener('click', function(e) { |
|
|
e.preventDefault(); |
|
|
const targetId = this.getAttribute('href').substring(1); |
|
|
|
|
|
|
|
|
sections.forEach(section => { |
|
|
section.classList.remove('active'); |
|
|
}); |
|
|
|
|
|
|
|
|
document.getElementById(targetId).classList.add('active'); |
|
|
|
|
|
|
|
|
navLinks.forEach(navLink => { |
|
|
navLink.parentElement.classList.remove('active'); |
|
|
}); |
|
|
this.parentElement.classList.add('active'); |
|
|
}); |
|
|
}); |
|
|
|
|
|
|
|
|
const closeBtn = document.querySelector('.close-notification'); |
|
|
const notification = document.querySelector('.notification'); |
|
|
|
|
|
if (closeBtn && notification) { |
|
|
closeBtn.addEventListener('click', function() { |
|
|
notification.style.display = 'none'; |
|
|
}); |
|
|
} |
|
|
|
|
|
|
|
|
renderCharts(); |
|
|
|
|
|
|
|
|
const deployButtons = document.querySelectorAll('.deploy-button'); |
|
|
deployButtons.forEach(button => { |
|
|
button.addEventListener('click', function() { |
|
|
|
|
|
showNotification('Model Deployment', 'Your selected AI model is being deployed. Please wait...', 'info'); |
|
|
|
|
|
|
|
|
setTimeout(() => { |
|
|
showNotification('Deployment Complete', 'Your AI model has been successfully deployed and is now active.', 'success'); |
|
|
}, 2000); |
|
|
}); |
|
|
}); |
|
|
|
|
|
|
|
|
const tierButtons = document.querySelectorAll('.tier-button'); |
|
|
tierButtons.forEach(button => { |
|
|
button.addEventListener('click', function() { |
|
|
const tierName = this.parentElement.querySelector('h3').textContent; |
|
|
showNotification('Subscription', `You're being redirected to subscribe to the ${tierName} data feed tier.`, 'info'); |
|
|
}); |
|
|
}); |
|
|
|
|
|
|
|
|
if (document.getElementById('research-lab')) { |
|
|
initResearchLab(); |
|
|
} |
|
|
|
|
|
|
|
|
if (document.getElementById('monetization-research')) { |
|
|
initMonetizationResearch(); |
|
|
} |
|
|
}); |
|
|
|
|
|
|
|
|
function renderSimpleCharts() { |
|
|
renderPerformanceChart(); |
|
|
renderDistributionChart(); |
|
|
renderRevenueChart(); |
|
|
renderPredictionChart(); |
|
|
} |
|
|
|
|
|
function renderPerformanceChart() { |
|
|
const container = document.getElementById('performanceChart'); |
|
|
if (!container) return; |
|
|
|
|
|
|
|
|
container.innerHTML = ''; |
|
|
|
|
|
|
|
|
const width = container.clientWidth; |
|
|
const height = container.clientHeight || 300; |
|
|
const margin = {top: 20, right: 30, bottom: 30, left: 40}; |
|
|
|
|
|
const svg = d3.select(container) |
|
|
.append('svg') |
|
|
.attr('width', width) |
|
|
.attr('height', height) |
|
|
.append('g') |
|
|
.attr('transform', `translate(${margin.left},${margin.top})`); |
|
|
|
|
|
|
|
|
const data = [ |
|
|
{month: 'Jan', tvl: 120, revenue: 10}, |
|
|
{month: 'Feb', tvl: 140, revenue: 15}, |
|
|
{month: 'Mar', tvl: 167, revenue: 22}, |
|
|
{month: 'Apr', tvl: 205, revenue: 34}, |
|
|
{month: 'May', tvl: 250, revenue: 55}, |
|
|
{month: 'Jun', tvl: 302, revenue: 78}, |
|
|
{month: 'Jul', tvl: 335, revenue: 120}, |
|
|
{month: 'Aug', tvl: 410, revenue: 190}, |
|
|
{month: 'Sep', tvl: 442, revenue: 250}, |
|
|
{month: 'Oct', tvl: 468, revenue: 320}, |
|
|
{month: 'Nov', tvl: 480, revenue: 380}, |
|
|
{month: 'Dec', tvl: 487, revenue: 427} |
|
|
]; |
|
|
|
|
|
|
|
|
const x = d3.scaleBand() |
|
|
.domain(data.map(d => d.month)) |
|
|
.range([0, width - margin.left - margin.right]) |
|
|
.padding(0.1); |
|
|
|
|
|
const y = d3.scaleLinear() |
|
|
.domain([0, d3.max(data, d => Math.max(d.tvl, d.revenue))]) |
|
|
.nice() |
|
|
.range([height - margin.top - margin.bottom, 0]); |
|
|
|
|
|
|
|
|
svg.append('g') |
|
|
.attr('transform', `translate(0,${height - margin.top - margin.bottom})`) |
|
|
.call(d3.axisBottom(x)); |
|
|
|
|
|
svg.append('g') |
|
|
.call(d3.axisLeft(y)); |
|
|
|
|
|
|
|
|
const tvlLine = d3.line() |
|
|
.x(d => x(d.month) + x.bandwidth()/2) |
|
|
.y(d => y(d.tvl)) |
|
|
.curve(d3.curveMonotoneX); |
|
|
|
|
|
const revenueLine = d3.line() |
|
|
.x(d => x(d.month) + x.bandwidth()/2) |
|
|
.y(d => y(d.revenue)) |
|
|
.curve(d3.curveMonotoneX); |
|
|
|
|
|
svg.append('path') |
|
|
.datum(data) |
|
|
.attr('fill', 'none') |
|
|
.attr('stroke', '#6c5ce7') |
|
|
.attr('stroke-width', 2) |
|
|
.attr('d', tvlLine); |
|
|
|
|
|
svg.append('path') |
|
|
.datum(data) |
|
|
.attr('fill', 'none') |
|
|
.attr('stroke', '#00cec9') |
|
|
.attr('stroke-width', 2) |
|
|
.attr('d', revenueLine); |
|
|
|
|
|
|
|
|
const legend = svg.append('g') |
|
|
.attr('font-family', 'sans-serif') |
|
|
.attr('font-size', 10) |
|
|
.attr('text-anchor', 'end') |
|
|
.selectAll('g') |
|
|
.data(['TVL Growth', 'Protocol Revenue']) |
|
|
.enter().append('g') |
|
|
.attr('transform', (d, i) => `translate(0,${i * 20})`); |
|
|
|
|
|
legend.append('rect') |
|
|
.attr('x', width - margin.left - margin.right - 19) |
|
|
.attr('width', 19) |
|
|
.attr('height', 19) |
|
|
.attr('fill', (d, i) => i === 0 ? '#6c5ce7' : '#00cec9'); |
|
|
|
|
|
legend.append('text') |
|
|
.attr('x', width - margin.left - margin.right - 24) |
|
|
.attr('y', 9.5) |
|
|
.attr('dy', '0.32em') |
|
|
.text(d => d); |
|
|
} |
|
|
|
|
|
function renderDistributionChart() { |
|
|
const container = document.getElementById('modelDistributionChart'); |
|
|
if (!container) return; |
|
|
|
|
|
|
|
|
container.innerHTML = ''; |
|
|
|
|
|
|
|
|
const width = container.clientWidth; |
|
|
const height = container.clientHeight || 250; |
|
|
|
|
|
const svg = d3.select(container) |
|
|
.append('svg') |
|
|
.attr('width', width) |
|
|
.attr('height', height) |
|
|
.append('g') |
|
|
.attr('transform', `translate(${width/2},${height/2})`); |
|
|
|
|
|
|
|
|
const data = [ |
|
|
{label: 'Yield Optimization', value: 35, color: '#00b894'}, |
|
|
{label: 'Risk Scoring', value: 25, color: '#ff7675'}, |
|
|
{label: 'Arbitrage Detection', value: 20, color: '#fdcb6e'}, |
|
|
{label: 'NFT Valuation', value: 15, color: '#6c5ce7'}, |
|
|
{label: 'Other', value: 5, color: '#b2bec3'} |
|
|
]; |
|
|
|
|
|
|
|
|
const pie = d3.pie() |
|
|
.value(d => d.value) |
|
|
.sort(null); |
|
|
|
|
|
const radius = Math.min(width, height) / 2 - 40; |
|
|
|
|
|
|
|
|
const arc = d3.arc() |
|
|
.innerRadius(radius * 0.6) |
|
|
.outerRadius(radius); |
|
|
|
|
|
|
|
|
const segments = svg.selectAll('path') |
|
|
.data(pie(data)) |
|
|
.enter() |
|
|
.append('path') |
|
|
.attr('d', arc) |
|
|
.attr('fill', d => d.data.color) |
|
|
.attr('stroke', 'white') |
|
|
.style('stroke-width', '2px'); |
|
|
|
|
|
|
|
|
const labelRadius = radius * 1.2; |
|
|
|
|
|
svg.selectAll('text') |
|
|
.data(pie(data)) |
|
|
.enter() |
|
|
.append('text') |
|
|
.attr('transform', d => { |
|
|
const pos = arc.centroid(d); |
|
|
const midAngle = d.startAngle + (d.endAngle - d.startAngle) / 2; |
|
|
pos[0] = labelRadius * Math.sin(midAngle); |
|
|
pos[1] = -labelRadius * Math.cos(midAngle); |
|
|
return `translate(${pos})`; |
|
|
}) |
|
|
.style('text-anchor', d => { |
|
|
const midAngle = d.startAngle + (d.endAngle - d.startAngle) / 2; |
|
|
return (midAngle < Math.PI ? 'start' : 'end'); |
|
|
}) |
|
|
.style('font-size', '12px') |
|
|
.text(d => d.data.label); |
|
|
} |
|
|
|
|
|
function renderRevenueChart() { |
|
|
const container = document.getElementById('revenueStreamsChart'); |
|
|
if (!container) return; |
|
|
|
|
|
|
|
|
container.innerHTML = ''; |
|
|
|
|
|
|
|
|
const width = container.clientWidth; |
|
|
const height = container.clientHeight || 250; |
|
|
const margin = {top: 20, right: 30, bottom: 40, left: 50}; |
|
|
|
|
|
const svg = d3.select(container) |
|
|
.append('svg') |
|
|
.attr('width', width) |
|
|
.attr('height', height) |
|
|
.append('g') |
|
|
.attr('transform', `translate(${margin.left},${margin.top})`); |
|
|
|
|
|
|
|
|
const data = [ |
|
|
{source: 'Model Marketplace', value: 120, color: 'rgba(108, 92, 231, 0.7)'}, |
|
|
{source: 'Data Feeds', value: 85, color: 'rgba(0, 206, 201, 0.7)'}, |
|
|
{source: 'Stablecoin Fees', value: 65, color: 'rgba(253, 121, 168, 0.7)'}, |
|
|
{source: 'Insurance Premiums', value: 45, color: 'rgba(0, 184, 148, 0.7)'}, |
|
|
{source: 'Credit Markets', value: 35, color: 'rgba(9, 132, 227, 0.7)'} |
|
|
]; |
|
|
|
|
|
|
|
|
const x = d3.scaleBand() |
|
|
.domain(data.map(d => d.source)) |
|
|
.range([0, width - margin.left - margin.right]) |
|
|
.padding(0.3); |
|
|
|
|
|
const y = d3.scaleLinear() |
|
|
.domain([0, d3.max(data, d => d.value)]) |
|
|
.nice() |
|
|
.range([height - margin.top - margin.bottom, 0]); |
|
|
|
|
|
|
|
|
svg.append('g') |
|
|
.attr('transform', `translate(0,${height - margin.top - margin.bottom})`) |
|
|
.call(d3.axisBottom(x)) |
|
|
.selectAll('text') |
|
|
.attr('transform', 'rotate(-45)') |
|
|
.style('text-anchor', 'end'); |
|
|
|
|
|
svg.append('g') |
|
|
.call(d3.axisLeft(y)); |
|
|
|
|
|
|
|
|
svg.selectAll('rect') |
|
|
.data(data) |
|
|
.enter() |
|
|
.append('rect') |
|
|
.attr('x', d => x(d.source)) |
|
|
.attr('y', d => y(d.value)) |
|
|
.attr('width', x.bandwidth()) |
|
|
.attr('height', d => height - margin.top - margin.bottom - y(d.value)) |
|
|
.attr('fill', d => d.color) |
|
|
.attr('rx', 5) |
|
|
.attr('ry', 5); |
|
|
} |
|
|
|
|
|
function renderPredictionChart() { |
|
|
const container = document.getElementById('predictionChart'); |
|
|
if (!container) return; |
|
|
|
|
|
|
|
|
container.innerHTML = ` |
|
|
<svg width="100%" height="100%" viewBox="0 0 100 50"> |
|
|
<path d="M0,40 C15,35 25,25 40,20 C55,15 65,22 80,18 C95,15 100,25 100,30" |
|
|
stroke="#f39c12" stroke-width="2" fill="none" /> |
|
|
<path d="M0,45 C20,40 30,35 50,30 C70,25 80,30 100,25" |
|
|
stroke="#0984e3" stroke-width="2" fill="none" /> |
|
|
</svg> |
|
|
`; |
|
|
} |
|
|
|
|
|
function loadLibraries() { |
|
|
return import('https://cdn.jsdelivr.net/npm/d3@7/+esm').then(d3Module => { |
|
|
window.d3 = d3Module; |
|
|
return { d3: window.d3 }; |
|
|
}); |
|
|
} |
|
|
|
|
|
function renderCharts() { |
|
|
loadLibraries().then(() => { |
|
|
renderSimpleCharts(); |
|
|
}).catch(error => { |
|
|
console.error('Error loading libraries:', error); |
|
|
}); |
|
|
} |
|
|
|
|
|
|
|
|
function showNotification(title, message, type = 'info') { |
|
|
|
|
|
let notificationCenter = document.querySelector('.notification-center'); |
|
|
if (!notificationCenter) { |
|
|
notificationCenter = document.createElement('div'); |
|
|
notificationCenter.className = 'notification-center'; |
|
|
document.body.appendChild(notificationCenter); |
|
|
} |
|
|
|
|
|
|
|
|
const notification = document.createElement('div'); |
|
|
notification.className = 'notification'; |
|
|
|
|
|
|
|
|
const iconSvg = document.createElementNS('http://www.w3.org/2000/svg', 'svg'); |
|
|
iconSvg.setAttribute('viewBox', '0 0 24 24'); |
|
|
iconSvg.setAttribute('width', '20'); |
|
|
iconSvg.setAttribute('height', '20'); |
|
|
|
|
|
let iconPath = ''; |
|
|
let iconClass = ''; |
|
|
|
|
|
switch(type) { |
|
|
case 'success': |
|
|
iconPath = ` |
|
|
<circle cx="12" cy="12" r="10" fill="none" stroke="currentColor" stroke-width="2"/> |
|
|
<path d="M8,12 L11,15 L16,9" fill="none" stroke="currentColor" stroke-width="2"/> |
|
|
`; |
|
|
iconClass = 'success'; |
|
|
break; |
|
|
case 'error': |
|
|
iconPath = ` |
|
|
<circle cx="12" cy="12" r="10" fill="none" stroke="currentColor" stroke-width="2"/> |
|
|
<line x1="8" y1="8" x2="16" y2="16" stroke="currentColor" stroke-width="2"/> |
|
|
<line x1="8" y1="16" x2="16" y2="8" stroke="currentColor" stroke-width="2"/> |
|
|
`; |
|
|
iconClass = 'error'; |
|
|
break; |
|
|
case 'warning': |
|
|
iconPath = ` |
|
|
<path d="M12,2 L22,22 L2,22 Z" stroke="currentColor" stroke-width="2" fill="none"/> |
|
|
<line x1="12" y1="10" x2="12" y2="14" stroke="currentColor" stroke-width="2"/> |
|
|
<circle cx="12" cy="18" r="1" fill="currentColor"/> |
|
|
`; |
|
|
iconClass = 'warning'; |
|
|
break; |
|
|
default: |
|
|
iconPath = ` |
|
|
<circle cx="12" cy="12" r="10" fill="none" stroke="currentColor" stroke-width="2"/> |
|
|
<line x1="12" y1="8" x2="12" y2="12" stroke="currentColor" stroke-width="2"/> |
|
|
<circle cx="12" cy="16" r="1" fill="currentColor"/> |
|
|
`; |
|
|
iconClass = 'info'; |
|
|
} |
|
|
|
|
|
iconSvg.innerHTML = iconPath; |
|
|
|
|
|
|
|
|
const notificationIcon = document.createElement('div'); |
|
|
notificationIcon.className = `notification-icon ${iconClass}`; |
|
|
notificationIcon.appendChild(iconSvg); |
|
|
|
|
|
const notificationContent = document.createElement('div'); |
|
|
notificationContent.className = 'notification-content'; |
|
|
notificationContent.innerHTML = `<h4>${title}</h4><p>${message}</p>`; |
|
|
|
|
|
const closeButton = document.createElement('button'); |
|
|
closeButton.className = 'close-notification'; |
|
|
closeButton.textContent = '×'; |
|
|
closeButton.addEventListener('click', function() { |
|
|
notification.style.opacity = '0'; |
|
|
setTimeout(() => { |
|
|
notification.remove(); |
|
|
}, 300); |
|
|
}); |
|
|
|
|
|
|
|
|
notification.appendChild(notificationIcon); |
|
|
notification.appendChild(notificationContent); |
|
|
notification.appendChild(closeButton); |
|
|
|
|
|
|
|
|
notificationCenter.appendChild(notification); |
|
|
|
|
|
|
|
|
setTimeout(() => { |
|
|
notification.style.opacity = '0'; |
|
|
setTimeout(() => { |
|
|
notification.remove(); |
|
|
}, 300); |
|
|
}, 5000); |
|
|
} |
|
|
|
|
|
|
|
|
let evolutionStep = 0; |
|
|
const evolutionInterval = setInterval(function() { |
|
|
if (evolutionStep < 5) { |
|
|
let modelType, improvement; |
|
|
|
|
|
switch(evolutionStep) { |
|
|
case 0: |
|
|
modelType = 'Yield Optimization'; |
|
|
improvement = '+2.3% APY improvement detected in yield models'; |
|
|
break; |
|
|
case 1: |
|
|
modelType = 'Risk Scoring'; |
|
|
improvement = 'New vulnerability pattern identified in lending protocol'; |
|
|
break; |
|
|
case 2: |
|
|
modelType = 'NFT Valuation'; |
|
|
improvement = 'Valuation model accuracy increased by 4.2%'; |
|
|
break; |
|
|
case 3: |
|
|
modelType = 'Arbitrage Detection'; |
|
|
improvement = 'New cross-chain arbitrage opportunity detected'; |
|
|
break; |
|
|
case 4: |
|
|
modelType = 'System'; |
|
|
improvement = 'Recursive self-improvement complete: v2.1 ready'; |
|
|
break; |
|
|
} |
|
|
|
|
|
showNotification(`AI Evolution: ${modelType}`, improvement, 'info'); |
|
|
evolutionStep++; |
|
|
} else { |
|
|
clearInterval(evolutionInterval); |
|
|
} |
|
|
}, 45000); |
|
|
|
|
|
|
|
|
setTimeout(function simulateMarketActivity() { |
|
|
const activities = [ |
|
|
{ title: 'Market Alert', message: 'Unusual trading volume detected in ETH/BTC pair', type: 'warning' }, |
|
|
{ title: 'Stablecoin Update', message: 'RME-USD successfully maintained peg during market volatility', type: 'success' }, |
|
|
{ title: 'New AI Model', message: 'A new Quantum-Symbolic hybrid model has been published to the marketplace', type: 'info' }, |
|
|
{ title: 'Federated Learning', message: 'Cross-instance knowledge transfer complete with 23% accuracy improvement', type: 'success' }, |
|
|
{ title: 'Security Alert', message: 'Potential adversarial attack detected and mitigated', type: 'warning' } |
|
|
]; |
|
|
|
|
|
const randomActivity = activities[Math.floor(Math.random() * activities.length)]; |
|
|
showNotification(randomActivity.title, randomActivity.message, randomActivity.type); |
|
|
|
|
|
|
|
|
const nextTime = 30000 + Math.random() * 60000; |
|
|
setTimeout(simulateMarketActivity, nextTime); |
|
|
}, 60000); |
|
|
|
|
|
|
|
|
function renderSymbolicNetwork() { |
|
|
const svgElement = document.getElementById('symbolNetwork'); |
|
|
if (!svgElement) return; |
|
|
|
|
|
|
|
|
const width = 400; |
|
|
const height = 200; |
|
|
|
|
|
const svg = d3.select(svgElement); |
|
|
|
|
|
|
|
|
const nodes = Array.from({ length: 15 }, (_, i) => ({ |
|
|
id: i, |
|
|
r: Math.random() * 5 + 3, |
|
|
group: Math.floor(Math.random() * 3) |
|
|
})); |
|
|
|
|
|
const links = []; |
|
|
for (let i = 0; i < nodes.length; i++) { |
|
|
const numLinks = Math.floor(Math.random() * 3) + 1; |
|
|
for (let j = 0; j < numLinks; j++) { |
|
|
const target = Math.floor(Math.random() * nodes.length); |
|
|
if (target !== i) { |
|
|
links.push({ source: i, target: target, value: Math.random() }); |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
const simulation = d3.forceSimulation(nodes) |
|
|
.force("link", d3.forceLink(links).id(d => d.id).distance(50)) |
|
|
.force("charge", d3.forceManyBody().strength(-30)) |
|
|
.force("center", d3.forceCenter(width / 2, height / 2)); |
|
|
|
|
|
|
|
|
const link = svg.append("g") |
|
|
.selectAll("line") |
|
|
.data(links) |
|
|
.enter().append("line") |
|
|
.style("stroke", "#a29bfe") |
|
|
.style("stroke-opacity", 0.6) |
|
|
.style("stroke-width", d => Math.sqrt(d.value) * 2); |
|
|
|
|
|
|
|
|
const node = svg.append("g") |
|
|
.selectAll("circle") |
|
|
.data(nodes) |
|
|
.enter().append("circle") |
|
|
.attr("r", d => d.r) |
|
|
.style("fill", d => ["#6c5ce7", "#00cec9", "#fd79a8"][d.group]) |
|
|
.call(d3.drag() |
|
|
.on("start", dragstarted) |
|
|
.on("drag", dragged) |
|
|
.on("end", dragended)); |
|
|
|
|
|
|
|
|
const pulsingNodes = svg.append("g") |
|
|
.selectAll("circle") |
|
|
.data(nodes.filter(d => Math.random() > 0.7)) |
|
|
.enter().append("circle") |
|
|
.attr("r", d => d.r + 5) |
|
|
.style("fill", "none") |
|
|
.style("stroke", d => ["#6c5ce7", "#00cec9", "#fd79a8"][d.group]) |
|
|
.style("stroke-opacity", 0.3) |
|
|
.style("stroke-width", 2); |
|
|
|
|
|
|
|
|
function pulsate() { |
|
|
pulsingNodes |
|
|
.transition() |
|
|
.duration(1500) |
|
|
.attr("r", d => d.r + 15) |
|
|
.style("stroke-opacity", 0.1) |
|
|
.transition() |
|
|
.duration(1500) |
|
|
.attr("r", d => d.r + 5) |
|
|
.style("stroke-opacity", 0.3) |
|
|
.on("end", pulsate); |
|
|
} |
|
|
|
|
|
pulsate(); |
|
|
|
|
|
simulation.on("tick", () => { |
|
|
link |
|
|
.attr("x1", d => Math.max(5, Math.min(width - 5, d.source.x))) |
|
|
.attr("y1", d => Math.max(5, Math.min(height - 5, d.source.y))) |
|
|
.attr("x2", d => Math.max(5, Math.min(width - 5, d.target.x))) |
|
|
.attr("y2", d => Math.max(5, Math.min(height - 5, d.target.y))); |
|
|
|
|
|
node |
|
|
.attr("cx", d => Math.max(5, Math.min(width - 5, d.x))) |
|
|
.attr("cy", d => Math.max(5, Math.min(height - 5, d.y))); |
|
|
|
|
|
pulsingNodes |
|
|
.attr("cx", d => Math.max(5, Math.min(width - 5, d.x))) |
|
|
.attr("cy", d => Math.max(5, Math.min(height - 5, d.y))); |
|
|
}); |
|
|
|
|
|
function dragstarted(event, d) { |
|
|
if (!event.active) simulation.alphaTarget(0.3).restart(); |
|
|
d.fx = d.x; |
|
|
d.fy = d.y; |
|
|
} |
|
|
|
|
|
function dragged(event, d) { |
|
|
d.fx = event.x; |
|
|
d.fy = event.y; |
|
|
} |
|
|
|
|
|
function dragended(event, d) { |
|
|
if (!event.active) simulation.alphaTarget(0); |
|
|
d.fx = null; |
|
|
d.fy = null; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
function renderLearningTrajectory() { |
|
|
const canvas = document.getElementById('trajectoryCanvas'); |
|
|
if (!canvas) return; |
|
|
|
|
|
|
|
|
const container = d3.select(canvas.parentNode); |
|
|
canvas.remove(); |
|
|
|
|
|
const width = container.node().clientWidth; |
|
|
const height = 200; |
|
|
|
|
|
const svg = container.append('svg') |
|
|
.attr('width', width) |
|
|
.attr('height', height); |
|
|
|
|
|
|
|
|
const data = [10, 15, 22, 28, 32, 35, 37, 45, 58, 67, 72, 76, 79, 82, 84, 85]; |
|
|
|
|
|
|
|
|
const x = d3.scaleLinear() |
|
|
.domain([0, data.length - 1]) |
|
|
.range([20, width - 20]); |
|
|
|
|
|
const y = d3.scaleLinear() |
|
|
.domain([0, 100]) |
|
|
.range([height - 20, 20]); |
|
|
|
|
|
|
|
|
const line = d3.line() |
|
|
.x((d, i) => x(i)) |
|
|
.y(d => y(d)) |
|
|
.curve(d3.curveMonotoneX); |
|
|
|
|
|
|
|
|
svg.append('path') |
|
|
.datum(data) |
|
|
.attr('fill', 'none') |
|
|
.attr('stroke', '#6c5ce7') |
|
|
.attr('stroke-width', 2) |
|
|
.attr('d', line); |
|
|
|
|
|
|
|
|
const area = d3.area() |
|
|
.x((d, i) => x(i)) |
|
|
.y0(height - 20) |
|
|
.y1(d => y(d)) |
|
|
.curve(d3.curveMonotoneX); |
|
|
|
|
|
svg.append('path') |
|
|
.datum(data) |
|
|
.attr('fill', 'rgba(108, 92, 231, 0.1)') |
|
|
.attr('d', area); |
|
|
} |
|
|
|
|
|
|
|
|
function updateResearchProgress() { |
|
|
const progressBar = document.querySelector('.research-progress .progress-value'); |
|
|
const progressLabel = document.querySelector('.progress-label span:last-child'); |
|
|
|
|
|
if (progressBar && progressLabel) { |
|
|
const currentProgress = parseInt(progressBar.style.width); |
|
|
let newProgress = currentProgress + Math.floor(Math.random() * 10) + 5; |
|
|
|
|
|
|
|
|
if (newProgress > 95) newProgress = 95; |
|
|
|
|
|
progressBar.style.width = newProgress + '%'; |
|
|
progressLabel.textContent = newProgress + '%'; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
function initResearchLab() { |
|
|
loadLibraries().then(() => { |
|
|
renderSymbolicNetwork(); |
|
|
renderLearningTrajectory(); |
|
|
|
|
|
|
|
|
setTimeout(() => { |
|
|
renderMonetizationData(); |
|
|
}, 500); |
|
|
|
|
|
|
|
|
const actionButtons = document.querySelectorAll('.research-action-panel button'); |
|
|
actionButtons.forEach(button => { |
|
|
button.addEventListener('click', function() { |
|
|
showNotification('Deep Research', 'Initiating advanced research protocol. Processing data...', 'info'); |
|
|
|
|
|
|
|
|
setTimeout(() => { |
|
|
const researchFindings = [ |
|
|
'Quantum-symbolic pattern discovered in market data. Potential arbitrage strategy identified with 15.2% ROI.', |
|
|
'Recursive AI model evolution complete. Performance improved by 23.7% with monetization potential of $34K/month.', |
|
|
'New monetization pathway identified: AI-driven prediction markets with 87% accuracy and estimated $182K annual revenue.', |
|
|
'Algorithmic stablecoin simulation shows 99.8% peg maintenance with recursive income generation of 12.3% APY.' |
|
|
]; |
|
|
|
|
|
const randomFinding = researchFindings[Math.floor(Math.random() * researchFindings.length)]; |
|
|
showNotification('Research Complete', randomFinding, 'success'); |
|
|
|
|
|
|
|
|
updateResearchProgress(); |
|
|
}, 3000); |
|
|
}); |
|
|
}); |
|
|
|
|
|
|
|
|
updateMonetizationMetrics(); |
|
|
}).catch(error => { |
|
|
console.error('Error loading libraries:', error); |
|
|
}); |
|
|
} |
|
|
|
|
|
|
|
|
function updateMonetizationMetrics() { |
|
|
const metrics = { |
|
|
'modelSales': { base: 2450, variance: 150 }, |
|
|
'subscriptions': { base: 3850, variance: 200 }, |
|
|
'apiCalls': { base: 1250000, variance: 50000 }, |
|
|
'defiYield': { base: 8.4, variance: 0.5 }, |
|
|
'revenueQoQ': { base: 23.5, variance: 2.1 } |
|
|
}; |
|
|
|
|
|
const updateMetric = (id, value) => { |
|
|
const element = document.getElementById(id); |
|
|
if (element) element.textContent = value; |
|
|
}; |
|
|
|
|
|
|
|
|
Object.keys(metrics).forEach(metricId => { |
|
|
const metric = metrics[metricId]; |
|
|
const value = metric.base + (Math.random() * 2 - 1) * metric.variance; |
|
|
|
|
|
if (metricId === 'apiCalls') { |
|
|
updateMetric(metricId, `${Math.round(value).toLocaleString()}`); |
|
|
} else if (metricId === 'defiYield' || metricId === 'revenueQoQ') { |
|
|
updateMetric(metricId, `${value.toFixed(1)}%`); |
|
|
} else { |
|
|
updateMetric(metricId, `$${Math.round(value).toLocaleString()}`); |
|
|
} |
|
|
}); |
|
|
|
|
|
|
|
|
setTimeout(updateMonetizationMetrics, 15000); |
|
|
} |
|
|
|
|
|
|
|
|
function initMonetizationResearch() { |
|
|
loadLibraries().then(() => { |
|
|
renderMonetizationData(); |
|
|
initRecursiveModels(); |
|
|
updateRMEMetrics(); |
|
|
renderSymbolicSequence(); |
|
|
}); |
|
|
} |
|
|
|
|
|
|
|
|
function renderSymbolicSequence() { |
|
|
const canvas = document.getElementById('symbolicSequenceCanvas'); |
|
|
if (!canvas) return; |
|
|
|
|
|
const ctx = canvas.getContext('2d'); |
|
|
const width = canvas.width; |
|
|
const height = canvas.height; |
|
|
|
|
|
|
|
|
ctx.clearRect(0, 0, width, height); |
|
|
|
|
|
|
|
|
const gradient = ctx.createLinearGradient(0, 0, width, 0); |
|
|
gradient.addColorStop(0, 'rgba(108, 92, 231, 0.1)'); |
|
|
gradient.addColorStop(0.5, 'rgba(0, 206, 201, 0.1)'); |
|
|
gradient.addColorStop(1, 'rgba(253, 121, 168, 0.1)'); |
|
|
ctx.fillStyle = gradient; |
|
|
ctx.fillRect(0, 0, width, height); |
|
|
|
|
|
|
|
|
ctx.font = '16px Monaco, Courier New, monospace'; |
|
|
ctx.fillStyle = '#6c5ce7'; |
|
|
ctx.textAlign = 'center'; |
|
|
|
|
|
const formula1 = "Qi∞(Φ⟨Creativity⟩ ⊗ Λ⟨Recursive Logic⟩)"; |
|
|
const formula2 = "→ Σ⟨Exploration⟩ ∇⟨Adaptive Insight⟩"; |
|
|
const formula3 = "→ Ω⟨Market Resonance⟩ ⊕ Θ⟨Quantum Integration⟩"; |
|
|
const formula4 = "→ Δ⟨Continuous Innovation⟩"; |
|
|
|
|
|
ctx.fillText(formula1, width/2, height/5); |
|
|
ctx.fillText(formula2, width/2, 2*height/5); |
|
|
ctx.fillText(formula3, width/2, 3*height/5); |
|
|
ctx.fillText(formula4, width/2, 4*height/5); |
|
|
|
|
|
|
|
|
const particles = []; |
|
|
for (let i = 0; i < 50; i++) { |
|
|
particles.push({ |
|
|
x: Math.random() * width, |
|
|
y: Math.random() * height, |
|
|
radius: Math.random() * 3 + 1, |
|
|
color: `rgba(${Math.floor(Math.random() * 100 + 100)}, ${Math.floor(Math.random() * 100 + 100)}, ${Math.floor(Math.random() * 100 + 150)}, 0.5)`, |
|
|
speedX: Math.random() * 1 - 0.5, |
|
|
speedY: Math.random() * 1 - 0.5 |
|
|
}); |
|
|
} |
|
|
|
|
|
function animateParticles() { |
|
|
ctx.clearRect(0, 0, width, height); |
|
|
|
|
|
|
|
|
ctx.fillStyle = gradient; |
|
|
ctx.fillRect(0, 0, width, height); |
|
|
|
|
|
|
|
|
ctx.font = '16px Monaco, Courier New, monospace'; |
|
|
ctx.fillStyle = '#6c5ce7'; |
|
|
ctx.textAlign = 'center'; |
|
|
ctx.fillText(formula1, width/2, height/5); |
|
|
ctx.fillText(formula2, width/2, 2*height/5); |
|
|
ctx.fillText(formula3, width/2, 3*height/5); |
|
|
ctx.fillText(formula4, width/2, 4*height/5); |
|
|
|
|
|
|
|
|
particles.forEach(particle => { |
|
|
ctx.beginPath(); |
|
|
ctx.arc(particle.x, particle.y, particle.radius, 0, Math.PI * 2); |
|
|
ctx.fillStyle = particle.color; |
|
|
ctx.fill(); |
|
|
|
|
|
particle.x += particle.speedX; |
|
|
particle.y += particle.speedY; |
|
|
|
|
|
|
|
|
if (particle.x < 0) particle.x = width; |
|
|
if (particle.x > width) particle.x = 0; |
|
|
if (particle.y < 0) particle.y = height; |
|
|
if (particle.y > height) particle.y = 0; |
|
|
}); |
|
|
|
|
|
requestAnimationFrame(animateParticles); |
|
|
} |
|
|
|
|
|
animateParticles(); |
|
|
} |
|
|
|
|
|
|
|
|
function initRecursiveModels() { |
|
|
const canvas = document.getElementById('recursiveModelCanvas'); |
|
|
if (!canvas) return; |
|
|
|
|
|
const ctx = canvas.getContext('2d'); |
|
|
const width = canvas.width; |
|
|
const height = canvas.height; |
|
|
|
|
|
|
|
|
const nodes = []; |
|
|
for (let i = 0; i < 20; i++) { |
|
|
nodes.push({ |
|
|
x: Math.random() * width, |
|
|
y: Math.random() * height, |
|
|
radius: Math.random() * 10 + 5, |
|
|
color: i < 5 ? '#6c5ce7' : (i < 10 ? '#00cec9' : '#fd79a8'), |
|
|
connections: [] |
|
|
}); |
|
|
} |
|
|
|
|
|
|
|
|
nodes.forEach((node, index) => { |
|
|
const numConnections = Math.floor(Math.random() * 3) + 1; |
|
|
for (let i = 0; i < numConnections; i++) { |
|
|
const targetIndex = Math.floor(Math.random() * nodes.length); |
|
|
if (targetIndex !== index) { |
|
|
node.connections.push(targetIndex); |
|
|
} |
|
|
} |
|
|
}); |
|
|
|
|
|
function render() { |
|
|
ctx.clearRect(0, 0, width, height); |
|
|
|
|
|
|
|
|
nodes.forEach((node, index) => { |
|
|
node.connections.forEach(targetIndex => { |
|
|
const target = nodes[targetIndex]; |
|
|
ctx.beginPath(); |
|
|
ctx.moveTo(node.x, node.y); |
|
|
ctx.lineTo(target.x, target.y); |
|
|
ctx.strokeStyle = 'rgba(108, 92, 231, 0.2)'; |
|
|
ctx.lineWidth = 1; |
|
|
ctx.stroke(); |
|
|
}); |
|
|
}); |
|
|
|
|
|
|
|
|
nodes.forEach(node => { |
|
|
ctx.beginPath(); |
|
|
ctx.arc(node.x, node.y, node.radius, 0, Math.PI * 2); |
|
|
ctx.fillStyle = node.color; |
|
|
ctx.fill(); |
|
|
|
|
|
|
|
|
ctx.beginPath(); |
|
|
ctx.arc(node.x, node.y, node.radius + 3 + Math.sin(Date.now() / 500) * 2, 0, Math.PI * 2); |
|
|
ctx.strokeStyle = node.color.replace(')', ', 0.3)').replace('rgb', 'rgba'); |
|
|
ctx.stroke(); |
|
|
|
|
|
|
|
|
node.x += (Math.random() * 2 - 1) * 0.5; |
|
|
node.y += (Math.random() * 2 - 1) * 0.5; |
|
|
|
|
|
|
|
|
if (node.x < node.radius) node.x = node.radius; |
|
|
if (node.x > width - node.radius) node.x = width - node.radius; |
|
|
if (node.y < node.radius) node.y = node.radius; |
|
|
if (node.y > height - node.radius) node.y = height - node.radius; |
|
|
}); |
|
|
|
|
|
requestAnimationFrame(render); |
|
|
} |
|
|
|
|
|
render(); |
|
|
} |
|
|
|
|
|
|
|
|
function updateRMEMetrics() { |
|
|
const metrics = { |
|
|
'modelMarketplace': { base: 2840, variance: 160 }, |
|
|
'dataFeeds': { base: 4250, variance: 220 }, |
|
|
'quantumComputing': { base: 1650, variance: 120 }, |
|
|
'recursiveGrowth': { base: 32.7, variance: 1.8 }, |
|
|
'monetizationIndex': { base: 87.3, variance: 2.5 } |
|
|
}; |
|
|
|
|
|
function updateMetric(id, value, format = 'number') { |
|
|
const element = document.getElementById(id); |
|
|
if (!element) return; |
|
|
|
|
|
if (format === 'currency') { |
|
|
element.textContent = `$${Math.round(value).toLocaleString()}`; |
|
|
} else if (format === 'percent') { |
|
|
element.textContent = `${value.toFixed(1)}%`; |
|
|
} else { |
|
|
element.textContent = value.toLocaleString(); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
Object.keys(metrics).forEach(metricId => { |
|
|
const metric = metrics[metricId]; |
|
|
const value = metric.base + (Math.random() * 2 - 1) * metric.variance; |
|
|
const format = metricId.includes('Growth') || metricId.includes('Index') ? 'percent' : 'currency'; |
|
|
updateMetric(metricId, value, format); |
|
|
}); |
|
|
|
|
|
|
|
|
setTimeout(updateRMEMetrics, 8000); |
|
|
} |
|
|
|
|
|
|
|
|
function renderMonetizationData() { |
|
|
const monetizationCtx = document.getElementById('monetizationChart'); |
|
|
if (!monetizationCtx) return; |
|
|
|
|
|
|
|
|
const container = d3.select(monetizationCtx); |
|
|
container.html(''); |
|
|
|
|
|
const width = container.node().clientWidth; |
|
|
const height = container.node().clientHeight || 300; |
|
|
|
|
|
const svg = container.append('svg') |
|
|
.attr('width', width) |
|
|
.attr('height', height); |
|
|
|
|
|
|
|
|
const centerX = width / 2; |
|
|
const centerY = height / 2; |
|
|
const radius = Math.min(width, height) / 2 - 40; |
|
|
|
|
|
|
|
|
const categories = [ |
|
|
'AI Model Marketplace', |
|
|
'Data Feed Subscriptions', |
|
|
'DeFi Integration', |
|
|
'Quantum-Symbolic Risk', |
|
|
'Insurance Products', |
|
|
'Stablecoin Revenues' |
|
|
]; |
|
|
|
|
|
const angleSlice = Math.PI * 2 / categories.length; |
|
|
|
|
|
|
|
|
categories.forEach((cat, i) => { |
|
|
const angle = i * angleSlice - Math.PI / 2; |
|
|
const lineX2 = centerX + radius * Math.cos(angle); |
|
|
const lineY2 = centerY + radius * Math.sin(angle); |
|
|
|
|
|
svg.append('line') |
|
|
.attr('x1', centerX) |
|
|
.attr('y1', centerY) |
|
|
.attr('x2', lineX2) |
|
|
.attr('y2', lineY2) |
|
|
.attr('stroke', '#dfe6e9') |
|
|
.attr('stroke-width', 1); |
|
|
|
|
|
|
|
|
const labelX = centerX + (radius + 20) * Math.cos(angle); |
|
|
const labelY = centerY + (radius + 20) * Math.sin(angle); |
|
|
|
|
|
svg.append('text') |
|
|
.attr('x', labelX) |
|
|
.attr('y', labelY) |
|
|
.attr('text-anchor', 'middle') |
|
|
.attr('alignment-baseline', 'middle') |
|
|
.attr('font-size', '10px') |
|
|
.text(cat); |
|
|
}); |
|
|
|
|
|
|
|
|
[0.2, 0.4, 0.6, 0.8, 1].forEach(r => { |
|
|
svg.append('circle') |
|
|
.attr('cx', centerX) |
|
|
.attr('cy', centerY) |
|
|
.attr('r', radius * r) |
|
|
.attr('fill', 'none') |
|
|
.attr('stroke', '#dfe6e9') |
|
|
.attr('stroke-width', 1); |
|
|
}); |
|
|
|
|
|
|
|
|
const currentData = [65, 78, 35, 28, 42, 30].map(val => val / 100); |
|
|
const potentialData = [85, 90, 75, 68, 80, 85].map(val => val / 100); |
|
|
|
|
|
|
|
|
function drawPolygon(data, color, opacity) { |
|
|
const points = data.map((val, i) => { |
|
|
const angle = i * angleSlice - Math.PI / 2; |
|
|
const x = centerX + radius * val * Math.cos(angle); |
|
|
const y = centerY + radius * val * Math.sin(angle); |
|
|
return `${x},${y}`; |
|
|
}).join(' '); |
|
|
|
|
|
svg.append('polygon') |
|
|
.attr('points', points) |
|
|
.attr('fill', color) |
|
|
.attr('fill-opacity', opacity) |
|
|
.attr('stroke', color) |
|
|
.attr('stroke-width', 2); |
|
|
} |
|
|
|
|
|
drawPolygon(currentData, 'rgba(108, 92, 231, 1)', 0.2); |
|
|
drawPolygon(potentialData, 'rgba(0, 206, 201, 1)', 0.2); |
|
|
|
|
|
|
|
|
const legend = svg.append('g') |
|
|
.attr('transform', `translate(${width - 140},20)`); |
|
|
|
|
|
const legendItems = [ |
|
|
{label: 'Current Revenue', color: 'rgba(108, 92, 231, 1)'}, |
|
|
{label: 'Growth Potential', color: 'rgba(0, 206, 201, 1)'} |
|
|
]; |
|
|
|
|
|
legendItems.forEach((item, i) => { |
|
|
legend.append('rect') |
|
|
.attr('x', 0) |
|
|
.attr('y', i * 20) |
|
|
.attr('width', 15) |
|
|
.attr('height', 15) |
|
|
.attr('fill', item.color) |
|
|
.attr('fill-opacity', 0.2) |
|
|
.attr('stroke', item.color); |
|
|
|
|
|
legend.append('text') |
|
|
.attr('x', 20) |
|
|
.attr('y', i * 20 + 12) |
|
|
.attr('font-size', '12px') |
|
|
.text(item.label); |
|
|
}); |
|
|
|
|
|
|
|
|
const forecastCtx = document.getElementById('forecastChart'); |
|
|
if (!forecastCtx) return; |
|
|
|
|
|
|
|
|
const forecastContainer = d3.select(forecastCtx); |
|
|
forecastContainer.html(''); |
|
|
|
|
|
const forecastWidth = forecastContainer.node().clientWidth; |
|
|
const forecastHeight = forecastContainer.node().clientHeight || 300; |
|
|
const margin = {top: 20, right: 60, bottom: 30, left: 60}; |
|
|
|
|
|
const forecastSvg = forecastContainer.append('svg') |
|
|
.attr('width', forecastWidth) |
|
|
.attr('height', forecastHeight) |
|
|
.append('g') |
|
|
.attr('transform', `translate(${margin.left},${margin.top})`); |
|
|
|
|
|
|
|
|
const months = 24; |
|
|
const baselineGrowth = Array.from({length: months}, (_, i) => 1000 * Math.pow(1.08, i)); |
|
|
const recursiveGrowth = Array.from({length: months}, (_, i) => 1000 * Math.pow(1.15, i)); |
|
|
const quantumBoostGrowth = Array.from({length: months}, (_, i) => { |
|
|
const quantumBoost = i > 12 ? 1.2 : 1; |
|
|
return 1000 * Math.pow(1.15, i) * quantumBoost; |
|
|
}); |
|
|
|
|
|
|
|
|
const xForecast = d3.scaleLinear() |
|
|
.domain([1, months]) |
|
|
.range([0, forecastWidth - margin.left - margin.right]); |
|
|
|
|
|
const yForecast = d3.scaleLinear() |
|
|
.domain([0, d3.max(quantumBoostGrowth)]) |
|
|
.nice() |
|
|
.range([forecastHeight - margin.top - margin.bottom, 0]); |
|
|
|
|
|
|
|
|
forecastSvg.append('g') |
|
|
.attr('transform', `translate(0,${forecastHeight - margin.top - margin.bottom})`) |
|
|
.call(d3.axisBottom(xForecast).ticks(6).tickFormat(d => `M${d}`)); |
|
|
|
|
|
forecastSvg.append('g') |
|
|
.call(d3.axisLeft(yForecast)); |
|
|
|
|
|
|
|
|
const line = d3.line() |
|
|
.x((d, i) => xForecast(i + 1)) |
|
|
.y(d => yForecast(d)) |
|
|
.curve(d3.curveMonotoneX); |
|
|
|
|
|
|
|
|
forecastSvg.append('path') |
|
|
.datum(baselineGrowth) |
|
|
.attr('fill', 'none') |
|
|
.attr('stroke', '#dfe6e9') |
|
|
.attr('stroke-width', 2) |
|
|
.attr('d', line); |
|
|
|
|
|
forecastSvg.append('path') |
|
|
.datum(recursiveGrowth) |
|
|
.attr('fill', 'none') |
|
|
.attr('stroke', '#6c5ce7') |
|
|
.attr('stroke-width', 2) |
|
|
.attr('d', line); |
|
|
|
|
|
forecastSvg.append('path') |
|
|
.datum(quantumBoostGrowth) |
|
|
.attr('fill', 'none') |
|
|
.attr('stroke', '#00cec9') |
|
|
.attr('stroke-width', 2) |
|
|
.attr('d', line); |
|
|
|
|
|
|
|
|
const forecastLegend = forecastSvg.append('g') |
|
|
.attr('transform', `translate(${forecastWidth - margin.left - margin.right - 150},0)`); |
|
|
|
|
|
const forecastLegendItems = [ |
|
|
{label: 'Baseline Growth', color: '#dfe6e9'}, |
|
|
{label: 'Recursive Growth', color: '#6c5ce7'}, |
|
|
{label: 'Quantum-Boosted', color: '#00cec9'} |
|
|
]; |
|
|
|
|
|
forecastLegendItems.forEach((item, i) => { |
|
|
forecastLegend.append('line') |
|
|
.attr('x1', 0) |
|
|
.attr('y1', i * 20 + 10) |
|
|
.attr('x2', 20) |
|
|
.attr('y2', i * 20 + 10) |
|
|
.attr('stroke', item.color) |
|
|
.attr('stroke-width', 2); |
|
|
|
|
|
forecastLegend.append('text') |
|
|
.attr('x', 25) |
|
|
.attr('y', i * 20 + 15) |
|
|
.attr('font-size', '12px') |
|
|
.text(item.label); |
|
|
}); |
|
|
} |