lexicon-mono-seq
Version:
LexiconMonoSeq, DOM Text based MSA visualization written in Javascript
2,938 lines • 89.2 kB
JavaScript
(function(root,factory) {
if (typeof define === "function" && define.amd) {
define([], factory);
} else if (typeof exports === "object") {
module.exports = factory();
} else {
root.LexiconMonoSeq = factory();
}
}(this, function() {
function LexiconMonoSeq(container,options){
container = typeof container === "string"
? document.querySelector(container)
: container.nodeType && container.nodeType === 1
? container
: document.body;
return new _LexiconMonoSeq(container,options);
};
function _LexiconMonoSeq(container,options){
if(!this.__defaultStyleApplied){
options && (this.textRendering = options.textRendering);
options && (this.fontKerning = options.fontKerning);
options && (this.webkitFontSmoothing = options.webkitFontSmoothing);
var style = document.createElement("style");
style.textContent = this.Style.string(this);
style.setAttribute("data-name","LexiconMonoSeqStyle");
document.head.appendChild(style);
this.constructor.prototype.__defaultStyleApplied = true;
}
this.container = container;
this.toggleClass(container,"LexiconMonoSeqContainer",true);
this._state = "IDLE";
this._labels = true;
var painters = this.painters = Array.apply(null,Array((options && options.parallelRendering) || 1))
.map(function(d,i){return new this.Paint(this);},this);
painters._counter = 0;
painters._length = painters.length;
this.wrapper = document.createElement("div");
this.wrapper.className = "LexiconMonoSeq wrapper custom";
this.div = this.wrapper.appendChild(document.createElement("div"));
this.div.className = "LexiconMonoSeq main custom";
this.divStyle = this.div.style;
this.hidden = this.wrapper.appendChild(document.createElement("div"));
this.hidden.className = "LexiconMonoSeq hidden";
this.hidden.textContent = "A";
this.busy = this.wrapper.appendChild(document.createElement("div"));
this.busy.className = "LexiconMonoSeq busy custom";
this.busyStyle = this.busy.style;
this.busy.textContent = "\u23f3";
this.sequences = [];
this.currentAnimationFrame = new this.AnimLedger(this) /*{u:undefined,a:undefined,r:undefined,s:undefined,sMan:undefined}*/;
this.ColorShift = new this.ColorShift(this);
this.ColorShiftRgba = new this.ColorShiftRgba(this);
this.update = function(arr,nOptions){
options = nOptions || options;
options
&& (options.labels !== undefined)
&& ((this._labels = !!options.labels) || true)
&& this.toggleClass(this.wrapper,"labelsOff",!options.labels);
this.scrollLeftOffset = this.fontWidth * this.maxAllowedLabelLength;
this.divStyle.transform = "translate(" + this.scrollLeftOffset + "px,0px)";
this.source = arr;
this.getMaxSeqLength(arr).currentAnimationFrame.cancelFrames().prepareForUpdate();//cancel frames and reset 'append' frame and set state as 'ANIM'
var l = arr.length,
ease = (options && options.ease)
? new this.Ease(options.ease[0],options.ease[1],{resolution:options.easeResolution,precision:options.easePrecision})
: this.ease,
e = this.sequences
.filter(function(d,i){return !d.rm;})
.filter(function(d,i){return (i > l - 1) && (d.rm = true);}),
u = this.sequences.filter(function(d,i){return !d.rm && (d.source = arr[i]);}),
a = Array.apply(null,Array(arr.length-u.length)).map(function(d,i){
d = new this.Sequence(arr[u.length + i],this);
d.painter = painters[(++painters._counter, painters._counter %= painters._length)];
this.sequences.push(d);
return d;
},this);
e.length && this.removeSequences(
e,
{ease:ease,startTime:undefined,options:options}
);
u.length && this.updateSequences(
u,
{ease:ease,startTime:undefined,options:options}
);
a.length && this.updateSequences(
a,
{ease:ease,startTime:undefined,options:options}
);
options
&& options.easePaint
&& (this.painters.forEach(function(d,i){
d.ease = new this.Ease(options.easePaint[0],options.easePaint[1],{resolution:options.easePaintResolution,precision:options.easePaintPrecision});
},this));
options
&& (options.durationPaint !== undefined)
&& (this.painters.forEach(function(d,i){
d.duration = options.durationPaint;
},this));
return this;
};
this.wrapper.addEventListener("scroll",this.repaintOnScroll(),false);
container.appendChild(this.wrapper);
return this;
};
/*
###############################
##############PROTO############
###############################
*/
_LexiconMonoSeq.prototype.version = "0.19.0";
_LexiconMonoSeq.prototype._scrollLeftOffset = 0;
_LexiconMonoSeq.prototype._50spaces = " ";
_LexiconMonoSeq.prototype.set = function(k,v){
this[k] = v;
return this;
};
_LexiconMonoSeq.prototype.maxAllowedLabelLength = 20;
_LexiconMonoSeq.prototype.displayPadding = 0.2;
_LexiconMonoSeq.prototype.generateRandomString = function(){
return (Math.random()*1e9 | 0).toString(16);
};
_LexiconMonoSeq.prototype.common = {
opacities: {
A: 0.95,
B: 0.95,
C: 0.95,
U: 0.95,
D: 0.95,
E: 0.95,
F: 0.95,
G: 0.95,
H: 0.95,
I: 0.95,
K: 0.95,
L: 0.95,
M: 0.95,
N: 0.95,
P: 0.95,
Q: 0.95,
R: 0.95,
S: 0.95,
T: 0.95,
V: 0.95,
W: 0.95,
X: 0.95,
Y: 0.95,
Z: 0.95,
"?": 0.8,
"-": 0.8,
":": 0.4,
"*": 0.2,
".": 0.1,
"·": 0.05,
" ": 0
},
opacitiesPunctuation: {
"-": 0.8,
":": 0.4,
"*": 0.2,
".": 0.1,
"·": 0.05,
" ": 0
}
};
_LexiconMonoSeq.prototype.colors = {
aa: {
"A": "#ffffc9",
"C": "#e3f9ad",
"U": "#e3f9ad",
"E": "#f93333",
"D": "#fb7979",
"G": "#c0c0c0",
"F": "#c7c88a",
"I": "#ffff4f",
"H": "#d5f6fb",
"K": "#baaafc",
"M": "#c3ed27",
"L": "#ffff79",
"N": "#ee72a7",
"Q": "#f9c3e3",
"P": "#f1f2f3",
"S": "#ca9ec8",
"R": "#8694fa",
"T": "#f0e4ef",
"W": "#85b0cd",
"V": "#ffffab",
"Y": "#7dafb9",
"X": "#333333",
"?": "#333333",
"-": "#778899",
":": "#778899",
"*": "#778899",
".": "#778899",
"·": "#778899",
" ": "#778899"
},
jalviewClustal: {
A: "#80a0f0",
B: "#ffffff",
C: "#f08080",
U: "#f08080",
D: "#c048c0",
E: "#c048c0",
F: "#80a0f0",
G: "#f09048",
H: "#15a4a4",
I: "#80a0f0",
K: "#f01505",
L: "#80a0f0",
M: "#80a0f0",
N: "#00ff00",
P: "#ffff00",
Q: "#00ff00",
R: "#f01505",
S: "#00ff00",
T: "#00ff00",
V: "#80a0f0",
W: "#80a0f0",
X: "#ffffff",
Y: "#15a4a4",
Z: "#ffffff",
"?": "#333333",
"-": "#778899",
":": "#778899",
"*": "#778899",
".": "#778899",
"·": "#778899",
" ": "#778899"
},
jalviewZappo: {
A: "#ffafaf",
B: "#ffffff",
C: "#ffff00",
U: "#ffff00",
D: "#ff0000",
E: "#ff0000",
F: "#ffc800",
G: "#ff00ff",
H: "#6464ff",
I: "#ffafaf",
K: "#6464ff",
L: "#ffafaf",
M: "#ffafaf",
N: "#00ff00",
P: "#ff00ff",
Q: "#00ff00",
R: "#6464ff",
S: "#00ff00",
T: "#00ff00",
V: "#ffafaf",
W: "#ffc800",
X: "#ffffff",
Y: "#ffc800",
Z: "#ffffff",
"?": "#333333",
"-": "#778899",
":": "#778899",
"*": "#778899",
".": "#778899",
"·": "#778899",
" ": "#778899"
},
jalviewTaylor: {
A: "#ccff00",
B: "#ffffff",
C: "#ffff00",
U: "#ffff00",
D: "#ff0000",
E: "#ff0066",
F: "#00ff66",
G: "#ff9900",
H: "#0066ff",
I: "#66ff00",
K: "#6600ff",
L: "#33ff00",
M: "#00ff00",
N: "#cc00ff",
P: "#ffcc00",
Q: "#ff00cc",
R: "#0000ff",
S: "#ff3300",
T: "#ff6600",
V: "#99ff00",
W: "#00ccff",
X: "#ffffff",
Y: "#00ffcc",
Z: "#ffffff",
"?": "#333333",
"-": "#778899",
":": "#778899",
"*": "#778899",
".": "#778899",
"·": "#778899",
" ": "#778899"
},
jalviewHydrophobicity: {
A: "#ad0052",
B: "#0c00f3",
C: "#c2003d",
U: "#c2003d",
D: "#0c00f3",
E: "#0c00f3",
F: "#cb0034",
G: "#6a0095",
H: "#1500ea",
I: "#ff0000",
K: "#0000ff",
L: "#ea0015",
M: "#b0004f",
N: "#0c00f3",
P: "#4600b9",
Q: "#0c00f3",
R: "#0000ff",
S: "#5e00a1",
T: "#61009e",
V: "#f60009",
W: "#5b00a4",
X: "#680097",
Y: "#4f00b0",
Z: "#0c00f3",
"?": "#333333",
"-": "#778899",
":": "#778899",
"*": "#778899",
".": "#778899",
"·": "#778899",
" ": "#778899"
},
jalviewHelixPropensity: {
A: "#e718e7",
B: "#49b649",
C: "#23dc23",
U: "#23dc23",
D: "#778877",
E: "#ff00ff",
F: "#986798",
G: "#00ff00",
H: "#758a75",
I: "#8a758a",
K: "#a05fa0",
L: "#ae51ae",
M: "#ef10ef",
N: "#1be41b",
P: "#00ff00",
Q: "#926d92",
R: "#6f906f",
S: "#36c936",
T: "#47b847",
V: "#857a85",
W: "#8a758a",
X: "#758a75",
Y: "#21de21",
Z: "#c936c9",
"?": "#333333",
"-": "#778899",
":": "#778899",
"*": "#778899",
".": "#778899",
"·": "#778899",
" ": "#778899"
},
jalviewStrandPropensity: {
A: "#5858a7",
B: "#4343bc",
C: "#9d9d62",
U: "#9d9d62",
D: "#2121de",
E: "#0000ff",
F: "#c2c23d",
G: "#4949b6",
H: "#60609f",
I: "#ecec13",
K: "#4747b8",
L: "#b2b24d",
M: "#82827d",
N: "#64649b",
P: "#2323dc",
Q: "#8c8c73",
R: "#6b6b94",
S: "#4949b6",
T: "#9d9d62",
V: "#ffff00",
W: "#c0c03f",
X: "#797986",
Y: "#d3d32c",
Z: "#4747b8",
"?": "#333333",
"-": "#778899",
":": "#778899",
"*": "#778899",
".": "#778899",
"·": "#778899",
" ": "#778899"
},
jalviewTurnPropensity: {
A: "#2cd3d3",
B: "#f30c0c",
C: "#a85757",
U: "#a85757",
D: "#e81717",
E: "#778888",
F: "#1ee1e1",
G: "#ff0000",
H: "#708f8f",
I: "#00ffff",
K: "#7e8181",
L: "#1ce3e3",
M: "#1ee1e1",
N: "#ff0000",
P: "#f60909",
Q: "#3fc0c0",
R: "#708f8f",
S: "#e11e1e",
T: "#738c8c",
V: "#07f8f8",
W: "#738c8c",
X: "#7c8383",
Y: "#9d6262",
Z: "#5ba4a4",
"?": "#333333",
"-": "#778899",
":": "#778899",
"*": "#778899",
".": "#778899",
"·": "#778899",
" ": "#778899"
},
jalviewBuriedIndex: {
A: "#00a35c",
B: "#00eb14",
C: "#0000ff",
U: "#0000ff",
D: "#00eb14",
E: "#00f10e",
F: "#008778",
G: "#009d62",
H: "#00d52a",
I: "#0054ab",
K: "#00ff00",
L: "#007b84",
M: "#009768",
N: "#00eb14",
P: "#00e01f",
Q: "#00f10e",
R: "#00fc03",
S: "#00d52a",
T: "#00db24",
V: "#005fa0",
W: "#00a857",
X: "#00b649",
Y: "#00e619",
Z: "#00f10e",
"?": "#333333",
"-": "#778899",
":": "#778899",
"*": "#778899",
".": "#778899",
"·": "#778899",
" ": "#778899"
},
jalviewNucleotide: {
A: "#64F73F",
B: "#ffffff",
C: "#FFB340",
D: "#ffffff",
G: "#EB413C",
H: "#ffffff",
I: "#ffffff",
K: "#ffffff",
M: "#ffffff",
N: "#ffffff",
R: "#ffffff",
S: "#ffffff",
T: "#3C88EE",
U: "#3C88EE",
V: "#ffffff",
W: "#ffffff",
X: "#ffffff",
Y: "#ffffff",
"?": "#333333",
"-": "#778899",
":": "#778899",
"*": "#778899",
".": "#778899",
"·": "#778899",
" ": "#778899"
},
jalviewPurinePyrimidine: {
A: "#FF83FA",
B: "#ffffff",
C: "#40E0D0",
D: "#ffffff",
G: "#FF83FA",
H: "#ffffff",
I: "#ffffff",
K: "#ffffff",
M: "#ffffff",
N: "#ffffff",
R: "#FF83FA",
S: "#ffffff",
T: "#40E0D0",
U: "#40E0D0",
V: "#ffffff",
W: "#ffffff",
X: "#ffffff",
Y: "#40E0D0",
"?": "#333333",
"-": "#778899",
":": "#778899",
"*": "#778899",
".": "#778899",
"·": "#778899",
" ": "#778899"
},
dna: {
"A": "#3f5fef",
"T": "#ee2f2f",
"G": "#2f2f2f",
"C": "#0f7f7f",
"-": "#778899",
":": "#778899",
"*": "#778899",
".": "#778899",
"·": "#778899",
" ": "#778899"
},
ruler: {
"0": "#de9d00",
"1": "#de9d00",
"2": "#de9d00",
"3": "#de9d00",
"4": "#de9d00",
"5": "#de9d00",
"6": "#de9d00",
"7": "#de9d00",
"8": "#de9d00",
"9": "#de9d00",
"·": "#6f4f0f",
" ": "#778899"
},
alphabet: { //https://www.omniglot.com/conscripts/coloralphabet.php
"K": "#ffff96",
"M": "#cd9135",
"L": "#ca3e5e",
"W": "#ff98d5",
"T": "#538cd0",
"V": "#b2dccd",
"C": "#92f846",
"Y": "#afc84a",
"F": "#b9b9b9",
"G": "#ebebde",
"I": "#ffff00",
"D": "#ffc82f",
"E": "#ff7600",
"O": "#ff0000",
"B": "#af0d66",
"S": "#792187",
"A": "#0000b4",
"N": "#0c4b64",
"U": "#009a25",
"H": "#646464",
"P": "#af9b32",
"Z": "#3f190c",
"J": "#371370",
"X": "#00004a",
"R": "#254619",
"Q": "#000000",
"-": "#778899",
":": "#778899",
"*": "#778899",
".": "#778899",
"·": "#778899",
" ": "#778899"
},
number: { //http://colorbrewer2.org/#type=qualitative&scheme=Set3&n=10
"0": "#8dd3c7",
"1": "#ffffb3",
"2": "#bebada",
"3": "#fb8072",
"4": "#80b1d3",
"5": "#fdb462",
"6": "#b3de69",
"7": "#fccde5",
"8": "#d9d9d9",
"9": "#bc80bd",
"-": "#778899",
":": "#778899",
"*": "#778899",
".": "#778899",
"·": "#778899",
" ": "#778899"
}
};
_LexiconMonoSeq.prototype.opacities = {
aa: _LexiconMonoSeq.prototype.common.opacities,
jalviewClustal: _LexiconMonoSeq.prototype.common.opacities,
jalviewZappo: _LexiconMonoSeq.prototype.common.opacities,
jalviewTaylor: _LexiconMonoSeq.prototype.common.opacities,
jalviewHydrophobicity: _LexiconMonoSeq.prototype.common.opacities,
jalviewHelixPropensity: _LexiconMonoSeq.prototype.common.opacities,
jalviewStrandPropensity: _LexiconMonoSeq.prototype.common.opacities,
jalviewTurnPropensity: _LexiconMonoSeq.prototype.common.opacities,
jalviewBuriedIndex: _LexiconMonoSeq.prototype.common.opacities,
jalviewNucleotide: _LexiconMonoSeq.prototype.common.opacities,
jalviewPurinePyrimidine: _LexiconMonoSeq.prototype.common.opacities,
dna: _LexiconMonoSeq.prototype.common.opacitiesPunctuation,
alphabet: _LexiconMonoSeq.prototype.common.opacitiesPunctuation,
number: _LexiconMonoSeq.prototype.common.opacitiesPunctuation,
ruler: {
"·": 0.05
}
};
_LexiconMonoSeq.prototype.textColors = {
aa: "rgba(0,0,0,0.9)",
jalviewClustal: "rgba(0,0,0,0.9)",
jalviewZappo: "rgba(0,0,0,0.9)",
jalviewTaylor: "rgba(0,0,0,0.9)",
jalviewHydrophobicity: "rgba(255,255,255,0.8)",
jalviewHelixPropensity: "rgba(255,255,255,0.8)",
jalviewStrandPropensity: "rgba(255,255,255,0.8)",
jalviewTurnPropensity: "rgba(255,255,255,0.8)",
jalviewBuriedIndex: "rgba(255,255,255,0.8)",
jalviewNucleotide: "rgba(0,0,0,0.9)",
jalviewPurinePyrimidine: "rgba(0,0,0,0.9)",
dna: "rgba(255,255,255,0.8)",
alphabet: "rgba(0,0,0,0.9)",
number: "rgba(255,255,255,0.8)",
ruler: "rgba(0,0,0,0.9)"
};
_LexiconMonoSeq.prototype.caveManCopy = function(obj){
return JSON.parse(JSON.stringify(obj));
};
_LexiconMonoSeq.prototype.registerType = function(name,colors,textColor,opacities){
var prt = _LexiconMonoSeq.prototype;
name
&& (colors && (prt.colors[name] = prt.caveManCopy(colors)))
&& (textColor && (prt.textColors[name] = textColor))
&& (
(opacities && (prt.opacities[name] = prt.caveManCopy(opacities)))
|| (prt.opacities[name] = {})
);
return this;
};
_LexiconMonoSeq.prototype.darkenColorScheme = function(type,replacer,overwrite){
replacer = replacer || "#7e7e7e";
var nType = type + "Dark";
if (this.colors[nType] && !overwrite) {
return nType;
}
var o = this.caveManCopy(this.colors[type]);
Object.keys(o).forEach(function(d){
if (typeof replacer === "function") {
o[d] = replacer(d,o[d]);
} else if(o[d].toLowerCase() === "#ffffff") {
o[d] = replacer.toLowerCase();
}
});
this.registerType(nType,o,this.textColors[type],this.opacities[type]);
return nType;
};
_LexiconMonoSeq.prototype.reDraw = function(){
try {
if(!this.source){
throw new ReferenceError("No source is available, the source has been detached.");
}
this.update(this.source);
} catch(e) {
console.log(e.message);
} finally {
return this;
}
};
_LexiconMonoSeq.prototype.detach = function(){
delete this.source;
return this;
};
_LexiconMonoSeq.prototype.ColorShift = function(instance){
this.colors = Object();
var that = this,
f = function(h1,h2){
var v,
k = "" + h1 + h2;
if (v = that.colors[k]) {
return v.f;
}
v = that.colors[k] = Object();
v.t = Object();
return v.f = that.shift(h1,h2,v.t);
};
f.clear = function(){
that.colors = Object();
return instance;
};
return f;
};
_LexiconMonoSeq.prototype.ColorShift.prototype.shift = function(h1,h2,preComputed){
var max = Math.max,
min = Math.min,
h1r = +("0x" + h1.slice(1,3)),
h1g = +("0x" + h1.slice(3,5)),
h1b = +("0x" + h1.slice(5)),
h2r = +("0x" + h2.slice(1,3)),
h2g = +("0x" + h2.slice(3,5)),
h2b = +("0x" + h2.slice(5));
return function(t){
t = (t * 1000 | 0) / 1000;
var k = "" + t,
v;
if ((v = preComputed[k]) !== undefined) {
return v;
}
return preComputed[k] = "#"
+ ("00" + (max(0,min(255,h1r + t * (h2r - h1r))) | 0).toString(16)).slice(-2)
+ ("00" + (max(0,min(255,h1g + t * (h2g - h1g))) | 0).toString(16)).slice(-2)
+ ("00" + (max(0,min(255,h1b + t * (h2b - h1b))) | 0).toString(16)).slice(-2);
}
};
_LexiconMonoSeq.prototype.ColorShiftRgba = function(instance){
this.colors = Object();
var that = this,
f = function(rgba1,rgba2){
var v,
k = "" + rgba1 + rgba2;
if (v = that.colors[k]) {
return v.f;
}
v = that.colors[k] = Object();
v.t = Object();
return v.f = that.shift(rgba1,rgba2,v.t);
};
f.clear = function(){
that.colors = Object();
return instance;
};
return f;
};
_LexiconMonoSeq.prototype.ColorShiftRgba.prototype.rgx = /([0-9.]+)/gi;
_LexiconMonoSeq.prototype.ColorShiftRgba.prototype.shift = function(rgba1,rgba2,preComputed){
var max = Math.max,
min = Math.min,
rgx = this.rgx,
grps = (rgba1 + rgba2).match(rgx),
rgba1r = +grps[0],
rgba1g = +grps[1],
rgba1b = +grps[2],
rgba1a = +grps[3],
rgba2r = +grps[4],
rgba2g = +grps[5],
rgba2b = +grps[6],
rgba2a = +grps[7];
return function(t){
t = (t * 1000 | 0) / 1000;
var k = "" + t,
v;
if ((v = preComputed[k]) !== undefined) {
return v;
}
return preComputed[k] = "rgba("
+ (max(0,min(255,rgba1r + t * (rgba2r - rgba1r))) | 0)
+ ","
+ (max(0,min(255,rgba1g + t * (rgba2g - rgba1g))) | 0)
+ ","
+ (max(0,min(255,rgba1b + t * (rgba2b - rgba1b))) | 0)
+ ","
+ max(0,min(1,rgba1a + t * (rgba2a - rgba1a)))
+ ")";
}
};
_LexiconMonoSeq.prototype.interpolateAndStoreAtEnd = function(arr,i,v,t,_t){
var vi = arr[i];
if (t < 1){
return vi + (v - vi) * _t;
} else {
return arr[i] = v;
}
};
_LexiconMonoSeq.prototype.interpolateAndStore = function(arr,i,v,t){
var _t = arr["_t"+i],
vi;
if(t >= 1) {
delete arr["_t"+i];
delete arr["_"+i];
return arr[i] = v;
}
if (t < _t) {
delete arr["_"+i];
}
vi = arr["_"+i] || (arr["_"+i] = arr[i]);
arr["_t"+i] = t;
return arr[i] = vi + (v - vi) * t;
};
_LexiconMonoSeq.prototype.interpolateAndStoreArr = function(arr,ref,t){
var l = arr.length,
_t = arr._t,
vi,
i;
if(t >= 1) {
delete arr._t;
for (i = 0;i < l;++i){
delete arr["_"+i];
arr[i] = ref[i];
}
return arr;
}
if (t < _t) {
for (i = 0;i < l;++i){
delete arr["_"+i];
}
}
while(~--l){
vi = arr["_"+l] || (arr["_"+l] = arr[l]);
arr[l] = vi + (ref[l] - vi) * t;
}
arr._t = t;
return arr;
};
_LexiconMonoSeq.prototype.interpolateAndStoreArrInt = function(arr,ref,t){
var l = arr.length,
_t = arr._t,
vi,
i;
if(t >= 1) {
delete arr._t;
for (i = 0;i < l;++i){
delete arr["_"+i];
arr[i] = ref[i];
}
return arr;
}
if (t < _t) {
for (i = 0;i < l;++i){
delete arr["_"+i];
}
}
while(~--l){
vi = arr["_"+l] || (arr["_"+l] = arr[l]);
arr[l] = (vi + (ref[l] - vi) * t) | 0;
}
arr._t = t;
return arr;
};
_LexiconMonoSeq.prototype.SVG = function(container){
var svg = document.createElementNS("http://www.w3.org/2000/svg","svg");
svg.setAttribute("viewBox","0 0 1 1");
svg.setAttribute("preserveAspectRatio","none");
if (container) {
container.appendChild(svg);
}
return svg;
};
_LexiconMonoSeq.prototype.toggleClass = function (node,className,bool,chain){
var classArr = node.className.split(" ").filter(function(d,i){return d;}),
temp = classArr.indexOf(className),
temp2 = !~temp;
if (bool || bool === undefined && temp2) {
temp2 && (node.className = classArr.concat(className).join(" "));
} else {
!temp2 && (node.className = classArr.reduce(function(ac,d,i,a){if(i !== temp ){ac += d + " ";} return ac;},""));
}
return chain || (chain = {
toggleClass: function(className,bool){
return _LexiconMonoSeq.prototype.toggleClass(node,className,bool,chain);
}
});
};
_LexiconMonoSeq.prototype._states = ["state","DOMState"];
Object.defineProperties(
_LexiconMonoSeq.prototype,
{
state:{
configurable: false,
get: function(){
return this._state;
},
set: function(v){
if(v === "ANIM") {
this._state = v;
this.busyStyle.visibility = "visible";
} else if (v === "IDLE") {
this._state = v;
this.busyStyle.visibility = "hidden";
}
}
},
scrollLeftOffset:{
configurable: false,
get: function(){
return this._labels ? this._scrollLeftOffset : 0;
},
set: function(v){
if(this._labels) {
this._scrollLeftOffset = v;
}
}
},
scrollLeft:{
configurable: false,
get: function(){
return this.wrapper.scrollLeft - this.scrollLeftOffset;
},
set: function(v){
this.wrapper.scrollLeft = v + this.scrollLeftOffset;
}
},
DOMState:{
configurable: false,
get: function(){
return this.painters.some(function(d,i){return d.active || Object.keys(d.frames).length !== 0})
? "ANIM"
: "IDLE";
}
},
oState:{
configurable: false,
get: function(){
return this._states.every(function(d,i){
return this[d] === "IDLE";
},this) ? "IDLE" : "ANIM";
}
},
fontRect: {
configurable: false,
get: function(){
if (this._fontRect) {
return this._fontRect;
}
var that = this,
r = document.createRange(),
t = this.hidden.firstChild,
l = t.length;
r.setStart(t,0);
r.setEnd(t,l);
window.requestAnimationFrame(function(){
delete that._fontRect;
r.detach && r.detach();
});
return this._fontRect = r.getBoundingClientRect();
}
},
fontWidth: {
configurable: false,
get: function(){
var l = this.hidden.firstChild.length;
return this.fontRect.width/l;
}
},
fontHeight: {
configurable: false,
get: function(){
return this.fontRect.height;
}
},
fontRatio: {
configurable: false,
get: function(){
if(this._fontRatio){
return this._fontRatio;
}
var that = this;
window.requestAnimationFrame(function(){
delete that._fontRatio;
});
return this._fontRatio = this.fontWidth/this.fontHeight;
}
},
containerRect: {
configurable:false,
get: function(){
if (this._containerRect) {
return this._containerRect;
}
var that = this;
window.requestAnimationFrame(function(){
delete that._containerRect;
});
return this._containerRect = this.container.getBoundingClientRect();
}
},
containerHeight: {
configurable:false,
get: function(){
return this.containerRect.height;
}
},
mainRect: {
configurable:false,
get: function(){
if (this._mainRect) {
return this._mainRect;
}
var that = this;
window.requestAnimationFrame(function(){
delete that._mainRect;
});
return this._mainRect = this.div.getBoundingClientRect();
}
},
mainWidth: {
configurable: false,
get: function(){
return this.mainRect.width;
}
},
viewportRect: {
configurable:false,
get: function(){
if (this._viewportRect) {
return this._viewportRect;
}
var that = this;
window.requestAnimationFrame(function(){
delete that._viewportRect;
});
return this._viewportRect = this.wrapper.getBoundingClientRect();
}
},
viewportWidth: {
configurable: false,
get: function(){
return this.viewportRect.width;
}
},
viewportHeight: {
configurable: false,
get: function(){
return this.viewportRect.height;
}
},
viewportWidthInChar:{
configurable: false,
get: function(){
return this.viewportWidth/this.fontWidth;
}
},
isInViewport: {
configurable: false,
value: function(point){
var rect = this.viewportRect;
return (point.x - rect.left > 0) && (point.x - rect.left < rect.width) && (point.y - rect.top > 0) && (point.y - rect.top < rect.height);
}
},
innerWidth: {
configurable: false,
get: function(){
if (this._innerWidth) {
return this._innerWidth;
}
var that = this;
window.requestAnimationFrame(function(){
delete that._innerWidth;
});
return this._innerWidth = Math.max(document.documentElement.clientWidth,window.innerWidth);
}
},
getScreenWidth: {
configurable:false,
get: function(){
return this.innerWidth;
}
},
innerHeight: {
configurable: false,
get: function(){
if (this._innerHeight) {
return this._innerHeight;
}
var that = this;
window.requestAnimationFrame(function(){
delete that._innerHeight;
});
return this._innerHeight = Math.max(document.documentElement.clientHeight,window.innerHeight);
}
},
getScreenHeight: {
configurable:false,
get: function(){
return this.innerHeight;
}
},
getScreenWidthInChars: {
configurable:false,
get: function(){
return this.innerWidth/this.fontWidth;
}
},
getMaxDisplayableChars: {
configurable:false,
get: function(){
if (this._getMaxDisplayableChars) {
return this._getMaxDisplayableChars;
}
return this._getMaxDisplayableChars = Math.min(this.getScreenWidth,this.viewportWidth)/this.fontWidth;
}
},
getMaxDisplayableSequences: {
configurable:false,
get: function(){
if (this._getMaxDisplayableSequences) {
return this._getMaxDisplayableSequences;
}
return this._getMaxDisplayableSequences = Math.min(this.getScreenHeight,this.viewportHeight,this.containerHeight)/this.sequences[0].trackHeight;
}
},
getCurrentPosLeft: {
configurable:false,
get: function(){
if (this._getCurrentPosLeft) {
return this._getCurrentPosLeft;
}
var that = this,
track = this.getMaxTrackLength;
window.requestAnimationFrame(function(){
delete that._getCurrentPosLeft;
});
return this._getCurrentPosLeft = {
posLeft: (this.scrollLeft - track.posOffsetTransform) / track.width * track.sequenceLength * track.charWidth,
posOffset: track.posOffset
};
}
},
getVisibleRangeVertical: {
configurable:false,
get: function(){
if(this._getVisibleRangeVertical) {
return this._getVisibleRangeVertical;
}
var that = this,
rectMain = this.mainRect,
rectContainer = this.containerRect,
top = Math.max(rectMain.top,rectContainer.top),
bot = Math.min(rectMain.bottom,rectContainer.bottom),
vRange = {start:0,end:0},
l = this.sequences.length,
maxDisplayableSequences = this.getMaxDisplayableSequences;
window.requestAnimationFrame(function(){
delete that._getVisibleRangeVertical;
});
if(bot <= top) {
vRange.start = -1;
vRange.end = -1;
return this._getVisibleRangeVertical = vRange;
}
vRange.start = (top - rectMain.top) / rectMain.height * l;
vRange.offset = -(vRange.start % 1);
vRange.start = Math.max(0,vRange.start - maxDisplayableSequences * this.displayPadding) | 0;
vRange.end = Math.ceil(Math.min(l,(bot - rectMain.top) / rectMain.height * l + maxDisplayableSequences * this.displayPadding));
return this._getVisibleRangeVertical = vRange;
}
},
getMaxTrackLength: {
configurable:false,
get: function(){
if(this._getMaxTrackLength) {
return this._getMaxTrackLength;
}
var a = this.sequences,
l = a.length-1,
s = a[l],
w;
while(~--l){
if(a[l].options.svgWidthInPx > s.options.svgWidthInPx) {
s = a[l];
}
}
//implicitly set main width
w = s.options.svgWidthInPx;
this.div.style.width = w + "px";
return this._getMaxTrackLength = {
posOffset: s.posOffset,
posOffsetTransform: s.options.posOffsetTransform,
width: w,
charWidth:s.charWidth,
sequenceLength: s.seq.length
};
}
}
}
);
_LexiconMonoSeq.prototype.strConcat = function(arr){
var chr = String.fromCharCode;
for(var i = 0,l = arr.length - 1,r = chr(arr[i]);i < l;++i){
r += chr(arr[i + 1]);
}
return r;
};
_LexiconMonoSeq.prototype.getMaxSeqLength = function(arr){
this.maxSeqLength = Math.max.apply(null,arr.map(function(d,i){return d.seq.length;}));
return this;
};
_LexiconMonoSeq.prototype.getInfoFromEvent = function(event){
var point;
if(!this.isInViewport(point = {
x:event.clientX !== undefined ? event.clientX : event.changedTouches[0].clientX,
y:event.clientY !== undefined ? event.clientY : event.changedTouches[0].clientY
})) {
return {detail:"MISS"};
}
var trackNumber = (point.y - this.mainRect.top) / this.mainRect.height * this.sequences.length | 0,
sequenceObj = this.sequences[trackNumber],
slabRect = sequenceObj && sequenceObj.slabRect,
slab = sequenceObj && sequenceObj.textSlab,
seq = slab && slab._seqArr;
if(!seq){
return {
detail:"MISS",
state: this.oState,
trackNumber: trackNumber,
target: sequenceObj
};
}
var rects = sequenceObj.rects,
range = rects.paintedRange,
options = sequenceObj.options,
offset = (point.x - slabRect.left + options.transformXOffset - options.posOffsetTransform) / slabRect.width * seq.length,
rCharNumber = offset | 0,
charNumber = rCharNumber + range.start;
if(seq[rCharNumber] === undefined) {
return {
detail:"MISS",
state: this.oState,
trackNumber: trackNumber,
target: sequenceObj
};
}
return {
detail: "HIT",
state: this.oState,
trackNumber: trackNumber,
target: sequenceObj,
pos: charNumber,
rPos: rCharNumber,
letter: String.fromCharCode(seq[rCharNumber]),
offset: offset- rCharNumber
}
};
_LexiconMonoSeq.prototype.garbage = function(){
this.detach();
this.wrapper.parentNode.removeChild(this.wrapper);
return this;
};
_LexiconMonoSeq.prototype.getInfoFromRect = function(rect){//top,left,width,height
var vRect,
trackHeight,
h,
o,
seq,
target,
widthInChar,
info,
start,
end,
prev;
if(!this.isInViewport({x:rect.left,y:rect.top})) {
return [];
}
vRect = this.viewportRect;
trackHeight = this._trackHeight;
rect = this.caveManCopy(rect);
rect.width = Math.min(rect.width,vRect.width - rect.left + vRect.left);
rect.height = Math.min(rect.height,vRect.height - rect.top + vRect.top);
widthInChar = rect.width/this.fontWidth;
o = [];
for (h = 0; true; h += trackHeight, h = Math.min(h, rect.height)){
info = this.getInfoFromEvent({clientX:rect.left, clientY: rect.top + h});
if(info.detail === "HIT") {
target = info.target;
seq = target.textSlab._seqArr;
start = info.rPos;
end = Math.min(seq.length, Math.ceil(start + widthInChar / target.charWidth + info.offset));
info.end = info.pos + end;
info.captured = seq.slice(start,end).map(function(d){return String.fromCharCode(d);});
}
if(!prev || prev !== info.trackNumber){
o.push(info);
}
if(h === rect.height) {
break;
}
prev = info.trackNumber;
}
return o;
};
_LexiconMonoSeq.prototype.enableDrag = function(options){
if(this._dragEnabled){return this;};
var wrapper = this.wrapper,
startDrag = this.startDrag(options);
this._dragEnabled = true;
wrapper.addEventListener("mousedown",startDrag,false);
wrapper.addEventListener("touchstart",startDrag,this.quirks.passiveSupported ? {capture:false, passive:false} : false);
this.toggleClass(wrapper,"drag",true);
return this;
};
_LexiconMonoSeq.prototype.disableDrag = function(){
if(!this._dragEnabled){return this;};
var wrapper = this.wrapper;
delete this._dragEnabled;
delete wrapper._dragging;
wrapper.removeEventListener("mousedown",wrapper._startDrag,false);
wrapper.removeEventListener("touchstart",wrapper._startDrag,this.quirks.passiveSupported ? {capture:false, passive:false} : false);
delete wrapper._startDrag;
this.toggleClass(wrapper,"drag",false);
return this;
};
_LexiconMonoSeq.prototype.startDrag = function(options){
var instance = this,
container = this.container,
wrapper = this.wrapper,
busy = false;
return wrapper._startDrag = function(e){
if(busy){return}
busy = true;
window.requestAnimationFrame(function(){
busy = false;
});
if(wrapper._dragging){return};
e.preventDefault();
wrapper._dragging = true;
instance.Drag(instance,container,wrapper,options,e);
}
};
_LexiconMonoSeq.prototype.Drag = function (instance,container,wrapper,options,e){
var xI = e.clientX !== undefined ? e.clientX : e.changedTouches[0].clientX,
yI = e.clientY !== undefined ? e.clientY : e.changedTouches[0].clientY,
sX = instance.scrollLeft,
sY = wrapper.scrollTop,
o = Object(),
refMove = instance.drag.bind(o,instance,container,wrapper,xI,yI,sX,sY,options),
refReset = function(e){
this.removeEventListener("resize",refReset,false);
this.removeEventListener("mouseup",refReset,false);
this.removeEventListener("touchend",refReset,false);
this.removeEventListener("touchmove",refMove,instance.quirks.passiveSupported ? {capture:false, passive:false} : false);
this.removeEventListener("mousemove",refMove,false);
instance.quirks.enableScroll();
wrapper._dragging = false;
options && options.end && options.end.call(instance,e,options);
};
instance.quirks.disableScroll();
window.addEventListener("resize",refReset,false);
window.addEventListener("mouseup",refReset,false);
window.addEventListener("touchend",refReset,false);
if (e.type === "touchstart") {
e.preventDefault();
window.addEventListener("touchmove",refMove,instance.quirks.passiveSupported ? {capture:false, passive:false} : false);
} else {
window.addEventListener("mousemove",refMove,false);
}
};
_LexiconMonoSeq.prototype.drag = function (instance,container,wrapper,xI,yI,sX,sY,options,e) {// this refers to empty object pointer
e.preventDefault();
if(this.busy){return}
if(!this.dragStarted) {
this.dragStarted = true;
options && options.start && options.start.call(instance,e,options);
}
var xF = e.clientX !== undefined ? e.clientX : e.changedTouches[0].clientX,
yF = e.clientY !== undefined ? e.clientY : e.changedTouches[0].clientY,
that = this;
this.busy = true;
window.requestAnimationFrame(function(){
that.busy = false;
});
instance.scrollLeft = sX - (xF - xI);
wrapper.scrollTop = sY - (yF - yI);
options && options.drag && options.drag.call(instance,e,options);
};
_LexiconMonoSeq.prototype.skipFrames = function(nFrames,argObj,parent,catcher){
nFrames = nFrames instanceof this.skipFrames.Timer ? nFrames : new this.skipFrames.Timer(nFrames);
var that = this,
argObj = typeof argObj !== "object"
? {value:argObj,done:true}
: that.skipFrames.isExtractable(argObj)
? argObj
: {value:argObj,done:true};
return {
_instance: that.skipFrames,
_parent: parent,
_invoked: false,
_child: null,
_isErrored: false,
_catch: catcher || null,
then: function(f){
this._invoked = true;
var thenable = this,
retVal = {value:undefined,done:false},
placeholder = null,
isExtractable = false;
that.watchman(
that,
function(nFrames){
if(argObj.value && argObj.value._instance === that.skipFrames) {
if(!argObj.value._invoked) {
argObj.value.then(function(x){
argObj.value = x;
});
}
return false;
}
return argObj.done && nFrames.decrement() <= 0;
},
function(){
if(argObj.value instanceof Error){
retVal.value = argObj.value;
thenable._isErrored = true;
} else {
try {
placeholder = f.call(that,argObj.value);
if(!(isExtractable = that.skipFrames.isExtractable(placeholder))) {
if ((retVal.value = placeholder) instanceof Error ){
throw retVal.value;
};
}
} catch (e) {
retVal.value = e;
thenable._isErrored = true;
}
}
if(isExtractable) {
that.watchman(
null,
function(){return placeholder.done;},
function(){that.skipFrames.Extractor(that,thenable,retVal,placeholder).PerformCatch(that,thenable,retVal);},
null
);
} else {
retVal.done = true;
that.skipFrames.PerformCatch(that,thenable,retVal);
}
},
nFrames
);
return this._child = that.skipFrames(new that.skipFrames.Timer(1,nFrames),retVal,this,this._catch);
},
skipFrames: function(_nFrames){
this._invoked = true;
return this._child = that.skipFrames(new that.skipFrames.Timer(_nFrames,nFrames),argObj,this,this._catch);
},
catch: function(f){
if (typeof f === "function") {
this._catch = f;
this._parent && (this._parent._catch = f);
}
return this;
}
};
};
_LexiconMonoSeq.prototype.skipFrames.Catcher = function(e){throw e;};
_LexiconMonoSeq.prototype.skipFrames.PerformCatch = function(instance,thenable,retVal){
if (!thenable._child._invoked && thenable._isErrored){
thenable._catch
? thenable._catch.call(instance,retVal.value)
: _LexiconMonoSeq.prototype.skipFrames.Catcher.call(instance,retVal.value);
}
};
_LexiconMonoSeq.prototype.skipFrames.Extractor = function(instance,thenable,retVal,placeholder){
retVal.value = placeholder.value;
retVal.done = placeholder.done;
if (retVal.value instanceof Error) {
thenable._isErrored = true;
}
return instance.skipFrames;
};
_LexiconMonoSeq.prototype.skipFrames.isExtractable = function(o){return typeof o === "object" && o.hasOwnProperty("done") && o.hasOwnProperty("value");};
_LexiconMonoSeq.prototype.skipFrames.Timer = function (counter,parent){
this.counter = counter || 1;
this.parent = parent || 0;
};
_LexiconMonoSeq.prototype.skipFrames.Timer.prototype.valueOf = function(){
return this.counter + this.parent;
};
_LexiconMonoSeq.prototype.skipFrames.Timer.prototype.decrement = function(){
--this.counter;
return this;
};
_LexiconMonoSeq.prototype.async = function(o){
return this.skipFrames(1,typeof o === "function" ? o.call(this) : o);
};
_LexiconMonoSeq.prototype.quirks = {
busy:false,
parent: _LexiconMonoSeq.prototype,
passiveSupported: false,
scrollDisabled: false,
disableScroll:function(){
if(this.scrollDisabled){return}
this.parent.toggleClass(document.body,"lock-scroll",true);
document.body.addEventListener("touchmove",this.disableScrollFunction,this.passiveSupported ? {capture:false, passive:false} : false);
this.scrollDisabled = true;
},
enableScroll:function(){
if(!this.scrollDisabled){return}
this.parent.toggleClass(document.body,"lock-scroll",false);
document.body.removeEventListener("touchmove",this.disableScrollFunction, this.passiveSupported ? {capture:false, passive:false} : false);
this.scrollDisabled = false;
}
};
(function(){
var quirks = _LexiconMonoSeq.prototype.quirks,
options = Object.defineProperty({},"passive",{
get: function(){
quirks.passiveSupported = true;
}
});
window.addEventListener("lexiconMonoSeqPassiveTest",null,options);
quirks.disableScrollFunction = function(e){
if(quirks.busy){return}
window.requestAnimationFrame(function(){
quirks.busy = false;
});
quirks.busy = true;
if(!e.cancelable) {
return
} else {
e.preventDefault();
}
};
})();
/*
###############################
##############PROTO############
###############################
*/
/*
###############################
#############STATIC############
###############################
*/
LexiconMonoSeq.createRuler = function (arr,inject,bottom){
var ruler = "",
charLength = Math.max.apply(null,arr.map(function(d,i){return d.seq.length * (d.charWidth || 1) + (d.posOffset || 0)})),
tick = 1,
counter = 20,
pass = 0;
while(~--charLength){
if(pass){
pass--;
counter++;
continue;
}
if(!(counter %= 20)){
pass = ("" + tick).length - 1;
ruler += tick;
tick += 20;
} else {
ruler += "·";
}
counter++;
}
if(inject){
if(bottom) {
arr.push({
name:"ruler",
seq:ruler,
type:"ruler"
});
} else {
arr.unshift({
name:"ruler",
seq:ruler,
type:"ruler"
});
}
return arr;
}
return ruler;
};
LexiconMonoSeq.readClustal = function (str,options){
var rndStr = _LexiconMonoSeq.prototype.generateRandomString(),
rndStrL = rndStr.length,
firstLine,
offsetLeft,
lineLength,
offsetRight,
trimLeft = /(?:\s|\t)(?:[0-9]+(?:\s+)?)?$/,
o = str.split("\n")
.slice(1)
.map(function(d,i,a){
switch((this.sequence.test(d) << 1) + ((options && options.conservation && this.previous) << 0)){
case 3:
return d;
case 2:
this.previous = true;
return d;
case 1:
this.previous = false;
return rndStr + d;
case 0:
return false;
}
},{sequence:/([A-Z_\-0-9]+)\s+([A-Z\-]+)(?:\s+[0-9]+)?/i,previous:false})
.filter(Boolean)
.reduce(function(ac,d,i,a){
var arr = d.split(/\s+/),
name = !d.indexOf(rndStr) ? "Cons." : arr[0],
seq;
if(!firstLine){
seq = arr[1];
firstLine = true;
offsetLeft = d.indexOf(seq);
lineLength = seq.length;
offsetRight = offsetLeft + lineLength;
} else if (name !== "Cons.") {
seq = d.slice(offsetLeft,offsetRight);
} else {
seq = d.slice(offsetLeft + rndStrL, offsetRight + rndStrL);
}
seq = seq.replace(trimLeft,"");
if(ac[name]){
ac[name] += seq;
} else {
ac[name] = seq;
}
return ac;
},{});
return Object.keys(o)
.map(function(d,i){
return {
name: d,
seq: o[d],
charWidth: (options && options.charWidth) || 1,
type: (options && options.type) || "aa"
};
})
};
//Below is directly from https://j11y.io/javascript/parsing-urls-with-the-dom/
//Kudos to JAMES PADOLSEY, great solution
LexiconMonoSeq.parseURL = function (url) {
var a = document.createElement('a');
a.href = url;
var result = {
source: url,
protocol: a.protocol.replace(':',''),
host: a.hostname,
port: a.port,
query: a.search,
params: (function(){
var ret = {},
seg = a.search.replace(/^\?/,'').split('&'),
len = seg.length, i = 0, s;
for (;i<len;i++) {
if (!seg[i]) { continue; }
s = seg[i].split('=');
ret[s[0]] = s[1];
}
return ret;
})(),
file: (a.pathname.match(/\/?([^/?#]+)$/i) || [,''])[1],
hash: a.hash.replace('#',''),
path: a.pathname.replace(/^([^/])/,'/$1'),
relative: (a.href.match(/tps?:\/\/[^/]+(.+)/) || [,''])[1],
segments: a.pathname.replace(/^\//,'').split('\/'),
};
result.isLocal = !/^https?|^\/\//i.test(result.source);
return result;
};
/*
###############################
#############STATIC############
###############################
*/
/*
###############################
###########ANIM LEDGER#########
###############################
*/
_LexiconMonoSeq.prototype.AnimLedger = function(instance){
Object.defineProperties(
this,
{
a: this.returnDescriptor("a",instance),
u: this.returnDescriptor("u",instance),
r: this.returnDescriptor("r",instance),
s: this.returnDescriptor("s",instance),
sMan: this.returnDescriptor("sMan",instance),
l: this.returnDescriptor("l",instance)
}
);
this.instance = instance;
};
_LexiconMonoSeq.prototype.AnimLedger.prototype.nonCancelableFrames = ["_r","_l"];
_LexiconMonoSeq.prototype.AnimLedger.prototype.returnDescriptor = function(key,instance){
//instance["_" + key] = undefined;
var obj = Object();
obj.configurable = false;
obj.get = function(){return this["_"+key];};
obj.set = function(v){
this["_"+key] = v;
if(v === undefined) {
if(this.getKeys().every(function(d,i){return this[d] === undefined},this)) {
instance.state = "IDLE";
}
}
};
return obj;
};
_LexiconMonoSeq.prototype.AnimLedger.prototype.getKeys = function(){
return Object.keys(this).filter(function(d,i){return d.slice(0,1) === "_"});
};
_LexiconMonoSeq.prototype.AnimLedger.prototype.getCancelable = function(){
return this.getKeys().filter(function(d,i){return !~this.nonCancelableFrames.indexOf(d);},this);
};
_LexiconMonoSeq.prototype.AnimLedger.prototype.cancelFrames = function(){
this.getCancelable()
.forEach(function(d,i){
window.cancelAnimationFrame(this[d]);
this[d.slice(1)] = undefined;
},this);
return this;
};
_LexiconMonoSeq.prototype.AnimLedger.prototype.prepareForUpdate = function(arr){
this.instance.state = "ANIM";
this.instance.sequences.forEach(function(d,i){delete d.source});
this._a = undefined;
this.instance
.set("_trackHeight",undefined)
.set("_getMaxTrackLength",undefined)
.set("_getMaxDisplayableChars",undefined)
.set("_getMaxDisplayableSequences",undefined);
return this;
};
/*
###############################
###########ANIM LEDGER#########
###############################
*/
/*
###############################
############SEQUENCE###########
###############################
*/
_LexiconMonoSeq.prototype.Sequence = function (seqObj,instance){
var that = this,
div = document.createElement("div"),
svg = this.svg = instance.SVG(div),
textDiv = div.appendChild(document.createElement("div")),
textSlab = div.appendChild(document.createElement("div"));
this
.set("rm",false)
.set("_rm",false)
/*painter:undefined, assigned during appending*/
.set("div",div)
.set("style",div.style)
.set("svg",svg)
.set("styleSVG",svg.style)
.set("textDiv",textDiv)
.set("styleTextDiv",textDiv.style)
.set("textSlab",textSlab)
.set("styleTextSlab",textSlab.style)
.set("parent",instance)
.set("seq",seqObj.seq)
.set("type",seqObj.type)
/*source:this, temporarily added later on update*/
.set("charWidth",seqObj.charWidth || 1)
.set("name",seqObj.name)
.set("posOffset",seqObj.posOffset || 0)
.set("isVisible",true);
this.style.transform = "translate(" + (-1 * instance.viewportWidth) + "px,0px)";
this.style.opacity = 0;
div.className = "LexiconMonoSeq sequence custom";
svg.setAttribute("class","LexiconMonoSeq custom");
textDiv.className = "LexiconMonoSeq textDiv custom";
textSlab.className = "LexiconMonoSeq textSlab custom";
textSlab._transformX = 0;
textSlab._textColor = "rgba(0,0,0,0)";
instance.div.appendChild(div);
new instance.Rect(this);
seqObj = undefined;//allow garbage collection
};
Object.defineProperties(
_LexiconMonoSeq.prototype.Sequence.prototype,
{
trackRect: {
configurable: false,
get: function(){
if (this._trackRect) {
return this._trackRect;
}
var that = this;
window.requestAnimationFrame(function(){
delete that._trackRect;
});
return this._trackRect = this.svg.getBoundingClientRect();
}
},
slabRect: {
configurable: false,
get: function(){
if (this._slabRect) {
return this._slabRect;
}
var that = this;
window.requestAnimationFrame(function(){
delete that._slabRect;
});
return this._slabRect = this.textSlab.getBoundingClientRect();
}
},
trackHeight: {
configurable: false,
get:function(){
var trackHeight = this.parent._trackHeight;
if(trackHeight) {
return trackHeight;
}
return this.parent._trackHeight = this.trackRect.height;
}
},
unitLength: {
configurable: false,
get:function(){
return this.seq.length * this.charWidth;
}
},
isInTrack: {
configurable: false,
writable:false,
value:function(point){
var rect = this.trackRect;
return (point.x - rect.left > 0) && (point.x - rect.left < rect.width);
}
},
visibleRange: {
configurable: false,
get:function(){
var currentPosLeft = this.parent.getCurrentPosLeft,
pLeft = currentPosLeft.posLeft - (this.posOffset - currentPosLeft.posOffset),
charWidth = this.charWidth,
uLen = this.unitLength,
offset = -(pLeft / charWidth % 1),
maxDisplayableChars = this.parent.getMaxDisplayableChars/charWidth,
start = pLeft/charWidth,
end = start + maxDisplayableChars;
if (pLeft >= uLen) {return -1}
return {start:start,end:end,offset:offset};
}
},
adjustRange: {
configurable: false,
writable:false,
value:function(range){
var charWidth = this.charWidth,
maxDisplayableChars = this.parent.getMaxDisplayableChars/charWidth,
padding = this.parent.displayPadding * maxDisplayableChars,
start = Math.max(0,range.start - padding | 0 ),
end = Math.min(this.seq.length,Math.max(0,Math.ceil(range.end + padding)));
return {start:start,end:end,offset:range.offset};
}
},
rangeWithinRange: {
configurable: false,
writable:false,
value:function(range,refRange){
return (range.start - refRange.start >= 0) && (range.end - refRange.end <= 0);
}
},
rangeEqual: {
configurable: false,
writable:false,
value:function(range,refRange){
return (range.start === refRange.start) && (range.end === refRange.end);
}
},
withinVerticalRange: {
configurable: false,
get:function(){
var i = this.parent.sequences.indexOf(this),
range = this.parent.getVisibleRangeVertical;
return ~i && !this.rm && (i >= range.start) && (i < range.end);
}
},
toggleVisibility: {
configurable: false,
writable:false,
value:function(show){
show = !!show;
if(show !== this.isVisible){
this.isVisible = show;
this.style.visibility = show ? "visible" : "hidden";
}
return this;
}
},
update: {
configurable: false,
writable:false,
value:function(t,options,uT){
var instance = this.parent,
index = instance.sequences.indexOf(this),
textSlab = this.textSlab;
if(!options.target){
if(!this._rm){
instance.toggleClass(this.div,"rm",true);
instance.sequences.splice(index,1);
this._rm = true;
}
this.style.transform = "translate(" + (options.viewportWidth * t) + "px,0px)";
this.style.opacity = 1-t;
if(t >= 1){
this.div.parentNode && instance.div.removeChild(this.div);
}
return;
}
if (!options.firstCall){
var lStart = " <" +(index + 1) + ". ",
lEnd = " /> ",
pad = lStart.length + lEnd.length,
rem = instance.maxAllowedLabelLength - pad,
lMid = this.name.length > rem ? this.name.slice(0,rem - 3) + "..." : (this.name + instance._50spaces).slice(0,rem),
lAll = lStart + lMid + lEnd;
if(lAll.length !== instance.maxAllowedLabelLength){
instance.scrollLeftOffset = instance.fontWidth * lAll.length;
instance.divStyle.transform = "translate(" + instance.scrollLeftOffset + "px,0px)";
}
this.textDiv.textContent = lAll;
textSlab._textColorInterpolator = instance.ColorShiftRgba(textSlab._textColor,instance.textColors[this.type] || "rgba(0,0,0,0.9)");
options.firstCall = true;
}
if (uT < 1){
this.styleTextSlab.color = textSlab._textColorInterpolator(t);
} else {
this.styleTextSlab.color = textSlab._textColor = textSlab._textColorInterpolator(t);
}
}
},
set: {
configurable: false,
writable: false,
value: function(k,v){
this[k] = v;
return this;
}
}
}
);
/*
###############################
############SEQUENCE###########
###############################
*/
/*
###############################
##############RECT#############
###############################
*/
_LexiconMonoSeq.prototype.Rect = function(seqInstance){
var unitType = SVGUnitTypes.SVG_UNIT_TYPE_USERSPACEONUSE,
p = seqInstance.parent;
seqInstance.rects = this;
this.id = p.generateRandomString();
this.parent = seqInstance;
this.svg = seqInstance.svg;
this.cNodes = this.svg.childNodes;
this.stopWidths = [];
this.stopOffsets = [];
this.stopColors = [];
this.stopOpacities = [];
this.paintedRange = {start:-1,end:-1};
this.fragment = document.createDocumentFragment();
this.depot = new this.Depot(this);
};
_LexiconMonoSeq.prototype.Rect.prototype.getVal = function(n,v) {
return n[v].baseVal.value;
};
_LexiconMonoSeq.prototype.Rect.prototype.setAttr = function(n,k,v){
return this.chain(n).setAttr(k,v);
};
_LexiconMonoSeq.prototype.Rect.prototype.setVal = function(n,k,v){
return this.chain(n).setVal(k,v);
};
_LexiconMonoSeq.prototype.Rect.prototype.chain = function(n){
return n._chain || (n._chain = new this.Chain(n));
};
_LexiconMonoSeq.prototype.Rect.prototype.Chain = function(n){
this.n = n;
};
_LexiconMonoSeq.prototype.Rect.prototype.Chain.prototype.u = SVGUnitTypes.SVG_UNIT_TYPE_USERSPACEONUSE;
_LexiconMonoSeq.prototype.Rect.prototype.Chain.prototype.setAttr = function(k,v){
this.n.setAttribute(k,v);
return this;
};
_LexiconMonoSeq.prototype.Rect.prototype.Chain.prototype.setVal = function(k,v){
this.n[k].baseVal.newValueSpecifiedUnits(this.u,v);
return this;
};
_LexiconMonoSeq.prototype.Rect.prototype.rect = (function(){
return this.setAttr(document.createElementNS("http://www.w3.org/2000/svg","rect"),"fill","#ffffff")
.setAttr("fill-opacity",0)
/*.setAttr("stroke-width",0)*/
.setVal("width",1)
.setVal("height",1)
/*.setVal("rx",0.125)*/
.setVal("x",0)
/*.setVal("y",0)*/
.n;
}).call(_LexiconMonoSeq.prototype.Rect.prototype);
_LexiconMonoSeq.prototype.Rect.prototype.setViewBox = function(nSVG,viewBox){
var SVGViewBox = nSVG.viewBox.baseVal,
key;
for(var key in viewBox) {
viewBox.hasOwnProperty(key) && (SVGViewBox[key] = viewBox[key]);
}
return nSVG;
};
_LexiconMonoSeq.prototype.Rect.prototype.update = function(force){
var p = this.parent.parent,
seqInstance = this.parent,
that = this,
depot = this.depot;
if(seqInstance.rm){
return;
}
if(!seqInstance.withinVerticalRange){
depot.claim();
return;
}
var options = seqInstance.options,
vR = seqInstance.visibleRange;
if(!force && seqInstance.rangeWithinRange(vR,that.paintedRange) && seqInstance.isVisible){
return;
}
var aR = seqInstance.adjustRange(vR),
dR = aR.end - aR.start;
if(!dR){
return
}
depot.claim(dR);
var fragmentNodes = [],
cNodeLength = that.cNodes.length,
l = 0;
for(;l < cNodeLength;++l){
fragmentNodes.push(that.cNodes[l])
}
depot.borrow(fragmentNodes,dR);
var seq = seqInstance.seq,
type = seqInstance.type,
uC = options.uC;
var i,
j,
k,
m,
n,
o;
m = options.stopOffsets = [];
for(i = 0,j = aR.start;i<dR;++i){
m.push((j + i) * uC);
}
m = options.stopOpacities = [];
for(i = 0,n = p.opacities[type];i<dR;++i){
k = +n[seq[j + i]];
m.push(k === k ? k : 0.8);
}
m = options.stopColors = [];
n = that.stopColors;
for(i = 0,k = n.length,o = p.colors[type];i<k;++i){
m.push(p.ColorShift(n[i],o[seq[j + i]]));
}
options.rects = that;
options.aR = aR;
var relocate;
l = fragmentNodes.length;
if (that.paintedRange.end - aR.end >= dR){
relocate = (aR.start + dR + 1) * uC;
while (~--l) {
that.stopOffsets[l] = relocate;
}
} else if (aR.start - that.paintedRange.start >= dR) {
relocate = (aR.start - dR) * uC;
while (~--l) {
that.stopOffsets[l] = relocate;
}
} else if (seqInstance.rangeEqual(this.paintedRange,aR)) {
relocate = (aR.start + aR.end) / 2 * uC;
while (~--l) {
that.stopOffsets[l] = relocate;
}
}
//max relocateRight, in case --> p._getMaxTrackLength - options.viewportWidth * (1 + 2 * p.displayPadding)
if(relocate = relocate / options.svgWidthInUnits * options.svgWidthInPx){
seqInstance.textSlab._transformX = relocate;
}
that.paintedRange = aR;
seqInstance.painter.schedulePaint(fragmentNodes,options);
};
_LexiconMonoSeq.prototype.Rect.prototype.Depot = function(rect){
this.isEmpty = true;
this.parent = rect;
this.rect = rect.rect;
this.svg = rect.svg;
this.cNodes = rect.cNodes;
this.mockSVG = rect.parent.parent.SVG();
this.mockSVG.style.display = "none";
this.fragment = rect.fragment;
this.stopColors = rect.stopColors;
this.stopOffsets = rect.stopOffsets;
this.stopOpacities = rect.stopOpacities;
this.stopWidths = rect.stopWidths;
};
_LexiconMonoSeq.prototype.Rect.prototype.Depot.prototype.nodes = [];
_LexiconMonoSeq.prototype.Rect.prototype.Depot.prototype.claim = function(limit){
if (limit) {
while(this.cNodes.length > limit) {
this.nodes.push(this.svg.removeChild(this.svg.lastChild));
this.stopOffsets.pop();
this.stopColors.pop();
this.stopOpacities.pop();
this.stopWidths.pop();
}
} else {
while(this.svg.hasChildNodes()) {
this.nodes.push(this.svg.removeChild(this.svg.lastChild));
this.stopOffsets.pop();
this.stopColors.pop();
this.stopOpacities.pop();
this.stopWidths.pop();
}
}
return this;
};
_LexiconMonoSeq.prototype.Rect.prototype.Depot.prototype.borrow = function(arr,dR){
var node;
while(arr.length < dR) {
node = this.nodes.pop() || this.rect.cloneNode(false);
arr.push(this.fragment.appendChild(node));
this.stopOffsets.push(0);
this.stopColors.push("#ffffff");
this.stopOpacities.push(0);
this.stopWidths.push(1);
}
this.isEmpty && (this.isEmpty = false);
return this;
};
_LexiconMonoSeq.prototype.Rect.prototype.Depot.prototype.emptyFragment = function(){
this.mockSVG.appendChild(this.fragment);
while(this.mockSVG.hasChildNodes()){
this.nodes.push(this.mockSVG.removeChild(this.mockSVG.lastChild));
this.stopOffsets.pop();
this.stopColors.pop();
this.stopOpacities.pop();
this.stopWidths.pop();
}
!this.isEmpty && (this.isEmpty = true);
return this;
};
_LexiconMonoSeq.prototype.Rect.prototype.Depot.prototype.transfer = function(){
this.svg.appendChild(this.fragment);
this.isEmpty = true;
};
/*
###############################
##############RECT#############
###############################
*/
/*
###############################
##############EASE#############
###############################
*/
_LexiconMonoSeq.prototype.Ease = function(p1,p2,options){
this._resolution = (options && options.resolution) || 1000;
this._precision = (options && options.precision) || 1e-6;
this._arr = [];
this.registerEase(p1,p2);
var that = this,
arr = this._arr,
l = arr.length,
max = Math.max,
min = Math.min;
return function(t){
return arr[((l - 2) * max(0,min(t,1)) | 0)];
}
};
_LexiconMonoSeq.prototype.Ease.prototype.returnParametric = function(xy,p1,p2,derivative){
if (derivative) {
return function(t){return 3 * t * t * (1 + 3 * p1[xy] - 3 * p2[xy]) + 6 * t * ( p2[xy] - 2 * p1[xy]) + 3 * p1[xy]}
} else {
return function(t){return 3 * p1[xy] * (1 - t) * (1 - t) * t + 3 * p2[xy] * (1 - t) * t * t + t * t * t}
}
};
_LexiconMonoSeq.prototype.Ease.prototype.registerEase = function(p1,p2){
var parX = this.returnParametric("x",p1,p2),
dParX_dt = this.returnParametric("x",p1,p2,true),
parY = this.returnParametric("y",p1,p2),
dParY_dt = this.returnParametric("y",p1,p2,true),
arr = this._arr,
resol = this._resolution,
step = 1/resol,
previous;
resol += 1;
for(var i = 0,t,y;i<=resol;++i){
t = previous = this.getCloseXTo(step*i,parX,dParX_dt,previous,this._precision);
y = parY(t);
arr.push(y);
}
return this;
};
_LexiconMonoSeq.prototype.Ease.prototype.getCloseXTo = function(yValue,f,fDer,previous,precision){
for(var max=1/precision,min=-1*max,xGuess = yValue,yGuess,dX,dY = 2*precision;dY/precision|0;){
yGuess = f(xGuess);
dY = yGuess - yValue;
dX = dY/fDer(xGuess);
xGuess -= dX;
if(xGuess >= max || xGuess <= min){
throw new RangeError("Target cannot be reached!");
}
}
if(xGuess !== xGuess){
xGuess = previous;
}
return xGuess;
};
/*
###############################
##############EASE#############
###############################
*/
_LexiconMonoSeq.prototype.ease = new _LexiconMonoSeq.prototype.Ease({x:0.75,y:0},{x:0.25,y:1});
_LexiconMonoSeq.prototype.easeElastic = new _LexiconMonoSeq.prototype.Ease({x:1,y:-1},{x:0,y:2});
/*
###############################
############PAINTER############
###############################
*/
_LexiconMonoSeq.prototype.Paint = function(instance){
var that = this;
this.parent = instance;
this.tasks = Object.defineProperties({},
{
_clearFrame: {
configurable:false,
writable: false,
value: function(id,doNotResume){
that.frames[id] && window.cancelAnimationFrame(that.frames[id]);
delete that.frames[id];
if(!doNotResume && !Object.keys(that.frames).length && that.active){
this._resumeTask();
}
}
},
_setTask: {
configurable:false,
writable: false,
value: function(id,tasks){
if(!Object.keys(that.frames).length){
that.active = false;
}
that.tasks[id] = tasks;
if(!that.active){
that.active = true;
tasks[0]();
}
}
},
_resumeTask: {
configurable:false,
writable: false,
value: function(){
var rndKey = this._rndKey;
if(rndKey){
that.tasks[rndKey][0]();
} else {
that.active = false;
}
}
},
_rndKey: {
configurable:false,
get: function(){
var keys = Object.keys(this).filter(function(d,i){return d.slice(0,1) !== "_";}),
i = Math.random() * keys.length | 0,
key = keys[i];
return key;
}
},
_destroyTasks: {
configurable:false,
writable: false,
value: function(){
for (var i = 0,keys = Object.keys(this),l = keys.length,key;i<l;++i) {
key = keys[i];
if (key.slice(0,1) !== "_") {
delete this[key];
}
}
}
}
}
);
this.frames = {};
this.active = false;
this.repaintScheduled = false;
};
_LexiconMonoSeq.prototype.Paint.prototype.schedulePaint = function(cNodes,options){
var l = cNodes.length,
taskLets = [];
for(var i = 0,j=0,lastIndex = 0;i<l;++i,++j){
if(!(j %= this.nodeLimit)){
taskLets.push([cNodes[i]]);
lastIndex = taskLets.length - 1;
if(!i){
taskLets[lastIndex]._firstTask = true;
}
} else {
taskLets[lastIndex].push(cNodes[i]);
}
cNodes[i]._i = i;
}
options.tasks = taskLets.map(function(d,i){return this.transformToTask(d,options);},this);
this.tasks._setTask(options.rects.id,options.tasks);
};
//_LexiconMonoSeq.prototype.Paint.prototype.ease = new _LexiconMonoSeq.prototype.Ease({x:1,y:-1.2},{x:0,y:2.2}); --> elastic(ish)
_LexiconMonoSeq.prototype.Paint.prototype.ease = new _LexiconMonoSeq.prototype.Ease({x:0.5,y:0.1},{x:0.75,y:0.9});
_LexiconMonoSeq.prototype.Paint.prototype.nodeLimit = 80;
_LexiconMonoSeq.prototype.Paint.prototype.duration = 150;
_LexiconMonoSeq.prototype.Paint.prototype.cornerRadius = 0;
_LexiconMonoSeq.prototype.Paint.prototype.transformToTask = function(taskLet,options){
var that = this,
instance = that.parent,
rects = options.rects,
l = taskLet.length,
startTime,
recurse = function(t){
startTime = startTime || t;
t = (t - startTime)/that.duration;
var tasks = options.tasks,
_t = that.ease(t);
if(taskLet._firstTask){
instance.interpolateAndStoreArrInt(seqArr,nSeqArr,_t);
textSlab.textContent = instance.strConcat(seqArr);
sTextSlab.transform = "translate(" + (textSlab._transformX = transformXI + (transformXF - transformXI) * _t) + "px,0px)";
if(!t && !depotTransfered){
depotTransfered = true;
rects.depot.transfer();
seqInstance.toggleVisibility(true);
}
}
for (var i = 0,j = 0,n=null;i<l;++i){
n = taskLet[i];
j = n._i;
n.parentNode && rects.setVal(n,"width",instance.interpolateAndStoreAtEnd(rects.stopWidths,j,options.uC,t,_t))
/*.setVal("rx",that.cornerRadius)*/
.setVal("x",instance.interpolateAndStoreAtEnd(rects.stopOffsets,j,options.stopOffsets[j],t,_t))
.setAttr("fill", t < 1 ? options.stopColors[j](_t) : (rects.stopColors[j] = options.stopColors[j](_t)))
.setAttr("fill-opacity",instance.interpolateAndStoreAtEnd(rects.stopOpacities,j,options.stopOpacities[j],t,_t));
}
if(t >= 1) {
tasks.shift();
if(!tasks.length){
delete that.tasks[rects.id];
delete that.frames[rects.id];
that.tasks._resumeTask();
} else {
tasks[0]();
}
return;
}
that.frames[rects.id] = window.requestAnimationFrame(recurse);
},
task = function(){
that.frames[rects.id] = window.requestAnimationFrame(recurse);
};
if(taskLet._firstTask){
var depotTransfered = false,
seqInstance = options.target,
textSlab = seqInstance.textSlab,
sTextSlab = seqInstance.styleTextSlab,
aR = options.aR,
dR = aR.end - aR.start,
nSeqArr = seqInstance.seq.slice(aR.start,aR.end).split("").map(function(d,i){return d.charCodeAt(0);}),
seqArr = textSlab._seqArr = textSlab._seqArr || Array.apply(null,Array(dR)).map(function(d,i){return "@".charCodeAt(0);}),
lastChar = seqArr[seqArr.length - 1],
svgWidthInPx = options.svgWidthInPx,
transformXI = textSlab._transformX,
transformXF = options.transformXOffset + options.stopOffsets[0] / options.svgWidthInUnits * svgWidthInPx;
while (seqArr.length < dR) {
seqArr.push(lastChar);
}
while(seqArr.length > dR) {
seqArr.pop();
}
}
return task;
};
/*
###############################
############PAINTER############
###############################
*/
/*
###############################
##########UPDATE FLOW##########
###############################
*/
_LexiconMonoSeq.prototype.toggleLabels = function(show,options){
window.cancelAnimationFrame(this.currentAnimationFrame.l);
this.state = "ANIM";
var that = this,
startTime,
initScrollLeftOffset = this.scrollLeftOffset,
scrollLeftOffset,
initOpacity = typeof this.sequenceTextDivOpacity === "number" ? this.sequenceTextDivOpacity : 1,
opacity,
duration = (options && options.duration) || 1500,
ease = (options && options.ease)
? new this.Ease(options.ease[0],options.ease[1],{resolution:options.easeResolution,precision:options.easePrecision})
: this.easeElastic;
if (show){
scrollLeftOffset = this.fontWidth * this.maxAllowedLabelLength;
opacity = 1;
} else {
scrollLeftOffset = 0;
opacity = 0;
}
function toggle(t){
startTime = startTime || t;
t = (t - startTime)/duration;
var _t = ease(t);
that.scrollLeftOffset = initScrollLeftOffset + (scrollLeftOffset - initScrollLeftOffset) * _t;
that.divStyle.transform = "translate(" + that.scrollLeftOffset + "px,0px)";
var l = that.sequences.length,
o;
while(~--l){
if((o = that.sequences[l]).rm){
continue;
}
o.styleTextDiv.opacity = that.sequenceTextDivOpacity = initOpacity + (opacity - initOpacity) * t;
if(!t && opacity) {
o.styleTextDiv.visibility = "visible";
} else if (t >= 1 && !opacity) {
o.styleTextDiv.visibility = "hidden";
}
}
if(t >= 1){
that.currentAnimationFrame.l = undefined;
++that.scrollLeft;//trigger repaint
return;
}
that.currentAnimationFrame.l = window.requestAnimationFrame(toggle);
}
this.currentAnimationFrame.l = window.requestAnimationFrame(toggle);
return this;
};
_LexiconMonoSeq.prototype.removeSequences = function(arr,ledger){
var that = this,
mock = {viewportWidth:this.viewportWidth};
arr.forEach(function(d,i){
delete d.painter.frames[d.rects.id];
});
function remove(t){
ledger.startTime = ledger.startTime || t;
t = ledger.ease((t - ledger.startTime)/((ledger.options && ledger.options.duration) || 1500));
var l = arr.length;
while (~--l) {
arr[l].update(t,mock);
}
if(t >= 1){
that.currentAnimationFrame.r = undefined;
return;
}
that.currentAnimationFrame.r = window.requestAnimationFrame(remove);
}
this.currentAnimationFrame.r = window.requestAnimationFrame(remove);
return this;
};
_LexiconMonoSeq.prototype.appendSequences = function(arr,ledger){
function append(t){
ledger.startTime = ledger.startTime || t;
t = ledger.ease((t - ledger.startTime)/((ledger.options && ledger.options.duration) || 1500));
var l = arr.length,
temp;
while (~--l) {
temp = arr[l].target;
if(temp.rm){
continue;
}
temp.style.transform = "translate(" + (arr[l].viewportWidth * (t-1)) + "px,0px)";
temp.style.opacity = t;
}
if(t >= 1){
return;
}
window.requestAnimationFrame(append);
}
window.requestAnimationFrame(append);
};
_LexiconMonoSeq.prototype.updateSequences = function(arr,ledger) {
var that = this,
frameKey = arr[0].source ? "u" : "a",
fontWidth = this.fontWidth,
viewportWidth = this.viewportWidth;
arr = arr.map(function(d,i){
var source = d.source || d;
if(frameKey === "u") {
d.seq = source.seq;
d.charWidth = source.charWidth || 1;
d.type = source.type;
d.name = source.name;
d.posOffset = source.posOffset || 0;
}
var letterSpacingInChar = d.charWidth - 1,
letterSpacing = letterSpacingInChar * fontWidth,
svgWidthInUnits = d.unitLength * this.fontRatio,
svgWidthInPx = d.unitLength * fontWidth,
posOffsetTransform = d.posOffset * fontWidth,
s = d.style,
sTextDiv = d.styleTextDiv;
s.letterSpacing = letterSpacing + "px";
s.width = svgWidthInPx + "px";
d.styleSVG.width = svgWidthInPx + "px";
d.styleSVG.transform = posOffsetTransform ? "translate(" + posOffsetTransform + "px,0px)" : "none";
sTextDiv.letterSpacing = "normal";
d.rects.setViewBox(d.svg,{width: svgWidthInUnits});
return d.options = {
frameKey:frameKey,
viewportWidth: viewportWidth,
uC: d.charWidth * this.fontRatio,
target:d,
firstCall:false,
posOffsetTransform: posOffsetTransform,
transformXOffset: posOffsetTransform + letterSpacing/2,
svgWidthInUnits: svgWidthInUnits,
svgWidthInPx: svgWidthInPx
};
},this);
if(frameKey === "a"){
this.appendSequences(arr,{ease:ledger.ease,startTime:undefined,options:ledger.options});
}
this.repaint(true);
function update(t) {
var temp,
l = arr.length,
_t;
ledger.startTime = ledger.startTime || t;
t = (t - ledger.startTime)/((ledger.options && ledger.options.duration) || 1500);
_t = ledger.ease(t);
while(~--l && (temp = arr[l])){
temp.target.update(_t,temp,t);
}
if(t >= 1){
that.currentAnimationFrame[frameKey] = undefined;
l = arr.length;
while(~--l && (temp = arr[l])){
delete temp.target.source;
}
return;
}
that.currentAnimationFrame[frameKey] = window.requestAnimationFrame(update);
}
this.currentAnimationFrame[frameKey] = window.requestAnimationFrame(update);
return this;
};
/*
###############################
##########UPDATE FLOW##########
###############################
*/
/*
###############################
#############STYLE#############
###############################
*/
_LexiconMonoSeq.prototype.Style = function(instance){
return [
"body.lock-scroll {",
" overflow:hidden;",
"}",
".LexiconMonoSeqContainer {",
"}",
"div.LexiconMonoSeq,svg.LexiconMonoSeq {",
" border:0px;",
" margin:0px;",
" padding:0px;",
" box-sizing:border-box;",
"}",
"div.LexiconMonoSeq.wrapper {",
" width:100%;",
" height:100%;",
" overflow:auto;",
" font-size:16px;",
" -webkit-overflow-scrolling:touch;",
" font-family: Consolas"/*'Courier New', Monospace;"*/,
"}",
"div.LexiconMonoSeq.wrapper::-webkit-scrollbar-track {",
" -webkit-box-shadow: inset 0 0 6px rgba(0,0,0,0.3);",
" border-radius: 0px;",
" background-color: #F5F5F5;",
"}",
"div.LexiconMonoSeq.wrapper::-webkit-scrollbar {",
" width: 8px;",
" height: 8px;",
" background-color: #F5F5F5;",
"}",
"div.LexiconMonoSeq.wrapper::-webkit-scrollbar-thumb {",
" border-radius: 0px;",
" -webkit-box-shadow: inset 0 0 6px rgba(0,0,0,.3);",
" background-color: #555;",
"}",
"div.LexiconMonoSeq.wrapper.drag {",
" cursor: move;",
"}",
"div.LexiconMonoSeq.main,div.LexiconMonoSeq.hidden {",
" font-size:100%;",
" white-space:pre;",
instance.textRendering ?
" text-rendering:" + instance.textRendering + ";" :
"",
instance.fontKerning ?
" font-kerning:" + instance.fontKerning + ";" :
"",
instance.webkitFontSmoothing ?
" -webkit-font-smoothing:" + instance.webkitFontSmoothing + ";" :
"",
"}",
"div.LexiconMonoSeq.sequence {",
" display:table;",
"}",
"div.LexiconMonoSeq.textDiv {",
" background-color: rgba(0,0,0,0.8);",
" color: rgba(255,255,255,0.9);",
" display: table;",
" transform: translate(-100%,0%);",
"}",
"div.LexiconMonoSeq.textSlab {",
" position:absolute;",
" top:0px;",
" left:0px;",
" z-index:-1;",
" height:100%;",
"}",
"svg.LexiconMonoSeq {",
" display:block;",
" position:absolute;",
" top:0px;",
" left:0px;",
" height:100%;",
" z-index:-2;",
" overflow:hidden;",
"}",
"div.LexiconMonoSeq.hidden {",
" position:absolute;",
" top:1px;",
" left:1px;",
" visibility:hidden;",
"}",
"div.LexiconMonoSeq.busy {",
" position:absolute;",
" visibility:hidden;",
" z-index:1;",
" top:0px;",
" left:0px;",
" font-size:500%;",
"}",
"div.LexiconMonoSeq.wrapper.labelsOff > .main {",
" transform: translate(0px,0px) !important;",
"}",
"div.LexiconMonoSeq.wrapper.labelsOff .textDiv {",
" visibility: hidden !important;",
"}"
].filter(function(d,i){return d});
};
_LexiconMonoSeq.prototype.Style.string = function(instance){
return this(instance).join("\n");
};
_LexiconMonoSeq.prototype.Style.array = function(instance){
return this(instance);
};
/*
###############################
#############STYLE#############
###############################
*/
/*
###############################
############SCROLL#############
###############################
*/
_LexiconMonoSeq.prototype.scrollToPos = function(n,nY,options){
window.cancelAnimationFrame(this.currentAnimationFrame.s);
var that = this,
e = (options && options.ease)
? new this.Ease(options.ease[0],options.ease[1],{resolution:options.easeResolution,precision:options.easePrecision})
: this.ease,
d = (options && options.duration) || 1500,
m = this.scrollToPos.methods,
viewportWidth,
viewportHeight,
trackLength,
trackHeight;
that.state = "ANIM";
that.currentAnimationFrame.s = window.requestAnimationFrame(function(){
that.currentAnimationFrame.s = window.requestAnimationFrame(function(){
viewportWidth = that.viewportWidth;
viewportHeight = that.viewportHeight;
that.currentAnimationFrame.s = window.requestAnimationFrame(function(){
trackLength = that.getMaxTrackLength;
trackHeight = that._trackHeight;
that.currentAnimationFrame.s = window.requestAnimationFrame(m.moveTo(n,nY,that,e,d,viewportWidth,viewportHeight,trackLength,trackHeight));
});
});
});
};
_LexiconMonoSeq.prototype.scrollToPos.methods = {
moveTo: function(n,nY,that,e,d,vW,vH,tL,tH){
var x = that.scrollLeft,
x_p = Math.max(0,n/(tL.sequenceLength * tL.charWidth + tL.posOffset) * (tL.width + tL.posOffsetTransform) - vW/2),
dx = (x_p - x),
y = that.wrapper.scrollTop,
y_p = typeof nY !== "number" ? y : Math.max(0, nY * tH - vH/2),
dy = (y_p - y),
startTime;
f = function(t){
startTime = startTime || t;
t = (t - startTime)/d;
var _t = e(t);
that.scrollLeft = x + dx * _t;
that.wrapper.scrollTop = y + dy * _t;
if(t >= 1){
that.currentAnimationFrame.s = undefined;
return
}
that.currentAnimationFrame.s = window.requestAnimationFrame(f);
};
return f;
}
};
_LexiconMonoSeq.prototype.repaintOnScroll = function(){
var that = this,
f = function(e){
if(f._busy){return}
that.currentAnimationFrame.sMan = window.requestAnimationFrame(function(){
that.painters.every(function(d,i){return !d.repaintScheduled;}) && that.repaint();
f._busy = false;
that.currentAnimationFrame.sMan = undefined;
});
f._busy = true;
that.state = "ANIM";
that.busyStyle.top = that.container.scrollTop + "px";
};
return f;
};
/*
###############################
############SCROLL#############
###############################
*/
/*
###############################
###########REPAINT#############
###############################
*/
_LexiconMonoSeq.prototype.repaint = function(force){
if(this.painters.some(function(d,i){return d.repaintScheduled})){return};
this.painters.forEach(function(d,i){d.repaintScheduled = true;});
var counter = {counter:0,framesCleared:false},
test = function(counter){
if(this.state === "IDLE"){
counter.counter++;
} else {
counter.counter = 0;
}
var seqs,l,depot,temp;
if(counter.counter === 1 && !counter.framesCleared) {
counter.framesCleared = true;
seqs = this.sequences;
l = seqs.length;
while(~--l){
temp = seqs[l];
temp.painter.tasks._clearFrame(temp.rects.id,true);
}
this.painters.forEach(function(d,i){d.tasks._destroyTasks()});
} else if(counter.counter === 23) {
seqs = this.sequences;
l = seqs.length;
while(~--l){
seqs[l].toggleVisibility(false);
}
} else if(counter.counter === 24) {
seqs = this.sequences;
l = seqs.length;
while(~--l){
depot = seqs[l].rects.depot;
!depot.isEmpty && depot.emptyFragment();
}
}
return counter.counter >= 25;
},
action = function(counter){
var seqs = this.sequences,
l = seqs.length;
while(~--l){
seqs[l].rects.update(force);
}
this.painters.forEach(function(d,i){d.repaintScheduled = false;});
};
this.watchman(this,test,action,counter);
};
/*
###############################
###########REPAINT#############
###############################
*/
/*
###############################
###########WATCHMAN############
###############################
*/
//copied from Mutaframe.com
_LexiconMonoSeq.prototype.watchman = function(obj,test,action,options){
var currentFrame = {value:undefined};
function watch(){
if(test.call(obj,options)){
action.call(obj,options);
return;
} else {
currentFrame.value = window.requestAnimationFrame(watch);
}
};
currentFrame.value = window.requestAnimationFrame(watch);
return currentFrame;
};
/*
###############################
###########WATCHMAN############
###############################
*/
/*
###############################
#############FETCH#############
###############################
*/
_LexiconMonoSeq.prototype.fetch = function (url,responseType) {
responseType = responseType || "text";
var parsed = LexiconMonoSeq.parseURL(url),
isLocal = parsed.isLocal,
ajax = new XMLHttpRequest(),
k = responseType === "text" ? "responseText" : "response",
result = {
done:false,
value:null
},
onerror = function(e){
result.done = true;
result.value = new Error("Request to " + parsed.file + " has failed.");
},
onload = function(){
result.done = true;
result.value = ajax[k];
};
if (isLocal) {
result.done = true;
result.value = new Error("Your URL refers to a local path. Fetch will not work.");
} else {
ajax.responseType = responseType;
ajax.onload = onload;
ajax.onerror = onerror;
ajax.open("GET",parsed.source,true);
ajax.send();
}
return this.async(result);
};
/*
###############################
#############FETCH#############
###############################
*/
/*
###############################
###########FONTCHECK###########
###############################
*/
_LexiconMonoSeq.prototype.isFontLoaded = function(freq,timeout){
timeout = (+timeout || 60000) / 17 | 0;
freq = (+freq || 170) / 17 | 0;
var hidden = this.hidden,
hiddenParent = hidden.parentNode,
control = hiddenParent.appendChild(hidden.cloneNode(true)),
test = hiddenParent.appendChild(hidden.cloneNode(true)),
rangeControl = document.createRange(),
rangeTest = document.createRange(),
result = {done:false,value:null},
TIMEDOUT = false,
round = function(x){
return Math.round(x * 100) / 100;
},
cleanup = function(){
rangeControl.detach && rangeControl.detach();
rangeTest.detach && rangeTest.detach();
hiddenParent.removeChild(control);
hiddenParent.removeChild(test);
};
control.textContent = "AYE";
test.textContent = "AYE";
control.style.fontFamily = "UnknownTestFont";
rangeControl.setStart(control.firstChild,0);
rangeControl.setEnd(control.firstChild,3);
rangeTest.setStart(test.firstChild,0);
rangeTest.setEnd(test.firstChild,3);
this.watchman(
this,
function(counter){
var controlRect,
testRect;
if (!(++counter.counter % freq)){
if (counter.counter >= timeout) {
TIMEDOUT = true;
return true;
}
controlRect = rangeControl.getBoundingClientRect();
testRect = rangeTest.getBoundingClientRect();
return (round(controlRect.width) !== round(testRect.width)) || (round(controlRect.height) !== round(testRect.height));
}
},
function(counter){
result.done = true;
if (TIMEDOUT) {
result.value = new Error("Font detection timedout.");
} else {
result.value = true;
}
cleanup();
},
{counter:-1}
);
return this.async(result);
};
/*
###############################
###########FONTCHECK###########
###############################
*/
return LexiconMonoSeq;
}));