PageSourceSearch

https://embed-goodfire-attr-graph.netlify.app/attribution_graph/init-cg.js

js embed-goodfire-attr-graph.netlify.app collected 2026-10-03 10:41:52 UTC 7,827 bytes, 206 lines download raw bytes

1window.initCg = async function (sel, slug, {clickedId, clickedIdCb, isModal, isGridsnap} = {}){
2  var data = await util.getFile(`/graph_data/${slug}.json`)
3  console.log(data)
4  
5  var visState = {
6    pinnedIds: [],
7    hiddenIds: [], 
8    hoveredId: null,
9    hoveredNodeId: null,
10    hoveredCtxIdx: null,
11    clickedId: null, 
12    clickedCtxIdx: null,
13    linkType: 'both',
14    isShowAllLinks: '',
15    isSyncEnabled: '',
16    subgraph: null,
17    isEditMode: 1,
18    isHideLayer: data.metadata.scan == util.scanSlugToName.h35 || data.metadata.scan == util.scanSlugToName.moc, 
19    sg_pos: '',
20    isModal: true,
21    isGridsnap,
22    ...data.qParams
23  }
24  
25  if (visState.clickedId?.includes('supernode')) delete visState.clickedId
26  if (clickedId && clickedId != 'null' && !clickedId.includes('supernode-')) visState.clickedId = clickedId
27  if (!visState.clickedId || visState.clickedId == 'null' || visState.clickedId == 'undefined') visState.clickedId = data.nodes.find(d => d.isLogit)?.nodeId
28  
29  if (visState.pinnedIds.replace) visState.pinnedIds = visState.pinnedIds.split(',')
30  if (visState.hiddenIds.replace) visState.hiddenIds = visState.hiddenIds.split(',')
31
32  await utilCg.formatData(data, visState)
33  
34  var renderAll = util.initRenderAll(['hClerpUpdate', 'clickedId', 'hiddenIds', 'pinnedIds', 'linkType', 'isShowAllLinks', 'features', 'isSyncEnabled', 'shouldSortByWeight', 'hoveredId'])
35
36  function colorNodes() {
37    data.nodes.forEach(d => d.nodeColor = '#fff')
38  }
39  colorNodes()
40
41  // global link color —  the color scale skips #fff so links are visible
42  // TODO: weight by input sum instead
43  function colorLinks() {
44    var absMax = d3.max(data.links, d => d.absWeight)
45    var _linearAbsScale = d3.scaleLinear().domain([-absMax, absMax])
46    var _linearPctScale = d3.scaleLinear().domain([-.4, .4])
47    var _linearTScale = d3.scaleLinear().domain([0, .5, .5, 1]).range([0, .5 - .001, .5 + .001, 1])
48
49    var widthScale = d3.scaleSqrt().domain([0, 1]).range([.00001, 3])
50
51    utilCg.pctInputColorFn = d => d3.interpolatePRGn(_linearTScale(_linearPctScale(d)))
52
53    data.links.forEach(d => {
54      // d.color = d3.interpolatePRGn(_linearTScale(_linearAbsScale(d.weight)))
55      d.strokeWidth = widthScale(Math.abs(d.pctInput))
56      d.pctInputColor = utilCg.pctInputColorFn(d.pctInput)
57      d.color = d3.interpolatePRGn(_linearTScale(_linearPctScale(d.pctInput)))
58    })
59  }
60  colorLinks()
61
62  renderAll.hClerpUpdate.fns.push(() => utilCg.hClerpUpdateFn(null, data))
63
64  renderAll.hoveredId.fns.push(() => {
65    // use hovered node if possible, otherwise use last occurence of feature
66    var targetCtxIdx = visState.hoveredCtxIdx ?? 999
67    var hoveredNodes = data.nodes.filter(n => n.featureId == visState.hoveredId)
68    var node = d3.sort(hoveredNodes, d => Math.abs(d.ctx_idx - targetCtxIdx))[0]
69    visState.hoveredNodeId = node?.nodeId
70  })
71
72  // set tmpClickedLink w/ strength of all the links connected the clickedNode
73  renderAll.clickedId.fns.push(() => {
74    clickedIdCb?.(visState.clickedId)
75
76    var node = data.nodes.idToNode[visState.clickedId]
77    if (!node){
78      // for a clicked supernode, sum over memberNode links to make tmpClickedLink
79      if (visState.clickedId?.startsWith('supernode-')) {
80        node = {
81          nodeId: visState.clickedId,
82          memberNodes: visState.subgraph.supernodes[+visState.clickedId.split('-')[1]]
83            .slice(1)
84            .map(id => data.nodes.idToNode[id])
85        }
86        node.memberSet = new Set(node.memberNodes.map(d => d.nodeId))
87
88        function combineLinks(links, isSrc) {
89          return d3.nestBy(links, d => isSrc ? d.sourceNode.nodeId : d.targetNode.nodeId)
90            .map(links => ({
91              source: isSrc ? links[0].sourceNode.nodeId : visState.clickedId,
92              target: isSrc ? visState.clickedId : links[0].targetNode.nodeId,
93              sourceNode: isSrc ? links[0].sourceNode : node,
94              targetNode: isSrc ? node : links[0].targetNode,
95              weight: d3.sum(links, d => d.weight),
96              absWeight: Math.abs(d3.sum(links, d => d.weight))
97            }))
98        }
99
100        node.sourceLinks = combineLinks(node.memberNodes.flatMap(d => d.sourceLinks), true)
101        node.targetLinks = combineLinks(node.memberNodes.flatMap(d => d.targetLinks), false)
102      } else {
103        return data.nodes.forEach(d => {
104          d.tmpClickedLink = null
105          d.tmpClickedSourceLink = null
106          d.tmpClickedTargetLink = null
107        })
108      }
109    }
110
111    var connectedLinks = [...node.sourceLinks, ...node.targetLinks]
112    var max = d3.max(connectedLinks, d => d.absWeight)
113    var colorScale = d3.scaleSequential(d3.interpolatePRGn).domain([-max*1.1, max*1.1])
114
115    // allowing supernode links means each node can have a both tmpClickedSourceLink and tmpClickedTargetLink
116    // currently we render bidirectional links where possible, falling back to the target side links otherwises
117    var nodeIdToSourceLink = {}
118    var nodeIdToTargetLink = {}
119    var featureIdToLink = {}
120    connectedLinks.forEach(link => {
121      if (link.sourceNode === node) {
122        nodeIdToTargetLink[link.targetNode.nodeId] = link
123        featureIdToLink[link.targetNode.featureId] = link
124        link.tmpClickedCtxOffset = link.targetNode.ctx_idx - node.ctx_idx
125      }
126      if (link.targetNode === node) {
127        nodeIdToSourceLink[link.sourceNode.nodeId] = link
128        featureIdToLink[link.sourceNode.featureId] = link
129        link.tmpClickedCtxOffset = link.sourceNode.ctx_idx - node.ctx_idx
130      }
131      // link.tmpColor = colorScale(link.pctInput)
132      link.tmpColor = link.pctInputColor
133    })
134
135    data.nodes.forEach(d => {
136      var link = nodeIdToSourceLink[d.nodeId] || nodeIdToTargetLink[d.nodeId]
137      d.tmpClickedLink = link
138      d.tmpClickedSourceLink = nodeIdToSourceLink[d.nodeId]
139      d.tmpClickedTargetLink = nodeIdToTargetLink[d.nodeId]
140    })
141
142    data.features.forEach(d => {
143      var link = featureIdToLink[d.featureId]
144      d.tmpClickedLink = link
145    })
146  })
147
148  function initGridsnap() {
149    var gridData = [
150      // {cur: {x: 0, y: 0,  w: 6, h: 1}, class: 'button-container'},
151      // {cur: {x: 0, y: 8, w: 8, h: 8}, class: 'subgraph'},
152      {cur: {x: 8, y: 1, w: 4, h: 6}, class: 'node-connections'},
153      {cur: {x: 8, y: 6, w: 4, h: 10}, class: 'feature-detail'},
154      {cur: {x: 0, y: 0, w: 8, h: 16}, class: 'link-graph', resizeFn: makeResizeFn(initCgLinkGraph)},
155      // {cur: {x: 0, y: 18, w: 6, h: 7}, class: 'clerp-list'},
156      // {cur: {x: 6, y: 30, w: 4, h: 7}, class: 'feature-scatter'},
157      // {cur: {x: 0, y: 30, w: 3, h: 8}, class: 'metadata'},
158     ].filter(d => d)
159
160    var initFns = [
161      // initCgButtonContainer, 
162      // initCgSubgraph,
163      initCgLinkGraph,
164      initCgNodeConnections, 
165      initCgFeatureDetail, 
166      // initCgClerpList, 
167      // initCgFeatureScatter, 
168    ].filter(d => d)
169    
170    var gridsnapSel = sel.html('').append('div.gridsnap.cg')
171      //.classed('is-edit-mode', visState.isGridsnap)
172    if (visState.isModal) gridsnapSel.st({width: '100%', height: '100%'})
173
174    
175    window.initGridsnap({
176      gridData,
177      gridSizeY: 50,
178      pad: 10,
179      sel: gridsnapSel,
180      isFullScreenY: false,
181      isFillContainer: visState.isModal,
182      serializedGrid: data.qParams.gridsnap
183    })
184
185    initFns.forEach(fn => fn({visState, renderAll, data, cgSel: sel}))
186
187    function makeResizeFn(fn){
188      return () => {
189        fn({visState, renderAll, data, cgSel: sel.select('.gridsnap.cg')})
190        Object.values(renderAll).forEach(d => d())
191      }
192    }
193  }
194
195  initGridsnap()
196  renderAll.hClerpUpdate()
197  renderAll.isShowAllLinks()
198  renderAll.linkType()
199  renderAll.clickedId()
200  renderAll.pinnedIds()
201  renderAll.features()
202  renderAll.isSyncEnabled()
203  renderAll.hoveredId()
204}
205
206window.init?.()

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.