biojs-vis-wigexplorer
Version:
visualization a wig formatted file
1,376 lines (1,190 loc) • 143 kB
JavaScript
require=(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
/**
* This component uses the D3 library to visualise a wig formatted file as an area chart, with panning and zooming functionality.
*
* @class
* @extends Biojs
*
* @author <a href="http://www.tgac.ac.uk/bioinformatics/sequencing-informatics/core-bioinformatics/anil-thanki/">Anil Thanki</a>
* @version 1.0.0
* @category 2
*
*
* @requires <a href='http://d3js.org/'>D3</a>
* @dependency <script src="http://d3js.org/d3.v2.min.js" type="text/javascript"></script>
*
*
* @requires <a href=''>jQuery UI 1.8.2+</a>
* @dependency <script type="text/javascript" src="../biojs/dependencies/jquery/jquery-ui-1.8.2.custom.min.js"></script>
*
* @requires <a href='http://code.jquery.com/jquery-1.6.4.js'>jQuery Core 1.6.4</a>
* @dependency <script language="JavaScript" type="text/javascript" src="../biojs/dependencies/jquery/jquery-1.6.4.js"></script>
*
* @requires jQuery UI CSS 1.8.2
* @dependency <link rel="stylesheet" href="../biojs/dependencies/jquery/jquery-ui-1.8.2.css" />
*
* @requires <a href='http://jquery.bassistance.de/tooltip/jquery.tooltip.js'>jQuery.tooltip</a>
* @dependency <script language="JavaScript" type="text/javascript" src="../biojs/dependencies/jquery/jquery.tooltip.js"></script>
*
* @requires <a href='http://jquery.bassistance.de/tooltip/jquery.tooltip.css'>jQuery.tooltip CSS</a>
* @dependency <link rel="stylesheet" href="../biojs/dependencies/jquery/jquery.tooltip.css"/>
*
* @requires <a href='../biojs/css/biojs.wigExplorer.css'>biojs.wigExplorer.css</a>
* @dependency <link rel="stylesheet" href="../biojs/css/biojs.wigExplorer.css" />
*
*
* @requires <a href='http://jqueryui.com/download/jquery-ui-1.8.20.custom.zip'>jQuery UI CSS 1.8.2</a>
* @dependency <link rel="stylesheet" href="../biojs/dependencies/jquery/jquery-ui-1.8.2.css" />
*
*
* @param {Object} options An object with the options for wigExplorer component.
*
* @option {string} target
* Identifier of the DIV tag where the component should be displayed.
*
*
* @example
* var instance = new Biojs.wigExplorer({
* target: "YourOwnDivId",
* selectionBackgroundColor: 'steelblue',
* dataSet: "../biojs/data/wigExplorerDataSet5.txt"
* });
*
* @option {string} dataSet
* File in text format including input data. Examples of text file ... <br/>
* <pre>variableStep chrom=chr2 span=5
* 10 34
* 20 41
* 30 46
* 40 49
* 50 52
*
* ...
*
* or
*
* fixedStep chrom=chr2 start=10 step=10 span=5
* 34
* 41
* 46
* 49
* 52
*
* ...</pre>
*
* @option {string} [selectionBackgroundColor]
* Name of the colour to be set as background for area chart
*
*/
var WigExplorer;
var Class = require('js-class');
module.exports = WigExplorer = Class(
/** @lends Biojs.wigExplorer# */
{
zoomSlider: '',
slider_stop: 0,
slider_start: 0,
track: [],
width: 1,
height: 1,
data_last_start: 1,
data_first_start: 1,
max: 0,
span: null,
chrom: [],
data: [],
main_data: [],
constructor: function (options) {
var self = this;
self.vis = null;
self.color = null;
self.foci = [];
this.track; // data
require('js-extend').extend(this.opt, options)
this._container = $("#wigFeaturePainter-holder");
$(this._container).addClass("graph");
// Apply options values
this._container.css({
'font-family': self.opt.fontFamily, // this is one example of the use of self instead of this
'background-color': self.opt.selectionBackgroundColor,
'color': self.opt.fontColor,
'font-size': '36px',
'text-align': 'center',
'vertical-align': 'middle',
'width': '700px',
'height': '100px',
'bottom': '0px'
});
// Disable text selection and
// Change the selection mouse pointer
// from text to hand.
this._container.css({
'-moz-user-select': 'none',
'-webkit-user-select': 'none',
'user-select': 'none'
});
this.color = self.opt.selectionBackgroundColor;
this.paintFeatures(self.opt.dataSet);
},
/**
* Default values for the options
* @name Biojs.wigExplorer-opt
*/
opt: {
target: "YourOwnDivId",
dataSet: "",
fontFamily: '"Andale mono", courier, monospace',
fontColor: "white",
backgroundColor: "",
selectionFontColor: "black",
selectionBackgroundColor: "yellow",
width: "100%",
height: "130",
radius: 10,
reference: null
},
/**
* Array containing the supported event names
* @name Biojs.wigExplorer-eventTypes
*/
eventTypes: [
/**
* No events added for now but can be added in future
*/
],
/**
* Repaints everything: ruler, shapes, and legend.
* @param {int} [newStart] Zoom from this sequence start value.
* @param {int} [newStop] Zoom to this sequence end value.
*
* @example
* instance._updateDraw();
*
*/
_updateDraw: function (newStart, newStop, target) {
var self = this;
//recalculate start and stop
if (newStart && newStop) {
this.slider_start = newStart;
this.slider_stop = newStop;
}
if (target) {
} else {
target = self.opt.target;
}
// if (this.slider_start < this.data_first_start) {
// if (newStart == newStop) {
// this.slider_stop += this.data_first_start - this.slider_start;
// }
// this.slider_start = this.data_first_start;
// }
// if (this.slider_stop > this.data_last_start) {
// if (newStart == newStop) {
// this.slider_start += this.data_last_start - this.slider_stop;
// }
// this.slider_stop = this.data_last_start;
// }
//recalculate start and stop
if ((parseFloat(this.slider_start) < parseFloat(this.slider_stop))) {
this.paintWig(this.slider_start, this.slider_stop, target);
}
},
/**
* Paint the features according to the values specified in the json object defined when creating the object.
* This method initializes the holder, paints the slider and print button depending on the options, and
* paints the features and legend.
*
* @example
* instance.paintFeatures("path-to-wig.txt");
*
* @param {string} dataSet Location of the file with the input data in text format.
* <pre>variableStep chrom=chr2 span=5
* 10 34
* 20 41
* 30 46
* 40 49
* 50 52
*
* ...
*
* or
*
* fixedStep chrom=chr2 start=10 step=10 span=5
* 34
* 41
* 46
* 49
* 52
*
* ...</pre>
*
*/
paintFeatures: function (dataSet) {
if (dataSet != undefined) {
this._setDataSource(dataSet);
this._init();
} else {
alert('Dataset not defined ');
}
},
/**
* Private: Initializes the component.
*/
_init: function () {
WigExplorer.myself = this;
var self = this;
var painter_div = jQuery("#" + this.opt.target);
painter_div.text('');
painter_div.append(this._withSliderOnly(100));
painter_div.append('<div id=' + this.opt.target + '_wigFeaturePainter-holder></div>');
var holder = document.getElementById(this.opt.target + '_wigFeaturePainter-holder');
if (!holder) {
this.jQueryerrorMsg = jQuery('<div id="wigFeaturePainter-errorInit"></div>')
.html('There was an unexpected failure, the image cannot be displayed.')
.dialog({
autoOpen: true,
title: 'Error',
modal: true
});
throw "Error";
}
holder.innerHTML = "";
holder.style.height = "250px";
holder.style.width = self.opt.width ? self.opt.width : "700px";
this.width = jQuery('#' + self.opt.target + '_wigFeaturePainter-holder').width(),
this.height = this.height = jQuery('#' + self.opt.target + '_wigFeaturePainter-holder').height(),
this.r = self.opt.radius;
self.opt.width = self.opt.width.toString();
if (self.opt.width.indexOf("%") >= 1){
self.opt.width = jQuery(this.opt.target).width * parseInt(self.opt.width.toString()) / 100;
}
else{
self.opt.width = parseInt(this.width);
}
//had similar problem before so I used contains and it should works
self.opt.height = self.opt.height.toString();
if (self.opt.height.indexOf("%") >= 1)
self.opt.height = self.opt.height.toString();
if (self.opt.height.indexOf("%") != -1)
this.height = this.height * (self.opt.height.substring(0, self.opt.height.length - 1) * 1) / 100.0;
else
this.height = self.opt.height * 1;
self.opt.height = parseInt(this.height);
self.color = function () {
return d3.scale.ordinal().range(self.colors);
}();
if (self.opt.dataSet.indexOf(".") >= 0 && self.opt.dataSet.length < 100) {
jQuery.ajax({
type: "GET",
url: self.opt.dataSet,
dataType: "text",
success: function (data) {
var wig = [];
var max = 0
var data_split = data.split("\n")
var data_len = data_split.length;
if (data.indexOf("variableStep") >= 0 || data.indexOf("fixedStep") >= 0) {
self.chrom = []
for (var i = 0; i < data_len; i++) {
if (data_split[i].indexOf("chrom") >= 0) {
var chr = data_split[i].split(/\s+/)[1].split("=")[1];
if (self.chrom.indexOf(chr) < 0) {
self.chrom.push(chr);
}
}
}
self._buildReferenceSelector();
} else {
alert("Unknown format detected")
}
},
error: function (qXHR, textStatus, errorThrown) {
alert(textStatus);
}
});
}else{
var data =self.opt.dataSet
var wig = [];
var max = 0
var data_split = data.split("\n")
var data_len = data_split.length;
if (data.indexOf("variableStep") >= 0 || data.indexOf("fixedStep") >= 0) {
self.chrom = []
for (var i = 0; i < data_len; i++) {
if (data_split[i].indexOf("chrom") >= 0) {
var chr = data_split[i].split(/\s+/)[1].split("=")[1];
if (self.chrom.indexOf(chr) < 0) {
self.chrom.push(chr);
}
}
}
self._buildReferenceSelector();
} else {
alert("Unknown format detected")
}
}
},
/**
* Private: Function to create reference dropdown.
* @ignore
*/
_buildReferenceSelector: function () {
var self = this;
this._headerDiv = jQuery('#' + self.opt.target + '_selectorMenu');
this._headerDiv.css({
'font-family': '"Heveltica Neue", Arial, "sans serif"',
'font-size': '14px'
}).append('Reference: ');
var selector_html = "<select id=" + self.opt.target + "ref_selector>";
for (var i = 0; i < this.chrom.length; i++) {
selector_html += "<option value='" + this.chrom[i] + "'>" + this.chrom[i] + "</option>"
}
selector_html += "/<select>";
this._formatSelector = jQuery(selector_html).appendTo(self._headerDiv);
this._formatSelector.change(function (e) {
self.opt.reference = jQuery(this).val();
self.setReference(self.opt.reference, self.opt.target)
});
self.setReference(this._formatSelector.val())
},
/**
* Private: Function to create slider only.
* @param {int} sizeX Width.
* @ignore
*/
_withSliderOnly: function (sizeX) {
var self = this;
var text =
'<table width="100%">' +
'<tr>' +
'<td width="75%">' +
'<div id="' + self.opt.target + '_wigFeaturePainter-slider" style="margin-left: 10px; text-align:left"></div>' +
'</td>' +
'<td><div id="' + self.opt.target + '_selectorMenu" style="margin-left: 10px;text-align:right"> </div>' +
'</td>' +
'</tr>' +
'</table>' +
'<br/>';
return text;
},
/**
* Private: Paints the slider
* Purpose: set up slider buttons
* Returns: -
* @ignore
*/
_paintSlider: function () {//holder size, left and right margins of the holder, and number of amino acids
var sequenceLength = 100;//config.sequenceLength;
var self = this;
if (!document.getElementById(self.opt.target + "_wigFeaturePainter-slider")) {
return;
}
var slider_div = jQuery("#" + self.opt.target + "_wigFeaturePainter-slider");
slider_div.text('');
slider_div.append('<label for="wigFeaturePainter-slider-values"></label>');
slider_div.append('<div type="text" id="wigFeaturePainter-slider-values" style="margin-bottom:5px" />');
var length = this.track.length - 1;
var difference = parseInt(this.track[length][0]) - parseInt(this.track[0][0]);
var diff = parseInt(difference / 20);
this.zoomSlider = jQuery('<div id="wigFeaturePainter-slider-bar" style="width:300px"></div>').appendTo(slider_div);
var id = self.opt.dataSet;
if(id.indexOf(" ")){
id= self.opt.dataSet.split(" ")[0]
}
var updater_html = '<button id = ' + id + ' class=zoomin>+</button>' +
'<button id = ' + id + ' class=zoomout>-</button>' +
'<button id = ' + id + ' class=left><</button>' +
'<button id = ' + id + ' class=right >></button>';
jQuery(slider_div).html("")
this._updateSelector = jQuery(updater_html).appendTo(slider_div);
this._updateSelector.click(function (e) {
if (jQuery(this).hasClass("left")) {
self._moveleft();
} else if (jQuery(this).hasClass("right")) {
self._moveright();
} else if (jQuery(this).hasClass("zoomin")) {
self._zoomin()
// self._updateDraw(diff, -1 * diff, self.opt.target);
} else if (jQuery(this).hasClass("zoomout")) {
self._zoomout();
}
});
},
/**
* zoom in 10% of viewwing area.
*
* @example
* instance._zoomin();
*
*/
_zoomin: function () {
var self = this;
var diff = (self.slider_stop - self.slider_start) / 10;
self._updateDraw(self.slider_start + diff, self.slider_stop - diff, self.opt.target);
},
/**
* zoom in 10% of viewwing area.
*
* @example
* instance._zoomout();
*
*/
_zoomout: function () {
var self = this;
var diff = (self.slider_stop - self.slider_start) / 10;
self._updateDraw(self.slider_start - diff, self.slider_stop + diff, self.opt.target);
},
/**
* move left 10% of viewwing area.
*
* @example
* instance._moveleft();
*
*/
_moveleft: function () {
var self = this;
var diff = (self.slider_stop - self.slider_start) / 10;
self._updateDraw(self.slider_start - diff, self.slider_stop - diff, self.opt.target);
},
/**
* move right 10% of viewwing area.
*
* @example
* instance._moveright();
*
*/
_moveright: function () {
var self = this;
var diff = (self.slider_stop - self.slider_start) / 10;
self._updateDraw(self.slider_start + diff, self.slider_stop + diff, self.opt.target);
},
/**
* Select reference from Wig file from the given parameter and then parse Data for reference
*
* @example
* instance.setReference("ref_name")
*
*/
setReference: function (ref_chr) {
var self = this;
var flag = false;
if (self.opt.dataSet.indexOf(".") >= 0 && self.opt.dataSet.length < 100) {
jQuery.ajax({
type: "GET",
url: self.opt.dataSet,
dataType: "text",
success: function (data) {
parseWig(data, self)
},
error: function (qXHR, textStatus, errorThrown) {
alert(textStatus);
}
}).done(function () {
self._paintSlider();
self._updateDraw();
});
} else {
var data = self.opt.dataSet
parseWig(data, self)
self._paintSlider();
self._updateDraw();
}
function parseWig(data, self) {
var wig = [];
var max = 0
var data_split = data.split("\n")
var data_len = data_split.length;
var span = null;
var ref = false;
if (data.indexOf("variableStep") >= 0) {
var data_split = data.split("\n")
var data_len = data_split.length;
for (var i = 0; i < data_len; i++) {
if (data_split[i].indexOf("chrom") >= 0) {
var chr = data_split[i].split(/\s+/)[1].split("=")[1];
flag = false;
if (chr == ref_chr) {
if (data_split[i].indexOf("span") >= 0) {
span = data_split[i].split(/\s+/)[2].split("=")[1]
}
flag = true;
ref = true;
}
}
else if (data_split[i].indexOf("#") >= 0) {
continue;
} else if (flag && data_split[i].length > 0) {
var temp_data = data_split[i].split(/\s+/);
wig.push([temp_data[0], temp_data[1], span]);
if (parseInt(temp_data[1]) > parseInt(max)) {
max = temp_data[1];
}
}
}
self.max = max;
self.track = wig;
if (ref == false) {
alert("Selected reference not found")
} else if (wig.length > 0) {
var start = parseInt(wig[0][0]);//config.requestedStart;
var stop = parseInt(wig[wig.length - 1][0]);
self.slider_start = start;
self.slider_stop = stop;
self.data_last_start = stop;
self.data_first_start = start;
}
else {
alert("No data for selected reference")
}
}
else if (data.indexOf("fixedStep") >= 0) {
var data_split = data.split("\n")
var data_len = data_split.length;
var start = null;
var step = null;
var ref = false;
for (var i = 0; i < data_len; i++) {
if (data_split[i].indexOf("chrom") >= 0) {
var line = data_split[i].split(/\s+/);
var chr = data_split[i].split(/\s+/)[1].split("=")[1];
flag = false;
if (chr == ref_chr) {
start = line[2].split("=")[1];
step = line[3].split("=")[1];
if (data_split[i].indexOf("span") >= 0) {
span = line[4].split("=")[1]
}
flag = true;
ref = true;
}
}
else if (data_split[i].indexOf("#") >= 0) {
continue;
} else if (flag && data_split[i].length > 0) {
var temp_data = data_split[i];
start = parseInt(start) + parseInt(step)
wig.push([start, temp_data, span]);
if (parseInt(temp_data) > parseInt(max)) {
max = temp_data;
}
}
}
self.max = max;
self.track = wig;
if (ref == false) {
alert("Selected reference not found")
} else if (wig.length > 0) {
var start = parseInt(wig[0][0]);//config.requestedStart;
var stop = parseInt(wig[wig.length - 1][0]);
self.slider_start = start;
self.slider_stop = stop;
self.data_last_start = stop;
self.data_first_start = start;
} else if (start == null || step == null) {
alert("Unknown format detected")
}
else {
alert("No data for selected reference")
}
}
else {
alert("Unknown format detected")
}
}
},
/**
* Draws area chart from wig file using D3.js based on the specified positions
*
* @example
* instance.paintWig(1000,100000,"target-div")
*
*/
paintWig: function (start, end, target) {
var self = this;
if (this.track.length > 0) {
var color = this.opt.selectionBackgroundColor
var left = "50px";
var top = "0px";
var filtered_track = [];
var height = this.height;
var width = this.width;
var max = this.max;
// filter data if start and end positions are defined
if (start && end) {
filtered_track = this.track;
filtered_track = jQuery.grep(filtered_track, function (element) {
return element[0] >= start && element[0] <= end; // retain appropriate elements
});
}
else {
filtered_track = this.track;
var length = this.track.length - 1;
end = parseInt(this.track[length][0]);
start = parseInt(this.track[0][0]);
}
var space = parseInt(width) / (end - start);
var length = filtered_track.length - 1;
if (length > 0) {
this._clear(target);
var svg = d3.select('#' + target + '_wigFeaturePainter-holder').append("svg")
.attr("width", this.width + 20)
.attr("height", $('#' + target + '_wigFeaturePainter-holder').height())
.append("g")
.attr("transform", "translate(" + left + "," + top + ")");
this._container = jQuery('#' + target + '_wigFeaturePainter-holder');
var d3line2 = d3.svg.line()
.x(function (d) {
return d.x;
})
.y(function (d) {
return d.y;
})
.interpolate("linear");
var end_val = parseInt(filtered_track[length][0]) + parseInt(filtered_track[1][0] - filtered_track[0][0]);
var start_val = parseInt(filtered_track[0][0]) - (parseInt(filtered_track[1][0] - filtered_track[0][0]));
if (start_val < 0) {
start_val = 0;
}
// add a 0 to start position
filtered_track.splice(0, 0, [start_val, 0]);
if (start < 0) {
filtered_track.splice(0, 0, [start, 0]);
}
// add a 0 to end position
filtered_track.splice(end, 0, [end_val, 0]);
filtered_track.splice(filtered_track.length - 1, 0, [end, 0]);
var pathinfo = [];
var last_start = 0;
// check for average difference between each positions
var diff = parseInt(filtered_track[1][0] - filtered_track[0][0]);
if (diff > parseInt(filtered_track[2][0] - filtered_track[1][0]) || diff > parseInt(filtered_track[3][0] - filtered_track[2][0])) {
if (diff > parseInt(filtered_track[2][0] - filtered_track[1][0])) {
diff = parseInt(filtered_track[2][0] - filtered_track[1][0])
}
else {
diff = parseInt(filtered_track[3][0] - filtered_track[2][0])
}
}
else {
}
// loop through each element and calculate x and y axis for chart
for (var i = 0; i < filtered_track.length - 1;) {
var tempx;
tempx = (filtered_track[i][0] - start) * space;
var tempy = height - (filtered_track[i][1] * height / max);
pathinfo.push({ x: tempx, y: tempy});
i++;
if (last_start < filtered_track[i][0] - diff) {
tempx = ((parseInt(last_start) + parseInt(diff)) - start) * space;
var tempy = height;
pathinfo.push({ x: tempx, y: tempy});
tempx = ((parseInt(filtered_track[i][0]) - parseInt(diff)) - start) * space;
var tempy = height;
pathinfo.push({ x: tempx, y: tempy});
}
last_start = filtered_track[i][0];
}
tempx = (filtered_track[filtered_track.length - 1][0] - start) * space;
var tempy = height - (filtered_track[filtered_track.length - 1][1] * height / max);
pathinfo.push({ x: tempx, y: tempy});
var path = svg.selectAll("path")
.data([1]);
//select 10 positions to be displayed on x axis
var filter_track_legend = [];
var legend_start = filtered_track[0][0]
var diff = (filtered_track[filtered_track.length - 1][0] - filtered_track[0][0]) / 10;
for (i = 0; i < 10; i++) {
if (filtered_track[i][2]) {
filter_track_legend.push([
[parseInt(legend_start) + parseInt(i * diff)],
[filtered_track[i][2]]
]);
} else {
filter_track_legend.push([
[parseInt(legend_start) + parseInt(i * diff)]
]);
}
}
//draw selected 10 positions as legend
var legendtext = svg.selectAll('text.day')
.data(filter_track_legend);
legendtext.enter().append('svg:text')
.attr('x', 40)
.attr('y', 155)
.attr("transform", function (d, i) {
return "translate(" + (((d[0] - start) * space) + 150) + "," + 100 + ")rotate(90)";
})
.text(function (d) {
if (d[0] > 1000000) {
return parseFloat(d[0] / 1000000).toFixed(2) + "M";
} else if (d[0] > 1000) {
return parseFloat(d[0] / 1000).toFixed(2) + "K";
} else {
if (d[1]) {
return parseInt(d[0]) + " - " + (parseInt(d[0]) + parseInt(d[1]));
} else {
return parseInt(d[0]);
}
}
});
// lines at bottom of diagram to show the positions
var line = svg.selectAll("line.bottom")
.data(filter_track_legend);
line.enter().insert("svg:line")
.attr("class", "line")
.attr("x1", function (d) {
return parseInt((d[0] - start) * space);
})
.attr("y1", 130)
.attr("x2",function (d) {
return parseInt((d[0] - start) * space);
}).attr("y2", 140)
.attr('stroke', function () {
return "black";
});
//draw path from calculated chart axis
path.enter().append("svg:path")
.attr("width", 200)
.attr("height", 200)
.attr("class", "path")
.attr('stroke', function () {
return "steelblue";
})
.attr('stroke-width', function () {
return "1px";
})
.attr("fill", function () {
return color;
})
.attr("d", d3line2(pathinfo));
}
else{
this._clear(target);
}
} else {
alert("Reference not set: use instance.setReference")
}
},
/**
* Private: Clears all divs content.
* @ignore
*/
_clear: function (target) {
jQuery('#' + target + '_wigFeaturePainter-holder').html("");
},
/**
* Private: sets data source.
* @param {string} [dataset], it sets file path to this.opt.dataset.
* @ignore
*/
_setDataSource: function (dataSet) {
this.opt.dataSet = dataSet;
},
_addSimpleClickTrigger: function () {
var self = this;
// Add the click event to each character in the content
this._container.find('span')
.click(function (e) {
// TIP: e.target contains the clicked DOM node
var selected = jQuery(e.target).text();
// Create an event object
var evtObject = { "selected": selected };
// We're ready to raise the event onClick of our component
self.trigger('onClick', evtObject);
});
}
}, {
myself: undefined
});
var Events = require('biojs-events');
Events.mixin(WigExplorer.prototype);
},{"biojs-events":4,"js-class":5,"js-extend":6}],2:[function(require,module,exports){
/**
* Standalone extraction of Backbone.Events, no external dependency required.
* Degrades nicely when Backone/underscore are already available in the current
* global context.
*
* Note that docs suggest to use underscore's `_.extend()` method to add Events
* support to some given object. A `mixin()` method has been added to the Events
* prototype to avoid using underscore for that sole purpose:
*
* var myEventEmitter = BackboneEvents.mixin({});
*
* Or for a function constructor:
*
* function MyConstructor(){}
* MyConstructor.prototype.foo = function(){}
* BackboneEvents.mixin(MyConstructor.prototype);
*
* (c) 2009-2013 Jeremy Ashkenas, DocumentCloud Inc.
* (c) 2013 Nicolas Perriault
*/
/* global exports:true, define, module */
(function() {
var root = this,
nativeForEach = Array.prototype.forEach,
hasOwnProperty = Object.prototype.hasOwnProperty,
slice = Array.prototype.slice,
idCounter = 0;
// Returns a partial implementation matching the minimal API subset required
// by Backbone.Events
function miniscore() {
return {
keys: Object.keys || function (obj) {
if (typeof obj !== "object" && typeof obj !== "function" || obj === null) {
throw new TypeError("keys() called on a non-object");
}
var key, keys = [];
for (key in obj) {
if (obj.hasOwnProperty(key)) {
keys[keys.length] = key;
}
}
return keys;
},
uniqueId: function(prefix) {
var id = ++idCounter + '';
return prefix ? prefix + id : id;
},
has: function(obj, key) {
return hasOwnProperty.call(obj, key);
},
each: function(obj, iterator, context) {
if (obj == null) return;
if (nativeForEach && obj.forEach === nativeForEach) {
obj.forEach(iterator, context);
} else if (obj.length === +obj.length) {
for (var i = 0, l = obj.length; i < l; i++) {
iterator.call(context, obj[i], i, obj);
}
} else {
for (var key in obj) {
if (this.has(obj, key)) {
iterator.call(context, obj[key], key, obj);
}
}
}
},
once: function(func) {
var ran = false, memo;
return function() {
if (ran) return memo;
ran = true;
memo = func.apply(this, arguments);
func = null;
return memo;
};
}
};
}
var _ = miniscore(), Events;
// Backbone.Events
// ---------------
// A module that can be mixed in to *any object* in order to provide it with
// custom events. You may bind with `on` or remove with `off` callback
// functions to an event; `trigger`-ing an event fires all callbacks in
// succession.
//
// var object = {};
// _.extend(object, Backbone.Events);
// object.on('expand', function(){ alert('expanded'); });
// object.trigger('expand');
//
Events = {
// Bind an event to a `callback` function. Passing `"all"` will bind
// the callback to all events fired.
on: function(name, callback, context) {
if (!eventsApi(this, 'on', name, [callback, context]) || !callback) return this;
this._events || (this._events = {});
var events = this._events[name] || (this._events[name] = []);
events.push({callback: callback, context: context, ctx: context || this});
return this;
},
// Bind an event to only be triggered a single time. After the first time
// the callback is invoked, it will be removed.
once: function(name, callback, context) {
if (!eventsApi(this, 'once', name, [callback, context]) || !callback) return this;
var self = this;
var once = _.once(function() {
self.off(name, once);
callback.apply(this, arguments);
});
once._callback = callback;
return this.on(name, once, context);
},
// Remove one or many callbacks. If `context` is null, removes all
// callbacks with that function. If `callback` is null, removes all
// callbacks for the event. If `name` is null, removes all bound
// callbacks for all events.
off: function(name, callback, context) {
var retain, ev, events, names, i, l, j, k;
if (!this._events || !eventsApi(this, 'off', name, [callback, context])) return this;
if (!name && !callback && !context) {
this._events = {};
return this;
}
names = name ? [name] : _.keys(this._events);
for (i = 0, l = names.length; i < l; i++) {
name = names[i];
if (events = this._events[name]) {
this._events[name] = retain = [];
if (callback || context) {
for (j = 0, k = events.length; j < k; j++) {
ev = events[j];
if ((callback && callback !== ev.callback && callback !== ev.callback._callback) ||
(context && context !== ev.context)) {
retain.push(ev);
}
}
}
if (!retain.length) delete this._events[name];
}
}
return this;
},
// Trigger one or many events, firing all bound callbacks. Callbacks are
// passed the same arguments as `trigger` is, apart from the event name
// (unless you're listening on `"all"`, which will cause your callback to
// receive the true name of the event as the first argument).
trigger: function(name) {
if (!this._events) return this;
var args = slice.call(arguments, 1);
if (!eventsApi(this, 'trigger', name, args)) return this;
var events = this._events[name];
var allEvents = this._events.all;
if (events) triggerEvents(events, args);
if (allEvents) triggerEvents(allEvents, arguments);
return this;
},
// Tell this object to stop listening to either specific events ... or
// to every object it's currently listening to.
stopListening: function(obj, name, callback) {
var listeners = this._listeners;
if (!listeners) return this;
var deleteListener = !name && !callback;
if (typeof name === 'object') callback = this;
if (obj) (listeners = {})[obj._listenerId] = obj;
for (var id in listeners) {
listeners[id].off(name, callback, this);
if (deleteListener) delete this._listeners[id];
}
return this;
}
};
// Regular expression used to split event strings.
var eventSplitter = /\s+/;
// Implement fancy features of the Events API such as multiple event
// names `"change blur"` and jQuery-style event maps `{change: action}`
// in terms of the existing API.
var eventsApi = function(obj, action, name, rest) {
if (!name) return true;
// Handle event maps.
if (typeof name === 'object') {
for (var key in name) {
obj[action].apply(obj, [key, name[key]].concat(rest));
}
return false;
}
// Handle space separated event names.
if (eventSplitter.test(name)) {
var names = name.split(eventSplitter);
for (var i = 0, l = names.length; i < l; i++) {
obj[action].apply(obj, [names[i]].concat(rest));
}
return false;
}
return true;
};
// A difficult-to-believe, but optimized internal dispatch function for
// triggering events. Tries to keep the usual cases speedy (most internal
// Backbone events have 3 arguments).
var triggerEvents = function(events, args) {
var ev, i = -1, l = events.length, a1 = args[0], a2 = args[1], a3 = args[2];
switch (args.length) {
case 0: while (++i < l) (ev = events[i]).callback.call(ev.ctx); return;
case 1: while (++i < l) (ev = events[i]).callback.call(ev.ctx, a1); return;
case 2: while (++i < l) (ev = events[i]).callback.call(ev.ctx, a1, a2); return;
case 3: while (++i < l) (ev = events[i]).callback.call(ev.ctx, a1, a2, a3); return;
default: while (++i < l) (ev = events[i]).callback.apply(ev.ctx, args);
}
};
var listenMethods = {listenTo: 'on', listenToOnce: 'once'};
// Inversion-of-control versions of `on` and `once`. Tell *this* object to
// listen to an event in another object ... keeping track of what it's
// listening to.
_.each(listenMethods, function(implementation, method) {
Events[method] = function(obj, name, callback) {
var listeners = this._listeners || (this._listeners = {});
var id = obj._listenerId || (obj._listenerId = _.uniqueId('l'));
listeners[id] = obj;
if (typeof name === 'object') callback = this;
obj[implementation](name, callback, this);
return this;
};
});
// Aliases for backwards compatibility.
Events.bind = Events.on;
Events.unbind = Events.off;
// Mixin utility
Events.mixin = function(proto) {
var exports = ['on', 'once', 'off', 'trigger', 'stopListening', 'listenTo',
'listenToOnce', 'bind', 'unbind'];
_.each(exports, function(name) {
proto[name] = this[name];
}, this);
return proto;
};
// Export Events as BackboneEvents depending on current context
if (typeof exports !== 'undefined') {
if (typeof module !== 'undefined' && module.exports) {
exports = module.exports = Events;
}
exports.BackboneEvents = Events;
}else if (typeof define === "function" && typeof define.amd == "object") {
define(function() {
return Events;
});
} else {
root.BackboneEvents = Events;
}
})(this);
},{}],3:[function(require,module,exports){
module.exports = require('./backbone-events-standalone');
},{"./backbone-events-standalone":2}],4:[function(require,module,exports){
var events = require("backbone-events-standalone");
events.onAll = function(callback,context){
this.on("all", callback,context);
return this;
};
// Mixin utility
events.oldMixin = events.mixin;
events.mixin = function(proto) {
events.oldMixin(proto);
// add custom onAll
var exports = ['onAll'];
for(var i=0; i < exports.length;i++){
var name = exports[i];
proto[name] = this[name];
}
return proto;
};
module.exports = events;
},{"backbone-events-standalone":3}],5:[function(require,module,exports){
(function (global){
/** @preserve http://github.com/easeway/js-class */
// Class Definition using ECMA5 prototype chain
function inherit(dest, src, noParent) {
while (src && src !== Object.prototype) {
Object.getOwnPropertyNames(src).forEach(function (name) {
if (name != '.class' && !dest.hasOwnProperty(name)) {
var desc = Object.getOwnPropertyDescriptor(src, name);
Object.defineProperty(dest, name, desc);
}
});
if (noParent) {
break;
}
src = src.__proto__;
}
return dest;
}
var Class = function (base, proto, options) {
if (typeof(base) != 'function') {
options = proto;
proto = base;
base = Object;
}
if (!proto) {
proto = {};
}
if (!options) {
options = {};
}
var meta = {
name: options.name,
base: base,
implements: []
}
var classProto = Class.clone(proto);
if (options.implements) {
(Array.isArray(options.implements) ? options.implements : [options.implements])
.forEach(function (implementedType) {
if (typeof(implementedType) == 'function' && implementedType.prototype) {
meta.implements.push(implementedType);
Class.extend(classProto, implementedType.prototype);
}
});
}
classProto.__proto__ = base.prototype;
var theClass = function () {
if (typeof(this.constructor) == 'function') {
this.constructor.apply(this, arguments);
}
};
meta.type = theClass;
theClass.prototype = classProto;
Object.defineProperty(theClass, '.class.meta', { value: meta, enumerable: false, configurable: false, writable: false });
Object.defineProperty(classProto, '.class', { value: theClass, enumerable: false, configurable: false, writable: false });
if (options.statics) {
Class.extend(theClass, options.statics);
}
return theClass;
};
Class.extend = inherit;
Class.clone = function (object) {
return inherit({}, object);
};
function findType(meta, type) {
while (meta) {
if (meta.type.prototype === type.prototype) {
return true;
}
for (var i in meta.implements) {
var implType = meta.implements[i];
var implMeta = implType['.class.meta'];
if (implMeta) {
if (findType(implMeta, type)) {
return true;
}
} else {
for (var proto = implType.prototype; proto; proto = proto.__proto__) {
if (proto === type.prototype) {
return true;
}
}
}
}
meta = meta.base ? meta.base['.class.meta'] : undefined;
}
return false;
}
var Checker = Class({
constructor: function (object) {
this.object = object;
},
typeOf: function (type) {
if (this.object instanceof type) {
return true;
}
var meta = Class.typeInfo(this.object);
return meta && findType(meta, type);
}
});
// aliases
Checker.prototype.a = Checker.prototype.typeOf;
Checker.prototype.an = Checker.prototype.typeOf;
Class.is = function (object) {
return new Checker(object);
};
Class.typeInfo = function (object) {
var theClass = object.__proto__['.class'];
return theClass ? theClass['.class.meta'] : undefined;
};
Class.VERSION = [0, 0, 2];
if (module) {
module.exports = Class;
} else {
global.Class = Class; // for browser
}
}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
//# sourceMappingURL=data:application/json;charset:utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIm5vZGVfbW9kdWxlcy9qcy1jbGFzcy9jbGFzcy5qcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E