wurmlab/sequenceserver

View on GitHub
public/packages/circosJS@1.7.0.js

Summary

Maintainability
F
1 mo
Test Coverage
var circosJS,
    indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; };

if (typeof Object.assign !== 'function') {
    Object.assign = function(target) {
        'use strict';
        var index, key, source;
        if (target === null) {
            throw new TypeError('Cannot convert undefined or null to object');
        }
        target = Object(target);
        index = 1;
        while (index < arguments.length) {
            source = arguments[index];
            if (source !== null) {
                for (key in source) {
                    if (Object.prototype.hasOwnProperty.call(source, key)) {
                        target[key] = source[key];
                    }
                }
            }
            index++;
        }
        return target;
    };
}

circosJS = function(conf) {
    var instance;
    instance = new circosJS.Core(conf);
    return instance;
};

circosJS.Core = function(conf) {
    this.tracks = {
        heatmaps: {},
        histograms: {},
        chords: {},
        scatters: {},
        lines: {},
        stacks: {},
        highlights: {},
        texts: {}
    };
    this.conf = circosJS.mixConf(conf, this.defaultConf);
    return this;
};

circosJS.Core.prototype.removeTracks = function(trackIds) {
    var id, l, len, ref, store, svg, trackId, type;
    svg = d3.select(this.conf.container);
    ref = this.tracks;
    for (type in ref) {
        store = ref[type];
        if (typeof trackIds === 'object') {
            for (l = 0, len = trackIds.length; l < len; l++) {
                id = trackIds[l];
                if (id in store) {
                    svg.select('.' + id).remove();
                    delete store[id];
                }
            }
        } else if (typeof trackIds === 'string') {
            if (trackIds in store) {
                svg.select('.' + trackIds).remove();
                delete store[trackIds];
            }
        } else if (typeof trackIds === 'undefined') {
            for (trackId in store) {
                svg.select('.' + trackId).remove();
                delete store[trackId];
            }
        }
    }
    return this;
};

circosJS.Core.prototype.layout = function(conf, data) {
    this._layout = new circosJS.Layout(conf, data);
    return this;
};

circosJS.log = function(level, code, message, data) {
    var levels;
    levels = ['Permanent log', 'Error', 'Warning', 'Info'];
    console.log('CircosJS: ', levels[level] + ' [' + code + '] ', message, data);
};

circosJS.mixConf = function(conf, defaultConf) {
    var key, newConf, value;
    newConf = {};
    for (key in defaultConf) {
        value = defaultConf[key];
        if (key in conf) {
            if (Object.prototype.toString.call(value) === '[object Array]') {
                newConf[key] = conf[key];
            } else if (typeof value === 'object' && (value != null)) {
                if ((value != null) && Object.keys(value).length === 0) {
                    newConf[key] = conf[key];
                } else {
                    newConf[key] = circosJS.mixConf(conf[key], value);
                }
            } else {
                newConf[key] = conf[key];
            }
        } else {
            newConf[key] = value;
        }
    }
    return newConf;
};

circosJS.Core.prototype.smartBorders = function() {
    var border, borders, currentBorder, l, layout, len, ref, store, track, trackId, trackType, width;
    width = this.conf.defaultTrackWidth;
    layout = {
        'in': this._layout.conf.innerRadius,
        out: this._layout.conf.outerRadius
    };
    borders = [];
    ref = this.tracks;
    for (trackType in ref) {
        store = ref[trackType];
        for (trackId in store) {
            track = store[trackId];
            if (track.conf.innerRadius) {
                borders.push({
                    'in': track.conf.innerRadius,
                    out: track.conf.outerRadius
                });
            }
        }
    }
    borders = borders.sort(function(a, b) {
        if (a.out > b.out) {
            1;
        }
        if (a.out < b.out) {
            -1;
        }
        return 0;
    });
    currentBorder = layout;
    for (l = 0, len = borders.length; l < len; l++) {
        border = borders[l];
        if (border.out < currentBorder['in'] - width) {
            return {
                'in': currentBorder['in'] - width,
                out: currentBorder['in']
            };
        }
        currentBorder = border;
    }
    if (currentBorder['in'] > width) {
        return {
            'in': currentBorder['in'] - width,
            out: currentBorder['in']
        };
    } else {
        return {
            'in': borders[0].out,
            out: borders[0].out + width
        };
    }
};

if (typeof module !== 'undefined' && module !== null) {
    module.exports = circosJS;
}

circosJS.checkParent = function(key, index, layoutSummary, header) {
    if (!(key in layoutSummary)) {
        circosJS.log(1, 'datum', 'unknown parent id', {
            line: index + 1,
            value: key,
            header: header,
            layoutSummary: layoutSummary
        });
        return false;
    }
    return true;
};

circosJS.checkNumber = function(keys, index) {
    var header, value;
    for (header in keys) {
        value = keys[header];
        if (isNaN(value)) {
            circosJS.log(1, 'datum', 'not a number', {
                line: index + 1,
                value: value,
                header: header
            });
            return false;
        }
    }
    return true;
};

circosJS.parseSpanValueData = function(data, layoutSummary) {
    var groups, sample;
    if (!(data.length > 0)) {
        return {
            data: [],
            meta: {
                min: null,
                max: null
            }
        };
    }
    sample = data[0];
    if ('parent_id' in sample && 'start' in sample && 'end' in sample && 'value' in sample) {
        data = data.map(function(datum) {
            return [datum.parent_id, datum.start, datum.end, datum.value];
        });
    }
    data = data.filter(function(datum, index) {
        return circosJS.checkParent(datum[0], index, layoutSummary, 'parent');
    }).filter(function(datum, index) {
        return circosJS.checkNumber({
            start: datum[1],
            end: datum[2],
            value: datum[3]
        }, index);
    }).map(function(datum) {
        if (datum[1] < 0 || datum[2] > layoutSummary[datum[0]]) {
            circosJS.log(2, 'position', 'position inconsistency', {
                datum: datum,
                layoutSummary: layoutSummary
            });
        }
        return {
            block_id: datum[0],
            start: Math.max(0, parseFloat(datum[1])),
            end: Math.min(layoutSummary[datum[0]], parseFloat(datum[2])),
            value: parseFloat(datum[3]) || 1
        };
    });
    groups = d3.nest().key(function(datum) {
        return datum.block_id;
    }).entries(data);
    return {
        data: groups,
        meta: {
            min: d3.min(data, function(d) {
                return d.value;
            }),
            max: d3.max(data, function(d) {
                return d.value;
            })
        }
    };
};

circosJS.parseSpanStringData = function(data, layoutSummary) {
    var groups, sample;
    sample = data[0];
    if ('parent_id' in sample && 'start' in sample && 'end' in sample && 'value' in sample) {
        data = data.map(function(datum) {
            return [datum.parent_id, datum.start, datum.end, datum.value];
        });
    }
    data = data.filter(function(datum, index) {
        return circosJS.checkParent(datum[0], index, layoutSummary, 'parent');
    }).filter(function(datum, index) {
        return circosJS.checkNumber({
            start: datum[1],
            end: datum[2]
        }, index);
    }).map(function(datum) {
        var value;
        if (datum[1] < 0 || datum[2] > layoutSummary[datum[0]]) {
            circosJS.log(2, 'position', 'position inconsistency', {
                datum: datum,
                layoutSummary: layoutSummary
            });
        }
        value = datum[3] != null ? datum[3] : null;
        return {
            block_id: datum[0],
            start: Math.max(0, parseFloat(datum[1])),
            end: Math.min(layoutSummary[datum[0]], parseFloat(datum[2])),
            value: value
        };
    });
    groups = d3.nest().key(function(datum) {
        return datum.block_id;
    }).entries(data);
    return {
        data: groups,
        meta: {
            min: d3.min(data, function(d) {
                return d.value;
            }),
            max: d3.max(data, function(d) {
                return d.value;
            })
        }
    };
};

circosJS.parsePositionValueData = function(data, layoutSummary) {
    var groups, sample;
    sample = data[0];
    if ('parent_id' in sample && 'position' in sample) {
        data = data.map(function(datum) {
            return [datum.parent_id, datum.position, datum.value];
        });
    }
    data = data.filter(function(datum, index) {
        return circosJS.checkParent(datum[0], index, layoutSummary, 'parent');
    }).filter(function(datum, index) {
        return circosJS.checkNumber({
            position: datum[1],
            value: datum[2]
        }, index);
    }).map(function(datum) {
        return {
            block_id: datum[0],
            position: Math.min(layoutSummary[datum[0]], parseFloat(datum[1])),
            value: parseFloat(datum[2]) || 1
        };
    });
    groups = d3.nest().key(function(datum) {
        return datum.block_id;
    }).entries(data);
    return {
        data: groups,
        meta: {
            min: d3.min(data, function(d) {
                return d.value;
            }),
            max: d3.max(data, function(d) {
                return d.value;
            })
        }
    };
};

circosJS.parsePositionTextData = function(data, layoutSummary) {
    var groups, sample;
    sample = data[0];
    if ('parent_id' in sample && 'position' in sample) {
        data = data.map(function(datum) {
            return [datum.parent_id, datum.position, datum.value];
        });
    }
    data = data.filter(function(datum, index) {
        return circosJS.checkParent(datum[0], index, layoutSummary, 'parent');
    }).filter(function(datum, index) {
        return circosJS.checkNumber({
            position: datum[1]
        }, index);
    }).map(function(datum) {
        return {
            block_id: datum[0],
            position: Math.min(layoutSummary[datum[0]], parseFloat(datum[1])),
            value: datum[2]
        };
    });
    groups = d3.nest().key(function(datum) {
        return datum.block_id;
    }).entries(data);
    return {
        data: groups,
        meta: {
            min: d3.min(data, function(d) {
                return d.value;
            }),
            max: d3.max(data, function(d) {
                return d.value;
            })
        }
    };
};

circosJS.parseChordData = function(data, layoutSummary) {
    var sample;
    sample = data[0];
    if ('source_id' in sample && 'source_start' in sample && 'source_end' && 'target_id' in sample && 'target_start' in sample && 'target_end' in sample) {
        data = data.map(function(datum) {
            var elts;
            elts = [datum.source_id, datum.source_start, datum.source_end, datum.target_id, datum.target_start, datum.target_end];
            if (datum.value != null) {
                elts.push(datum.value);
            }
            return elts;
        });
    }
    data = data.filter(function(datum, index) {
        return circosJS.checkParent(datum[0], index, layoutSummary, 'source_id');
    }).filter(function(datum, index) {
        return circosJS.checkParent(datum[3], index, layoutSummary, 'target_id');
    }).filter(function(datum, index) {
        return circosJS.checkNumber({
            source_start: datum[1],
            source_end: datum[2],
            target_start: datum[4],
            target_end: datum[5],
            value: datum[6] || 1
        }, index);
    }).map(function(datum) {
        return {
            source: {
                id: datum[0],
                start: Math.max(0, parseFloat(datum[1])),
                end: Math.min(layoutSummary[datum[0]], parseFloat(datum[2]))
            },
            target: {
                id: datum[3],
                start: Math.max(0, parseFloat(datum[4])),
                end: Math.min(layoutSummary[datum[3]], parseFloat(datum[5]))
            },
            value: parseFloat(datum[6]),
            hsp: datum[7]
        };
    });
    return {
        data: data,
        meta: {
            min: d3.min(data, function(d) {
                return d.value;
            }),
            max: d3.max(data, function(d) {
                return d.value;
            })
        }
    };
};

circosJS.Layout = function(conf, data) {
    var block_nb, gap, k, offset, ref, ref1, size, v;
    if (data == null) {
        circosJS.log(2, 'no layout data', '');
    }
    this.conf = circosJS.mixConf(conf, JSON.parse(JSON.stringify(this.defaultConf)));
    this.data = data;
    this.blocks = {};
    this.size = 0;
    offset = 0;
    ref = this.data;
    for (k in ref) {
        v = ref[k];
        this.blocks[v.id] = {
            label: v.label,
            len: v.len,
            color: v.color,
            offset: offset
        };
        v.offset = offset;
        offset += v.len;
    }
    this.size = offset;
    gap = this.conf.gap;
    size = this.size;
    block_nb = this.data.length;
    ref1 = this.data;
    for (k in ref1) {
        v = ref1[k];
        this.blocks[v.id].start = v.offset / size * (2 * Math.PI - block_nb * gap) + k * gap;
        this.blocks[v.id].end = (v.offset + v.len) / size * (2 * Math.PI - block_nb * gap) + k * gap;
        v.start = v.offset / size * (2 * Math.PI - block_nb * gap) + k * gap;
        v.end = (v.offset + v.len) / size * (2 * Math.PI - block_nb * gap) + k * gap;
    }
    this.getAngle = function(blockId, unit) {
        var block;
        block = this.blocks[blockId].start / this._size;
        if (unit === 'deg') {
            return block * 360;
        } else if (unit === 'rad') {
            return block * 2 * Math.PI;
        } else {
            return null;
        }
    };
    this.summary = function() {
        var d, l, layoutSummary, len, ref2;
        layoutSummary = {};
        ref2 = this._data;
        for (l = 0, len = ref2.length; l < len; l++) {
            d = ref2[l];
            layoutSummary[d.id] = d.len;
        }
        return layoutSummary;
    };
    return this;
};

circosJS.Core.prototype.heatmap = function(id, conf, data) {
    var track;
    track = new circosJS.Heatmap();
    track.build(this, conf, data);
    this.tracks.heatmaps[id] = track;
    return this;
};

circosJS.Core.prototype.histogram = function(id, conf, data) {
    var track;
    track = new circosJS.Histogram();
    track.build(this, conf, data);
    this.tracks.histograms[id] = track;
    return this;
};

circosJS.Core.prototype.chord = function(id, conf, data) {
    var track;
    track = new circosJS.Chord();
    track.build(this, conf, data);
    this.tracks.chords[id] = track;
    return this;
};

circosJS.Core.prototype.scatter = function(id, conf, data) {
    var track;
    track = new circosJS.Scatter();
    track.build(this, conf, data);
    this.tracks.scatters[id] = track;
    return this;
};

circosJS.Core.prototype.line = function(id, conf, data) {
    var track;
    track = new circosJS.Line();
    track.build(this, conf, data);
    this.tracks.lines[id] = track;
    return this;
};

circosJS.Core.prototype.stack = function(id, conf, data) {
    var track;
    track = new circosJS.Stack();
    track.build(this, conf, data);
    this.tracks.stacks[id] = track;
    return this;
};

circosJS.Core.prototype.highlight = function(id, conf, data) {
    var track;
    track = new circosJS.Highlight();
    track.build(this, conf, data);
    this.tracks.highlights[id] = track;
    return this;
};

circosJS.Core.prototype.text = function(id, conf, data) {
    var track;
    track = new circosJS.Text();
    track.build(this, conf, data);
    this.tracks.texts[id] = track;
    return this;
};

circosJS.Chord = function() {
    circosJS.Track.call(this);
    this.parseData = circosJS.parseChordData;
    this.applyRules = function(rules, data) {
        var datum, l, len, results, rule;
        rules = rules || [];
        results = [];
        for (l = 0, len = data.length; l < len; l++) {
            datum = data[l];
            results.push((function() {
                var len1, m, results1;
                results1 = [];
                for (m = 0, len1 = rules.length; m < len1; m++) {
                    rule = rules[m];
                    if (rule.condition(datum)) {
                        results1.push(datum[rule.parameter] = rule.value);
                    } else {
                        results1.push(void 0);
                    }
                }
                return results1;
            })());
        }
        return results;
    };
    this.getSource = (function(_this) {
        return function(d, layout) {
            var block, endAngle, result, startAngle;
            d = d.source;
            block = layout.blocks[d.id];
            startAngle = block.start + d.start / block.len * (block.end - block.start);
            endAngle = block.start + d.end / block.len * (block.end - block.start);
            return result = {
                radius: layout.conf.innerRadius,
                startAngle: startAngle,
                endAngle: endAngle
            };
        };
    })(this);
    this.getTarget = (function(_this) {
        return function(d, layout) {
            var block, endAngle, result, startAngle;
            d = d.target;
            block = layout.blocks[d.id];
            startAngle = block.start + d.start / block.len * (block.end - block.start);
            endAngle = block.start + d.end / block.len * (block.end - block.start);
            return result = {
                radius: layout.conf.innerRadius,
                startAngle: startAngle,
                endAngle: endAngle
            };
        };
    })(this);
    this.dimChords = function (parentElement, d, conf, index) {
        parentElement.selectAll('path').style('opacity', function (p, i) {
            if (index == i) {
                return 1;
            }
            return 0;
        });
    };
    this.resetChords = function (parentElement,conf) {
        parentElement.selectAll('path').style('opacity',conf.opacity);
    };
    this.renderChords = function(parentElement, name, conf, data, layout, ratio, getSource, getTarget) {
        var link, track;
        track = parentElement.append('g').attr('class', conf.colorPalette);
        link = track.selectAll('.chord').data(data).enter().append('path').attr('class', 'chord').attr('d', d3.svg.chord().source(function(d) {
            return getSource(d, layout);
        }).target(function(d) {
            return getTarget(d, layout);
        })).attr('opacity', function(d) {
            return conf.opacity;
        }).attr('id',function (d) {
            return d.source.id+'_'+d.target.id;
        }).on('mouseover', (function(_this) {
            return function(d, i, j) {
                _this.dimChords(track, d, conf, i);
                return _this.dispatch.mouseover(d, i, j);
            };
        })(this)).on('mouseout', (function(_this) {
            return function(d, i, j) {
                _this.resetChords(track,conf);
                return _this.dispatch.mouseout(d, i, j);
            };
        })(this));
        if (conf.usePalette) {
            link.attr('class', function(d) {
                return 'q' + ratio(d.value, conf.cmin, conf.cmax, conf.colorPaletteSize, conf.colorPaletteReverse, conf.logScale) + '-' + conf.colorPaletteSize;
            });
        } else {
            link.attr('fill', function(d) {
                return d.color || conf.color;
            });
        }
        return link;
    };
    this.render = (function(_this) {
        return function(instance, parentElement, name) {
            var selection, track;
            parentElement.select('.' + name).remove();
            track = parentElement.append('g').attr('class', name).attr('z-index', _this.conf.zIndex);
            selection = _this.renderChords(track, name, _this.conf, _this.data, instance._layout, _this.ratio, _this.getSource, _this.getTarget);
            if (_this.conf.tooltipContent != null) {
                return circosJS.registerTooltip(instance, _this, selection, _this.conf);
            }
        };
    })(this);
    return this;
};

circosJS.Heatmap = function() {
    circosJS.Track.call(this);
    this.parseData = circosJS.parseSpanValueData;
    this.renderDatumContainer = (function(_this) {
        return function(instance, parentElement, name, data, conf) {
            var group, track;
            track = parentElement.append('g').attr('class', conf.colorPalette);
            return group = _this.renderBlock(track, data, instance._layout, conf);
        };
    })(this);
    this.renderDatum = function(parentElement, conf, layout, utils) {
        return parentElement.selectAll('tile').data(function(d) {
            return d.values;
        }).enter().append('path').attr('class', 'tile').attr('opacity', function(d) {
            return d.opacity || conf.opacity;
        }).attr('d', d3.svg.arc().innerRadius(conf.innerRadius).outerRadius(conf.outerRadius).startAngle(function(d, i) {
            return utils.theta(d.start, layout.blocks[d.block_id]);
        }).endAngle(function(d, i) {
            return utils.theta(d.end, layout.blocks[d.block_id]);
        })).attr('class', function(d) {
            return 'q' + utils.ratio(d.value, conf.cmin, conf.cmax, conf.colorPaletteSize, conf.colorPaletteReverse, conf.logScale) + '-' + conf.colorPaletteSize;
        });
    };
    return this;
};

circosJS.Highlight = function() {
    circosJS.Track.call(this);
    this.parseData = circosJS.parseSpanStringData;
    this.renderDatumContainer = (function(_this) {
        return function(instance, parentElement, name, data, conf) {
            var group;
            return group = _this.renderBlock(parentElement, data, instance._layout, conf);
        };
    })(this);
    this.renderDatum = function(parentElement, conf, layout, utils) {
        return parentElement.selectAll('tile').data(function(d) {
            return d.values;
        }).enter().append('path').attr('class', 'tile').attr('d', d3.svg.arc().innerRadius(conf.innerRadius).outerRadius(conf.outerRadius).startAngle(function(d, i) {
            return utils.theta(d.start, layout.blocks[d.block_id]);
        }).endAngle(function(d, i) {
            return utils.theta(d.end, layout.blocks[d.block_id]);
        })).attr('fill', function(d) {
            return d.value || conf.color;
        }).attr('opacity', function(d) {
            return d.opacity || conf.opacity;
        }).attr('stroke-width', function(d) {
            return d.strokeWidth || conf.strokeWidth;
        }).attr('stroke', function(d) {
            return d.strokeColor || conf.strokeColor;
        });
    };
    return this;
};

circosJS.Histogram = function() {
    circosJS.Track.call(this);
    this.parseData = circosJS.parseSpanValueData;
    this.renderDatumContainer = (function(_this) {
        return function(instance, parentElement, name, data, conf) {
            var group, track;
            track = parentElement.append('g').attr('class', _this.conf.colorPalette);
            return group = _this.renderBlock(track, data, instance._layout, conf);
        };
    })(this);
    this.renderDatum = function(parentElement, conf, layout, utils) {
        var bin;
        bin = parentElement.selectAll('.bin').data(function(d) {
            return d.values;
        }).enter().append('path').attr('class', 'bin').attr('opacity', function(d) {
            return d.opacity || conf.opacity;
        }).attr('d', d3.svg.arc().innerRadius(function(d) {
            var height;
            if (conf.direction === 'in') {
                height = utils.ratio(d.value, conf.cmin, conf.cmax, conf.outerRadius - conf.innerRadius, false, conf.logscale);
                return conf.outerRadius - height;
            } else {
                return conf.innerRadius;
            }
        }).outerRadius(function(d) {
            var height;
            if (conf.direction === 'out') {
                height = utils.ratio(d.value, conf.cmin, conf.cmax, conf.outerRadius - conf.innerRadius, false, conf.logscale);
                return conf.innerRadius + height;
            } else {
                return conf.outerRadius;
            }
        }).startAngle(function(d) {
            return utils.theta(d.start, layout.blocks[d.block_id]);
        }).endAngle(function(d) {
            return utils.theta(d.end, layout.blocks[d.block_id]);
        }));
        if (conf.usePalette) {
            bin.attr('class', function(d) {
                return 'q' + utils.ratio(d.value, conf.cmin, conf.cmax, conf.colorPaletteSize, conf.colorPaletteReverse, conf.logScale) + '-' + conf.colorPaletteSize;
            });
        } else {
            bin.attr('fill', d.color || conf.color);
        }
        return bin;
    };
    return this;
};

circosJS.Line = function() {
    circosJS.Track.call(this);
    this.parseData = circosJS.parsePositionValueData;
    this.renderDatumContainer = (function(_this) {
        return function(instance, parentElement, name, data, conf) {
            var group, track;
            track = parentElement.append('g').attr('class', name);
            return group = _this.renderBlock(track, data, instance._layout, conf);
        };
    })(this);
    this.renderDatum = function(parentElement, conf, layout, utils) {
        var line;
        line = d3.svg.line().x(function(d) {
            return utils.x(d, layout, conf);
        }).y(function(d) {
            return utils.y(d, layout, conf);
        }).interpolate(conf.interpolation);
        return parentElement.append('path').datum(function(d) {
            return d.values;
        }).attr('class', 'line').attr('d', line).attr('opacity', function(d) {
            return d.opacity || conf.opacity;
        }).attr('stroke-width', function(d) {
            return d.thickness || conf.thickness;
        }).attr('stroke', function(d) {
            return d.color || conf.color;
        }).attr('fill', function(d) {
            var color, fill;
            fill = d.fill || conf.fill;
            color = d.fill_color || conf.fill_color;
            if (fill) {
                return color;
            } else {
                return 'none';
            }
        });
    };
    return this;
};

circosJS.Scatter = function() {
    circosJS.Track.call(this);
    this.parseData = circosJS.parsePositionValueData;
    this.renderDatumContainer = (function(_this) {
        return function(instance, parentElement, name, data, conf) {
            var group, track;
            track = parentElement.append('g').attr('class', name);
            return group = _this.renderBlock(track, data, instance._layout, conf);
        };
    })(this);
    this.renderDatum = function(parentElement, conf, layout, utils) {
        var point;
        point = parentElement.selectAll('.point').data(function(d) {
            return d.values;
        }).enter().append('path').attr('class', 'point').attr('opacity', function(d) {
            return d.opacity || conf.opacity;
        }).attr('d', d3.svg.symbol().type(conf.glyph.shape).size(conf.glyph.size)).attr('transform', (function(_this) {
            return function(d) {
                return 'translate(' + utils.x(d, layout, conf) + ',' + utils.y(d, layout, conf) + ') rotate(' + utils.theta(d.position, layout.blocks[d.block_id]) * 360 / (2 * Math.PI) + ')';
            };
        })(this)).attr('stroke', function(d) {
            return d.glyph_strokeColor || conf.glyph.strokeColor;
        }).attr('stroke-width', function(d) {
            return d.glyph_strokeWidth || conf.glyph.strokeWidth;
        }).attr('fill', function(d) {
            var color, fill;
            fill = d.glyph_fill || conf.glyph.fill;
            color = d.glyph_color || conf.glyph.color;
            if (fill) {
                return color;
            } else {
                return 'none';
            }
        });
        return point;
    };
    return this;
};

circosJS.Stack = function() {
    circosJS.Track.call(this);
    this.parseData = circosJS.parseSpanValueData;
    this.build = function(instance, conf, data, rules, backgrounds) {
        this.loadData(data, instance);
        this.conf = this.processConf(conf, this.defaultConf, this.meta, instance, this);
        this.buildLayers(this.data, this.conf.margin);
        return this.applyRules(conf.rules, this.data);
    };
    this.buildLayers = function(data, margin) {
        var block, datum, i, idx, l, lastDatumInLayer, layer, layers, len, len1, m, placed, ref;
        for (idx in data) {
            block = data[idx];
            block.values = block.values.sort(function(a, b) {
                if (a.start < b.start) {
                    return -1;
                }
                if (a.start === b.start && a.end > b.end) {
                    return -1;
                }
                if (a.start === b.start && a.end === b.end) {
                    return 0;
                }
                return 1;
            });
            layers = [];
            ref = block.values;
            for (l = 0, len = ref.length; l < len; l++) {
                datum = ref[l];
                placed = false;
                for (i = m = 0, len1 = layers.length; m < len1; i = ++m) {
                    layer = layers[i];
                    lastDatumInLayer = layer.slice(0).pop();
                    if (lastDatumInLayer.end + margin < datum.start) {
                        layer.push(datum);
                        datum.layer = i;
                        placed = true;
                        break;
                    }
                }
                if (!placed) {
                    datum.layer = layers.length;
                }
                if (!placed) {
                    layers.push([datum]);
                }
            }
        }
    };
    this.applyRules = function(rules, data) {
        var datum, i, k, layer, results, rule, v;
        rules = rules || [];
        results = [];
        for (k in data) {
            v = data[k];
            results.push((function() {
                var ref, results1;
                ref = v.layers;
                results1 = [];
                for (i in ref) {
                    layer = ref[i];
                    results1.push((function() {
                        var l, len, results2;
                        results2 = [];
                        for (l = 0, len = layer.length; l < len; l++) {
                            datum = layer[l];
                            results2.push((function() {
                                var len1, m, results3;
                                results3 = [];
                                for (m = 0, len1 = rules.length; m < len1; m++) {
                                    rule = rules[m];
                                    if (rule.condition(v.parent, datum, i)) {
                                        results3.push(datum[rule.parameter] = rule.value);
                                    } else {
                                        results3.push(void 0);
                                    }
                                }
                                return results3;
                            })());
                        }
                        return results2;
                    })());
                }
                return results1;
            })());
        }
        return results;
    };
    this.datumRadialPosition = (function(_this) {
        return function(d) {
            var origin, radialEnd, radialStart;
            radialStart = (_this.conf.thickness + _this.conf.radialMargin) * d.layer;
            radialEnd = radialStart + _this.conf.thickness;
            if (_this.conf.direction === 'out') {
                return [_this.conf.innerRadius + radialStart, Math.min(_this.conf.innerRadius + radialEnd, _this.conf.outerRadius)];
            }
            if (_this.conf.direction === 'in') {
                return [Math.max(_this.conf.outerRadius - radialEnd, _this.conf.innerRadius), _this.conf.outerRadius - radialStart];
            }
            if (_this.conf.direction === 'center') {
                origin = Math.floor((_this.conf.outerRadius + _this.conf.innerRadius) / 2);
                radialStart = (_this.conf.thickness + _this.conf.radialMargin) * Math.floor(d.layer / 2);
                radialEnd = radialStart + _this.conf.thickness;
                if (d.layer % 2 === 0) {
                    return [origin + radialStart, origin + radialEnd];
                } else {
                    return [origin - radialStart - _this.conf.radialMargin, origin - radialEnd - _this.conf.radialMargin];
                }
            }
        };
    })(this);
    this.datumInnerRadius = (function(_this) {
        return function(d, i, j) {
            return _this.datumRadialPosition(d, i, j)[0];
        };
    })(this);
    this.datumOuterRadius = (function(_this) {
        return function(d, i, j) {
            return _this.datumRadialPosition(d, i, j)[1];
        };
    })(this);
    this.renderDatumContainer = (function(_this) {
        return function(instance, parentElement, name, data, conf) {
            var group, track;
            track = parentElement.append('g').attr('class', conf.colorPalette);
            return group = _this.renderBlock(track, data, instance._layout, conf);
        };
    })(this);
    this.renderDatum = function(parentElement, conf, layout, utils) {
        var tile;
        tile = parentElement.selectAll('.tile').data(function(d) {
            return d.values;
        }).enter().append('path').attr('class', 'tile').attr('d', d3.svg.arc().innerRadius(utils.datumInnerRadius).outerRadius(utils.datumOuterRadius).startAngle(function(d) {
            return utils.theta(d.start, layout.blocks[d.block_id]);
        }).endAngle(function(d) {
            return utils.theta(d.end, layout.blocks[d.block_id]);
        }));
        tile.attr('opacity', function(d) {
            return d.opacity || conf.opacity;
        });
        tile.attr('stroke-width', function(d) {
            return d.strokeWidth || conf.strokeWidth;
        });
        tile.attr('stroke', function(d) {
            return d.strokeColor || conf.strokeColor;
        });
        tile.attr('fill', function(d) {
            return d.color || conf.color;
        });
        tile.attr('class', function(d) {
            var usePalette;
            usePalette = d.usePalette || conf.usePalette;
            if (usePalette) {
                return 'q' + utils.ratio(d.value, conf.cmin, conf.cmax, conf.colorPaletteSize, conf.colorPaletteReverse, conf.logScale) + '-' + conf.colorPaletteSize;
            }
        });
        return tile;
    };
    return this;
};

circosJS.Text = function() {
    circosJS.Track.call(this);
    this.parseData = circosJS.parsePositionTextData;
    this.renderDatumContainer = (function(_this) {
        return function(instance, parentElement, name, data, conf) {
            var group, track;
            track = parentElement.append('g').attr('class', name);
            return group = _this.renderBlock(track, data, instance._layout, conf);
        };
    })(this);
    this.renderDatum = function(parentElement, conf, layout, utils) {
        var key, ref, text, value;
        text = parentElement.selectAll('g').data(function(d) {
            return d.values;
        }).enter().append('g').append('text').text(function(d) {
            return d.value;
        }).attr('transform', function(d) {
            var angle;
            angle = utils.theta(d.position, layout.blocks[d.block_id]) * 360 / (2 * Math.PI) - 90;
            return 'rotate(' + angle + ')' + 'translate(' + conf.innerRadius + ',0)';
        });
        ref = conf.style;
        for (key in ref) {
            value = ref[key];
            text.style(key, value);
        }
        return text;
    };
    return this;
};

circosJS.Track = function() {
    this.build = function(instance, conf, data) {
        this.dispatch = d3.dispatch('mouseover', 'mouseout');
        this.loadData(data, instance);
        this.conf = this.processConf(conf, this.defaultConf, this.meta, instance, this);
        return this.applyRules(conf.rules, this.data);
    };
    this.loadData = function(data, instance) {
        var d, l, layoutSummary, len, ref, result;
        layoutSummary = {};
        ref = instance._layout.data;
        for (l = 0, len = ref.length; l < len; l++) {
            d = ref[l];
            layoutSummary[d.id] = d.len;
        }
        result = this.parseData(data, layoutSummary);
        this.data = result.data;
        return this.meta = result.meta;
    };
    this.processConf = function(conf, defaultConf, meta, instance, utils) {
        var smartBorders;
        conf = circosJS.mixConf(conf, Object.assign({}, defaultConf));
        conf = utils.computeMinMax(conf, meta);
        if (conf.innerRadius === 0 && conf.outerRadius === 0) {
            smartBorders = instance.smartBorders();
            conf.innerRadius = smartBorders['in'];
            conf.outerRadius = smartBorders.out;
        }
        return conf;
    };
    this.applyRules = function(rules, data) {
        var datum, i, k, results, rule, v;
        rules = rules || [];
        results = [];
        for (k in data) {
            v = data[k];
            results.push((function() {
                var ref, results1;
                ref = v.values;
                results1 = [];
                for (i in ref) {
                    datum = ref[i];
                    results1.push((function() {
                        var l, len, results2;
                        results2 = [];
                        for (l = 0, len = rules.length; l < len; l++) {
                            rule = rules[l];
                            if (rule.condition(v.key, datum, i)) {
                                results2.push(datum[rule.parameter] = rule.value);
                            } else {
                                results2.push(void 0);
                            }
                        }
                        return results2;
                    })());
                }
                return results1;
            })());
        }
        return results;
    };
    this.computeMinMax = function(conf, meta) {
        conf.cmin = conf.min === 'smart' ? meta.min : conf.min;
        conf.cmax = conf.max === 'smart' ? meta.max : conf.max;
        return conf;
    };
    this.ratio = function(value, min, max, scope, reverse, logScale) {
        var fraction, scaleLogBase, x;
        scaleLogBase = logScale ? 2.3 : 1;
        if (min === max || (value === min && !reverse) || (value === max && reverse)) {
            return 0;
        }
        if (value === max || (value === min && reverse)) {
            return scope - 1;
        }
        fraction = (value - min) / (max - min);
        x = Math.exp(1 / scaleLogBase * Math.log(fraction));
        if (reverse) {
            x = 1 - x;
        }
        return Math.floor(scope * x);
    };
    this.render = (function(_this) {
        return function(instance, parentElement, name) {
            var datumContainer, ref, selection, track;
            parentElement.select('.' + name).remove();
            track = parentElement.append('g').attr('class', name).attr('z-index', _this.conf.zIndex);
            datumContainer = _this.renderDatumContainer(instance, track, name, _this.data, _this.conf);
            if ((ref = _this.conf.axes) != null ? ref.display : void 0) {
                _this.renderAxes(datumContainer, _this.conf, instance._layout, _this.data);
            }
            selection = _this.renderDatum(datumContainer, _this.conf, instance._layout, _this);
            if (_this.conf.tooltipContent != null) {
                circosJS.registerTooltip(instance, _this, selection, _this.conf);
            }
            selection.on('mouseover', function(d, i, j) {
                return _this.dispatch.mouseover(d, i, j);
            });
            return selection.on('mouseout', function(d, i, j) {
                return _this.dispatch.mouseout(d, i, j);
            });
        };
    })(this);
    this.renderBlock = function(parentElement, data, layout, conf) {
        var block, scope;
        scope = conf.outerRadius - conf.innerRadius;
        block = parentElement.selectAll('.block').data(data).enter().append('g').attr('class', 'block').attr('transform', function(d) {
            return 'rotate(' + layout.blocks[d.key].start * 360 / (2 * Math.PI) + ')';
        });
        if (conf.backgrounds) {
            block.selectAll('.background').data(conf.backgrounds).enter().append('path').attr('class', 'background').attr('fill', function(background) {
                return background.color;
            }).attr('opacity', function(background) {
                return background.opacity || 1;
            }).attr('d', d3.svg.arc().innerRadius(function(background) {
                if (conf.direction === 'in') {
                    return conf.outerRadius - scope * background.start;
                } else {
                    return conf.innerRadius + scope * background.start;
                }
            }).outerRadius(function(background) {
                if (conf.direction === 'in') {
                    return conf.outerRadius - scope * background.end;
                } else {
                    return conf.innerRadius + scope * background.end;
                }
            }).startAngle(function(d, i, j) {
                return 0;
            }).endAngle(function(d, i, j) {
                return layout.blocks[data[j].key].end - layout.blocks[data[j].key].start;
            }));
        }
        return block;
    };
    this.renderAxes = function(parentElement, conf, layout, data) {
        var axes, axis, x;
        if (conf.axes.minor.spacingType === 'pixel') {
            axes = (function() {
                var l, ref, ref1, ref2, results;
                results = [];
                for (x = l = ref = conf.innerRadius, ref1 = conf.outerRadius, ref2 = conf.axes.minor.spacing; ref2 > 0 ? l <= ref1 : l >= ref1; x = l += ref2) {
                    results.push(x);
                }
                return results;
            })();
        }
        axis = d3.svg.arc().innerRadius(function(d) {
            return d;
        }).outerRadius(function(d) {
            return d;
        }).startAngle(0).endAngle(function(d, i, j) {
            var block;
            block = layout.blocks[data[j].key];
            return block.end - block.start;
        });
        return parentElement.selectAll('.axis').data(axes).enter().append('path').attr('opacity', conf.opacity).attr('class', 'axis').attr('d', axis).attr('stroke-width', function(d, i) {
            if (i % conf.axes.major.spacing === 0) {
                return conf.axes.major.thickness;
            } else {
                return conf.axes.minor.thickness;
            }
        }).attr('stroke', function(d, i) {
            if (i % conf.axes.major.spacing === 0) {
                return conf.axes.major.color;
            } else {
                return conf.axes.minor.color;
            }
        });
    };
    this.theta = function(position, block) {
        return position / block.len * (block.end - block.start);
    };
    this.x = (function(_this) {
        return function(d, layout, conf) {
            var angle, height, r;
            height = _this.ratio(d.value, conf.cmin, conf.cmax, conf.outerRadius - conf.innerRadius, false, conf.logscale);
            if (conf.direction === 'in') {
                r = conf.outerRadius - height;
            } else {
                r = conf.innerRadius + height;
            }
            angle = _this.theta(d.position, layout.blocks[d.block_id]) - Math.PI / 2;
            return r * Math.cos(angle);
        };
    })(this);
    this.y = (function(_this) {
        return function(d, layout, conf) {
            var angle, height, r;
            height = _this.ratio(d.value, conf.cmin, conf.cmax, conf.outerRadius - conf.innerRadius, false, conf.logscale);
            if (conf.direction === 'in') {
                r = conf.outerRadius - height;
            } else {
                r = conf.innerRadius + height;
            }
            angle = _this.theta(d.position, layout.blocks[d.block_id]) - Math.PI / 2;
            return r * Math.sin(angle);
        };
    })(this);
    this.ratio = function(value, min, max, scope, reverse, logScale) {
        var fraction, scaleLogBase, x;
        scaleLogBase = logScale ? 2.3 : 1;
        if (min === max || (value === min && !reverse) || (value === max && reverse)) {
            return 0;
        }
        if (value === max || (value === min && reverse)) {
            return scope - 1;
        }
        fraction = (value - min) / (max - min);
        x = Math.exp(1 / scaleLogBase * Math.log(fraction));
        if (reverse) {
            x = 1 - x;
        }
        return Math.floor(scope * x);
    };
    return this;
};

circosJS.renderLayout = function(d3, parentElement, instance) {
    var block, conf, entry, layout;
    conf = instance._layout.conf;
    parentElement.select('.cs-layout').remove();
    layout = parentElement.append('g').attr('class', 'cs-layout').attr('z-index', conf.zIndex).on('click', conf.onClick);
    block = layout.selectAll('g').data(instance._layout.data).enter().append('g').attr('class', function(d) {
        return d.id;
    }).attr('opacity', conf.opacity);
    entry = d3.svg.arc().innerRadius(conf.innerRadius).outerRadius(conf.outerRadius).cornerRadius(conf.cornerRadius).startAngle(function(d) {
        return d.start;
    }).endAngle(function(d) {
        return d.end;
    });
    block.append('path').attr('d', entry).attr('fill', function(d) {
        return d.color;
    }).attr('id', function(d) {
        return d.id;
    });
    if (conf.labels.display) {
        circosJS.renderLayoutLabels(conf, d3, block);
    }
    if (conf.ticks.display) {
        return circosJS.renderLayoutTicks(conf, layout, d3, instance);
    }
};

circosJS.renderLayoutLabels = function(conf, d3, block) {
    var label, labelArc, r;
    r = conf.innerRadius + conf.labels.radialOffset;
    labelArc = d3.svg.arc().innerRadius(r).outerRadius(r).startAngle(function(d, i) {
        return d.start;
    }).endAngle(function(d, i) {
        return d.end;
    });
    block.append('path').attr('fill', 'none').attr('stroke', 'none').attr('d', labelArc).attr('id', function(d) {
        return 'arc-label' + d.id;
    });
    label = block.append('text').attr('font-size', conf.labels.size).attr('text-anchor', 'middle');
    return label.append('textPath').attr('startOffset', '25%').attr('xlink:href', function(d) {
        return '#arc-label' + d.id;
    }).style('fill', conf.labels.color).text(function(d) {
        var arc_len = d.end - d.start;
        return d.label.slice(0, Math.floor(21 * arc_len)) + '..';
    });
};

circosJS.renderLayoutTicks = function(conf, layout, d3, instance) {
    var blockTicks, displayLabel, ticks;
    blockTicks = function(d) {
        var k,space;
        k = (d.end - d.start) / d.len;
        if ((d.end - d.start) > 1.57) {
            space = 8;
        } else if ((d.end - d.start) > 0.785) {
            space = 4;
        } else if ((d.end - d.start) > 0.3925) {
            space = 2;
        } else if ((d.end - d.start) > 0) {
            space = 0;
        }
        var arr = [];
        var item = {angle: 0 * k + d.start, label: 0};
        arr.push(item);
        var temp_scale = d3.scale.linear()
            .domain([1, d.len])
            .range([d.start, d.end]);
        var len = temp_scale.ticks(space).length;
        temp_scale.ticks(space).map(function (v,i) {
            var init = v * k + d.start;
            var final = d.len * k +d.start;
            if ((final - init) > 0.5) {
            }
            var item = {
                angle: v * k + d.start,
                label: v / conf.ticks.labelDenominator + conf.ticks.labelSuffix
            };
            arr.push(item);
        });
        arr.splice(len, 1);
        var item = {
            angle: (d.len * k + d.start) - 0.006,
            label: d.len / conf.ticks.labelDenominator + conf.ticks.labelSuffix
        };
        arr.push(item);
        return arr;
    };
    displayLabel = function(v, i) {
        if (conf.ticks.labels === false) {
            return null;
        } else if (conf.ticks.labelDisplay0 === false && i === 0) {
            return null;
        } else if (i % conf.ticks.labelSpacing) {
            return null;
        } else if (i === 0) {
            return v / conf.ticks.labelDenominator; // added support for 0 without suffix.
        }
        else {
            return v / conf.ticks.labelDenominator + conf.ticks.labelSuffix;
        }
    };
    ticks = layout.append('g').selectAll('g').data(instance._layout.data).enter().append('g').selectAll('g').data(blockTicks).enter().append('g').attr('transform', function(d) {
        return 'rotate(' + (d.angle * 180 / Math.PI - 90) + ')' + 'translate(' + conf.outerRadius + ',0)';
    });
    ticks.append('line').attr('x1', 0).attr('y1', 1).attr('x2', function(d, i) {
        return conf.ticks.size.major;
    }).attr('y2', 1).style('stroke', conf.ticks.color);
    return ticks.append('text').attr('x', 8).attr('dy', '.35em').attr('transform', function(d) {
        if (d.angle > Math.PI) {
            return 'rotate(180)translate(-16)';
        } else {
            return null;
        }
    }).attr('text-anchor', function(d) {
        if (d.angle > Math.PI) {
            return 'end';
        } else {
            return null;
        }
    }).attr('font-size', conf.ticks.labelSize).style('fill', conf.ticks.labelColor).text(function(d) {
        return d.label;
    });
};

circosJS.Core.prototype.render = function(ids, removeTracks) {
    var name, ref, ref1, renderAll, svg, track, trackStore, trackType, tracks, translated;
    if (typeof ids === 'undefined') {
        renderAll = true;
        ids = [];
    }
    if (removeTracks) {
        ref = this.tracks;
        for (trackType in ref) {
            trackStore = ref[trackType];
            for (name in trackStore) {
                track = trackStore[name];
                svg.select('.' + name).remove();
            }
        }
    }
    svg = d3.select(this.conf.container).attr('width', this.conf.width).attr('height', this.conf.height);
    translated = svg.select('.all');
    if (translated.empty()) {
        translated = svg.append('g').attr('class', 'all').attr('transform', 'translate(' + parseInt(this.conf.width / 2) + ',' + parseInt(this.conf.height / 2) + ')');
    }
    ref1 = this.tracks;
    for (trackType in ref1) {
        trackStore = ref1[trackType];
        for (name in trackStore) {
            track = trackStore[name];
            if (renderAll || indexOf.call(ids, name) >= 0) {
                track.render(this, translated, name);
            }
        }
    }
    if (renderAll || indexOf.call(ids, 'layout') >= 0) {
        circosJS.renderLayout(d3, translated, this);
    }
    tracks = svg.selectAll('.all > g').remove();
    tracks[0].sort(function(a, b) {
        if (parseInt(a.getAttribute('z-index')) < parseInt(b.getAttribute('z-index'))) {
            return -1;
        } else if (parseInt(a.getAttribute('z-index')) > parseInt(b.getAttribute('z-index'))) {
            return 1;
        } else {
            return 0;
        }
    });
    svg.select('.all').selectAll('g').data(tracks[0]).enter().append(function(d) {
        return d;
    });
    return this;
};

circosJS.Core.prototype.defaultConf = {
    width: 700,
    height: 700,
    container: 'circos',
    defaultTrackWidth: 10
};

circosJS.Layout.prototype.defaultConf = {
    innerRadius: 250,
    outerRadius: 300,
    cornerRadius: 5,
    gap: 0.04,
    opacity: 1,
    labels: {
        position: 'center',
        display: true,
        size: 14,
        color: '#000',
        radialOffset: 20
    },
    ticks: {
        display: true,
        color: 'grey',
        spacing: 10000000,
        labels: true,
        labelSpacing: 10,
        labelSuffix: 'Mb',
        labelDenominator: 1000000,
        labelDisplay0: true,
        labelSize: 10,
        labelColor: '#000',
        labelFont: 'default',
        majorSpacing: 5,
        size: {
            minor: 2,
            major: 5
        }
    },
    onClick: null,
    onMouseOver: null,
    zIndex: 100
};

circosJS.axes = {
    display: false,
    minor: {
        spacing: 5,
        spacingType: 'pixel',
        color: '#d3d3d3',
        thickness: 2
    },
    major: {
        spacing: 5,
        color: '#000000',
        thickness: 2
    }
};

circosJS.Heatmap.prototype.defaultConf = {
    innerRadius: 0,
    outerRadius: 0,
    min: 'smart',
    max: 'smart',
    colorPalette: 'YlGnBu',
    colorPaletteSize: 9,
    colorPaletteReverse: false,
    logScale: false,
    rules: [],
    backgrounds: [],
    zIndex: 1,
    opacity: 1,
    tooltipContent: null
};

circosJS.Histogram.prototype.defaultConf = {
    innerRadius: 0,
    outerRadius: 0,
    min: 'smart',
    max: 'smart',
    direction: 'out',
    colorPaletteSize: 9,
    colorPalette: 'YlGnBu',
    usePalette: true,
    colorPaletteReverse: false,
    color: '#fd6a62',
    logScale: false,
    axes: circosJS.axes,
    rules: [],
    backgrounds: [],
    zIndex: 1,
    opacity: 1,
    tooltipContent: null
};

circosJS.Chord.prototype.defaultConf = {
    colorPaletteSize: 9,
    colorPalette: 'PuBuGn',
    usePalette: true,
    colorPaletteReverse: false,
    color: '#fd6a62',
    opacity: 0.7,
    min: 'smart',
    max: 'smart',
    logScale: false,
    rules: [],
    backgrounds: [],
    zIndex: 1,
    tooltipContent: null
};

circosJS.Scatter.prototype.defaultConf = {
    innerRadius: 0,
    outerRadius: 0,
    min: 'smart',
    max: 'smart',
    direction: 'out',
    logScale: false,
    glyph: {
        color: '#fd6a62',
        fill: true,
        size: 15,
        shape: 'circle',
        strokeColor: '#d3d3d3',
        strokeWidth: 2
    },
    axes: circosJS.axes,
    rules: [],
    backgrounds: [],
    zIndex: 1,
    opacity: 1,
    tooltipContent: null
};

circosJS.Line.prototype.defaultConf = {
    innerRadius: 0,
    outerRadius: 0,
    min: 'smart',
    max: 'smart',
    direction: 'out',
    logScale: false,
    color: '#fd6a62',
    fill: true,
    fill_color: '#d3d3d3',
    thickness: 2,
    max_gap: 10000000,
    interpolation: 'linear',
    axes: circosJS.axes,
    rules: [],
    backgrounds: [],
    zIndex: 1,
    opacity: 1,
    tooltipContent: null
};

circosJS.Stack.prototype.defaultConf = {
    innerRadius: 0,
    outerRadius: 0,
    colorPaletteSize: 9,
    colorPalette: 'PuBuGn',
    usePalette: true,
    colorPaletteReverse: false,
    color: '#fd6a62',
    min: 'smart',
    max: 'smart',
    direction: 'out',
    logScale: false,
    color: '#fd6a62',
    thickness: 10,
    radialMargin: 2,
    margin: 2,
    strokeWidth: 1,
    strokeColor: '#000000',
    axes: circosJS.axes,
    rules: [],
    backgrounds: [],
    zIndex: 1,
    opacity: 1,
    tooltipContent: null
};

circosJS.Highlight.prototype.defaultConf = {
    innerRadius: 0,
    outerRadius: 0,
    defaultColor: '#fd6a62',
    opacity: 0.5,
    rules: [],
    zIndex: 101,
    strokeColor: '#d3d3d3',
    strokeWidth: 0,
    tooltipContent: null
};

circosJS.Text.prototype.defaultConf = {
    innerRadius: 0,
    outerRadius: 0,
    rules: [],
    backgrounds: [],
    zIndex: 1,
    style: {},
    tooltipContent: null
};

circosJS.registerTooltip = function(instance, track, element, trackParams) {
    track.tip = d3.tip().direction('s').offset([20, 0]).html(trackParams.tooltipContent);
    element.call(track.tip);
    track.dispatch.on('mouseover', function(d, i, j) {
        return track.tip.attr('class', 'd3-tip appear').show(d);
    });
    return track.dispatch.on('mouseout', function(d, i, j) {
        track.tip.attr('class', 'd3-tip').show(d);
        return track.tip.hide();
    });
};