/**
* @file overlayUtils.js Interface to ask information to OSD
* @author Leslie Solorzano
* @see {@link overlayUtils}
*/
/**
* @namespace overlayUtils
* @property {Bool} overlayUtils._drawRegions - If false then disable the drawing of regions
* @property {Object} overlayUtils._d3nodes - Main group or container of all d3 svg groups of overlays corresponding to the 3 main marker data groups
* @property {Number} overlayUtils._percentageForSubsample - Take this percentage of each barcode when downsamplir for lower resolutions
* @property {Number} overlayUtils._zoomForSubsample - When the zoom is bigger than this, display all the checked genes
*/
overlayUtils = {
_drawRegions: false,
_d3nodes: {},
_percentageForSubsample: 0.25,
_zoomForSubsample:5.15,
_layerOpacities:{},
_linkMarkersToChannels:false,
_collectionMode:false
}
/**
* This method is used to add all layers from tmapp */
overlayUtils.addAllLayers = function() {
/* For backward compatibility with tmapp.fixed_file, but converted to a layer */
if (tmapp.fixed_file && tmapp.fixed_file != "") {
tmapp.layers.unshift({"name":tmapp.slideFilename, "tileSource":tmapp.fixed_file})
/*overlayUtils.addLayer(tmapp.slideFilename, tmapp._url_suffix + tmapp.fixed_file, -1)*/
tmapp.fixed_file = "";
}
tmapp.layers.forEach(function(layer, i) {
overlayUtils.addLayer(layer, i-1);
});
overlayUtils.addAllLayersSettings();
setTimeout(overlayUtils.setCollectionMode,500);
}
/**
* This method is used to add all layer settings */
overlayUtils.addAllLayersSettings = function() {
var settingsPanel = document.getElementById("image-overlay-panel");
settingsPanel.innerHTML = "";
tmapp.layers.forEach(function(layer, i) {
overlayUtils.addLayerSettings(layer.name, layer.tileSource, i-1);
});
filterUtils.setRangesFromFilterItems();
// Add collection mode checkbox:
if (document.getElementById("setCollectionModeRow")) {
document.getElementById("setCollectionModeRow").remove();
}
var extraAttributes = {
class: "form-check-input",
type: "checkbox"
};
if (projectUtils._activeState.collectionMode) {
extraAttributes.checked = true;
}
var input11 = HTMLElementUtils.createElement({
kind: "input",
id: "setCollectionMode",
extraAttributes: extraAttributes,
});
var label11 = HTMLElementUtils.createElement({
kind: "label",
extraAttributes: { for: "setCollectionMode" },
});
label11.innerHTML = " Collection mode";
var row = HTMLElementUtils.createRow({ id: "setCollectionModeRow"});
var col1 = HTMLElementUtils.createColumn({ width: 12 });
col1.appendChild(input11);
col1.appendChild(label11);
row.appendChild(col1);
settingsPanel.after(row);
input11.addEventListener("change", (event) => {
projectUtils._activeState.collectionMode = event.target.checked;
overlayUtils.setCollectionMode();
});
}
/**
* This method is used to add a layer */
overlayUtils.addLayerSettings = function(layerName, tileSource, layerIndex, checked) {
var settingsPanel = document.getElementById("image-overlay-panel");
var layerTable = document.getElementById("image-overlay-tbody");
if (!layerTable) {
layerTable = document.createElement("table");
layerTable.id = "image-overlay-table";
layerTable.className += "table table-striped"
layerTable.style.marginBottom = "0px";
filterHeaders = "";
for (filterIndex = 0; filterIndex < filterUtils._filtersUsed.length; filterIndex++) {
filterHeaders += "<th class='text-center'>" + filterUtils._filtersUsed[filterIndex] + "</th>";
}
layerTable.innerHTML = `<thead>
<th class='text-center'>Name</th>
<th class='text-center'>Visible</th>
<th class='text-center'>Opacity</th>` +
filterHeaders +
"</thead><tbody id='image-overlay-tbody'></tbody>"
settingsPanel.appendChild(layerTable);
}
layerTable = document.getElementById("image-overlay-tbody");
var tr = document.createElement("tr");
var visible = document.createElement("input");
visible.type = "checkbox";
if (layerIndex < 0 || checked)
visible.checked = true;
visible.id = "visible-layer-" + (layerIndex + 1);
visible.classList.add("visible-layers");
visible.classList.add("form-check-input")
visible.setAttribute("layer", (layerIndex + 1));
var td_visible = document.createElement("td");
td_visible.appendChild(visible);
td_visible.classList.add("text-center");
var opacity = document.createElement("input");
opacity.classList.add("overlay-slider");
opacity.classList.add("form-range");
opacity.type = "range";
opacity.setAttribute("min", "0");
opacity.setAttribute("max", "1");
opacity.setAttribute("step", "0.1");
opacity.setAttribute("layer", (layerIndex + 1));
opacity.id = "opacity-layer-" + (layerIndex + 1);
var td_opacity = document.createElement("td");
td_opacity.appendChild(opacity);
td_opacity.classList.add("text-center");
tileSource = tileSource.replace(/\\/g, '\\\\');
var td_name = HTMLElementUtils.createElement({kind:"td",extraAttributes:{"data-source":tileSource, "class":"layerSettingButton"}});
td_name.innerHTML = layerName;
tr.appendChild(td_name);
tr.appendChild(td_visible);
tr.appendChild(td_opacity);
for (filterIndex = 0; filterIndex < filterUtils._filtersUsed.length; filterIndex++) {
filterName = filterUtils._filtersUsed[filterIndex];
filterParams = filterUtils.getFilterParams(filterName)
filterParams.layer = layerIndex + 1;
filterInput = filterUtils.createHTMLFilter(filterParams);
if (filterParams.type == "range") {
filterInput.classList.add("overlay-slider");
filterInput.classList.add("form-range");
}
else if (filterParams.type == "checkbox") {
filterInput.classList.add("form-check-input");
}
else if (filterParams.type == "color") {
filterInput.classList.add("form-range");
}
var td_filterInput = document.createElement("td");
td_filterInput.classList.add("text-center");
td_filterInput.appendChild(filterInput);
tr.appendChild(td_filterInput);
}
layerTable.prepend(tr);
visible.addEventListener("change", function(ev) {
var layer = ev.srcElement.getAttribute("layer")
var slider = document.querySelectorAll('[layer="' + layer + '"][type="range"]')[0];
var checkbox = ev.srcElement;
if (checkbox.checked) {
overlayUtils._layerOpacities[layer] = slider.value;
} else {
overlayUtils._layerOpacities[layer] = 0;
}
overlayUtils.setItemOpacity(layer);
});
opacity.addEventListener("input", function(ev) {
var layer = ev.srcElement.getAttribute("layer")
var slider = ev.srcElement;
var checkbox = document.querySelectorAll('[layer="' + layer + '"][type="checkbox"]')[0];
if (checkbox.checked) {
overlayUtils._layerOpacities[layer] = slider.value;
} else {
overlayUtils._layerOpacities[layer] = 0;
}
overlayUtils.setItemOpacity(layer);
});
overlayUtils.addLayerSlider();
}
/**
* This method is used to add a layer */
overlayUtils.addLayerSlider = function() {
if (document.getElementById("channelRangeInput") == undefined) {
var elt = document.createElement('div');
elt.className = "channelRange px-1 mx-1 viewer-layer";
elt.id = "channelRangeDiv"
elt.style.zIndex = "100";
var span = document.createElement('div');
span.innerHTML = "Channel 1"
span.id = "channelValue"
span.style.maxWidth="200px";
span.style.overflow="hidden";
var channelRange = document.createElement("input");
channelRange.classList.add("form-range");
channelRange.type = "range";
channelRange.style.width = "200px";
channelRange.id = "channelRangeInput";
elt.appendChild(span);
elt.appendChild(channelRange);
changeFun = function(ev) {
var slider = $(channelRange)[0];
channel = slider.value;
$(".visible-layers").prop("checked",true);$(".visible-layers").click();$("#visible-layer-"+(channel- -1)).click();
channelName = tmapp.layers[channel- -1].name
channelId = channelName.replace(".dzi","");
document.getElementById("channelValue").innerHTML = "Channel " + (channel - -2) + ": " + channelName;
if (overlayUtils._linkMarkersToChannels) {
$(".uniquetab-marker-input").prop("checked",false);
if (document.getElementById("uniquetab_"+channelId+"_check")) {
$(document.getElementById("uniquetab_"+channelId+"_check")).click();
}
else {
$("#uniquetab_all_check").prop("checked",true);
$("#uniquetab_all_check").click();
}
}
};
channelRange.addEventListener("input", changeFun);
var mousewheelevt = (/Firefox/i.test(navigator.userAgent)) ? "DOMMouseScroll" : "mousewheel";
$(elt).bind(mousewheelevt, moveSlider);
function moveSlider(e){
var zoomLevel = parseInt($(channelRange).val());
// detect positive or negative scrolling
if ( e.originalEvent.wheelDelta < 0 ) {
//scroll down
$(channelRange).val(zoomLevel+1);
} else {
//scroll up
$(channelRange).val(zoomLevel-1);
}
// trigger the change event
changeFun(e.originalEvent);
//prevent page fom scrolling
return false;
}
tmapp['ISS_viewer'].addControl(elt,{anchor: OpenSeadragon.ControlAnchor.BOTTOM_LEFT});
}
channelRange = document.getElementById("channelRangeInput");
var op = tmapp["object_prefix"];
var nLayers = tmapp.layers.length;
if (tmapp.fixed_file && tmapp.fixed_file != "") {
nLayers += 1
}
channelRange.setAttribute("min", -1);
channelRange.setAttribute("max", nLayers - 2);
channelRange.setAttribute("step", "1");
channelRange.setAttribute("value", "-1");
if (nLayers <= 1) {
document.getElementById("channelRangeDiv").style.display = "none";
}
else {
document.getElementById("channelRangeDiv").style.display = "table";
}
}
/**
* This method is used to add a layer from select input */
overlayUtils.addLayerFromSelect = function() {
var e = document.getElementById("layerSelect");
var layerName = e.options[e.selectedIndex].text;
var tileSource = e.options[e.selectedIndex].value;
var layer = {
name: layerName,
tileSource: tileSource
}
tmapp.layers.push(layer);
i = tmapp.layers.length - 1;
overlayUtils.addLayer(layer, i);
overlayUtils.addAllLayersSettings();
}
/**
* This method is used to add a layer */
overlayUtils.addLayer = function(layer, i, visible) {
const queryString = window.location.search;
const urlParams = new URLSearchParams(queryString);
const path = urlParams.get('path')
var layerName = layer.layerName
var tileSource = layer.tileSource
if (path != null) {
tileSource = path + "/" + tileSource
}
var op = tmapp["object_prefix"];
var vname = op + "_viewer";
var opacity = 1.0;
if (i >= 0 && !visible) {
opacity = 0.0;
}
var showModal = true;
var loadingModal = null;
setTimeout(function(){
if (showModal)
loadingModal = interfaceUtils.loadingModal("Converting image, please wait...");
},800);
if (tmapp["ISS_viewer"].world.getItemCount() != 0) {
if (tmapp["ISS_viewer"].world.getItemAt(0).source.getTileUrl(0,0,0) == null) {
tmapp["ISS_viewer"].close();
}
}
var x = layer.x || 0;
var y = layer.y || 0;
var scale = layer.scale || 1;
var flip = layer.flip || false;
var rotation = layer.rotation || 0;
if (layer.transform_matrix) {
var transform_matrix = layer.transform_matrix.map(Number)
rotation = Math.atan2(transform_matrix[1], transform_matrix[0]) * 360 / (2*Math.PI)
var shear_y = Math.atan2(transform_matrix[4], transform_matrix[1]) - Math.PI/2 - (2*Math.PI*rotation / 360)
var scale_x = Math.sqrt(transform_matrix[0] * transform_matrix[0] + transform_matrix[3] * transform_matrix[3])
var scale_y = Math.sqrt(transform_matrix[1] * transform_matrix[1] + transform_matrix[4] * transform_matrix[4]) * Math.cos(shear_y)
if (scale_x < 0) {
scale_x = -scale_x;
flip = true;
}
if (scale_y < 0) {
scale_y = -scale_y;
flip = true;
rotation += 180;
}
scale = (scale_x + scale_y) / 2.;
x = transform_matrix[2]
y = transform_matrix[5]
layer.x = x;
layer.y = y;
layer.scale = scale;
layer.rotation = rotation;
layer.flip = flip;
}
tmapp[vname].addTiledImage({
index: i + 1,
x: 0,
y: 0,
tileSource: tmapp._url_suffix + tileSource,
opacity: opacity,
success: function(i) {
layer0X = tmapp[op + "_viewer"].world.getItemAt(0).getContentSize().x;
layerNX = tmapp[op + "_viewer"].world.getItemAt(tmapp[op + "_viewer"].world.getItemCount()-1).getContentSize().x;
tmapp[op + "_viewer"].world.getItemAt(tmapp[op + "_viewer"].world.getItemCount()-1).setWidth(scale*layerNX/layer0X);
var point = new OpenSeadragon.Point(x/layer0X, y/layer0X);
tmapp[op + "_viewer"].world.getItemAt(tmapp[op + "_viewer"].world.getItemCount()-1).setPosition(point);
tmapp[op + "_viewer"].world.getItemAt(tmapp[op + "_viewer"].world.getItemCount()-1).setRotation(rotation);
tmapp[op + "_viewer"].world.getItemAt(tmapp[op + "_viewer"].world.getItemCount()-1).setFlip(flip);
if (loadingModal) {
setTimeout(function(){$(loadingModal).modal("hide");}, 500);
}
showModal = false;
if (filterUtils._compositeMode == "collection") {
filterUtils.setCompositeOperation();
}
},
error: function(i) {
if (loadingModal) {
setTimeout(function(){$(loadingModal).modal("hide");}, 500);
}
interfaceUtils.alert("Impossible to load file.")
showModal = false;
}
});
}
/**
* @summary Set collection mode of layers */
overlayUtils.setCollectionMode = function() {
var op = tmapp["object_prefix"];
overlayUtils.waitLayersReady().then(() => {
if (projectUtils._activeState.collectionMode) {
overlayUtils._collectionMode = true;
var collectionLayout = {
tileSize: 1, tileMargin: 0.1,
columns: Math.ceil(Math.sqrt(tmapp.layers.length))
}
if (projectUtils._activeState["collectionLayout"] !== undefined) {
collectionLayout = projectUtils._activeState["collectionLayout"];
}
tmapp["ISS_viewer"].world.arrange(collectionLayout);
var inputs = document.querySelectorAll(".visible-layers");
for(var i = 0; i < inputs.length; i++) {
inputs[i].checked = false;
inputs[i].click();
}
tmapp["ISS_viewer"].viewport.goHome();
$(".channelRange").hide();
}
else if (overlayUtils._collectionMode){
overlayUtils._collectionMode = false;
tmapp["ISS_viewer"].world.setAutoRefigureSizes(false);
for (var i = 0; i < tmapp["ISS_viewer"].world._items.length; i++) {
layer = tmapp.layers[i];
var x = layer.x || 0;
var y = layer.y || 0;
var scale = layer.scale || 1;
var item = tmapp["ISS_viewer"].world._items[i];
var layer0X = tmapp[op + "_viewer"].world.getItemAt(0).getContentSize().x;
var layerNX = item.getContentSize().x;
item.setWidth(scale*layerNX/layer0X);
var point = new OpenSeadragon.Point(x/layer0X, y/layer0X);
item.setPosition(point);
}
tmapp["ISS_viewer"].world.setAutoRefigureSizes(true);
tmapp["ISS_viewer"].viewport.goHome();
$(".channelRange").show();
}
});
}
/**
* @param {Number} item Index of an OSD tile source
* @summary Set the opacity of a tile source */
overlayUtils.setItemOpacity = function(item) {
opacity = overlayUtils._layerOpacities[item];
var op = tmapp["object_prefix"];
if (!tmapp[op + "_viewer"].world.getItemAt(item)) {
setTimeout(function() {
overlayUtils.setItemOpacity(item);
}, 100);
return;
}
tmapp[op + "_viewer"].world.getItemAt(item).setOpacity(opacity);
}
overlayUtils.areAllFullyLoaded = function () {
var tiledImage;
var op = tmapp["object_prefix"];
var count = tmapp[op + "_viewer"].world.getItemCount();
for (var i = 0; i < count; i++) {
tiledImage = tmapp[op + "_viewer"].world.getItemAt(i);
if (Object.keys(tiledImage.loadingCoverage).length > 0) {
if (!tiledImage.getFullyLoaded() && tiledImage.getOpacity() != 0) {
return false;
}
}
}
return true;
}
overlayUtils.waitLayersReady = function () {
function sleep (time) {
return new Promise((resolve) => setTimeout(resolve, time));
}
return new Promise((resolve, reject) => {
sleep(200).then (()=>{
var op = tmapp["object_prefix"];
if (!tmapp[op + "_viewer"].world || !tmapp[op + "_viewer"].world.getItemCount() != tmapp.layers.length) {
resolve();
return;
}
else {
overlayUtils.waitLayersReady().then(()=>{
setTimeout(resolve,200);
return;
});
}
});
});
}
overlayUtils.waitFullyLoaded = function () {
function sleep (time) {
return new Promise((resolve) => setTimeout(resolve, time));
}
return new Promise((resolve, reject) => {
sleep(400).then (()=>{
if (overlayUtils.areAllFullyLoaded()) {
resolve();
return;
}
else {
overlayUtils.waitFullyLoaded().then(()=>{
resolve();
return;
});
}
});
});
}
/**
* @param {String} layerName name of an existing d3 node
* @param {Number} opacity desired opacity
* @summary Set the opacity of a tile source */
overlayUtils.setLayerOpacity= function(layerName,opacity){
if(layerName in overlayUtils._d3nodes){
var layer = overlayUtils._d3nodes[layerName];
layer._groups[0][0].style.opacity=opacity;
}else{
console.log("layer does not exist or is not a D3 node");
}
}
/**
* @param {String} colortype A string from [hex,hsl,rgb]
* @summary Get a random color in the desired format
*/
overlayUtils.randomColor = function (colortype) {
if (!colortype) {
colortype = "hex";
}
//I need random colors that are far away from the palette in the image
//in this case Hematoxilyn and DAB so far away from brown and light blue
//and avoid light colors because of the white background
//in HSL color space this means L from 0.2 to 0.75
//H [60,190],[220,360], S[0.3, 1.0]
var rh1 = Math.floor(Math.random() * (190 - 60 + 1)) + 60;
var rh2 = Math.floor(Math.random() * (360 - 220 + 1)) + 220;
var H = 0.0;
if (Math.random() > 0.5) { H = rh1; } else { H = rh2; }
var L = Math.floor(Math.random() * (75 - 20 + 1)) + 20 + '%';
var S = Math.floor(Math.random() * (100 - 40 + 1)) + 40 + '%';
var hslstring = 'hsl(' + H.toString() + ',' + S.toString() + ',' + L.toString() + ')';
var d3color = d3.hsl(hslstring);
if (colortype == "hsl") return hslstring;
if (colortype == "rgb") {
return d3color.rgb().toString();
}
if (colortype == "hex") {
var hex = function (value) {
value = Math.max(0, Math.min(255, Math.round(value) || 0));
return (value < 16 ? "0" : "") + value.toString(16);
}
var rgbcolor = d3color.rgb();
return "#" + hex(rgbcolor.r) + hex(rgbcolor.g) + hex(rgbcolor.b);
}
}
/**
* Main function to update the view if there has been a reason for it.
* It computes all the elements that have to be drawn.
*/
overlayUtils.modifyDisplayIfAny = function () {
//get four corners of view
var op = tmapp["object_prefix"];
var bounds = tmapp[op + "_viewer"].viewport.getBounds();
var currentZoom = tmapp[op + "_viewer"].viewport.getZoom();
var xmin, xmax, ymin, ymax;
xmin = bounds.x; ymin = bounds.y;
xmax = xmin + bounds.width; ymax = ymin + bounds.height;
var imageWidth = OSDViewerUtils.getImageWidth();
var imageHeight = OSDViewerUtils.getImageHeight();
if (xmin < 0) { xmin = 0; }; if (xmax > 1.0) { xmax = 1.0; };
if (ymin < 0) { ymin = 0; }; if (ymax > imageHeight / imageWidth) { ymax = imageHeight / imageWidth; };
var total = imageWidth * imageHeight;
//convert to global image coords
xmin *= imageWidth; xmax *= imageWidth; ymin *= imageWidth; ymax *= imageWidth;
var portion = (xmax - xmin) * (ymax - ymin);
var percentage = portion / total;
}
/**
* Save the current SVG overlay to open in a vector graphics editor for a figure for example
*/
overlayUtils.saveSVG=function(){
var svg = d3.select("svg");
var svgData = svg._groups[0][0].outerHTML;
var svgBlob = new Blob([svgData], {type:"image/svg+xml;charset=utf-8"});
var svgUrl = URL.createObjectURL(svgBlob);
var downloadLink = document.createElement("a");
downloadLink.href = svgUrl;
downloadLink.download = "currentview.svg";
document.body.appendChild(downloadLink);
downloadLink.click();
document.body.removeChild(downloadLink);
}
/**
* Save the current canvas as a PNG image
*/
overlayUtils.savePNG=function() {
interfaceUtils.prompt("Resolution for export (1 = screen resolution):<br/>High resolution can take time to load!</small>","4","Capture viewport","number")
.then((resolution) => {
var bounds = tmapp.ISS_viewer.viewport.getBounds();
var loading=interfaceUtils.loadingModal();
tmapp.ISS_viewer.world.getItemAt(0).immediateRender = true
var strokeWidth = regionUtils._polygonStrokeWidth
regionUtils._polygonStrokeWidth *= resolution
overlayUtils.waitFullyLoaded().then(() => {
overlayUtils.getCanvasPNG(resolution)
.then (() => {
// We go back to original size:
regionUtils._polygonStrokeWidth = strokeWidth;
tmapp.ISS_viewer.world.getItemAt(0).immediateRender = false
tmapp.ISS_viewer.viewport.fitBounds(bounds, true);
setTimeout(()=>{$(loading).modal("hide");}, 300);
document.getElementById("ISS_viewer").style.setProperty("visibility", "unset");
})
});
})
}
/**
* Get the current canvas as a PNG image
*/
overlayUtils.getCanvasPNG=function(tiling) {
tiling = tiling ? Math.ceil(tiling) : 1;
function sleep (time) {
return new Promise((resolve) => setTimeout(resolve, time));
}
function getCanvasCtx_aux (index, size, ctx, bounds) {
return new Promise((resolve, reject) => {
if (index == size*size) {
resolve(ctx);
return;
}
var index_x = index % size;
var index_y = Math.floor(index/size);
var newBounds = new OpenSeadragon.Rect(
bounds.x+index_x*bounds.width/size,
bounds.y+index_y*bounds.height/size,
bounds.width/size,
bounds.height/size,
0
);
console.log(bounds, newBounds);
tmapp.ISS_viewer.viewport.fitBounds(newBounds, true);
overlayUtils.waitFullyLoaded().then(() => {
overlayUtils.getCanvasCtx().then ((ctx_offset) => {
ctx.drawImage(
ctx_offset.canvas,
ctx_offset.canvas.width * index_x,
ctx_offset.canvas.height * index_y,
ctx_offset.canvas.width,
ctx_offset.canvas.height
);
setTimeout(() => {
getCanvasCtx_aux(index+1, size, ctx, bounds).then(
(ctx)=>{
resolve(ctx);
return;
}
)
},200);
});
});
});
}
return new Promise((resolve, reject) => {
if (tiling > 1) {
var canvas = document.createElement("canvas");
var ctx = canvas.getContext("2d");
var ctx_osd = document.querySelector(".openseadragon-canvas canvas").getContext("2d");
var ctx_webgl = document.querySelector("#gl_canvas").getContext("webgl2", glUtils._options);
canvas.width = tiling * Math.min(ctx_osd.canvas.width, ctx_webgl.canvas.width);
canvas.height = tiling * Math.min(ctx_osd.canvas.height, ctx_webgl.canvas.height);
var bounds = tmapp.ISS_viewer.viewport.getBounds();
getCanvasCtx_aux(0, tiling, ctx, bounds).then((ctx_tiling) => {
var png = ctx_tiling.canvas.toDataURL("image/png");
var a = document.createElement("a"); //Create <a>
a.href = png; //Image Base64 Goes here
a.download = "TissUUmaps_capture.png"; //File name Here
a.click(); //Downloaded file
resolve(png);
})
}
else {
overlayUtils.getCanvasCtx().then((ctx) =>{
var png = ctx.canvas.toDataURL("image/png");
var a = document.createElement("a"); //Create <a>
a.href = png; //Image Base64 Goes here
a.download = "TissUUmaps_capture.png"; //File name Here
a.click(); //Downloaded file
resolve(png);
})
}
})
}
/**
* Get the current canvas as a 2d context
*/
overlayUtils.getCanvasCtx=function() {
return new Promise((resolve, reject) => {
// Create an empty canvas element
var canvas = document.createElement("canvas");
var ctx_osd = document.querySelector(".openseadragon-canvas canvas").getContext("2d");
var ctx_webgl = document.querySelector("#gl_canvas").getContext("webgl2", glUtils._options);
canvas.width = Math.min(ctx_osd.canvas.width, ctx_webgl.canvas.width);
canvas.height = Math.min(ctx_osd.canvas.height, ctx_webgl.canvas.height);
// Copy the image contents to the canvas
var ctx = canvas.getContext("2d");
ctx.drawImage(ctx_osd.canvas, 0, 0, canvas.width, canvas.height);
ctx.drawImage(ctx_webgl.canvas, 0, 0, canvas.width, canvas.height);
var svgString = new XMLSerializer().serializeToString(document.querySelector('.openseadragon-canvas svg'));
var DOMURL = self.URL || self.webkitURL || self;
var img = new Image();
var svg = new Blob([svgString], {type: "image/svg+xml;charset=utf-8"});
var url = DOMURL.createObjectURL(svg);
img.onload = function() {
ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
resolve(ctx);
DOMURL.revokeObjectURL(url);
};
img.src = url;
})
}