/* globals OpenSeadragon, seadragon, d3, getD3Symbol, addDefaultPlotSettings, $, jQuery, geneFilters, getSubcellActivePlotID, imageLoad */ // eslint-disable-next-line no-unused-vars var subcellColorMap = { 'Actin filaments': '#37B2D2', 'Aggresome': '#37BACF', 'Cell Junctions': '#F9A237', 'Centriolar satellite': '#37C2CC', 'Centrosome': '#37C8C2', 'Cleavage furrow': '#37C9B6', 'Cytokinetic bridge': '#37C4A4', 'Cytoplasmic bodies': '#37BF91', 'Cytosol': '#37BB77', 'Endoplasmic reticulum': '#F58D37', 'Endosomes': '#F27937', 'Focal adhesion sites': '#37B854', 'Golgi apparatus': '#EB5B37', 'Intermediate filaments': '#4AB737', 'Kinetochore': '#F13791', 'Lipid droplets': '#E83F37', 'Lysosomes': '#F1374E', 'Microtubule ends': '#79BB37', 'Microtubules': '#A4C237', 'Midbody ring': '#D9C537', 'Midbody': '#C2C637', 'Mitochondria': '#E9C237', 'Mitotic chromosome': '#E837A4', 'Mitotic spindle': '#F7BE37', 'Nuclear bodies': '#DC37B8', 'Nuclear membrane': '#CB37CD', 'Nuclear speckles': '#A037CE', 'Nucleoli fibrillar center': '#4737CD', 'Nucleoli rim': '#3757CB', 'Nucleoli': '#7437CE', 'Nucleoplasm': '#3774C9', 'Peroxisomes': '#F83765', 'Plasma membrane': '#FB3770', 'Rods & Rings': '#F9B037', 'Vesicles': '#F9377E', 'Multilocalizing': '#b0b0b0', }; $(window).on("load", function() { 'use strict'; var svgCell = $("#svg_cell"); if (svgCell.length) { var svg = $(svgCell[0].contentDocument).find('svg'); svg.prependTo(svgCell.parent()); svgCell.hide(); // Highlight organelles gene page var loc_txt = ''; var all_locs = ''; $('td.main_location, td.other_location').each(function() { var locs = $(this).attr('data-name').split(','); if (locs.length>0 && locs[0] !== "") { for (var i in locs) { if (locs.hasOwnProperty(i)) { var loc = locs[i].trim(); $('g.'+loc+' path').css({'fill':'#7fd822', 'opacity':0.5}); all_locs += (all_locs? ', ' : '')+loc.replace(/_/g, ' ').ucfirst(); } } } }); if (all_locs) { loc_txt += ' detected in '+all_locs.replace(/,([^,]*)$/,' and$1'); } var extracellular_td = $('td.extracellular_location'); if (extracellular_td.length && extracellular_td.html().length > 0) { $('g.secreted_proteins path').css({'fill': '#7fd822', 'opacity': 0.5}); loc_txt += (loc_txt ? '; and' : '') + ' is predicted to be secreted'; } if (loc_txt) { D3wrap var $txt = $('#cell_grey .legend').show().find('#cell_legend').text($('.gene_name[id]').text() + loc_txt); if (loc_txt.length > 100) d3.selectAll('#cell_legend').call(D3wrap, 520); } // Hover highlight organelles $('tr.organelle a, span.cell_organelle, #cell g[id], #cell_grey g[id]').on('mouseover', function() { $('svg g.col').hide(); var names; if ($(this).is('g')) { names = $(this).attr('id').split(' '); } else if ($(this).is('span.cell_organelle')) { names = $(this).attr('name').split(','); } else { names = $(this).closest('div').attr('name').split(','); } for (var i in names) { if (names.hasOwnProperty(i)) { var loc = names[i].replace('_ton','').trim(); $('svg g.'+loc).show(); $('svg g.'+loc+'.ton').hide(); } } }).on('mouseout', function() { $('svg g:not(.legend)').show(); }); // Make cell elements links $("svg#cell g[id], svg#cell_grey g[id]").each(function() { var loc = $(this).attr("id").replace(/_ton$/, "").trim(); if ($("span[name='"+loc+"'] a").length) { $(this).css('cursor', 'pointer'); $(this).on("click", function() { document.location.href=$('span[name="'+loc+'"] a').attr('href'); }); } }); } }); function imgClickHandler(elem) { var chImage = elem.querySelector('.channel_image'); return imageLoad(elem, chImage.dataset.imgload1, chImage.dataset.imgload2, chImage.dataset.imgload3, '', chImage.dataset.zindex); } $(function() { 'use strict'; // LUT button $(document).on('click', '.lut_button', function() { var $container = $(this).closest('.cellImages, #seadragon'); $(this).toggleClass('channel_inactive').trigger('blur'); // If lut active limit to 1 channel if (!$(this).hasClass('channel_inactive')) { $container.find('.channel_button:not(.channel_inactive):not(:first)').addClass('channel_inactive'); $container.find('.cell_intensity_legend').show(); } else { $container.find('.cell_intensity_legend').hide(); } $container.toggleChannel(); }); // Segmentation button $(document).on('click', '.segm_button', function() { $(this).toggleClass('channel_inactive').trigger('blur'); $('img.segm_image').trigger('toggle_segm_image'); $('#seadragon').trigger('toggle_segm_seadragon'); }); $(document).on('toggle_segm_image', 'img.segm_image', function() { var $container = $(this).closest('.cellImages, #seadragon'); var segm_button = $container.find('.segm_button'); if (segm_button.length) { // Segmentation button exists if (segm_button.hasClass('channel_inactive')) { $(this).hide(); } else { var $img = $(this).prev('img'); if ($img.attr("base") === "") { return; } var base = $img.attr('base').replace('//images.proteinatlas.org','').replace('/images', ''); var medium = $img.attr('src').indexOf('medium') === -1? '' : '_medium'; var thumb = $img.attr('src').indexOf('thumb') === -1? '' : '_thumb'; $(this).attr('src', '/images_cell_segmentation' + base + '_segmentation' + medium + thumb +'.png').show(); } } }); $(document).on('toggle_segm_seadragon', '#seadragon', function() { var $container = $(this).closest('.cellImages, #seadragon'); var segm_button = $container.find('.segm_button'); if (segm_button.length) { // Segmentation button exists var OsViewer = ($container.attr('id') === 'seadragon')? seadragon() : false; if (segm_button.hasClass('channel_inactive')) { OsViewer.removeOverlay($('#seadragon_overlay_img')[0]); } else { var $overlay = $('#seadragon_overlay').find('img').clone(true).attr('id', 'seadragon_overlay_img'); var coord = OsViewer.viewport.imageToViewportRectangle(0, 0, $overlay.data('width'), $overlay.data('height')); OsViewer.addOverlay($overlay[0], coord, OpenSeadragon.OverlayPlacement.TOP_LEFT); } } }); // Compare sample $('.cellImg.thumb').draggable({ start: function() { }, stop: function() { var over = $(this).data('over'); if (over) { placeImage($(this), over, true); } }, revert: true, revertDuration: 50 }).each(function() { $(this).draggable("option", "containment", $(this).closest('.cellImages')); }).on('click', function() { return imgClickHandler(this); }).each(function() { $(this).attr('onclick', ''); }); $('.cellImg.medium').droppable({ over: function(event, ui) { ui.draggable.data('over', $(this)); }, out: function(event, ui) { ui.draggable.removeData('over'); } }); $('button.compare').on('click', function() { var container = $(this).closest('.cellImages'); if (typeof container.data('checked') !== 'undefined') { for (var i in container.data('checked')) { if (container.data('checked').hasOwnProperty(i)) { placeImage(container.find('.cellImg.thumb[data-name="'+container.data('checked')[i].val()+'"]'), container.find('.medium[data-name="'+(i*1+1)+'"]')); } } } }); $('input.compare').on('change', function() { var container = $(this).closest('.cellImages'); if (typeof container.data('checked') === 'undefined') { container.data('checked', []); } var checked = []; // remove me from selected for (var i in container.data('checked')) { if (container.data('checked').hasOwnProperty(i)) { if (!container.data('checked')[i].is($(this))) { checked.push(container.data('checked')[i]); } } } // add me if checked if ($(this).is(':checked')) { checked.push($(this)); } // remove first if too many if (checked.length > 3) { checked.shift().prop('checked', false); } container.data('checked', checked); }); function placeImage($el, $slot, drag) { var outerContainer = $el.closest('.cellImages'); var imgContainer = $slot.closest('.cellImage'); $slot.off('click'); $slot.on('click', function() { return imgClickHandler(this); }); // Replace image $slot.html($el.html().replace(/thumb/g, 'medium')).attr({ 'href': $el.attr('href') }); var imgElem = $el.find('img.channel_image').get(0).dataset; if (imgElem.hasOwnProperty('stack')) { $slot.get(0).stackData = JSON.parse(imgElem.stack); } else { $slot.get(0).stackData = undefined; } // Text updateImageInfo(imgContainer, $el); // Update numbers & checkboxes(drag) if (drag) { outerContainer.find('input.compare').prop('checked', false).trigger('change'); } outerContainer.find('.thumb .image_number').text(""); outerContainer.find('.medium .channel_image[base]').each(function() { var num = $(this).parent().attr('data-name'); var base = $(this).attr('base'); $(this).siblings('.image_number').text(num); outerContainer.find('.thumb img[base="'+base+'"]').siblings('.image_number').each(function() { var txt = $(this); txt.text((txt.text() ? txt.text()+',' : '')+num); }); if (drag) { var name = $(this).attr('data-name'); outerContainer.find('#compare_'+name).prop('checked', true).trigger('change'); } }); } function updateImageInfo(container, $el) { var imageinfoEl = container.find('span.imageinfo'); imageinfoEl.text($el.find('.channel_image').attr('alt')); var channelImage = $el.find('.channel_image').get(0); var zindex = parseInt(channelImage.dataset.zindex, 10); var stackImageEl = container.find('.stack_image'); var stackSliderP = container.find('.stackSlider'); if (zindex) { var ztotal = channelImage.dataset.ztotal; stackImageEl.text(subcell_stack_text(zindex, ztotal)); var slider = stackSliderP.find('input[type="range"]'); slider.prop('value', zindex); slider.prop('max', ztotal); stackSliderP.show(); } else { stackImageEl.text(''); stackSliderP.hide(); } } $('.stackSlider .slider').on('input', function() { var newValue = this.value; var maxValue = this.max; $(this).closest('.cellImage').find('.stack_image').text(subcell_stack_text(newValue, maxValue)); var c1 = $(this).parents('.cellImages').get(0); var c = $(c1).getChannelString($(c1).getActiveChannels()); var cellImg = $(this).parentsUntil('.cellImage').parent(); var imgData = cellImg.find('.cellImg').get(0).stackData[newValue]; var newSrc = imgData.filename + '_' + c + '_medium.jpg'; cellImg.find('.channel_image').get(0).src = newSrc; cellImg.find('.cellImg').get(0).href = newSrc; cellImg.find('.channel_image').get(0).dataset.zindex = newValue; cellImg.find('.channel_image').prop('base', imgData.filename); cellImg.find('.channel_image').attr('base', imgData.filename); }); $('body').on('input', '#seadragon_meta input.stackSlider', function() { var newValue = this.value; var maxValue = this.max; $(this).parent().find('.stack_image').text(subcell_stack_text(newValue, maxValue)); var sea = $(this).closest('#seadragon'); var imgData = $('#seadragon_meta').get(0).stackData[newValue]; sea.data('base', imgData.filename); sea.toggleChannel(true); }); $('.cellImages, #seadragon').each(function() { if ($(this).find('input.compare:checked').length) { $(this).find('input.compare:checked').trigger('change'); } else { var interval = $(this).attr('interval'); if (!interval) { interval = 2; } var inpts = $(this).find('td:not(.nocompareinit) input.compare'); var c = 0; if ($(this).closest("#sirna").length) { var z = $("#sirna tr.scrambled td:not(.nocompareinit) input.compare:first"); var ab = z.closest("tr").attr("class").match("ab[0-9]+")[0]; var z2 = $("#sirna tr.notscrambled."+ab+" td:not(.nocompareinit) input.compare"); z.prop('checked', true).trigger('change'); c = 1; z2.each(function() { if (c>=3) { return; } $(this).prop('checked', true).trigger('change'); c++; }); } else { inpts.each(function(i) { if (c===3) { return; } if (i%interval === 0 || inpts.length<5) { $(this).prop('checked', true).trigger('change'); c++; } }); } } $(this).find('button.compare').trigger('click'); }); // Reactome // Check if gene exists in Reactome if ($(".reactome").length) { $.get('https://reactome.org/ContentService/data/mapping/ENSEMBL/'+$('.gene_name[id]').attr('id')+'/pathways', function() { $(".reactome").each(function() { // The URL of the analysis method var reactomeURI = 'https://reactome.org/AnalysisService/identifiers/url/projection?pageSize=1&page=1'; // The URL of our sample to be submitted for analysis var dataUrl = 'https://'+window.location.hostname+"/download/if_location.php?"; var locs = $(this).attr('data-name').split(','); if (locs.length>0 && locs[0] !== "") { for (var i in locs) { if (locs.hasOwnProperty(i)) { dataUrl += "locations[]=" + locs[i].trim() + "&"; } } } var $container = $(this); // Perform the ajax call to the analysis service jQuery.ajax({ type: "POST", url: reactomeURI, data: dataUrl, dataType: "json", headers: { "Content-Type": "text/plain" } }).done(function (data, textStatus) { if (textStatus === 'success') { $.each(data.pathways, function(){ $container.find(".reactomeLink").html('<a href="https://reactome.org/PathwayBrowser/#/DTAB=AN&ANALYSIS='+data.summary.token+'&FLG='+$('.gene_name[id]').text()+'" target="_blank" rel="noopener">View proteome in REACTOME</a>'); }); } }).fail(function () { $container.find(".reactomeLink").html("(Failed to get Reactome Data)"); }); }); }); } $('div#clusterPlotSlider .active').trigger('change'); $('#locationLegend .location .locationName, #locationLegend .location .color').on('click', function() { // Add or remove active class from the clicked element var elem; if (!$(this).hasClass('locationName')) { elem = $(this).siblings('.locationName'); } else { elem = $(this); } elem.toggleClass('active'); if (elem.hasClass('active')) { elem.removeClass('inactive'); } if ($('#locationLegend .location .locationName.active').length) { // If at least one location is active, make sure all non-active locations have the inactive class // to grey out the inactive legends $('#locationLegend .location .locationName:not(.active):not(.inactive)').addClass('inactive'); } else { $('#locationLegend .location .locationName').removeClass('inactive'); } var name = []; $('#locationLegend .location .locationName.active').each(function() { name.push($(this).text()); }); geneFilters.location = name.length ? name : undefined; $('#' + getSubcellActivePlotID()).trigger('plot_filter'); }); }); $.fn.mvavgScatterPlot = function(data, inSettings) { 'use strict'; var plot = {}; var extraDefaults = { xMin: false, xMax: false, yMin: false, yMax: false, xTickFormat: ".2s", xNumMaxTicks: 6, xNumMinTicks: 4, yNumMaxTicks: 10, yNumMinTicks: 4, transitionTime: 1000 }; var settings = addDefaultPlotSettings(inSettings, extraDefaults); plot.settings = settings; // Inner dimension var w = plot.w = settings.dimension.w - settings.padding.l - settings.padding.r; // inner width var h = plot.h = settings.dimension.h - settings.padding.t - settings.padding.b; // inner height var xMin = Infinity; var xMax = -Infinity; var yMin = Infinity; var yMax = -Infinity; var scatter = data.scatter; for (var i in scatter) { if (!scatter.hasOwnProperty(i)) { continue; } for (var j in scatter[i].data) { if (!scatter[i].data.hasOwnProperty(j)) { continue; } xMin = settings.xMin===false? Math.min(xMin, scatter[i].data[j].x) : settings.xMin; xMax = settings.xMax===false? Math.max(xMax, scatter[i].data[j].x) : settings.xMax; yMin = settings.yMin===false? Math.min(yMin, scatter[i].data[j].y) : settings.yMin; yMax = settings.yMax===false? Math.max(yMax, scatter[i].data[j].y) : settings.yMax; } } plot.xMin = xMin; plot.xMax = xMax; plot.yMin = yMin; plot.yMax = yMax; var color = plot.color = d3.scaleOrdinal() .range(settings.color) .domain(d3.map(data.scatter, function(d, idx) { return idx; })); // X axis var xScale = plot.x = d3.scaleLinear() .domain([xMin, xMax]) .range([0, w]); // Y axis var yScale = plot.y = d3.scaleLinear() .domain([yMin, yMax]) .range([h, 0]); var xAxis = d3.axisBottom(xScale) .tickFormat(d3.format(settings.xTickFormat)) .ticks(Math.min(Math.max(Math.ceil(xMax), settings.xNumMinTicks), settings.xNumMaxTicks)); var yAxis = d3.axisLeft(yScale) .tickFormat(d3.format(settings.yTickFormat)) .ticks(Math.min(Math.max(Math.ceil(yMax), settings.yNumMinTicks), settings.yNumMaxTicks)); if (settings.grid) { yAxis.tickSizeInner(-w); } // Visualisation selection var vis = plot.vis = d3.select($(this).get(0)) .append("svg") .attr("width", settings.dimension.w) .attr("height", settings.dimension.h) .attr("class", "chart scatterplot") .append("g") .attr("transform", "translate(" + settings.padding.l + "," + settings.padding.t + ")"); // Plot area background vis.append("rect") .attr("class", "plotBG") .attr("width", xScale(xMax)) .attr("height", yScale(0)); // The background areas var area = d3.area() .x(function(d) { return xScale(parseFloat(data.confidence[0].data[d].mvavg_x)); }) .y0(function(d) { return yScale(parseFloat(data.confidence[0].data[d].mvavgs_10p)); }) .y1(function(d) { return yScale(parseFloat(data.confidence[0].data[d].mvavgs_90p)); }); vis.append("path") .datum(d3.range( data.confidence[0].data.length)) .attr("fill", data.confidence[0].colors.outer) .attr('d', area); area = d3.area() .x(function(d) { return xScale(parseFloat(data.confidence[0].data[d].mvavg_x)); }) .y0(function(d) { return yScale(parseFloat(data.confidence[0].data[d].mvavgs_25p)); }) .y1(function(d) { return yScale(parseFloat(data.confidence[0].data[d].mvavgs_75p)); }); vis.append("path") .datum(d3.range( data.confidence[0].data.length)) .attr("fill", data.confidence[0].colors.inner) .attr('d', area); // The points var group = vis.selectAll(".group") .data(scatter) .enter().append("g") .attr("class", function(d, idx) { return "group group" + idx; }) .attr("name", function(d, idx) { return "group" + idx; }) .style("fill", function(d, idx) { return d.color ? d.color : color(idx); }) .attr("fill-opacity", "0.3") .each(function(d) { d3.select(this).selectAll('.dot') .data(d.data) .enter() .append("a") .attr('class', function(d) { return d.class ? 'dot ' + d.class : 'dot'; }) .attr('transform', function(d) { return 'translate(' + [xScale(d.x), yScale(d.y)] + ')'; }) .each(function(d) { if (d.url) { d3.select(this).attr("xlink:href", d.url); } if (d.tooltip) { d3.select(this).attr("title", d.tooltip); } if (settings.valueLabels) { d3.select(this).append('text').text(d.x+','+d.y); } }) .append("path") .attr('d', d3.symbol().size(d.size||15).type(getD3Symbol(d.symbol))); }); // The line for average var average = d3.line() .x(function(d) { return xScale(parseFloat(data.confidence[0].data[d].mvavg_x)); }) .y(function(d) { return yScale(parseFloat(data.confidence[0].data[d].mvavg_y)); }); vis.append("path") .datum(d3.range( data.confidence[0].data.length)) .attr("fill", "none") .attr("stroke", data.confidence[0].colors.line) .attr('d', average); // Add larger tooltip area behind dot group.selectAll("a") .append("circle") .attr("r", 4) .style("fill", 'transparent'); // Y axis if (settings.yAxisLabel) { var xPos = -h/2; var yPos = -30; var yAxisLabel = vis.append("g") .attr("class", "y axis") .call(yAxis) .append("text") .attr("transform", "rotate(-90)") .attr("y", yPos) .attr("x", xPos) .attr("class", "label") .attr("text-anchor", "middle"); if (settings.yAxisLabel.indexOf("\n") !== -1) { var yLabels = settings.yAxisLabel.split("\n"); var dy = -1 * (yLabels.length-1); for (var label of yLabels) { yAxisLabel.append("tspan") .attr("x", xPos) .attr("dy", dy+"em") .text(label); dy = 1.2; } } else { yAxisLabel.text(settings.yAxisLabel); } } // X axis if (settings.xAxisLabel) { vis.append("g") .attr("class", "x axis") .attr("transform", "translate(0," + h + ")") .call(xAxis) .append("text") .attr("y",30) .attr("x", w/2) .attr("class", "label") .style("text-anchor", "middle") .text(settings.xAxisLabel); } // Legend if (settings.legend !== '') { var legend = vis.selectAll(".legend") .data(data) .enter().append("g") .attr("class", function(d, i) { return 'legend legend' + i; }) .attr("name", function(d, i) { return 'legend' + i; }) .attr("transform", function(d, i) { return 'translate(' + settings.legend.x + ',' + (settings.legend.y + i * (settings.legend.size + 2)) + ')'; }); legend.append("rect") .attr("width", settings.legend.size) .attr("height", settings.legend.size) .style("fill", function(d, i) { return d.color ? d.color : color(i); }); legend.append("text") .attr("x", settings.legend.size+2) .attr("y", settings.legend.size/2) .attr("dy", ".35em") .text(function(d) { return d.name; }); } $(this).on('rescale', function(e, scale) { var plot = $(this).data('plot'); if (scale === 'xlog') { xScale = plot.x = d3.scaleLog() .domain([Math.max(0.0001, xMin), xMax]) .range([0, w]); xAxis = d3.axisBottom(xScale) .tickValues([1e-3,1e-2,1e-1,1e0,1e1,1e2,1e3].filter(function(d) { return (d < xMax); })); vis.selectAll('.x.axis .label').text(function() { return 'log ' + d3.select(this).text(); }); } else if (scale === 'xlin') { xScale = plot.x = d3.scaleLinear() .domain([xMin, xMax]) .range([0, w]); xAxis = d3.axisBottom(xScale) .tickFormat(d3.format(".2s")); vis.selectAll('.x.axis .label').text(function() { return d3.select(this).text().replace('log ', ''); }); } else if (scale === 'ylog') { yScale = plot.y = d3.scaleLog() .domain([Math.max(0.0001, yMin), yMax]) .range([h, 0]); yAxis = d3.axisLeft(yScale) .tickValues([1e-3,1e-2,1e-1,1e0,1e1,1e2,1e3].filter(function(d) { return (d < yMax); })); vis.selectAll('.y.axis .label').text(function() { return 'log ' + d3.select(this).text(); }); } else if (scale === 'ylin') { yScale = plot.y = d3.scaleLinear() .domain([yMin, yMax]) .range([h, 0]); yAxis = d3.axisLeft(yScale) .tickFormat(d3.format(".2s")); vis.selectAll('.y.axis .label').text(function() { return d3.select(this).text().replace('log ', ''); }); } else { return; } var t = d3.transition().duration(settings.transitionTime); group.each(function(d) { d3.select(this).selectAll('.dot') .data(d.data) .transition(t) .attr('transform', function(d) { var xp = xScale(d.x); var yp = yScale(d.y); return (xp === -Infinity || yp === -Infinity) ? 'translate(0,' + h + ')' : 'translate(' + [xp, yp] + ')'; }); }); vis.selectAll(".xScaleDependent") .transition(t) .attr('transform', function() { var node = d3.select(this); if (node.classed('yScaleDependent')) { return 'translate('+xScale(node.attr('xVal'))+', '+yScale(node.attr('yVal'))+')'; } else { return 'translate('+xScale(node.attr('xVal'))+')'; } }); vis.selectAll(".axis.x") .transition(t) .call(xAxis); vis.selectAll(".axis.y") .transition(t) .call(yAxis); $(this).data('plot', plot); }); $(this).data('plot', plot); return plot; }; function subcell_stack_text(currentValue, maxValue) { return `Z-stack: ${currentValue}/${maxValue}`; }