1// possible improvements: 2// - persist to url in diff view 3// - support multiple scatter plots 4// - color by x 5// - facet by x 6// - brush to filter 7// - scatter plot of links 8 9window.initCgFeatureScatter = function({visState, renderAll, data, cgSel}){ 10 var nodes = data.nodes//.filter(d => !d.isLogit) 11 12 var numericCols = Object.entries(nodes[0]) 13 .filter(([k, v]) => typeof v != 'object' && typeof v != 'function' && !utilCg.keysToSkip.has(k) && isFinite(v)) 14 .map(([k]) => k) 15 16 var xKey = util.params.get('feature_scatter_x') || 'ctx_idx' 17 var yKey = util.params.get('feature_scatter_y') || 'target_influence' 18 function addSelect(isX){ 19 var options = isX ? ['Distribution'].concat(numericCols) : numericCols 20 selectSel.append('select').st({marginRight: 10}) 21 .on('change', function(){ 22 isX ? xKey = options[this.selectedIndex] : yKey = options[this.selectedIndex] 23 isX ? util.params.set('feature_scatter_x', xKey) : util.params.set('feature_scatter_y', yKey) 24 renderScales() 25 }) 26 .appendMany('option', options) 27 .text(d => d) 28 .at({value: d => d}) 29 .filter(d => isX && d == xKey || !isX && d == yKey).at({selected: 'selected'}) 30 } 31 32 var sel = cgSel.select('.feature-scatter').html('') 33 var selectSel = sel.append('div.select-container').st({marginLeft: 35}) 34 var chartSel = sel.append('div.chart-container') 35 addSelect(1) 36 addSelect(0) 37
38 function renderScales(){ 39 var c = d3.conventions({ 40 sel: chartSel.html('').append('div'), 41 margin: {left: 35, bottom: 30, top: 2, right: 6}, 42 }) 43 44 if (xKey == 'Distribution'){ 45 d3.sort(d3.sort(nodes, d => +d[yKey]), d => d.feature_type) 46 .forEach((d, i) => d.Distribution = i/nodes.length) 47 } 48 49 c.x.domain(d3.extent(nodes, d => +d[xKey])).nice() 50 c.y.domain(d3.extent(nodes, d => +d[yKey])).nice() 51 52 c.yAxis.ticks(3) 53 c.xAxis.ticks(5) 54 c.drawAxis() 55 util.ggPlot(c) 56 util.addAxisLabel(c, xKey + ' â', yKey + ' â', '', 0, 5) 57 58 var nodeSel = c.svg.appendMany('text.node', nodes) 59 .translate(d => [c.x(d[xKey]) ?? -2, c.y(d[yKey]) ?? c.height + 2]) 60 .text(d => utilCg.featureTypeToText(d.feature_type)) 61 .at({ 62 fontSize: 7, 63 stroke: '#000', 64 strokeWidth: .2, 65 textAnchor: 'middle', 66 dominantBaseline: 'central', 67 fill: 'rgba(0,0,0,.1)' 68 }) 69 .call(utilCg.addFeatureTooltip) 70 .call(utilCg.addFeatureEvents(visState, renderAll)) 71 72 // TODO: add hover circle? 73 utilCg.updateFeatureStyles(nodeSel) 74 renderAll.hoveredId.fns['featureScatter'] = () => utilCg.updateFeatureStyles(nodeSel) 75 renderAll.clickedId.fns['featureScatter'] = () => utilCg.updateFeatureStyles(nodeSel) 76 renderAll.pinnedIds.fns['featureScatter'] = () => utilCg.updateFeatureStyles(nodeSel) 77 renderAll.hiddenIds.fns['featureScatter'] = () => utilCg.updateFeatureStyles(nodeSel) 78 } 79 80 // TODO: awkward, maybe gridsnap/widget inits need to be restructured? 81 if (!sel.datum().resizeFn) renderScales() 82 sel.datum().resizeFn = renderScales 83} 84 85window.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.