PageSourceSearch

https://topmd.co.uk/static/js/balloon-tree.js

js topmd.co.uk collected 2026-09-29 08:44:42 UTC 6,845 bytes, 217 lines download raw bytes

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.