add event_date column to event_knowledge and event_predictions tables; update related logic in admin panel and augorWorker
This commit is contained in:
parent
8c20cf3817
commit
c31f8b0b16
1 changed files with 43 additions and 30 deletions
73
admin.html
73
admin.html
|
|
@ -1277,10 +1277,6 @@ function renderIntelGraph(nodes, links) {
|
|||
|
||||
const g = svg.append('g');
|
||||
|
||||
svg.call(
|
||||
d3.zoom().scaleExtent([0.15, 5]).on('zoom', ev => g.attr('transform', ev.transform))
|
||||
);
|
||||
|
||||
// arrow marker
|
||||
svg.append('defs').append('marker')
|
||||
.attr('id', 'ig-arrow')
|
||||
|
|
@ -1296,32 +1292,27 @@ function renderIntelGraph(nodes, links) {
|
|||
|
||||
const maxCount = Math.max(...links.map(l => l.count), 1);
|
||||
|
||||
const zoomBehavior = d3.zoom().scaleExtent([0.1, 5]).on('zoom', ev => g.attr('transform', ev.transform));
|
||||
svg.call(zoomBehavior);
|
||||
|
||||
const simulation = d3.forceSimulation(nodes)
|
||||
.force('link', d3.forceLink(links).id(d => d.key).distance(110))
|
||||
.force('charge', d3.forceManyBody().strength(-320))
|
||||
.force('link', d3.forceLink(links).id(d => d.key).distance(150))
|
||||
.force('charge', d3.forceManyBody().strength(-500))
|
||||
.force('center', d3.forceCenter(width / 2, height / 2))
|
||||
.force('collide', d3.forceCollide(32));
|
||||
.force('collide', d3.forceCollide(40));
|
||||
|
||||
|
||||
const linkLines = g.append('g')
|
||||
.selectAll('line')
|
||||
.data(links)
|
||||
.join('line')
|
||||
.attr('stroke', '#1e293b')
|
||||
.attr('stroke-width', d => 1 + (d.count / maxCount) * 3.5)
|
||||
.attr('stroke-opacity', d => 0.35 + (d.count / maxCount) * 0.55)
|
||||
.attr('stroke', '#334155')
|
||||
.attr('stroke-width', d => 1 + (d.count / maxCount) * 3)
|
||||
.attr('stroke-opacity', d => 0.3 + (d.count / maxCount) * 0.6)
|
||||
.attr('marker-end', 'url(#ig-arrow)');
|
||||
|
||||
|
||||
const linkLabels = g.append('g')
|
||||
.selectAll('text')
|
||||
.data(links)
|
||||
.join('text')
|
||||
.text(d => d.type)
|
||||
.attr('font-size', 9)
|
||||
.attr('fill', '#334155')
|
||||
.attr('text-anchor', 'middle')
|
||||
.attr('pointer-events', 'none');
|
||||
// relationship type on hover only via title
|
||||
linkLines.append('title').text(d => `${d.type} (×${d.count})`);
|
||||
|
||||
|
||||
const nodeGroups = g.append('g')
|
||||
|
|
@ -1346,18 +1337,27 @@ function renderIntelGraph(nodes, links) {
|
|||
});
|
||||
|
||||
nodeGroups.append('circle')
|
||||
.attr('r', d => d.tracked ? 14 : 9)
|
||||
.attr('r', d => d.tracked ? 16 : 11)
|
||||
.attr('fill', d => d.tracked ? '#1e3a5f' : '#0f172a')
|
||||
.attr('stroke', d => d.tracked ? '#3b82f6' : '#475569')
|
||||
.attr('stroke-width', d => d.tracked ? 2 : 1.5);
|
||||
|
||||
nodeGroups.append('text')
|
||||
.text(d => d.ticker || d.name.slice(0, 7))
|
||||
// ticker label inside tracked nodes; short name below untracked nodes
|
||||
nodeGroups.filter(d => d.tracked).append('text')
|
||||
.text(d => d.ticker || d.name.slice(0, 5))
|
||||
.attr('text-anchor', 'middle')
|
||||
.attr('dominant-baseline', 'middle')
|
||||
.attr('font-size', d => d.tracked ? 9 : 8)
|
||||
.attr('font-weight', d => d.tracked ? '600' : '400')
|
||||
.attr('fill', d => d.tracked ? '#93c5fd' : '#64748b')
|
||||
.attr('font-size', 9)
|
||||
.attr('font-weight', '600')
|
||||
.attr('fill', '#93c5fd')
|
||||
.attr('pointer-events', 'none');
|
||||
|
||||
nodeGroups.filter(d => !d.tracked).append('text')
|
||||
.text(d => d.name.length > 12 ? d.name.slice(0, 11) + '…' : d.name)
|
||||
.attr('text-anchor', 'middle')
|
||||
.attr('y', 20)
|
||||
.attr('font-size', 9)
|
||||
.attr('fill', '#475569')
|
||||
.attr('pointer-events', 'none');
|
||||
|
||||
nodeGroups.append('title').text(d => d.name);
|
||||
|
|
@ -1370,12 +1370,25 @@ function renderIntelGraph(nodes, links) {
|
|||
.attr('x2', d => d.target.x)
|
||||
.attr('y2', d => d.target.y);
|
||||
|
||||
linkLabels
|
||||
.attr('x', d => (d.source.x + d.target.x) / 2)
|
||||
.attr('y', d => (d.source.y + d.target.y) / 2 - 4);
|
||||
|
||||
nodeGroups.attr('transform', d => `translate(${d.x},${d.y})`);
|
||||
});
|
||||
|
||||
// fit everything into view once the simulation has cooled enough
|
||||
simulation.on('end', () => {
|
||||
const bounds = g.node().getBBox();
|
||||
if (!bounds.width || !bounds.height) return;
|
||||
|
||||
const pad = 40;
|
||||
const scaleX = width / (bounds.width + pad * 2);
|
||||
const scaleY = height / (bounds.height + pad * 2);
|
||||
const scale = Math.min(scaleX, scaleY, 1);
|
||||
|
||||
const tx = width / 2 - scale * (bounds.x + bounds.width / 2);
|
||||
const ty = height / 2 - scale * (bounds.y + bounds.height / 2);
|
||||
|
||||
svg.transition().duration(600)
|
||||
.call(zoomBehavior.transform, d3.zoomIdentity.translate(tx, ty).scale(scale));
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue