<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8" />
    <meta name="author" content="Joe Brown - Base2 Genomics" />
    <title>covviz - Base2 Genomics</title>
    <script type="text/javascript" src="https://code.jquery.com/jquery-3.3.1.js"></script>
    <!-- datatables, bootstrap 4 with select, responsive, scroller, searchpanes and html5 buttons -->
    <script type="text/javascript"
        src="https://cdn.datatables.net/v/bs4/dt-1.10.20/b-1.6.1/b-html5-1.6.1/r-2.2.3/sc-2.0.1/sp-1.0.1/sl-1.3.1/datatables.min.js"></script>
    <script type="text/javascript"
        src="https://cdnjs.cloudflare.com/ajax/libs/selectize.js/0.12.6/js/standalone/selectize.min.js"></script>
    <script type="text/javascript"
        src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js"></script>
    <script type="text/javascript" src="https://cdn.plot.ly/plotly-latest.min.js"></script>

    <link rel="stylesheet" type="text/css"
        href="https://cdn.datatables.net/v/bs4/dt-1.10.20/b-1.6.1/b-html5-1.6.1/r-2.2.3/sc-2.0.1/sp-1.0.1/sl-1.3.1/datatables.min.css" />
    <link rel="stylesheet" type="text/css"
        href="https://cdnjs.cloudflare.com/ajax/libs/selectize.js/0.12.6/css/selectize.bootstrap3.min.css">
    <link rel="stylesheet" type="text/css"
        href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css">

    <style type="text/css">
        .disabled_div {
            pointer-events: none;
            opacity: 0.4
        }

        div.dataTables_wrapper div.dataTables_info {
            padding-top: 0em;
        }

        tr.selected {
            background-color: rgba(161, 234, 247, 0.5) !important;
            color: black !important
        }

        .tab-content>.tab-pane:not(.active),
        .pill-content>.pill-pane:not(.active) {
            display: block;
            height: 0;
            overflow-y: hidden;
        }

        .nav-pills .nav-link.active,
        .nav-pills .show>.nav-link {
            background-color: #6c757d !important;
        }

        .selectize-input {
            min-height: 38px !important;
            padding: 7px 12px !important;
        }

        .form-control.selectize-control {
            height: 40px !important;
            padding: 0px 0px 0px;
        }

        #gene_search_div {
            width: 250px;
        }

        .remove-single {
            color: gray !important;
            top: -1px !important;
            font-size: 20px !important;
        }

        table.dataTable thead th.sorting:after,
        table.dataTable thead th.sorting_asc:after,
        table.dataTable thead th.sorting_desc:after,
        table.dataTable thead th.sorting:before,
        table.dataTable thead th.sorting_asc:before,
        table.dataTable thead th.sorting_desc:before {
            font-family: FontAwesome !important;
        }

        table.dataTable.dtr-inline.collapsed>tbody>tr[role="row"]>td:first-child::before,
        table.dataTable.dtr-inline.collapsed>tbody>tr[role="row"]>th:first-child::before {
            top: 8px;
            background-color: #6c757d;
        }
    </style>
</head>

<body>
    <nav class="navbar navbar-dark navbar-expand-md p-0" style="background-color: #3C444C;">
        <a class="navbar-brand m-0 p-1 text-light"><img class="pr-4"
                src='data:image/png;base64, '
                alt="" height="58">
        </a>
        <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbar-items"
            aria-controls="navbar-items" aria-expanded="false" aria-label="Toggle navigation">
            <span class="navbar-toggler-icon"></span>
        </button>
        <div class="collapse navbar-collapse" id="navbar-items">
            <ul class="nav nav-pills mr-auto" role="tablist">
                <li class="nav-item">
                    <a class="nav-link text-white active" data-toggle="tab" role="tab" href="#chrom_coverage"
                        aria-controls="chrom_coverage" aria-selected="true">Chromosome Coverage</a>
                </li>
                <li class="nav-item" id="global_qc_nav" hidden>
                    <a class="nav-link text-white" data-toggle="tab" role="tab" href="#global_qc"
                        aria-controls="global_qc" aria-selected="false">Global QC</a>
                </li>
            </ul>
            <div class="pr-2" id="gene_search_div" hidden>
                <div class="input-group">
                    <input type="text" class="form-control" id="gene-search" aria-label="gene-search">
                </div>
            </div>
        </div>

    </nav>
    <div class="container-fluid w-90 pt-3">
        <div class="tab-content">
            <div class="tab-pane fade show active" id="chrom_coverage" role="tabpanel" aria-labelledby="scaled_tab">
                <div class="row">
                    <div class="col-12" id="chrom_selector_div">
                        <div id="chrom_selector"
                            class="btn-group btn-group-toggle d-flex justify-content-center flex-wrap"
                            data-toggle="buttons">
                            <div class="input-group-prepend d-none d-xl-block">
                                <span class="input-group-text">Chromosome:</span>
                            </div>
                            <div class="input-group-prepend d-xl-none">
                                <span class="input-group-text">Chr:</span>
                            </div>
                        </div>
                    </div>
                </div>
                <ul class="nav nav-tabs pt-3" role="tablist">
                    <li class="nav-item">
                        <a class="nav-link active text-secondary" id="scaled_tab" data-toggle="tab" href="#scaled"
                            role="tab" aria-controls="scaled" aria-selected="true">Scaled chromosome coverage</a>
                    </li>
                    <li class="nav-item">
                        <a class="nav-link text-secondary" id="cov_tab" data-toggle="tab" href="#cov" role="tab"
                            aria-controls="cov" aria-selected="false">Proportions covered</a>
                    </li>
                </ul>
                <div class="tab-content">
                    <div class="tab-pane fade show active mb-3" id="scaled" role="tabpanel"
                        aria-labelledby="scaled_tab">
                        <div style="height:600px" id="scaled_plot_placeholder">
                            <div
                                class="mt-3 d-flex justify-content-center align-items-center bg-light text-muted h-100">
                                <div class="d-flex flex-column">
                                    <div>
                                        Loading...
                                    </div>
                                </div>
                            </div>
                        </div>
                        <div class="row pt-3 mb-3" id="scaled_plot" hidden></div>
                    </div>
                    <div class="tab-pane fade mb-3" id="cov" role="tabpanel" aria-labelledby="cov_tab">
                        <div style="height:600px" id="cov_plot_placeholder">
                            <div
                                class="mt-3 d-flex justify-content-center align-items-center bg-light text-muted h-100">
                                <div class="d-flex flex-column">
                                    <div>
                                        Loading...
                                    </div>
                                </div>
                            </div>
                        </div>
                        <div class="row pt-3 mb-3" id="cov_plot" hidden></div>
                    </div>
                </div>
            </div>
            <div class="tab-pane fade" id="global_qc" role="tabpanel" aria-labelledby="global_qc">
                <div id="global_qc_plots" class="container-fluid w-90">
                    <div class="row border-bottom">
                        <div class="col-6">
                            <h4>Inferred sex</h4>
                        </div>
                        <div class="col-6">
                            <h4>Problematic low and non-uniform coverage bins</h4>
                        </div>
                    </div>
                    <div class="row">
                        <div id="inferred_sex" class="col-6"></div>
                        <div id="bin_counts" class="col-6"></div>
                    </div>
                </div>
            </div>
        </div>
        <div class="container-fluid mb-5">
            <div class="row pt-3 pb-3">
                <div class="col-12">
                    <div class="table-responsive">
                        <table id="ped_table" class="table table-hover table-striped table-sm display nowrap"
                            width="100%"></table>
                    </div>
                </div>
            </div>
        </div>
    </div>
</body>

<script>
    // MIT License

    // Copyright (c) 2013 pieroxy

    // Permission is hereby granted, free of charge, to any person obtaining a copy
    // of this software and associated documentation files (the "Software"), to deal
    // in the Software without restriction, including without limitation the rights
    // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    // copies of the Software, and to permit persons to whom the Software is
    // furnished to do so, subject to the following conditions:

    // The above copyright notice and this permission notice shall be included in all
    // copies or substantial portions of the Software.
    var LZString = function () { function o(o, r) { if (!t[o]) { t[o] = {}; for (var n = 0; n < o.length; n++)t[o][o.charAt(n)] = n } return t[o][r] } var r = String.fromCharCode, n = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=", e = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-$", t = {}, i = { compressToBase64: function (o) { if (null == o) return ""; var r = i._compress(o, 6, function (o) { return n.charAt(o) }); switch (r.length % 4) { default: case 0: return r; case 1: return r + "==="; case 2: return r + "=="; case 3: return r + "=" } }, decompressFromBase64: function (r) { return null == r ? "" : "" == r ? null : i._decompress(r.length, 32, function (e) { return o(n, r.charAt(e)) }) }, compressToUTF16: function (o) { return null == o ? "" : i._compress(o, 15, function (o) { return r(o + 32) }) + " " }, decompressFromUTF16: function (o) { return null == o ? "" : "" == o ? null : i._decompress(o.length, 16384, function (r) { return o.charCodeAt(r) - 32 }) }, compressToUint8Array: function (o) { for (var r = i.compress(o), n = new Uint8Array(2 * r.length), e = 0, t = r.length; t > e; e++) { var s = r.charCodeAt(e); n[2 * e] = s >>> 8, n[2 * e + 1] = s % 256 } return n }, decompressFromUint8Array: function (o) { if (null === o || void 0 === o) return i.decompress(o); for (var n = new Array(o.length / 2), e = 0, t = n.length; t > e; e++)n[e] = 256 * o[2 * e] + o[2 * e + 1]; var s = []; return n.forEach(function (o) { s.push(r(o)) }), i.decompress(s.join("")) }, compressToEncodedURIComponent: function (o) { return null == o ? "" : i._compress(o, 6, function (o) { return e.charAt(o) }) }, decompressFromEncodedURIComponent: function (r) { return null == r ? "" : "" == r ? null : (r = r.replace(/ /g, "+"), i._decompress(r.length, 32, function (n) { return o(e, r.charAt(n)) })) }, compress: function (o) { return i._compress(o, 16, function (o) { return r(o) }) }, _compress: function (o, r, n) { if (null == o) return ""; var e, t, i, s = {}, p = {}, u = "", c = "", a = "", l = 2, f = 3, h = 2, d = [], m = 0, v = 0; for (i = 0; i < o.length; i += 1)if (u = o.charAt(i), Object.prototype.hasOwnProperty.call(s, u) || (s[u] = f++ , p[u] = !0), c = a + u, Object.prototype.hasOwnProperty.call(s, c)) a = c; else { if (Object.prototype.hasOwnProperty.call(p, a)) { if (a.charCodeAt(0) < 256) { for (e = 0; h > e; e++)m <<= 1, v == r - 1 ? (v = 0, d.push(n(m)), m = 0) : v++; for (t = a.charCodeAt(0), e = 0; 8 > e; e++)m = m << 1 | 1 & t, v == r - 1 ? (v = 0, d.push(n(m)), m = 0) : v++ , t >>= 1 } else { for (t = 1, e = 0; h > e; e++)m = m << 1 | t, v == r - 1 ? (v = 0, d.push(n(m)), m = 0) : v++ , t = 0; for (t = a.charCodeAt(0), e = 0; 16 > e; e++)m = m << 1 | 1 & t, v == r - 1 ? (v = 0, d.push(n(m)), m = 0) : v++ , t >>= 1 } l-- , 0 == l && (l = Math.pow(2, h), h++), delete p[a] } else for (t = s[a], e = 0; h > e; e++)m = m << 1 | 1 & t, v == r - 1 ? (v = 0, d.push(n(m)), m = 0) : v++ , t >>= 1; l-- , 0 == l && (l = Math.pow(2, h), h++), s[c] = f++ , a = String(u) } if ("" !== a) { if (Object.prototype.hasOwnProperty.call(p, a)) { if (a.charCodeAt(0) < 256) { for (e = 0; h > e; e++)m <<= 1, v == r - 1 ? (v = 0, d.push(n(m)), m = 0) : v++; for (t = a.charCodeAt(0), e = 0; 8 > e; e++)m = m << 1 | 1 & t, v == r - 1 ? (v = 0, d.push(n(m)), m = 0) : v++ , t >>= 1 } else { for (t = 1, e = 0; h > e; e++)m = m << 1 | t, v == r - 1 ? (v = 0, d.push(n(m)), m = 0) : v++ , t = 0; for (t = a.charCodeAt(0), e = 0; 16 > e; e++)m = m << 1 | 1 & t, v == r - 1 ? (v = 0, d.push(n(m)), m = 0) : v++ , t >>= 1 } l-- , 0 == l && (l = Math.pow(2, h), h++), delete p[a] } else for (t = s[a], e = 0; h > e; e++)m = m << 1 | 1 & t, v == r - 1 ? (v = 0, d.push(n(m)), m = 0) : v++ , t >>= 1; l-- , 0 == l && (l = Math.pow(2, h), h++) } for (t = 2, e = 0; h > e; e++)m = m << 1 | 1 & t, v == r - 1 ? (v = 0, d.push(n(m)), m = 0) : v++ , t >>= 1; for (; ;) { if (m <<= 1, v == r - 1) { d.push(n(m)); break } v++ } return d.join("") }, decompress: function (o) { return null == o ? "" : "" == o ? null : i._decompress(o.length, 32768, function (r) { return o.charCodeAt(r) }) }, _decompress: function (o, n, e) { var t, i, s, p, u, c, a, l, f = [], h = 4, d = 4, m = 3, v = "", w = [], A = { val: e(0), position: n, index: 1 }; for (i = 0; 3 > i; i += 1)f[i] = i; for (p = 0, c = Math.pow(2, 2), a = 1; a != c;)u = A.val & A.position, A.position >>= 1, 0 == A.position && (A.position = n, A.val = e(A.index++)), p |= (u > 0 ? 1 : 0) * a, a <<= 1; switch (t = p) { case 0: for (p = 0, c = Math.pow(2, 8), a = 1; a != c;)u = A.val & A.position, A.position >>= 1, 0 == A.position && (A.position = n, A.val = e(A.index++)), p |= (u > 0 ? 1 : 0) * a, a <<= 1; l = r(p); break; case 1: for (p = 0, c = Math.pow(2, 16), a = 1; a != c;)u = A.val & A.position, A.position >>= 1, 0 == A.position && (A.position = n, A.val = e(A.index++)), p |= (u > 0 ? 1 : 0) * a, a <<= 1; l = r(p); break; case 2: return "" }for (f[3] = l, s = l, w.push(l); ;) { if (A.index > o) return ""; for (p = 0, c = Math.pow(2, m), a = 1; a != c;)u = A.val & A.position, A.position >>= 1, 0 == A.position && (A.position = n, A.val = e(A.index++)), p |= (u > 0 ? 1 : 0) * a, a <<= 1; switch (l = p) { case 0: for (p = 0, c = Math.pow(2, 8), a = 1; a != c;)u = A.val & A.position, A.position >>= 1, 0 == A.position && (A.position = n, A.val = e(A.index++)), p |= (u > 0 ? 1 : 0) * a, a <<= 1; f[d++] = r(p), l = d - 1, h--; break; case 1: for (p = 0, c = Math.pow(2, 16), a = 1; a != c;)u = A.val & A.position, A.position >>= 1, 0 == A.position && (A.position = n, A.val = e(A.index++)), p |= (u > 0 ? 1 : 0) * a, a <<= 1; f[d++] = r(p), l = d - 1, h--; break; case 2: return w.join("") }if (0 == h && (h = Math.pow(2, m), m++), f[l]) v = f[l]; else { if (l !== d) return null; v = s + s.charAt(0) } w.push(v), f[d++] = s + v.charAt(0), h-- , s = v, 0 == h && (h = Math.pow(2, m), m++) } } }; return i }(); "function" == typeof define && define.amd ? define(function () { return LZString }) : "undefined" != typeof module && null != module && (module.exports = LZString);
</script>

<script>
    const compressed_data = "{{data}}"
    const data = JSON.parse(LZString.decompressFromBase64(compressed_data))
    const sample_column = data.sample_column
    const cov_color = 'rgba(108,117,125,0.2)'
    // const highlight_color = 'rgb(255,147,0)'
    const cov_layout = {
        title: "",
        margin: { t: 10, b: 40 },
        height: 600,
        xaxis: { title: "Scaled Coverage", showgrid: false, range: [0, 1.5] },
        yaxis: { title: "Proportion of Regions Covered", range: [0, 1.] },
        hovermode: "closest",
        showlegend: false,
    }
    const scaled_layout = {
        title: "",
        margin: { t: 10, b: 40 },
        height: 600,
        xaxis: { title: "Position", rangeslider: {}, autorange: true, showgrid: false, showlines: false, zeroline: false },
        yaxis: { title: "Scaled Coverage", fixedrange: true, domain: [0, 3], showgrid: true, showticklabels: true, tickvals: [0, 1, 2, 3], zeroline: false },
        hovermode: "closest",
        showlegend: false,
    }
    var ped = false
    var cov_traces = []
    var scaled_traces = []
    var scatter_point_color = 'rgba(31,120,180,0.5)'
    var scatter_point_color_light = 'rgba(255,255,255,0.1)'
    var gene_search_obj
    var ped_table

    const load_buttons = (arr) => {
        var btngrp = document.getElementById("chrom_selector");
        for (var i = 0; i < arr.length; i++) {
            if (i == 0) {
                btngrp.insertAdjacentHTML('beforeend', '<label class="btn btn-secondary active" id="chrbtn' + arr[i] + '"><input type="radio" name="options" data-name="' + arr[i] + '" autocomplete="off" id="chrinp' + arr[i] + '" checked="true"> ' + arr[i] + ' </label>')
            } else {
                btngrp.insertAdjacentHTML('beforeend', '<label class="btn btn-secondary" id="chrbtn' + arr[i] + '"><input type="radio" name="options" data-name="' + arr[i] + '" autocomplete="off" id="chrinp' + arr[i] + '"> ' + arr[i] + ' </label>')
            }
        }
        let chr = $('#chrom_selector input:radio:checked').data('name')
        build_gene_search()
        build_cov(chr)
        build_scaled(chr)
    }

    const build_cov = (chr) => {
        // hide the placeholder
        $('#cov_plot_placeholder').prop('hidden', true)
        // show the plot
        $('#cov_plot').prop('hidden', false)
        cov_layout.xaxis.range = [0, 1.5]
        cov_layout.yaxis.range = [0, 1.]
        cov_traces = data["roc"][chr]

        let cov_plot = document.getElementById("cov_plot")
        Plotly.react(cov_plot, cov_traces, cov_layout)
        cov_plot.removeAllListeners("plotly_click")
        cov_plot.removeAllListeners("plotly_doubleclick")
        cov_plot.on("plotly_click", handle_plot_click)
        cov_plot.on("plotly_doubleclick", handle_plot_doubleclick)
    }

    const build_scaled = (chr, range = false) => {
        // hide the placeholder
        $('#scaled_plot_placeholder').prop('hidden', true)
        // show the plot
        $('#scaled_plot').prop('hidden', false)
        scaled_layout.xaxis.autorange = true
        if (range) {
            scaled_layout.xaxis.autorange = false
            scaled_layout.xaxis.range = range
        }
        scaled_traces = data[chr]

        let scaled_plot = document.getElementById("scaled_plot")
        Plotly.react(scaled_plot, scaled_traces, scaled_layout)
        scaled_plot.removeAllListeners("plotly_click")
        scaled_plot.removeAllListeners("plotly_doubleclick")
        scaled_plot.on("plotly_click", handle_plot_click)
        scaled_plot.on("plotly_doubleclick", handle_plot_doubleclick)
        $("#scaled_plot").removeClass("disabled_div")
    }

    const csv_button_click = () => {
        ped_table.button('.buttons-csv').trigger()
    }

    const copy_button_click = () => {
        ped_table.button('.buttons-copy').trigger()
    }

    const build_table = () => {
        if ("ped" in data) {
            ped_table = $("#ped_table").DataTable({
                data: data.ped.slice(1),
                columns: data.ped[0],
                responsive: true,
                // scrollX: true,
                scrollCollapse: true,
                paging: false,
                // pagingType: "simple",
                scrollY: "40vh",
                bSortClasses: false,
                buttons: [
                    'copyHtml5',
                    {
                        extend: 'csvHtml5',
                        title: 'covviz_export',
                    },
                ],
                dom: '<"top row"<"col-6"i><"col-6"f>>rt<"bottom"><"clear">',
                infoCallback: (oSettings, iStart, iEnd, iMax, iTotal, sPre) => {
                    let msg
                    // selection
                    if (iMax != iTotal) {
                        msg = `Selected ${iTotal} of ${iMax} records`
                    } else {
                        msg = `${iTotal} records`
                    }
                    return `
                <span class="datatable-info">
                    <span class="pr-3">${msg}</span>

                    <span class="btn-group input-group-sm" data-toggle="buttons">
                        <span class="input-group-prepend">
                            <span class="input-group-text">Export:</span>
                        </span>
                        <button type="button" class="btn btn-secondary btn-sm" onclick="csv_button_click()">CSV</button>
                        <button type="button" class="btn btn-secondary btn-sm" onclick="copy_button_click()">Copy</button>
                    </span>
                </span>
                `
                },
            })

            // track if we actually have a table rendered
            if ("sample_column" in data) {
                ped = true
                // register table clicks on sample_column
                ped_table.on('click', 'tr', function () {
                    if ($(this).hasClass('selected')) {
                        ped_table.$('tr.selected').removeClass('selected')
                        reset_line_plots()
                    }
                    else {
                        ped_table.$('tr.selected').removeClass('selected')
                        $(this).addClass('selected')
                        let sample_id = ped_table.rows('.selected').data()[0][sample_column]
                        highlight_plot_traces(sample_id)
                    }
                })
            }
        }
    }

    const get_scatter_data = (x, y, text, colors = 'rgba(31,120,180,0.5)', hover = false) => {
        return {
            x: x,
            y: y,
            mode: "markers",
            type: "scatter",
            text: text,
            hovertext: hover,
            hoverinfo: 'text',
            marker: { size: 12, color: colors, line: { color: 'rgb(40,40,40)', width: 1 } },
        }
    }

    const build_scatter_plot = (div, data, x_label, y_label) => {
        let el = document.getElementById(div)
        Plotly.react(el, [data], {
            margin: { t: 15, },
            height: 400,
            xaxis: { title: x_label },
            yaxis: { title: y_label },
            hovermode: "closest",
            legend: { orientation: "h", x: 0, y: 1.125, },
            dragmode: "lasso",
        })
        el.removeAllListeners("plotly_selected")
        el.removeAllListeners("plotly_deselect")
        el.on("plotly_selected", handle_scatter_selection)
        el.on("plotly_deselect", build_scatter_plots)
    }

    const build_scatter_plots = () => {
        // inferred sex
        build_scatter_plot(
            "inferred_sex",
            get_scatter_data(data.depth.inferred.x, data.depth.inferred.y, data.depth.bins.samples, data.depth.inferred.color, data.depth.inferred.hover),
            "X copy number",
            "Y copy number"
        )

        // bin counts
        build_scatter_plot(
            "bin_counts",
            get_scatter_data(data.depth.bins.x, data.depth.bins.y, data.depth.bins.samples),
            "Proportion of bins with depth < 0.15",
            "Proportion of bins with depth<br>outside of (0.85, 1.15)"
        )

        // pca plots
        if ("pca_1" in data.depth.pca) {
            build_scatter_plot(
                "pca_1",
                get_scatter_data(data.depth.pca.pca_1, data.depth.pca.pca_2, data.depth.bins.samples),
                "PC1",
                "PC2"
            )
            build_scatter_plot(
                "pca_2",
                get_scatter_data(data.depth.pca.pca_1, data.depth.pca.pca_3, data.depth.bins.samples),
                "PC1",
                "PC3"
            )
        }
    }

    const build_global_qc = () => {
        // constructs required html and then calls building of plots
        if (!("depth" in data)) {
            return
        }

        $("#global_qc_nav").prop('hidden', false)

        // PCAs
        if ("pca_1" in data.depth.pca) {
            // insert HTML into plot area
            let pa = document.getElementById("global_qc_plots")
            pa.insertAdjacentHTML(
                'beforeend',
                `<div class="row border-bottom">
                <div class="col-6">
                    <h4>PCA 1 vs 2</h4>
                </div>
                <div class="col-6">
                    <h4>PCA 1 vs 3</h4>
                </div>
            </div>
            <div class="row">
                <div id="pca_1" class="col-6"></div>
                <div id="pca_2" class="col-6"></div>
            </div>`
            )
        }

        build_scatter_plots()
    }

    $('#chrom_selector').on("change", () => {
        // $('#tab_names a[href="#scaled"]').tab('show')
        let chr = $('#chrom_selector input:radio:checked').data('name')
        let sample_id
        if ("genes" in data) {
            gene_search_obj.clear()
        }
        $("#scaled_plot").addClass("disabled_div")
        if (ped) {
            let tables = $('.dataTable').DataTable()
            let table = tables.table('#ped_table')
            // remove all filters and reset table
            // table.search('').columns().search('').draw()
            // de-select all rows
            // table.$('tr.selected').removeClass('selected')
            table_data = table.rows('.selected').data()
            if (table_data.length == 1) {
                sample_id = table_data[0][sample_column]
            }
        }
        build_cov(chr)
        build_scaled(chr)
        if (sample_id) {
            highlight_plot_traces(sample_id)
        }
    })

    const search_datatable = (sample_id) => {
        let tables = $('.dataTable').DataTable()
        let table = tables.table('#ped_table')
        // remove selection
        table.$('tr.selected').removeClass('selected')
        // run the search
        table.search(sample_id).draw()
        // highlight the selected sample within the search results
        table.rows().every(function (row_index, table_loop, row_loop) {
            if (sample_id == this.data()[sample_column]) {
                table.rows([row_index]).nodes().to$().addClass('selected')
            }
        })
    }

    const reset_datatable = () => {
        let tables = $('.dataTable').DataTable()
        let table = tables.table('#ped_table')
        table.$('tr.selected').removeClass('selected')
        table.search('').columns().search('').draw()
    }

    const handle_plot_click = (click_data) => {
        if (click_data.points[0].data.tracktype == 'gff') {
            let genes = click_data.points[0].text.split(";")
            for (var i = 0; i < genes.length; i++) {
                window.open("https://www.genecards.org/cgi-bin/carddisp.pl?gene=" + genes[i], "_blank")
            }
        } else if (click_data.points[0].data.tracktype == 'vcf') {
            // nothing yet
            return
        } else if (click_data.points[0].data.tracktype == 'bed') {
            // nothing yet
            return
        } else {
            let sample_id = click_data.points[0].data.text
            if (sample_id) {
                highlight_plot_traces(sample_id)
                if (ped) {
                    search_datatable(sample_id)
                }
            }
        }
    }

    const handle_scatter_selection = (event) => {
        // plot click event
        if (event === undefined) {
            return
        }
        var sample_ids = event.points.map(point => point.text)
        var colors = []
        for (var i = 0; i < data.depth.bins.samples.length; i++) {
            colors.push(scatter_point_color_light)
        }
        event.points.forEach((pt) => {
            colors[pt.pointNumber] = scatter_point_color
        })

        Plotly.restyle('inferred_sex', 'marker.color', [colors])
        Plotly.restyle('bin_counts', 'marker.color', [colors])
        if ("pca_1" in data.depth.pca) {
            Plotly.restyle('pca_1', 'marker.color', [colors])
            Plotly.restyle('pca_2', 'marker.color', [colors])
        }
    }

    const reset_line_plots = () => {
        scaled_layout.xaxis.autorange = true
        // de-select scaled plot
        Plotly.react("scaled_plot", scaled_traces, scaled_layout)
        cov_layout.xaxis.range = [0, 1.5]
        cov_layout.yaxis.range = [0, 1.]
        // de-select cov plot
        Plotly.react("cov_plot", cov_traces, cov_layout)
    }

    const handle_plot_doubleclick = () => {
        reset_line_plots()
        // de-select in table
        if ("ped" in data) {
            reset_datatable()
        }
    }

    const highlight_plot_traces = (sample_id) => {
        let s_traces = []
        let c_traces = []
        let k_traces = []
        let highlight_color;
        for (var i = 0; i < scaled_traces.length; i++) {
            // let trace = scaled_traces[i]
            let trace = $.extend(true, {}, scaled_traces[i])
            // limit to significant sample traces
            if (trace.name == "significant") {
                // de-prioritize; gray
                if (trace.text != sample_id) {
                    trace.marker.color = cov_color
                }
                else {
                    highlight_color = scaled_traces[i].marker.color
                }
            }
            s_traces.push(trace)
        }
        for (var i = 0; i < cov_traces.length; i++) {
            let trace = $.extend(true, {}, cov_traces[i])
            if (trace.text != sample_id) {
                trace.marker.color = cov_color
            } else {
                trace.marker.color = highlight_color
            }
            c_traces.push(trace)
        }
        Plotly.react("cov_plot", c_traces, cov_layout)
        Plotly.react("scaled_plot", s_traces, scaled_layout)
    }

    const build_gene_search = () => {
        if ("genes" in data) {

            // re-organize the buttons and show the search field
            // $('#chrom_selector_div').removeClass('col-12').addClass('col-10')
            $("#gene_search_div").prop('hidden', false)

            // n = name, v = [chrom, start, end]
            let gene_search = $('#gene-search').selectize({
                // plugins: ['remove_button'],
                valueField: 'v',
                labelField: 'n',
                searchField: 'n',
                options: data['genes'],
                placeholder: 'Gene ID',
                mode: 'single',
                closeAfterSelect: false,
                maxItems: 1,
                maxOptions: 20,
            })
            gene_search_obj = gene_search[0].selectize
            // register handler
            $('#gene-search').on('change', function () {
                update_scaled_range(gene_search_obj.items[0])
            })
        }
    }

    const update_scaled_range = (coords) => {
        if (!coords) {
            return
        }

        coords = coords.split(',')
        let chrom = coords[0]
        let padding = 100000
        let start = parseInt(coords[1]) - padding
        let end = parseInt(coords[2]) + padding

        let current_chr = $('#chrom_selector input:radio:checked').data('name')

        if (current_chr != chrom) {
            // change the button
            $("#chrbtn" + current_chr).removeClass('active')
            $("#chrinp" + current_chr).prop('checked', false)
            $("#chrbtn" + chrom).addClass('active')
            $("#chrinp" + chrom).prop('checked', true)

            // temp disable
            $("#scaled_plot").addClass("disabled_div")

            // change both plots to currently selected chromosome
            build_cov(chrom)
        }

        // zoom the scaled plot
        build_scaled(chrom, [start, end])
    }

    $(document).ready(function () {
        load_buttons(data.chromosomes)
        build_table()
        build_global_qc()
    })

</script>

</html>
