1/* 2 * Copyright (c) 2019 University of Southampton. Authors: [email protected], [email protected] 3 */ 4 5const height_base_mul = 500000; 6const height_name_push = height_base_mul/20; 7const gene_info_window = null; 8const cylinderGeo = new Cesium.CylinderGeometry({ 9 length: height_base_mul, 10 topRadius: 40000, 11 bottomRadius: 40000, 12 outline: false, 13 slices: 16 14}); 15 16//const gl = canvas.getContext('webgl1'); 17// enable necessary extensions 18//gl.getExtension('EXT_color_buffer_float'); 19//gl.getExtension('EXT_float_blend'); 20 21const gradientColors = tinygradient(['#B42521', '#5C10A7', '#548235', '#7F6000', '#2F5597']); 22const gradient = gradientColors.rgb(360) 23 24const primitiveCollection = new Cesium.PrimitiveCollection(); 25 26function RGBToHSL(r, g, b) { 27 // Find greatest and smallest channel values 28 let cmin = Math.min(r, g, b), 29 cmax = Math.max(r, g, b), 30 delta = cmax - cmin, 31 h = 0, 32 s = 0, 33 l = 0; 34 35 // Calculate hue 36 // No difference 37 if (delta == 0) 38 h = 0; 39 // Red is max 40 else if (cmax == r) 41 h = ((g - b) / delta) % 6; 42 // Green is max 43 else if (cmax == g) 44 h = (b - r) / delta + 2; 45 // Blue is max 46 else 47 h = (r - g) / delta + 4; 48 49 h = Math.round(h * 60); 50 51 // Make negative hues positive behind 360° 52 if (h < 0) 53 h += 360; 54 55 return h 56} 57 58function draw_grid(viewer) { 59 for (let lat = -90; lat < 90; lat += 4) { 60 for (let long = -180; long < 180; long += 4) { 61 let point_size = 1; 62 63 // If we're plotting a major grid point, make it bigger 64 if ((lat % 10 == 0) || (long % 10 == 0)) 65 point_size = 2.5; 66 67 const point = viewer.entities.add({ 68 position: Cesium.Cartesian3.fromDegrees(lat, long), 69 point: { 70 color: colorThemes[darkTheme ? 'dark' : 'light'].grid, 71 pixelSize: point_size, 72 }, 73 }); 74 75 gridArray.push(point) 76 } 77 } 78} 79 80function add_root_distance(nodelist, dist, node) { 81 node.root_distance = dist; 82 83 for (let i = 0; i < node.children.length; i++) {
84 let child_node = nodelist[node.children[i]]; 85 add_root_distance(nodelist, dist + 1, child_node); 86 } 87} 88 89function add_backward_references(nodelist) { 90 let root_nodes = []; 91 92 for (let n in nodelist) { 93 let node = nodelist[n]; 94 node['root_distance'] = 0; 95 node['children'] = []; 96 } 97 98 for (let node_name in nodelist) { 99 let node = nodelist[node_name]; 100 101 if (node.flow != node_name) { 102 let parent_node = nodelist[node.flow]; 103 parent_node.children.push(node_name); 104 } else { 105 // If flow field refers to itself, it's a root node 106 root_nodes.push(node_name); 107 } 108 } 109 110 return root_nodes; 111} 112 113function create_network(viewer, nodelist, root_nodes) { 114 const filter = filterRange ? filterRange.value : 0 115 for (let i = 0; i < root_nodes.length; i++) { 116 let node = nodelist[root_nodes[i]]; 117 if (node.zorder >= filter) { 118 create_subnode_tree(nodelist, 0, node, null, cylinderGeo); 119 } 120 } 121 122 viewer.scene.requestRender(); 123} 124 125function create_subnode_tree(nodelist, dist, node, cjs_parent_node, geometry) { 126 const actual_height = height_base_mul * node.height 127 const propBag = new Cesium.PropertyBag(); 128 propBag.addProperty('Weblink', "https://www.uniprot.org/uniprotkb?query="+node.name); 129 130 const hue = RGBToHSL(node.color[0], node.color[1], node.color[2]) 131 const color = gradient[hue] 132 133 const instance = new Cesium.GeometryInstance({ 134 geometry: geometry, 135 modelMatrix: Cesium.Matrix4.multiplyByScale(Cesium.Matrix4.multiplyByTranslation(Cesium.Transforms.eastNorthUpToFixedFrame( 136 Cesium.Cartesian3.fromDegrees(node.lat, node.long)), new Cesium.Cartesian3(0.0, 0.0, actual_height / 2), new Cesium.Matrix4()), 137 new Cesium.Cartesian3(1.0, 1.0, node.height), new Cesium.Matrix4()), 138 attributes: { 139 color: new Cesium.ColorGeometryInstanceAttribute(color._r / 255, color._g / 255, color._b / 255, 1.0) 140 }, 141 id: "https://www.uniprot.org/uniprotkb?query="+node.name 142 }); 143 144 primitiveCollection.add(new Cesium.Primitive({ 145 geometryInstances: instance, 146 appearance: new Cesium.PerInstanceColorAppearance({ 147 flat: true, 148 translucent: true 149 }), 150 properties: propBag 151 })); 152 153 if (!node.color) { 154 console.log('**** Error: No Color element specified in visualisation JSON'); 155 } 156 157 const cjs_label = { 158 text: node.name, 159 font: '24px Ubuntu 900', 160 fillColor: Cesium.Color.WHITE, 161 outlineColor: Cesium.Color.BLACK, 162 outlineWidth: 2, 163 style: Cesium.LabelStyle.FILL_AND_OUTLINE , 164 verticalOrigin: Cesium.VerticalOrigin.TOP, 165 // eyeOffset: new Cesium.Cartesian3(0, 0, -1.0e5), 166 // pixelOffset: new Cesium.Cartesian2(0, 10), 167 scaleByDistance: new Cesium.NearFarScalar(2.0e2, 2, 1.0e7, 0.0), 168 // showBackground: true, 169 // backgroundColor: Cesium.Color.WHITE, 170 }; 171 172 const cjs_node = viewer.entities.add({ 173 name: 'Gene: ' + node.name, 174 position: Cesium.Cartesian3.fromDegrees(node.lat, node.long, actual_height + height_name_push), 175 description: '<a href="' + node.Weblink + '" target="_blank">' + node.name + '</a>', 176 parent: cjs_parent_node, 177 properties: propBag, 178 show: true 179 }); 180 181 // Add Gene to autoComplete list for search 182 geneArray.push({ gene: node.name, position: cjs_node.position['_value']}) 183 184 cjs_node.label = new Cesium.LabelGraphics(cjs_label); 185 186 node['cjs_node'] = cjs_node; 187 node['root_distance'] = dist; 188 189 node['cjs_children'] = []; 190 for (let i = 0; i < node.children.length; i++) {
191 let child_node = nodelist[node.children[i]]; 192 193 let cjs_child_node = create_subnode_tree(nodelist, dist + 1, child_node, cjs_node, cylinderGeo); 194 node['cjs_children'].push(cjs_child_node); 195 196 // Add in line joining and associating this new child with its parent 197 let child_line = viewer.entities.add({ 198 parent: cjs_node, 199 show: true, 200 polyline: { 201 positions: Cesium.Cartesian3.fromDegreesArray([node.lat, node.long, child_node.lat, child_node.long]), 202 width: 2, 203 material: new Cesium.Color(1, 1, 1, 0.5) 204 } 205 }); 206 } 207 208 return cjs_node; 209} 210 211function show_gene_details(viewer, entity) { 212 if (entity.properties) { 213 var gid = entity.properties.getValue('Weblink'); 214 var weblink = gid['Weblink']; 215 window.open(weblink, 'myWindow', 'width=600, height=400'); 216 } 217}
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.