UNPKG

cgview

Version:

CGView: Circular Genome Viewer

18 lines 222 kB
/*! * CGView.js – Interactive Circular Genome Viewer * Copyright © 2016–2025 Jason R. Grant * https://github.com/sciguy/cgview-js * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ var CGView=function(t,e){"use strict";function s(t){var e=Object.create(null);return t&&Object.keys(t).forEach((function(s){if("default"!==s){var i=Object.getOwnPropertyDescriptor(t,s);Object.defineProperty(e,s,i.get?i:{enumerable:!0,get:function(){return t[s]}})}})),e.default=t,Object.freeze(e)}var i=s(e),r="1.8.0";class n extends Array{constructor(...t){let e=t;if(1===t.length&&Array.isArray(t[0])&&(e=t[0]),1===e.length)super(),this.push(e[0]);else if(e.length>2e4){super();for(let t=0,s=e.length;t<s;t++)this.push(e[t])}else super(...e)}toString(){return"CGArray"}present(){return this.length>0}empty(){return 0===this.length}remove(t){return this.filter((e=>e!==t))}get first(){return this[0]}get last(){return this[this.length-1]}filter(t,e){if("Function"!=typeof t&&"function"!=typeof t||!this)throw new TypeError;let s=this.length>>>0,i=new Array(s),r=this,o=0,a=-1;if(void 0===e)for(;++a!==s;)a in this&&t(r[a],a,r)&&(i[o++]=r[a]);else for(;++a!==s;)a in this&&t.call(e,r[a],a,r)&&(i[o++]=r[a]);return i.length=o,new n(i)}flat(){var t=this,e=isNaN(arguments[0])?1:Number(arguments[0]);return e?Array.prototype.reduce.call(this,(function(s,i){return Array.isArray(i)?s.push.apply(s,t.flat.call(i,e-1)):s.push(i),s}),[]):Array.prototype.slice.call(this)}map(...t){return 0===this.length?this:super.map(...t)}move(t,e){if(e>=this.length){let t=e-this.length;for(;1+t--;)this.push(void 0)}return this.splice(e,0,this.splice(t,1)[0]),this}get(t){return void 0===t?this:Number.isInteger(t)?this[t-1]:"string"==typeof t?this.filter((e=>e.name&&e.name.toLowerCase()===t.toLowerCase()))[0]:Array.isArray(t)?this.filter((e=>t.some((t=>e.name===t)))):new n}unique(){return n.from(new Set(this))}attr(t){if(1===arguments.length&&"object"==typeof t){const e=Object.keys(t),s=e.length;for(let i=0,r=this.length;i<r;i++)for(let r=0;r<s;r++)this[i][e[r]]=t[e[r]]}else if(2===arguments.length)for(let t=0,e=this.length;t<e;t++)this[t][arguments[0]]=arguments[1];else if(void 0!==t)throw new Error("attr(): must be 2 arguments or a single object");return this}each(t){for(let e=0,s=this.length;e<s;e++)t.call(this[e],e,this[e]);return this}asArray(){return Array.from(this)}static arrayerize(t){return"CGArray"===t.toString()?t:new n(t)}}const o={defaultFor:function(t,e){return void 0===t?e:t},validate:function(t,e){const s=(t=n.arrayerize(t)).filter((function(t){return e.indexOf(t)<0}));return 0===s.length||(console.error(`The value(s) '${s.join(",")}' is/are not one of the following valid options: ${e.join(", ")}`),!1)},booleanify:function(t){return"false"!==t&&"False"!==t&&void 0!==t&&!1!==t},capitalize:function(t){return t.replace(/^\w/,(t=>t.toUpperCase()))},getPixelRatio:function(t){const e=t.getContext("2d");return(window.devicePixelRatio||1)/(e.webkitBackingStorePixelRatio||e.mozBackingStorePixelRatio||e.msBackingStorePixelRatio||e.oBackingStorePixelRatio||e.backingStorePixelRatio||1)},scaleResolution:function(t,e){if(1!==e){const s=t.width,i=t.height;t.width=s*e,t.height=i*e,t.style.width=`${s}px`,t.style.height=`${i}px`,t.getContext("2d").scale(e,e)}},elapsedTime:function(t){return`${(new Date).getTime()-t} ms`},angleFromPosition:function(t,e){let s=.5*Math.PI;return 0!==t&&(s=Math.atan(Math.abs(e/t))),e>=0&&t>=0?s=0-s:e<0&&t>=0||(e<0&&t<0?s=Math.PI-s:e>=0&&t<0&&(s=Math.PI+s)),s},clockPositionForAngle:function(t){let e=Math.round((t+Math.PI/2)*(6/Math.PI));return e>12?e-=12:e<1&&(e+=12),e},rectOriginForAttachementPoint:function(t,e,s,i){let r,n;switch(e){case 1:case 2:r=t.x-s,n=t.y;break;case 3:r=t.x-s,n=t.y-i/2;break;case 4:case 5:r=t.x-s,n=t.y-i;break;case 6:r=t.x-s/2,n=t.y-i;break;case 7:case 8:r=t.x,n=t.y-i;break;case 9:r=t.x,n=t.y-i/2;break;case 10:case 11:r=t.x,n=t.y;break;case 12:r=t.x-s/2,n=t.y}return{x:r,y:n}},round:function(t,e){return e=e||2,Number(t.toFixed(e))},commaNumber:function(t){return i.format(",")(t)},dotProduct:function(t,e){let s=0;for(let i=0,r=t.length;i<r;i++)s+=t[i]*e[i];return s},pointsAdd:function(t,e){const s=[0,0];return s[0]=t[0]+e[0],s[1]=t[1]+e[1],s},pointsSubtract:function(t,e){const s=[0,0];return s[0]=t[0]-e[0],s[1]=t[1]-e[1],s},circleAnglesFromIntersectingLine:function(t,e,s,i,r){const n=o.pointsSubtract([i,r],[e,s]),a=[e,s],h=o.dotProduct(n,n),l=2*o.dotProduct(a,n);let c=l*l-4*h*(o.dotProduct(a,a)-t*t);const g={};if(c>=0){c=Math.sqrt(c);const t=(-l-c)/(2*h),n=(-l+c)/(2*h);if(t>=0&&t<=1){const n=e+t*(i-e),a=s+t*(r-s);g.t1=o.angleFromPosition(n,a)}if(n>=0&&n<=1){const t=e+n*(i-e),a=s+n*(r-s);g.t2=o.angleFromPosition(t,a)}}return g},circleAnglesFromIntersectingRect:function(t,e,s,i,r){let n=[];if(n.push(o.circleAnglesFromIntersectingLine(t,e,s,e+i,s)),n.push(o.circleAnglesFromIntersectingLine(t,e+i,s,e+i,s-r)),n.push(o.circleAnglesFromIntersectingLine(t,e+i,s-r,e,s-r)),n.push(o.circleAnglesFromIntersectingLine(t,e,s-r,e,s)),n=n.filter((t=>Object.keys(t).length>0)),n.length>0){const t=Object.keys(n[0]);1===t.length&&"t1"===t[0]&&n.push(n.shift()),2===t.length&&(n.push({t1:n[0].t1}),n[0].t1=void 0),n=n.map((t=>{const e=[];return void 0!==t.t1&&e.push(t.t1),void 0!==t.t2&&e.push(t.t2),e})),n=[].concat(...n)}return n},indexOfValue:function(t,e,s){let i,r,n=0,o=t.length-1;if(t[n]>=e)return n;if(t[o]<=e)return o;for(;o-n>1;)if(i=(n+o)/2|0,r=t[i],r<e)n=i;else{if(!(r>e))return i;o=i}return s?o:n},oppositeSigns:function(t,e){return t*e<0},base2:function(t){return Math.pow(2,Math.ceil(Math.log(t)/Math.log(2)))},constrain:function(t,e,s){return Math.max(Math.min(s,t),e)},merge:function(...t){const e={};let s,i,r;for(let n=0,o=arguments.length;n<o;n++)if(s=t[n],"object"==typeof s){i=Object.keys(s);for(let t=0,n=i.length;t<n;t++)r=i[t],e[r]=s[r]}return e},scaleValue:function(t,e={min:0,max:1},s={min:0,max:1}){return(s.max-s.min)*(t-e.min)/(e.max-e.min)+s.min},uniqueName:function(t,e){return e.includes(t)?o.uniqueId(`${t}-`,2,e):t},uniqueId:function(t,e,s){let i;do{i=t+e,e++}while(s.indexOf(i)>-1);return i},randomHexString:function(t){let e="";const s="abcdef0123456789";for(let i=0;i<t;i++)e+=s.charAt(Math.floor(Math.random()*s.length));return e},getOffset:function(t){let e=0,s=0;for(;t&&!isNaN(t.offsetLeft)&&!isNaN(t.offsetTop);)e+=t.offsetLeft-t.scrollLeft,s+=t.offsetTop-t.scrollTop,t=t.offsetParent;return{top:s,left:e}},isNumeric:function(t){return isFinite(t)&&parseFloat(t)===t},colors:function(t,e,s,i,r,n,o,a,h,l){const c=[];void 0===t&&(t=50),void 0===e&&(e=200),void 0===s&&(s=30),void 0===i&&(i=1),void 0===r&&(r=2.4),void 0===n&&(n=2.4),void 0===o&&(o=2.4),void 0===a&&(a=0),void 0===h&&(h=2),void 0===l&&(l=4);for(let g=0;g<t;++g){const t=Math.round(Math.sin((r*g+a)*s)+e),d=Math.round(Math.sin((n*g+h)*s)+e),u=Math.round(Math.sin((o*g+l)*s)+e);c.push(`rgba(${t},${d},${u},${i})`)}return c},testColors:function(t){t.forEach((function(t){document.write(`<font style="color:${t}">&#9608;</font>`)})),document.write("<br/>")}};class a{constructor(t,e){this._viewer=t,this.value=e}toString(){return"Position"}static get names(){return["top-left","top-center","top-right","middle-left","middle-center","middle-right","bottom-left","bottom-center","bottom-right"]}static percentsFromName(t){const[e,s]=t.split("-");let i,r;return"top"===e?r=0:"middle"===e?r=50:"bottom"===e&&(r=100),"left"===s?i=0:"center"===s?i=50:"right"===s&&(i=100),{xPercent:i,yPercent:r}}static nameFromPercents(t,e){const s=[0,50,100];if(s.includes(t)&&s.includes(e)){let s="";return 0===e?s+="top":50===e?s+="middle":100===e&&(s+="bottom"),0===t?s+="-left":50===t?s+="-center":100===t&&(s+="-right"),s}}get viewer(){return this._viewer}get canvas(){return this.viewer.canvas}get x(){return this._x}get y(){return this._y}get point(){return{x:this.x,y:this.y}}get value(){return this._value}set value(t){return this._processValue(t)}get type(){return this._type}get name(){return a.names.includes(this.value)&&this.value||a.nameFromPercents(this.xPercent,this.yPercent)}get xPercent(){return this._xPercent}get yPercent(){return this._yPercent}get on(){return this._on}set on(t){"map"===t?this.convertToOnMap():"canvas"===t&&this.convertToOnCanvas()}get onMap(){return"map"===this.on}get onCanvas(){return"canvas"===this.on}get offsetType(){return this._offsetType}get offsetPositive(){if(this.onMap){const{bbOffsetPercent:t,mapOffset:e}=this.value;return("map"===this.offsetType?e:t)>=0}}formatNumber(t,e=0,s=100,i=1){return o.round(o.constrain(t,e,s),i)}_processValue(t){if("string"==typeof t)this._value=o.validate(t,a.names)?t:"middle-center",this._on="canvas",this._type="name";else if("object"==typeof t){const e=Object.keys(t);if(e.includes("xPercent")&&e.includes("yPercent")){const{xPercent:e,yPercent:s}=t;this._xPercent=this.formatNumber(e),this._yPercent=this.formatNumber(s),this._value={xPercent:this.xPercent,yPercent:this.yPercent},this._on="canvas",this._type="percent"}else if(e.includes("lengthPercent")){const{lengthPercent:e}=t;this._value={lengthPercent:this.formatNumber(e,0,100,6)},this._on="map",this._type="percent"}else e.includes("bp");if(this.onMap){const{mapOffset:e,bbOffsetPercent:s}=t;o.isNumeric(e)?(this._offsetType="map",this._value.mapOffset=Math.round(e)):o.isNumeric(s)?(this._offsetType="backbone",this._value.bbOffsetPercent=this.formatNumber(s,-100,100,0)):(this._offsetType="map",this._value.mapOffset=20)}}this.refresh()}refresh(){let t;this.onCanvas?"name"===this.type?t=this._originFromName(this.value):"percent"===this.type&&(t=this._originFromCanvasPercents(this.value)):this.onMap&&"percent"===this.type&&(t=this._originFromMapPercent(this.value)),this._x=t.x,this._y=t.y}_originFromName(t){const{xPercent:e,yPercent:s}=a.percentsFromName(t);return this._xPercent=e,this._yPercent=s,this._originFromCanvasPercents({xPercent:e,yPercent:s})}_originFromCanvasPercents({xPercent:t,yPercent:e}){return{x:this.canvas.width*t/100,y:this.canvas.height*e/100}}_originFromMapPercent(t=this.value){let e;if(50===t.lengthPercent&&0===t.mapOffset)e=this.viewer.layout.centerCaptionPoint();else{const s=this.viewer.sequence.length*t.lengthPercent/100,i=this.centerOffset(t);e=this.canvas.pointForBp(s,i)}return e}centerOffset(t=this.value){const{bbOffsetPercent:e,mapOffset:s}=t,i=this.viewer.layout;let r;return r="backbone"===this.offsetType?i.centerOffsetForBBOffsetPercent(e):i.centerOffsetForMapOffset(s),r}convertToOnMap(){if(this.onMap)return this;const t=this.viewer,e=this.canvas,s=t.layout,i=this.point,r=e.bpForPoint(i),n=this.formatNumber(r/t.sequence.length*100),o=s.centerOffsetForPoint(i),a=t.backbone.adjustedCenterOffset;let h,l;return o>=s.centerOutsideOffset?(h=o-s.centerOutsideOffset,this.value={lengthPercent:n,mapOffset:h}):o<=s.centerInsideOffset?(h=o-s.centerInsideOffset,this.value={lengthPercent:n,mapOffset:h}):o>=a?(l=(o-a)/s.bbOutsideOffset*100,this.value={lengthPercent:n,bbOffsetPercent:l}):o<a&&(l=(a-o)/s.bbInsideOffset*100,this.value={lengthPercent:n,bbOffsetPercent:l}),this}convertToOnCanvas(){if(this.onCanvas)return this;const t=this.viewer,e=this.canvas,s=this.value,i=this.centerOffset(s),r=t.sequence.length*s.lengthPercent/100,n=e.pointForBp(r,i);return this.value={xPercent:this.formatNumber(n.x/t.width*100),yPercent:this.formatNumber(n.y/t.height*100)},this}moveTo(t){if(this.onMap){const e=this.viewer.sequence.length*this.value.lengthPercent/100,s=this.viewer.backbone.adjustedCenterOffset-this.centerOffset();this.viewer.moveTo(e,null,{duration:t,bbOffset:s})}}toJSON(t={}){return this.value}}class h{constructor(t){"string"==typeof t?"auto"===t?this.auto=!0:this.name=t:"object"==typeof t?(this.xPercent=o.defaultFor(Number(t.xPercent),50),this.yPercent=o.defaultFor(Number(t.yPercent),50)):(this.xPercent=50,this.yPercent=50)}toString(){return"Anchor"}get auto(){return this._auto}set auto(t){this._auto=Boolean(t)}get xPercent(){return this._xPercent}set xPercent(t){this._xPercent=Math.round(o.constrain(t,0,100)),this._name=a.nameFromPercents(this.xPercent,this.yPercent)}get yPercent(){return this._yPercent}set yPercent(t){this._yPercent=Math.round(o.constrain(t,0,100)),this._name=a.nameFromPercents(this.xPercent,this.yPercent)}get name(){return this._name}set name(t){t&&o.validate(t,a.names)&&(this._name=t,this._updatePercentsFromName(t))}_updatePercentsFromName(t){const{xPercent:e,yPercent:s}=a.percentsFromName(t);this._xPercent=e,this._yPercent=s}autoUpdateForPosition(t){if(this.auto)if(t.onCanvas)this.xPercent=t.xPercent,this.yPercent=t.yPercent;else if(t.onMap){const e=t.viewer.format,s=t.offsetPositive,i=t.value.lengthPercent;"linear"===e?(this.yPercent=s?100:0,this.xPercent=i):"circular"===e&&(i<=7?(this.xPercent=(i+7)/14*100,this.yPercent=100):i>7&&i<43?(this.xPercent=0,this.yPercent=(i-7)/36*100):i>=43&&i<=57?(this.xPercent=(i-43)/14*100,this.yPercent=0):i>57&&i<93?(this.xPercent=100,this.yPercent=(i-57)/36*100):i>=93&&(this.xPercent=(i-93)/14*100,this.yPercent=100))}}toJSON(){return this.auto?"auto":this.name?this.name:{xPercent:this.xPercent,yPercent:this.yPercent}}}let l=0;class c{constructor(t,e={},s={}){this._viewer=t,this.meta=o.merge(e.meta,s),this.visible=o.defaultFor(e.visible,!0),this._cgvID="cgv-id-"+l++,t._objects[this.cgvID]=this}toString(){return"CGObject"}get cgvID(){return this._cgvID}get viewer(){return this._viewer}get canvas(){return this.viewer.canvas}get layout(){return this.viewer.layout}get sequence(){return this.viewer.sequence}get visible(){return this._visible}set visible(t){this._visible=t}get meta(){return this._meta}set meta(t){this._meta=t}deleteFromObjects(){delete this.viewer._objects[this.cgvID]}addPluginOptions(t,e){this.viewer.plugins?._addPluginOptions(this,t,e)}updatePluginOptions(t,e){this.viewer.plugins?._updatePluginOptions(this,t,e)}hasPlugin(t){return this.viewer.plugins?._hasPlugin(this,t)}optionsForPlugin(t){return this.viewer.plugins?._optionsForPlugin(this,t)}}class g{constructor(t,e,s,i,r){this.x=t,this.y=e,this.width=s,this.height=i,this._label=r}get width(){return this._width}set width(t){this._width=t}get height(){return this._height}set height(t){this._height=t}get x(){return this._x}set x(t){this._x=t}get y(){return this._y}set y(t){this._y=t}get bottom(){return this.y+this.height}get top(){return this.y}get left(){return this.x}get right(){return this.x+this.width}overlap(t){const e=this;let s=!1;for(let i=0,r=t.length;i<r;i++){const r=t[i];if(e.x<=r.right&&r.x<=e.right+4&&e.y<=r.bottom&&r.y<=e.bottom){s=r;break}s=!1}return s}containsPt(t,e){return t>=this.x&&t<=this.x+this.width&&e>=this.y&&e<=this.y+this.height}ptForClockPosition(t){let e,s;switch(t){case 1:case 2:e=this.x+this.width,s=this.y;break;case 3:e=this.x+this.width,s=this.y+this.height/2;break;case 4:case 5:e=this.x+this.width,s=this.y+this.height;break;case 6:e=this.x+this.width/2,s=this.y+this.height;break;case 7:case 8:e=this.x,s=this.y+this.height;break;case 9:e=this.x,s=this.y+this.height/2;break;case 10:case 11:e=this.x,s=this.y;break;case 12:e=this.x+this.width/2,s=this.y}return{x:e,y:s}}}class d{constructor(t,e={}){this._annotation=t,this._initialLabelLineLength=t._labelLineLength,this._labelLineMarginInner=t._labelLineMarginInner,this._labelLineMarginOuter=t._labelLineMarginOuter}get viewer(){return this.annotation.viewer}get annotation(){return this._annotation}get canvas(){return this.viewer.canvas}get initialLabelLineLength(){return this._initialLabelLineLength}rectCenterOffset(t=this.initialLabelLineLength){return this._rectOffsetWithoutLineLength+t}toString(){return"LabelPlacementDefault"}get name(){return"default"}placeLabels(t,e){const s=this.canvas;let i,r,a,h;this._rectOffsetWithoutLineLength=e+this._labelLineMarginInner+this._labelLineMarginOuter;const l=new n;for(let e=0,n=t.length;e<n;e++){i=t[e],r=i.bp,a=this.initialLabelLineLength;do{const t=s.pointForBp(r,this.rectCenterOffset(a)),e=o.rectOriginForAttachementPoint(t,i.lineAttachment,i.width,i.height);i.rect=new g(e.x,e.y,i.width,i.height),h=i.rect.overlap(l),a+=i.height}while(h);l.push(i.rect),i.attachementPt=i.rect.ptForClockPosition(i.lineAttachment)}}}class u extends d{constructor(t,e={}){super(t,e),this.viewer.off("click.labels-test"),this.viewer.on("click.labels-test",(t=>{if("label"===t.elementType){const e=t.element;console.log(`LABEL: ${e.name}, BP:${e.bp}, aBP:${e._attachBp}, D:${e._direction}, P:${e._popped}`),console.log(e,e._island)}}))}toString(){return"LabelPlacementAngled"}get name(){return"angled"}_nextLabel(t,e=1){return e>=0?t._next:t._prev}_prevLabel(t,e=1){return e>=0?t._prev:t._next}placeLabels(t,e){this._debug&&console.log("LABELS -----------------------------------------");const s=this.canvas;let i;this._rectOffsetWithoutLineLength=e+this._labelLineMarginInner+this._labelLineMarginOuter;const r=1/s.pixelsPerBp(this.rectCenterOffset());this._boundaryMarginBp=t[0]?.height*r/2,t.sort(((t,e)=>t.bp-e.bp));this.maxBpAdjustment=this.maxBpAdjustForAngle(80);for(let e=0,r=t.length;e<r;e++){i=t[e],i._attachBp=i.bp,i._direction=0,i._popped=!1,i._placementIndex=e,i._next=e===r-1?t[0]:t[e+1],i._prev=0===e?t[t.length-1]:t[e-1];const n=s.pointForBp(i.bp,this.rectCenterOffset()),a=o.rectOriginForAttachementPoint(n,i.lineAttachment,i.width,i.height);i._defaultRect=new g(a.x,a.y,i.width,i.height),i.rect=i._defaultRect,i._lineLength=this.initialLabelLineLength,i._maxBpAdjustment=[6,12].includes(i.lineAttachment)?this.maxBpAdjustment/2:this.maxBpAdjustment}let n=this.findIslands(t);this.placeIslands(n),n=this.mergeIslands(n),this.finalLabelAdjust(t);for(let e=0,s=t.length;e<s;e++){const s=t[e];s.rect&&(s.attachementPt=s.rect.ptForClockPosition(s.lineAttachment))}}findIslands(t=[]){const e=this.viewer.sequence,s=e.length/2;let i,r;const n=[];if(0===t.length)return n;let o=new p(this,t[0]);for(let a=1,h=t.length;a<h;a++){i=t[a],r=this._prevLabel(i);const h=i._defaultRect.overlap([r._defaultRect]),l=e.lengthOfRange(r.bp,i.bp);h&&l<=s?o.addLabels(i):(n.push(o),o=new p(this,i))}return n.push(o),n}placeIslands(t){for(let e=0,s=t.length;e<s;e++){t[e].placeLabels()}}mergeIslands(t){const e=this.viewer.sequence;if(t.length<=1)return t;let s,i,r,n=t,o=t[0]?.labels,a=0;do{s=!1,i=[],a++;for(let t=0,a=n.length;t<a;t++){const h=n[t],l=t>=a-1?n[0]:n[t+1];if(h.placeLabels(),l.placeLabels(),l===h)break;if(h.clash(l)){if(h.canMergeWith(l)){if(o=h.labels.concat(l.labels),r=new p(this,o),r.startBoundaryBp=h.startBoundaryBp,h===n[a-1]){i[0]=r,r.placeLabels();break}i.push(r),n[t+2]&&(i=i.concat(n.slice(t+2))),n=i,s=!0;break}{const t=e.lengthOfRange(h.lastLabel.bp,l.firstLabel.bp);if(t<e.length/4){let s=t/2;s-=this._boundaryMarginBp,s=s<0?0:s,h.stopBoundaryBp=e.addBp(h.lastLabel.bp,s),l.startBoundaryBp=e.subtractBp(l.firstLabel.bp,s),h.placeLabels()}i.push(h)}}else i.push(h)}}while(s&&a<t.length);return i}_getNextAttachPt(t,e=1){const s=this.viewer.scale,i=e>0,r=this.rectCenterOffset(),n=r*r;let o,a,h,l,c=t.height,g=t.width;const d=this._prevLabel(t,e)?.rect;if(!d)return this.canvas.pointForBp(t.bp,r);const u="linear"===this.viewer.format;switch(t.lineAttachment){case 7:case 8:a=i?d.bottom+c+2:d.top-2,h=s.y.invert(a),l=Math.sqrt(n-h*h),o=s.x(l);break;case 9:a=i?d.bottom+c/2+2:d.top-c/2-2,h=s.y.invert(a),l=Math.sqrt(n-h*h),o=s.x(l);break;case 10:case 11:a=i?d.bottom+2:d.top-c-2,h=s.y.invert(a),l=Math.sqrt(n-h*h),o=s.x(l);break;case 12:o=i?d.left-g/2-2:d.right+g/2+2,l=s.x.invert(o),h=-Math.sqrt(n-l*l),a=s.y(h);break;case 1:case 2:a=i?d.top-c-2:d.bottom+2,h=s.y.invert(a),l=-Math.sqrt(n-h*h),o=s.x(l);break;case 3:a=i?d.top-c/2-2:d.bottom+c/2+2,h=s.y.invert(a),l=-Math.sqrt(n-h*h),o=s.x(l);break;case 4:case 5:a=i?d.top-2:d.bottom+c+2,h=s.y.invert(a),l=-Math.sqrt(n-h*h),o=s.x(l);break;case 6:o=i?d.right+g/2+2:d.left-g/2-2,u?a=d.top:(l=s.x.invert(o),h=Math.sqrt(n-l*l),a=s.y(h))}return{x:o,y:a}}maxBpAdjustForAngle(t){this.rectCenterOffset();const e=this.initialLabelLineLength,s=t*Math.PI/180,i=e*Math.tan(s),r=this.canvas.pointForBp(1,this.rectCenterOffset());r.x+=i;const n=this.canvas.bpForPoint(r);return this._debug&&console.log(`BP Diff for angle ${t}°: ${n}`),n}finalLabelAdjust(t){const e=this.canvas;let s,i,r,a;const h=new n;for(let n=0,l=t.length;n<l;n++){s=t[n],i=s._attachBp,r=s._lineLength;do{const t=e.pointForBp(i,this.rectCenterOffset(r)),n=o.rectOriginForAttachementPoint(t,s.lineAttachment,s.width,s.height);s.rect=new g(n.x,n.y,s.width,s.height),a=s.rect.overlap(h),r+=s.height}while(a);s._lineLength=r,h.push(s.rect),s.attachementPt=s.rect.ptForClockPosition(s.lineAttachment)}}}class p{constructor(t,e){this.labelPlacement=t,this._labels=[],this.canvas=t.canvas,this.viewer=t.viewer,this.sequence=this.viewer.sequence,this._placedRects=[],this.addLabels(e)}get labels(){return this._labels}get length(){return this.labels.length}get single(){return 1===this.labels.length}get firstLabel(){return this.labels[0]}get lastLabel(){return this.labels[this.labels.length-1]}get placedRects(){return this._placedRects}addLabels(t){if(t)if(Array.isArray(t)){this._labels=this._labels.concat(t);for(const e of t)e._island=this}else this._labels.push(t),t._island=this}placeLabels(){let t,e;if(!this.single){const s=Math.floor((this.length-1)/2);t=this.adjustLabels(s,1),e=this.adjustLabels(s,-1)}(t||e)&&(this.placeWithMaxAngle(),this.placePoppedLabels()),this._placedRects=this.labels.map((t=>t.rect))}adjustLabels(t,e){const s=this.canvas;for(let i=t+e,r=this.labels.length;e>0?i<r:i>=0;i+=e){const t=this.labels[i];let r=this.labelPlacement._getNextAttachPt(t,e),n=s.bpForPoint(r);if(e>0){if(n>this.stopBoundaryBp)return!0}else if(e<0&&n<this.startBoundaryBp)return!0;if(isNaN(n)||Math.abs(n-t.bp)>t._maxBpAdjustment)return!0;this.adjustLabelWithAttachPt(t,r)}}placeWithMaxAngle(){let t,e,s,i,r;this.canvas,this.adjustLabelToMaxAngle(this.firstLabel,-1),this.adjustLabelToMaxAngle(this.lastLabel,1);for(let n=1,o=this.labels.length;n<o;n++){if(t=n,e=o-1-n,t>e)return;if(t===e){r=this.labels[e],this.adjustLabelToNextAttachPt(r,1);const s=isNaN(r._attachBp),n=i||this.lastLabel;return void((this.labelsClash(r,n)||s)&&(this.poppedStartIndex=t,this.poppedStopIndex=e))}s=this.labels[t],i=this.labels[e],this.adjustLabelToNextAttachPt(s,1),this.adjustLabelToNextAttachPt(i,-1);const a=isNaN(s._attachBp)||isNaN(NaN===i._attachBp);if(this.labelsClash(s,i)||a)return this.poppedStartIndex=this.adjustPopIndex(t,-1),void(this.poppedStopIndex=this.adjustPopIndex(e,1))}}adjustPopIndex(t,e){let s=t;for(let i=t+e,r=this.labels.length;e>0?i<r:i>=0;i+=e){if(this.labels[i]._direction==e)break;s=i}return s}placePoppedLabels(){if(void 0===this.poppedStartIndex||void 0===this.poppedStopIndex)return;let t,e,s;const i=this.viewer.sequence;i.length;let r=this.labels.filter(((t,e)=>e<this.poppedStartIndex||e>this.poppedStopIndex)).map((t=>t.rect));const n=this.firstLabel?._prev?._island;n&&(r=r.concat(n.placedRects));const o=Math.max(this.poppedStartIndex-1,0),a=Math.min(this.poppedStopIndex+1,this.labels.length-1),h=this.labels[o]._attachBp,l=this.labels[a]._attachBp,c=i.lengthOfRange(h,l)/(this.poppedStopIndex-this.poppedStartIndex+2);let g,d,u=1,p=this.labelPlacement.initialLabelLineLength;for(let i=this.poppedStartIndex;i<=this.poppedStopIndex;i++){t=this.labels[i],e=h+c*u,t._popped=!0;let n=u/(this.poppedStopIndex-this.poppedStartIndex+1);n*=5;let o=p/this.labelPlacement.initialLabelLineLength;o/=5,g=p-1.1*t.height*n*o,g=Math.max(g,this.labelPlacement.initialLabelLineLength),d=-1;do{const i=this.canvas.pointForBp(e,this.labelPlacement.rectCenterOffset(p));this.adjustLabelWithAttachPt(t,i),s=t.rect.overlap(r),p+=1.1*t.height*d,p<g&&(d=1,p=g)}while(s);t._lineLength=p,r.push(t.rect),u++}}adjustLabelToNextAttachPt(t,e){let s=this.labelPlacement._getNextAttachPt(t,e);this.adjustLabelWithAttachPt(t,s)}adjustLabelWithAttachPt(t,e){const s=o.rectOriginForAttachementPoint(e,t.lineAttachment,t.width,t.height);t.rect=new g(s.x,s.y,t.width,t.height),t._attachBp=this.canvas.bpForPoint(e);const i=t.bp-t._attachBp;t._direction=i>0?-1:i<0?1:0;const r=this.viewer.sequence.length/2;Math.abs(i)>r&&(t._direction*=-1)}forwardBoundary(){if(this.stopBoundaryBp)return this.stopBoundaryBp;const t=this.lastLabel,e=t._next;this.viewer.sequence.length;let s=this.sequence.lengthOfRange(t.bp,e.bp);return s=s>t._maxBpAdjustment?t._maxBpAdjustment:s,t.bp+s}backwardBoundary(){if(this.startBoundaryBp)return this.startBoundaryBp;const t=this.firstLabel,e=this.firstLabel._prev,s=this.viewer.sequence.length;let i;return e?._attachBp>t.bp?i=s-e.bp+t.bp:e&&(i=t.bp-e._attachBp-this.labelPlacement._boundaryMarginBp),i=i>t._maxBpAdjustment?t._maxBpAdjustment:i,t.bp-i}adjustLabelToMaxAngle(t,e){t._maxBpAdjustment;let s;t.bp,e>0?s=this.forwardBoundary():e<0&&(s=this.backwardBoundary());const i=this.canvas.pointForBp(s,this.labelPlacement.rectCenterOffset());this.adjustLabelWithAttachPt(t,i)}clash(t){return this.labelsClash(this.lastLabel,t.firstLabel)}labelsClash(t,e){const s=this.viewer.sequence,i=t.rect.overlap([e.rect]),r=s.lengthOfRange(t.bp,e.bp),n=s.lengthOfRange(t._attachBp,e._attachBp),o=r<s.length/2&&n>s.length/2;return i||o}canMergeWith(t){const e=this.viewer.sequence,s=1*(this.firstLabel._maxBpAdjustment+t.lastLabel._maxBpAdjustment),i=e.lengthOfRange(this.firstLabel._attachBp,t.lastLabel._attachBp),r=e.lengthOfRange(this.firstLabel.bp,t.lastLabel.bp);return i<=s&&r<=s}}class f{constructor(){this._handlers={}}on(t,e){const s=this._handlers;m(t);const i=v(t);s[i]||(s[i]=[]),s[i].push(new b(t,e))}off(t,e){const s=this._handlers;m(t);const i=v(t),r=w(t);void 0===e?r?i?s[i]=s[i].filter((t=>t.namespace!==r)):Object.keys(s).forEach((function(t){s[t]=s[t].filter((t=>t.namespace!==r))})):s[i]=void 0:s[i]=s[i].filter((t=>t.callback!==e)),this._handlers=s}trigger(t,e){const s=this._handlers;m(t);const i=v(t),r=w(t);Array.isArray(s[i])&&s[i].forEach((function(t){r?t.namespace===r&&t.callback.call(null,e):t.callback.call(null,e)}))}}const m=function(t){if("string"!=typeof t)throw new Error("Type must be a string")},b=function(t,e){this.callback=e,this.eventType=v(t),this.namespace=w(t)},v=function(t){return t.replace(/\..*/,"")},w=function(t){const e=t.match(/\.(.*)/);return e?e[1]:void 0};class _ extends f{constructor(t){super(),this._rawFont=t}toString(){return"Font"}set _rawFont(t){if("string"==typeof t||t instanceof String)this.string=t;else{const e=Object.keys(t);e.includes("family")&&e.includes("style")&&e.includes("size")?(this._family=t.family,this._style=t.style,this._size=Number(t.size),this._generateFont()):console.log("Font objects require the following keys: family, style, and size")}}get string(){return`${this.family},${this.style},${this.size}`}set string(t){const e=(t=t.replace(/ +/g,"")).split(",");3===e.length?(this._family=e[0],this._style=e[1],this._size=Number(e[2])):console.log("Font must have 3 parts"),this._generateFont()}get css(){return this._font}cssScaled(t){return t&&1!==t?`${this._styleAsCss()} ${this.size*t}px ${this.family}`:this.css}get family(){return this._family||"sans-serif"}set family(t){this._family=t,this._generateFont()}get size(){return this._size||12}set size(t){this._size=Number(t),this._generateFont()}get style(){return this._style||"plain"}set style(t){this._style=t,this._generateFont()}get bold(){return"bold"===this.style||"bold-italic"===this.style}set bold(t){t?"plain"===this.style?this.style="bold":"italic"===this.style&&(this.style="bold-italic"):"bold"===this.style?this.style="plain":"bold-italic"===this.style&&(this.style="italic")}get italic(){return"italic"===this.style||"bold-italic"===this.style}set italic(t){t?"plain"===this.style?this.style="italic":"bold"===this.style&&(this.style="bold-italic"):"italic"===this.style?this.style="plain":"bold-italic"===this.style&&(this.style="bold")}get height(){return this.size}width(t,e){return t.font=this.css,t.measureText(e).width}copy(){return new _(this.string)}_styleAsCss(){return"plain"===this.style?"normal":"bold"===this.style?"bold":"italic"===this.style?"italic":"bold-italic"===this.style?"italic bold":""}_generateFont(){this._font=`${this._styleAsCss()} ${this.size}px ${this.family}`,this.trigger("change",this)}}_.calculateWidths=function(t,e,s){t.save();const i=[],r=[];for(let t=0,i=e.length;t<i;t++)r.push({index:t,font:e[t],text:s[t]});r.sort(((t,e)=>t.font>e.font?1:-1));let n,o,a="";for(let e=0,s=r.length;e<s;e++)n=r[e].font,o=r[e].text,n!==a&&(t.font=n,a=n),i[r[e].index]=t.measureText(o).width;return t.restore(),i};class y{constructor(t){this.setColor(t)}toString(){return"Color"}setColor(t){if("string"==typeof t||t instanceof String)this._string=t;else if("Color"===t.toString())this._string=t.rgbaString;else{const e=Object.keys(t);e.includes("h")&&e.includes("s")&&e.includes("v")?this.hsv=t:e.includes("r")&&e.includes("g")&&e.includes("b")&&e.includes("a")?this.rgba=t:e.includes("r")&&e.includes("g")&&e.includes("b")&&(this.rgb=t)}}set _string(t){const e=y.string2rgba(t,this.opacity);this._rgbaString=y.rgba2String(e),this._updateOpacityFromRgba()}get opacity(){return void 0===this._opacity?1:this._opacity}set opacity(t){this._opacity=y._validateOpacity(t),this._updateRgbaOpacity()}get rgbaString(){return this._rgbaString}get rgbString(){return y.rgb2String(this.rgb)}get rgb(){const t=/^rgba\((\d+),(\d+),(\d+)/.exec(this.rgbaString);return t?{r:Number(t[1]),g:Number(t[2]),b:Number(t[3])}:void 0}set rgb(t){this._string=y.rgb2String(t),this._updateOpacityFromRgba()}get rgba(){const t=/^rgba\((\d+),(\d+),(\d+),([\d.]+)/.exec(this.rgbaString);return t?{r:Number(t[1]),g:Number(t[2]),b:Number(t[3]),a:Number(t[4])}:void 0}set rgba(t){this._string=y.rgba2String(t),this._updateOpacityFromRgba()}get hsv(){return y.rgb2hsv(this.rgb)}set hsv(t){const e=y.hsv2rgb(t);e.a=this.opacity,this.rgba=e}get hex(){return y.rgb2hex(this.rgb)}get hsl(){return y.rgb2hsl(this.rgb)}set hsl(t){const e=y.hsl2rgb(t);e.a=this.opacity,this.rgba=e}copy(){return new y(this.rgbaString)}equals(t,e=!1){const s=this.rgba,i=t.rgba;return e?s.r===i.r&&s.g===i.g&&s.b===i.b:s.r===i.r&&s.g===i.g&&s.b===i.b&&s.a===i.a}inArray(t,e){let s=!1;for(const i of t)if(this.equals(i,e)){s=!0;break}return s}highlight(t=.25){const e=this.hsv;e.v+=e.v<.5?t:-t,this.hsv=e}lighten(t){const e=this.hsl;return e.l+=o.constrain(t,0,1),e.l=Math.min(e.l,1),this.hsl=e,this}darken(t){const e=this.hsl;return e.l-=o.constrain(t,0,1),e.l=Math.max(e.l,0),this.hsl=e,this}invert(){const t=this.rgb;return this.rgb={r:255-t.r,g:255-t.g,b:255-t.b},this}_updateRgbaOpacity(){this._rgbaString=this._rgbaString.replace(/^(rgba\(.*,)([\d.]+?)(\))/,((t,e,s,i)=>e+this.opacity+i))}_updateOpacityFromRgba(){const t=/^rgba.*,([\d.]+?)\)$/.exec(this.rgbaString);t&&(this._opacity=y._validateOpacity(t[1]))}}y.string2rgba=function(t,e=1){if(/^#/.test(t))return y.hexString2rgba(t,e);if(/^rgb\(/.test(t))return y.rgbString2rgba(t,e);if(/^rgba\(/.test(t))return y.rgbaString2rgba(t,e);if(/^hsl\(/.test(t))return y.hslStringToRgba(t,e);{const s=y.name2HexString(t);return y.hexString2rgba(s,e)}},y._validateOpacity=function(t){return t=Number(t),isNaN(t)||t>1?t=1:t<0&&(t=0),t},y._validateRgba=function(t){return{r:y._validateRgbNumber(t.r),g:y._validateRgbNumber(t.g),b:y._validateRgbNumber(t.b),a:y._validateOpacity(t.a)}},y._validateRgbNumber=function(t){return t=Number(t),isNaN(t)?t=0:t>255?t=255:t<0&&(t=0),t},y.rgbString2rgba=function(t,e=1){t=t.replace(/ +/g,"");const s=/^rgb\((\d+),(\d+),(\d+)\)/.exec(t);return s?{r:Number(s[1]),g:Number(s[2]),b:Number(s[3]),a:e}:void 0},y.rgbaString2rgba=function(t){t=t.replace(/ +/g,"");const e=/^rgba\((\d+),(\d+),(\d+),([\d.]+)\)/.exec(t);return e?{r:Number(e[1]),g:Number(e[2]),b:Number(e[3]),a:Number(e[4])}:void 0},y.hslStringToRgba=function(t){console.log("NOT IMPLEMENTED")},y.rgb2hsv=function(t){let e,s,i,r,n=t.r,o=t.g,a=t.b;return(n>1||o>1||a>1)&&(n/=255,o/=255,a/=255),i=Math.max(n,o,a),r=i-Math.min(n,o,a),e=0===r?null:i===n?(o-a)/r+(o<a?6:0):i===o?(a-n)/r+2:(n-o)/r+4,e=e%6*60,s=0===r?0:r/i,{h:e,s:s,v:i}},y.hsv2rgb=function(t){let e,s,i,r,n,o=t.h%360/60;n=t.v*t.s,r=n*(1-Math.abs(o%2-1)),e=s=i=t.v-n,o=~~o,e+=[n,r,0,0,r,n][o],s+=[r,n,n,r,0,0][o],i+=[0,0,r,n,n,r][o];return{r:Math.round(255*e),g:Math.round(255*s),b:Math.round(255*i)}},y.hexString2rgba=function(t,e=1){t=t.replace(/^#?([a-f\d])([a-f\d])([a-f\d])$/i,(function(t,e,s,i){return e+e+s+s+i+i}));let s=0,i=0,r=0;const n=/^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(t);return n&&(s=parseInt(n[1],16),i=parseInt(n[2],16),r=parseInt(n[3],16)),{r:s,g:i,b:r,a:e}},y.rgb2hex=function(t){function e(t){var e=t.toString(16);return 1==e.length?"0"+e:e}return(e(t.r)+e(t.g)+e(t.b)).toUpperCase()},y.rgb2hsl=function(t){const e=t.r/255,s=t.g/255,i=t.b/255,r=Math.max(e,s,i),n=Math.min(e,s,i);let o,a,h=(r+n)/2;if(r===n)o=a=0;else{const t=r-n;switch(a=h>.5?t/(2-r-n):t/(r+n),r){case e:o=(s-i)/t+(s<i?6:0);break;case s:o=(i-e)/t+2;break;case i:o=(e-s)/t+4}o/=6}return{h:o,s:a,l:h}},y.hsl2rgb=function(t){const e=t.h,s=t.s,i=t.l;let r,n,o;if(0===s)r=n=o=i;else{function a(t,e,s){return s<0&&(s+=1),s>1&&(s-=1),s<1/6?t+6*(e-t)*s:s<.5?e:s<2/3?t+(e-t)*(2/3-s)*6:t}const t=i<.5?i*(1+s):i+s-i*s,h=2*i-t;r=a(h,t,e+1/3),n=a(h,t,e),o=a(h,t,e-1/3)}return r=Math.floor(255*r),n=Math.floor(255*n),o=Math.floor(255*o),{r:r,g:n,b:o}},y.rgba2String=function(t){return`rgba(${(t=y._validateRgba(t)).r},${t.g},${t.b},${t.a})`},y.rgb2String=function(t){return`rgb(${t.r},${t.g},${t.b})`},y.name2HexString=function(t){t=t.toLowerCase();const e=y.names()[t];return e||(console.log("Name not found! Defaulting to Black"),"#000000")},y.getColor=function(t=[],e=128,s=127,i=1){const r=[],n=2*t.length+1;for(let t=0;t<n;++t){const n=Math.round(Math.sin(2.4*t+0)*s+e),o=Math.round(Math.sin(2.4*t+4)*s+e),a=Math.round(Math.sin(2.4*t+2)*s+e);r.push(new y(`rgba(${n}, ${o}, ${a}, ${i})`))}let o=t.length;if(o>0)for(;o<r.length;o++){if(!r[o].inArray(t))break}return r[o]},y.names=function(){return{aliceblue:"#f0f8ff",antiquewhite:"#faebd7",aqua:"#00ffff",aquamarine:"#7fffd4",azure:"#f0ffff",beige:"#f5f5dc",bisque:"#ffe4c4",black:"#000000",blanchedalmond:"#ffebcd",blue:"#0000ff",blueviolet:"#8a2be2",brown:"#a52a2a",burlywood:"#deb887",cadetblue:"#5f9ea0",chartreuse:"#7fff00",chocolate:"#d2691e",coral:"#ff7f50",cornflowerblue:"#6495ed",cornsilk:"#fff8dc",crimson:"#dc143c",cyan:"#00ffff",darkblue:"#00008b",darkcyan:"#008b8b",darkgoldenrod:"#b8860b",darkgray:"#a9a9a9",darkgrey:"#a9a9a9",darkgreen:"#006400",darkkhaki:"#bdb76b",darkmagenta:"#8b008b",darkolivegreen:"#556b2f",darkorange:"#ff8c00",darkorchid:"#9932cc",darkred:"#8b0000",darksalmon:"#e9967a",darkseagreen:"#8fbc8f",darkslateblue:"#483d8b",darkslategray:"#2f4f4f",darkslategrey:"#2f4f4f",darkturquoise:"#00ced1",darkviolet:"#9400d3",deeppink:"#ff1493",deepskyblue:"#00bfff",dimgray:"#696969",dimgrey:"#696969",dodgerblue:"#1e90ff",firebrick:"#b22222",floralwhite:"#fffaf0",forestgreen:"#228b22",fuchsia:"#ff00ff",gainsboro:"#dcdcdc",ghostwhite:"#f8f8ff",gold:"#ffd700",goldenrod:"#daa520",gray:"#808080",grey:"#808080",green:"#008000",greenyellow:"#adff2f",honeydew:"#f0fff0",hotpink:"#ff69b4",indianred:"#cd5c5c",indigo:"#4b0082",ivory:"#fffff0",khaki:"#f0e68c",lavender:"#e6e6fa",lavenderblush:"#fff0f5",lawngreen:"#7cfc00",lemonchiffon:"#fffacd",lightblue:"#add8e6",lightcoral:"#f08080",lightcyan:"#e0ffff",lightgoldenrodyellow:"#fafad2",lightgray:"#d3d3d3",lightgrey:"#d3d3d3",lightgreen:"#90ee90",lightpink:"#ffb6c1",lightsalmon:"#ffa07a",lightseagreen:"#20b2aa",lightskyblue:"#87cefa",lightslategray:"#778899",lightslategrey:"#778899",lightsteelblue:"#b0c4de",lightyellow:"#ffffe0",lime:"#00ff00",limegreen:"#32cd32",linen:"#faf0e6",magenta:"#ff00ff",maroon:"#800000",mediumaquamarine:"#66cdaa",mediumblue:"#0000cd",mediumorchid:"#ba55d3",mediumpurple:"#9370db",mediumseagreen:"#3cb371",mediumslateblue:"#7b68ee",mediumspringgreen:"#00fa9a",mediumturquoise:"#48d1cc",mediumvioletred:"#c71585",midnightblue:"#191970",mintcream:"#f5fffa",mistyrose:"#ffe4e1",moccasin:"#ffe4b5",navajowhite:"#ffdead",navy:"#000080",oldlace:"#fdf5e6",olive:"#808000",olivedrab:"#6b8e23",orange:"#ffa500",orangered:"#ff4500",orchid:"#da70d6",palegoldenrod:"#eee8aa",palegreen:"#98fb98",paleturquoise:"#afeeee",palevioletred:"#db7093",papayawhip:"#ffefd5",peachpuff:"#ffdab9",peru:"#cd853f",pink:"#ffc0cb",plum:"#dda0dd",powderblue:"#b0e0e6",purple:"#800080",rebeccapurple:"#663399",red:"#ff0000",rosybrown:"#bc8f8f",royalblue:"#4169e1",saddlebrown:"#8b4513",salmon:"#fa8072",sandybrown:"#f4a460",seagreen:"#2e8b57",seashell:"#fff5ee",sienna:"#a0522d",silver:"#c0c0c0",skyblue:"#87ceeb",slateblue:"#6a5acd",slategray:"#708090",slategrey:"#708090",snow:"#fffafa",springgreen:"#00ff7f",steelblue:"#4682b4",tan:"#d2b48c",teal:"#008080",thistle:"#d8bfd8",tomato:"#ff6347",turquoise:"#40e0d0",violet:"#ee82ee",wheat:"#f5deb3",white:"#ffffff",whitesmoke:"#f5f5f5",yellow:"#ffff00",yellowgreen:"#9acd32"}};class k{constructor(t=[],e={}){this.intervals=[],this.circularLength=e.circularLength,this.startProperty=e.startProperty||"start",this.stopProperty=e.stopProperty||"stop",this.fill(t)}get length(){return this._length}_normalize(t){let e;const s=[];for(let i=0,r=t.length;i<r;i++)e=t[i],e[this.startProperty]<=e[this.stopProperty]?s.push({interval:e,index:i}):(s.push({interval:e,index:i,[this.startProperty]:this.start(e),[this.stopProperty]:this.circularLength,crossesOrigin:!0}),s.push({interval:e,index:i,[this.startProperty]:1,[this.stopProperty]:this.end(e),crossesOrigin:!0}));return s}fill(t){if(this._length=t.length,0===t.length)return void(this.topList=[]);const e=this.sublist;t=this._normalize(t),this.intervals=t,t.sort(((t,e)=>this.start(t)!==this.start(e)?this.start(t)-this.start(e):this.end(e)-this.end(t)));const s=[];let i,r,n=[];if(this.topList=n,n.push(t[0]),1!==t.length)for(let o=1,a=t.length;o<a;o++)if(i=t[o],this.end(i)<this.end(t[o-1]))s.push(n),n=new Array(i),e(t[o-1],n);else for(;;){if(0===s.length){n.push(i);break}if(r=s[s.length-1],this.end(r[r.length-1])>this.end(i)){n.push(i);break}n=s.pop()}}end(t){return t[this.stopProperty]||t.interval[this.stopProperty]}start(t){return t[this.startProperty]||t.interval[this.startProperty]}sublist(t,e){t.sublist=e}_run(t,e=t,s=1,i=function(){},r=this.topList){let n,o;const a=r.length;let h,l;for(s>0?(l=1,h=this._binarySearch(r,t,!0,"end")):s<0&&(l=-1,h=this._binarySearch(r,e,!1,"start"));h>=0&&h<a&&(1===l?this.start(r[h])<=e:this.end(r[h])>=t);)n=!1,o=!1,this.visbleRangeCrossesOrigin&&this.start(r[h])<e&&this.end(r[h])>t&&(o=!0),(r[h].crossesOrigin||o)&&(-1!==this._runIntervalsCrossingOrigin.indexOf(r[h].interval)?n=!0:this._runIntervalsCrossingOrigin.push(r[h].interval)),n||r[h].index%s!=0||i.call(r[h].interval,r[h].interval),r[h].sublist&&this._run(t,e,s,i,r[h].sublist),h+=l}run(t,e=t,s=1,i=function(){}){this._runIntervalsCrossingOrigin=[],this.circularLength&&e<t?(this.visbleRangeCrossesOrigin=!0,this._run(t,this.circularLength,s,i),this._run(1,e,s,i)):(this.visbleRangeCrossesOrigin=!1,this._run(t,e,s,i))}count(t,e,s){let i=0;return this.run(t,e,s,(()=>{i++})),i}find(t,e,s){const i=[];return this.run(t,e,s,(t=>{i.push(t)})),i}_binarySearch(t,e,s,i){let r,n,o=-1,a=t.length;for(;a-o>1;)if(r=(o+a)/2|0,n=this[i](t[r]),n<e)o=r;else{if(!(n>e))return r;a=r}return s?a:o}static test(){function t(t,e,s,i){const r=t.find(e,s).map((t=>t.name)).sort().join(", ");let n=`${e}..${s}: ${i=i.sort().join(", ")} - `;n+=r===i?"Pass":`FAIL - ${r}`,console.log(n)}const e=new k([{name:"A",start:1,stop:20},{name:"B",start:10,stop:15},{name:"C",start:10,stop:20},{name:"D",start:15,stop:30},{name:"E",start:20,stop:30},{name:"F",start:20,stop:50},{name:"G",start:80,stop:100},{name:"H",start:90,stop:95},{name:"I",start:90,stop:5},{name:"J",start:95,stop:15},{name:"K",start:95,stop:2},{name:"L",start:92,stop:50}],{circularLength:100});return t(e,10,20,["A","B","C","D","E","F","J","L"]),t(e,40,85,["F","G","L"]),t(e,40,95,["F","G","H","I","J","K","L"]),t(e,95,10,["A","B","C","G","H","I","J","K","L"]),e}static testMapStarts(){const t=new k([{name:"A",mapStart:10,mapStop:10},{name:"B",mapStart:20,mapStop:21},{name:"C",mapStart:950,mapStop:5}],{circularLength:1e3,startProperty:"mapStart",stopProperty:"mapStop"});return function(t,e,s,i){const r=t.find(e,s).map((t=>t.name)).sort().join(", ");let n=`${e}..${s}: ${i=i.sort().join(", ")} - `;n+=r===i?"Pass":`FAIL - ${r}`,console.log(n)}(t,900,200,["A","B","C"]),t}static testMapStarts2(){const t=new k([{name:"A",start:10,stop:10},{name:"B",start:20,stop:21},{name:"C",start:950,stop:5}],{circularLength:1e3,startProperty:"start",stopProperty:"stop"});return function(t,e,s,i){const r=t.find(e,s).map((t=>t.name)).sort().join(", ");let n=`${e}..${s}: ${i=i.sort().join(", ")} - `;n+=r===i?"Pass":`FAIL - ${r}`,console.log(n)}(t,900,200,["A","B","C"]),t}}class x extends c{constructor(t,e={},s={}){super(t,e,s),this._labels=new n,this.font=o.defaultFor(e.font,"monospace, plain, 12"),this.labelLineLength=o.defaultFor(e.labelLineLength,20),this.priorityMax=o.defaultFor(e.priorityMax,50),this._labelLineMarginInner=10,this._labelLineMarginOuter=5,this._labelLineWidth=1,this.refresh(),this._visibleLabels=new n,this.color=e.color,this.lineCap="round",this.onlyDrawFavorites=o.defaultFor(e.onlyDrawFavorites,!1),this.labelPlacement=o.defaultFor(e.labelPlacement,"default"),this.viewer.trigger("annotation-update",{attributes:this.toJSON({includeDefaults:!0})})}toString(){return"Annotation"}get color(){return this._color}set color(t){void 0===t||"Color"===t.toString()?this._color=t:this._color=new y(t)}get labelLineLength(){return this._labelLineLength}set labelLineLength(t){this._labelLineLength=t}get priorityMax(){return this._priorityMax}set priorityMax(t){this._priorityMax=t}get font(){return this._font}set font(t){"Font"===t.toString()?this._font=t:this._font=new _(t),this.refreshLabelWidths(),this._font.on("change",(()=>this.refreshLabelWidths()))}get length(){return this._labels.length}set labelPlacement(t){const e=this._initialializeLabelPlacement(t);this._labelPlacementFast=e,this._labelPlacementFull=e}get labelPlacementFast(){return this._labelPlacementFast}set labelPlacementFast(t){this._labelPlacementFast=this._initialializeLabelPlacement(t)}get labelPlacementFull(){return this._labelPlacementFull}set labelPlacementFull(t){this._labelPlacementFull=this._initialializeLabelPlacement(t)}_initialializeLabelPlacement(t){if("string"!=typeof t)return new t(this);switch(t){case"default":return new d(this);case"angled":return new u(this);default:throw new Error(`Label Placement name '${t}' unknown. Use one of 'default', 'angled'`)}}labels(t){return this._labels.get(t)}addLabel(t){this._labels.push(t)}removeLabels(t){t="CGArray"===t.toString()?t:new n(t),this._labels=this._labels.filter((e=>!t.includes(e))),this.refresh()}refresh(){const t=this._labels.filter((t=>t.feature.visible&&t.feature.contig?.visible&&t.feature.tracks().some((t=>t.visible))));this._availableLabels=t;for(const e of t)e.bpDefault=e.feature.mapRange.middle;this._labelsNCList=new k(t,{circularLength:this.sequence.length,startProperty:"mapStart",stopProperty:"mapStop"})}refreshLabelWidths(){const t=this._labels.map((t=>t.font.css)),e=this._labels.map((t=>t.name)),s=_.calculateWidths(this.canvas.context("map"),t,e);for(let t=0,e=this._labels.length;t<e;t++)this._labels[t].width=s[t]}_calculatePositions(t){t=t||this._labels;const e=this._visibleRange;let s,i,r,n,o,a;const h=this.sequence;for(let l=0,c=t.length;l<c;l++)if(s=t[l],i=s.feature,r=e.containsMapBp(i.mapStart),n=e.containsMapBp(i.mapStop),r&&n)s.bp=s.bpDefault,s.lineAttachment=s.lineAttachmentDefault;else{if(r)s.bp=i.mapRange.getStartPlus(h.lengthOfRange(i.mapStart,e.stop)/2);else if(n)s.bp=i.mapRange.getStopPlus(-h.lengthOfRange(e.start,i.mapStop)/2);else{o=h.lengthOfRange(e.stop,i.mapStop),a=h.lengthOfRange(i.mapStart,e.start);const t=e.length/2,r=e.start+t;s.bp=a>o?r+t*o/(o+a):r+t*a/(o+a)}s.lineAttachment=this.viewer.layout.clockPositionForBp(s.bp,!0)}}_calculatePriorityLabelRectsFast(t){t=t||this._labels;const e=this.canvas;let s,i,r,a;const h=this._outerCenterOffset+this._labelLineMarginInner,l=new n;for(let n=0,c=t.length;n<c;n++){s=t[n],i=s.bp,r=this.labelLineLength;do{const t=e.pointForBp(i,h+r+this._labelLineMarginOuter),n=o.rectOriginForAttachementPoint(t,s.lineAttachment,s.width,s.height);s.rect=new g(n.x,n.y,s.width,s.height),a=s.rect.overlap(l),r+=s.height}while(a);l.push(s.rect),s.attachementPt=s.rect.ptForClockPosition(s.lineAttachment)}}_calculatePriorityLabelRects(t){!this._fastDraw||t.length<20?this.labelPlacementFull.placeLabels(t,this._outerCenterOffset):this.labelPlacementFast.placeLabels(t,this._outerCenterOffset)}_calculateLabelRects(t){t=t||this._labels;const e=this.canvas;let s,i;const r=this._outerCenterOffset+this._labelLineMarginInner;for(let n=0,a=t.length;n<a;n++){s=t[n],i=s.bp;const a=e.pointForBp(i,r+this.labelLineLength+this._labelLineMarginOuter),h=o.rectOriginForAttachementPoint(a,s.lineAttachment,s.width,s.height);s.rect=new g(h.x,h.y,s.width,s.height),s.attachementPt=s.rect.ptForClockPosition(s.lineAttachment)}}visibleLabels(){let t=new n;const e=this._visibleRange;return e&&(t=1===e.start&&e.stop===this.sequence.length?this._availableLabels:this._labelsNCList.find(e.start,e.stop)),t}_onlyFavoriteLabels(t){const e=(t=t||this._labels).findIndex((t=>!t.feature.favorite));return-1!==e?t.slice(0,e):t}_sortByPriority(t){return(t=t||this._labels).sort(((t,e)=>e.feature.favorite===t.feature.favorite?e.feature.length-t.feature.length:t.feature.favorite?-1:1)),t}invertColors(){this.color&&this.update({color:this.color.invert().rgbaString})}drawLabelLine(t,e,s){const i=this.canvas.pointForBp(t.bp,this._outerCenterOffset+this._labelLineMarginInner),r=t.attachementPt,n=this.color||t.feature.color;e.beginPath(),e.moveTo(i.x,i.y),e.lineTo(r.x,r.y),e.strokeStyle=n.rgbaString,e.lineCap=this.lineCap,e.lineWidth=s||this._labelLineWidth,e.stroke()}draw(t,e,s){this._fastDraw=s,this._visibleRange=this.canvas.visibleRangeForCenterOffset(e,{float:!0,margin:100}),this._innerCenterOffset=t,this._outerCenterOffset=e;let i=this.visibleLabels(e);i=this._sortByPriority(i),this.onlyDrawFavorites&&(i=this._onlyFavoriteLabels(i)),this._calculatePositions(i);const r=i.slice(0,this.priorityMax),n=i.slice(this.priorityMax);this._calculatePriorityLabelRects(r),this._calculateLabelRects(n);const o=r.map((t=>t.rect));this._visibleLabels=r;for(let t=0,e=n.length;t<e;t++){const e=n[t];e.rect.overlap(o)||(this._visibleLabels.push(e),o.push(e.rect))}const a=this.canvas.context("map");let h,l;a.font=this.font.css,a.textAlign="left",a.textBaseline="alphabetic";for(let t=0,e=this._visibleLabels.length;t<e;t++)h=this._visibleLabels[t],h.feature.visible&&(this.color||h.feature.color,this.drawLabelLine(h,a));const c=this.viewer.settings.backgroundColor.copy();c.opacity=.75;for(let t=0,e=this._visibleLabels.length;t<e;t++){if(h=this._visibleLabels[t],!h.feature.visible)continue;const e=this.color||h.feature.color;a.fillStyle=c.rgbaString,l=h.rect,a.fillRect(l.x,l.y,l.width,l.height),a.fillStyle=e.rgbaString,a.fillText(h.name,h.rect.x,h.rect.bottom-1)}this.viewer.debug&&this.viewer.debug.data.n&&(this.viewer.debug.data.n.labels=this._visibleLabels.length)}update(t){this.viewer.updateRecords(this,t,{recordClass:"Annotation",validKeys:["color","font","onlyDrawFavorites","visible","labelPlacement"]}),this.viewer.trigger("annotation-update",{attributes:t})}toJSON(t={}){return{font:this.font.string,color:this.color&&this.color.rgbaString,onlyDrawFavorites:this.onlyDrawFavorites,labelPlacement:this.labelPlacementFull.name,visible:this.visible}}}class S extends c{constructor(t,e={},s={}){super(t,e,s),this.color=o.defaultFor(e.color,"grey"),this.colorAlternate=o.defaultFor(e.colorAlternate,"rgb(200,200,200)"),this.thickness=o.defaultFor(e.thickness,5),this._bpThicknessAddition=0;const i=this.sequence.hasMultipleContigs?"arrow":"arc";this.decoration=o.defaultFor(e.decoration,i),this.viewer.trigger("backbone-update",{attributes:this.toJSON({includeDefaults:!0})})}toString(){return"Backbone"}get visible(){return this._visible}set visible(t){this._visible=t,this.viewer._initialized&&this.refreshThickness(),this.viewer.layout&&this.viewer.layout._adjustProportions()}get color(){return this._color}set color(t){"Color"===t.toString()?this._color=t:this._color=new y(t)}get colorAlternate(){return this._colorAlternate}set colorAlternate(t){"Color"===t.toString()?this._colorAlternate=t:this._colorAlternate=new y(t)}get decoration(){return this._decoration}set decoration(t){this._decoration=t}set centerOffset(t){o.isNumeric(t)&&(this._centerOffset=t,this.viewer._updateZoomMax())}get centerOffset(){return this._centerOffset}get adjustedCenterOffset(){return this.layout.adjustedBackboneCenterOffset(this.centerOffset)}set thickness(t){o.isNumeric(t)&&(this._thickness=Number(t),this.viewer.layout&&this.viewer.layout._adjustProportions())}get thickness(){return this.visible?this._thickness:0}get adjustedThickness(){return this.visible?Math.min(this.viewer.zoomFactor,4)*this.thickness+this.bpThicknessAddition:0}get maxThickness(){return Math.max(this.adjustedThickness,this.sequence.thickness)}get bpThicknessAddition(){return this._bpThicknessAddition}get visibleRange(){return this._visibleRange}get pixelLength(){return this.layout.pixelsPerBp(this.adjustedCenterOffset)/this.viewer.zoomFactor*this.sequence.length}containsCenterOffset(t){const e=this.adjustedThickness/2,s=this.adjustedCenterOffset;return t>=s-e&&t<=s+e}maxZoomFactor(){return this.sequence.length*(this.sequence.bpSpacing+2*this.sequence.bpMargin)/this.pixelLength}pixelsPerBp(){return this.layout.pix