index.html 12.1 KB
Newer Older
1
2
3
<!DOCTYPE html>
<html>
<head>
4
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
5
    <meta charset="UTF-8">
6
    <title>Allele Visualisation - FDSTools</title>
7
    <!-- VERSION 1.0.0beta1 -->
8
9
10
11
12
13
14
    <!-- BEGIN_LIBRARIES -->
    <script src="http://vega.github.io/vega-editor/vendor/d3.min.js"></script>
    <script src="http://vega.github.io/vega/vega.min.js"></script>
    <!-- END_LIBRARIES -->
    <style>
        * {
            font-family: Helvetica Neue, Helvetica, Arial, sans-serif;
15
            font-size: 10pt;
16
17
        }
        body {
18
            margin: 0px;
19
20
21
        }
        div.options {
            position: absolute;
22
23
            padding: 5px;
            background-color: rgba(255, 255, 255, 0.8);
24
25
            z-index: 10;
        }
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
        table.optiongroup {
            padding: 10px 0px 0px 0px;
            margin: 0px;
            border-spacing: 0px;
            border: none;
        }
        table.optiongroup td {
            padding-right: 10px;
        }
        table.optiongroup th {
            text-align: left;
            font-weight: bold;
            padding-top: 5px;
        }
        .description {
            max-width: 250px;
            text-align: justify;
43
        }
44
45
46
47
48
49
50
51
52
        .description p:first-child{
            margin-top: 0px;
        }
        .description p:last-child{
            margin-bottom: 0px;
        }
        #optionsheader {
            cursor: pointer;
            font-variant: small-caps;
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
            border-bottom: 1px dashed black;
        }
        div#vis {
            position: absolute;
            overflow: auto;
            bottom: 0px;
            top: 0px;
            right: 0px;
            left: 0px;
            text-align: right;
        }
    </style>
</head>
<body>
    <div class="options">
        <strong id="optionsheader">Options</strong><br>
        <div id="options">
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
            <table class="optiongroup" id="fileselectgroup" style="display: none">
                <tr>
                    <th>Input file</th>
                </tr>
                <tr>
                    <td>Allele list file:</td>
                </tr>
                <tr>
                    <td><input id="fileselect" type="file"></td>
                </tr>
                <tr>
                    <td>(or drag a file onto this page)</td>
                </tr>
            </table>
            <table class="optiongroup description">
                <tr>
                    <th>Description</th>
                </tr>
                <tr>
                    <td>
                        <p>
                        The graph depicts every allele among the reference
                        samples as a circle. The size of the circle corresponds
                        to the number of samples with that particular allele. A
                        black inner circle depicts the number of homozygotes.
                        </p>
                        <p>
                        The circles of two alleles are connected by a line
                        whenever samples exist that have a combination of the
                        two connected alleles. The thickness of the line
                        corresponds to the number of heterozygotes with that
                        particular combination of alleles.
                        </p>
                    </td>
                </tr>
            </table>
            <table class="optiongroup">
                <tr>
                    <th colspan="3">Display options</th>
                </tr>
                <tr>
                    <td>Graph width</td>
                    <td colspan="2"><input type="text" value="600" id="graphwidth" size="3"> px</td>
                </tr>
                <tr>
                    <td>Graph height</td>
                    <td colspan="2"><input type="text" value="500" id="graphheight" size="3"> px</td>
                </tr>
                <tr>
                    <td>Renderer</td>
                    <td><input type="radio" name="renderer" value="svg" id="renderSVG" checked> SVG</td>
                    <td><input type="radio" name="renderer" value="canvas" id="renderCanvas"> Canvas</td>
                </tr>
            </table>
124
125
126
127
128
129
            <a id="saveLink" href="javascript:void(saveImage())" style="display: none">Save image</a>
        </div>
    </div>
    <div id="vis"></div>
    <script type="text/javascript">
        var graph = false;
130
131
        var fileName = "graph";
        var stamp = 0;
132
        function parse(){
133
            var this_stamp = ++stamp;
134
            vg.parse.spec(graph_spec, function(chart){
135
                //Cancel rendering if a new parse() call was made.
136
137
138
139
140
                if(this_stamp != stamp)
                    return;

                var visdiv = document.getElementById("vis");
                graph = chart({el: visdiv, renderer: document.querySelector("input[name=renderer]:checked").value});
141
142
143
144
145
146
147
148
                graph.update();
                document.getElementById("saveLink").style.display = "inline";

                //Scroll to the right; the graph is more interesting than the long labels.
                visdiv.scrollLeft = visdiv.scrollWidth;
            });
        }

149
150
151
        function setSignalValue(signalname, value){
            if(!graph_spec)
                return;
152
153
            var visdiv = document.getElementById("vis");
            var scrollRight = (visdiv.scrollLeft >= visdiv.scrollWidth - visdiv.clientWidth);
154
155
156
157
158
159
160
161
162
163
164
165
            if(signalname == "width")
                graph_spec.width = value;
            if(signalname == "height")
                graph_spec.height = value;
            for(i in graph_spec.signals){
                if(graph_spec.signals[i].name == signalname){
                    graph_spec.signals[i].init = value;
                    break;
                }
            }
            if(graph)
                graph.signal(signalname, value).padding("auto").update();
166
167
            if(scrollRight)
                visdiv.scrollLeft = visdiv.scrollWidth;
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
            return;
        }

        function getSignalValue(signalname){
            if(!graph_spec)
                return false;
            if(signalname == "width")
                return graph_spec.width;
            if(signalname == "height")
                return graph_spec.height;
            for(i in graph_spec.signals)
                if(graph_spec.signals[i].name == signalname)
                    return graph_spec.signals[i].init;
            return false;
        }

184
185
        function setRenderer(value){
            if(graph)
186
                graph.renderer(value).update();
187
188
        }

189
190
191
192
193
194
195
196
197
198
        function setFileName(value){
            if(!value)
                value = "graph";
            fileName = value;
            if(value == "graph")
                document.title = "Allele Visualisation - FDSTools";
            else
                document.title = value + " - Allele Visualisation - FDSTools";
        }

199
        //Load the data (input is a fileList object; only the first file is loaded).
200
        var currentlyLoadedFile = "no/file/loaded";
201
        function loadDataset(fileList){
202
            if(!graph_spec || !fileList || !fileList.length || fileList[0].name == currentlyLoadedFile)
203
                return;
204
            currentlyLoadedFile = fileList[0].name;
205
            var reader = new FileReader();
206
207
            reader.onload = function(e){
                if(fileList && fileList.length && fileList[0].name)
208
                    setFileName(fileList[0].name.substr(0, fileList[0].name.lastIndexOf(".")));
209
                else
210
                    setFileName(false);
211
                graph_spec.data[0].values = reader.result;
212
213
214
215
216
217
218
                parse();
            };
            reader.readAsText(fileList[0]);
        }

        //Save image function.
        function saveImage(){
219
            var imageType = document.getElementById("renderSVG").checked? "svg": "png";
220
221
222
223
224
225
226
227
228
229
230
231
            if(window.navigator.msSaveOrOpenBlob){
                //Internet Explorer has its own ways of doing things.
                var b;
                if(imageType == "svg")
                    b = new Blob([graph._el.innerHTML], {type: "image/svg+xml;charset=utf-8"});
                else
                    b = graph._el.firstChild.msToBlob();
                window.navigator.msSaveOrOpenBlob(b, fileName + "." + imageType);
                if(b.msClose)
                    b.msClose();
            }
            else{
232
                var link = document.getElementById("saveLink");
233
234
235
236
237
238
                link.setAttribute("href", graph.toImageURL(imageType));
                link.setAttribute("download", fileName + "." + imageType);
                link.click();
                link.setAttribute("href", "javascript:void(saveImage())");
                link.removeAttribute("download");
            }
239
240
241
242
243
            return false;
        }

        function onLoadSpec(has_data){
            if(!has_data){
244
245
246
247
248
249
                //Handle files from the file input.
                document.getElementById("fileselect").addEventListener('change', function(){
                    loadDataset(document.getElementById("fileselect").files);
                }, false);
                document.getElementById("fileselectgroup").style.display = "table";

250
251
252
253
254
255
256
257
                //Allow files to be dragged onto the page.
                document.addEventListener('dragover', function(evt){
                    evt.stopPropagation();
                    evt.preventDefault();
                }, false);
                document.addEventListener('drop', function(evt){
                    evt.stopPropagation();
                    evt.preventDefault();
258
259
260
261
262

                    //Try to clear the currently displayed file, then try to set
                    //the drag-'n-dropped file as the selected one on the file input.
                    //Both actions are not supported in all major browsers.
                    document.getElementById("fileselect").value = "";
263
                    document.getElementById("fileselect").files = evt.dataTransfer.files;
264
                    loadDataset(evt.dataTransfer.files);
265
266
                }, false);
            }
267
268
            else if(graph_spec.data[0].fdstools_filename)
                setFileName(graph_spec.data[0].fdstools_filename);
269
270
271
272
273
274
275
276
277
278
279
280

            //Update graph when rendering mode or axis scale is changed.
            document.getElementById("renderCanvas").addEventListener('change', function(){
                setRenderer(this.value);
            }, false);
            document.getElementById("renderSVG").addEventListener('change', function(){
                setRenderer(this.value);
            }, false);
            document.getElementById("graphwidth").addEventListener('change', function(){
                var value = parseFloat(this.value);
                if(isNaN(value))
                    return;
281
                setSignalValue("width", value);
282
            }, false);
283
            document.getElementById("graphheight").addEventListener('change', function(){
284
285
286
                var value = parseFloat(this.value);
                if(isNaN(value))
                    return;
287
                setSignalValue("height", value);
288
            }, false);
289

290
291
292
293
294
295
296
297
298
299
            //Toggle options visibility.
            document.getElementById("optionsheader").addEventListener('click', function(){
                var opts = document.getElementById("options");
                if(opts.style.display == "none")
                    document.getElementById("options").style.display = "block";
                else
                    document.getElementById("options").style.display = "none";
            }, false);

            //Sync graph_spec and display.
300
301
            document.getElementById("graphwidth").value = getSignalValue("width");
            document.getElementById("graphheight").value = getSignalValue("height");
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
            if(has_data){
                document.getElementById("options").style.display = "none";
                parse();
            }
        }
    </script>
    <!-- BEGIN_LOAD_SCRIPT -->
    <script type="text/javascript">
        var graph_spec = false;
        vg.util.load({url: "allelevis.json"}, function(err, result){
            graph_spec = JSON.parse(result);
            onLoadSpec(false);
        });
    </script>
    <!-- END_LOAD_SCRIPT -->
</body>
</html>