diff --git a/.gitignore b/.gitignore index 485dee64bcfb48793379b200a1afd14e85a8aaf4..ae8e990699b73d4eb7c669bdcbaa25baf7b33eb5 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ .idea +.*.swp diff --git a/genome-vuer/src/js/app.js b/genome-vuer/src/js/app.js index 8e0a70779dcdce6222af2b1e9885dab0c0e79e42..000877528fdb4c0f13ce18e6a2998d3b18cd5d61 100644 --- a/genome-vuer/src/js/app.js +++ b/genome-vuer/src/js/app.js @@ -5,7 +5,7 @@ var app = new Vue({ id: "my-genome", start: 1706479, end: 1718084, - tooltip: null + tooltip: "name: {name}
description: {description}
start: {start}
end: {end}" }, feature_data: [ { name: "Gene 1", @@ -95,7 +95,6 @@ var app = new Vue({ end: 1716321, strand: '+', type: "gene", - color: '#454aff', color_border: '#000000' }, { name: "Gene 11", @@ -103,9 +102,7 @@ var app = new Vue({ start: 1717235, end: 1718084, strand: '-', - type: "gene", - color: '#454aff', - color_border: '#000000' + type: "rRNA" } ] } diff --git a/genome-vuer/src/js/axis.js b/genome-vuer/src/js/axis.js index 3d41d25f2b3bbf536743917f4af96869321e53ae..209c2e505d0e16ad71bd05439c918f14164614a7 100644 --- a/genome-vuer/src/js/axis.js +++ b/genome-vuer/src/js/axis.js @@ -1,37 +1,75 @@ -Vue.component("axis",{ - template: + + +/*********************************** + * TODO: + * add logic to print human readable tick sizes, i.e. + * 10 kb instead of 10,000 bp + */ + + +Vue.component( "axis", { + template: ` -
- TODO: im the axis component -
+ + + + + + + + {{ tick.genomePos }} + + `, props: { - todoprop1: { - validator (value) { - return true - } - }, - todoprop2: { - validator (value) { - return true - } - } + x: Number, + y: Number, + start: Number, + stop: Number, + genomeSize: Number, + width: Number, + height: Number, + xOffset: Number, + vOffset: Number, }, methods: { - my_method(){ - console.log(this.todo) - console.log(this.Todo) - }, + genomeToPixel( pos ) { + return (this.width*(pos-this.start))/(this.length) + } }, - computed: { - Todo(){ - return this.todo.charAt(0).toUpperCase() + this.todo.substr(1); + computed:{ + power(){ + return Math.floor(Math.log10(this.length)) + }, + length(){ + return (this.stop - this.start) + }, + genomeSectionSize(){ + return (this.start > this.stop) ? (this.genomeSize-this.start + this.end) : Math.abs(this.stop-this.start) // genome section in bp + }, + tickSize(){ + return Math.pow(10, this.power-1) + //return Math.pow( 10, Math.round( Math.log10( this.genomeSectionSize / this.noTicks ) ) ) // axis tick size in log 10 bp + }, + noTicks(){ + return Math.floor(this.length/this.tickSize)+2 + }, + ticks(){ + const firstTickPos = Math.round(this.start/this.tickSize)*this.tickSize//Math.pow( 10, Math.floor( Math.log10( this.start ) ) ) + let ticks = new Array(this.noTicks) + for(i=0; i - TODO: im the feature component - + + + `, - props: { - todoprop1: { - validator (value) { - return true + props: ['svgWidth', 'svgHeight', 'svgX', 'svgY', 'color', 'borderColor', 'featureId'], + computed: { + featureStyle () { + return { + 'fill': this.color, + 'stroke': this.borderColor, + 'stroke-width': 1 } }, - todoprop2: { - validator (value) { - return true - } - } - }, - methods: { - my_method(){ - console.log(this.todo) - console.log(this.Todo) + arrow_coordinates () { + let points = [ + '0, ' + this.svgHeight * 0.25, + '0, ' + this.svgHeight * 0.75, + this.svgWidth * 0.7 + ', ' + this.svgHeight * 0.75, + this.svgWidth * 0.7 + ', ' + this.svgHeight * 0.95, + this.svgWidth + ', ' + this.svgHeight * 0.5, + this.svgWidth * 0.7 + ', ' + this.svgHeight * 0.05, + this.svgWidth * 0.7 + ', ' + this.svgHeight * 0.25 + ] + return points.join(' ') }, }, - computed: { - Todo(){ - return this.todo.charAt(0).toUpperCase() + this.todo.substr(1); + methods: { + clickEvent (evt) { + this.$emit('click', this.featureId) }, + hoverEvent (evt) { + this.$emit('hover', this.featureId) + } }, data: function(){ return { todo: "todo" } - }, + } }) diff --git a/genome-vuer/src/js/genome_viewer.js b/genome-vuer/src/js/genome_viewer.js index 4f2c76327215287816b1082876ac8b094c2aa4df..6f896c039b41db5c52eb03ed80109fce20ca9596 100644 --- a/genome-vuer/src/js/genome_viewer.js +++ b/genome-vuer/src/js/genome_viewer.js @@ -1,23 +1,24 @@ Vue.component("genome-viewer",{ template: `
-
+ - - - - - - - - - + --> + + + + + + + + + + +
`, props: { genomeStats: { @@ -41,11 +42,144 @@ Vue.component("genome-viewer",{ return true } } - } + }, + defaultColor: { + default: "#000000" + }, + defaultBorderColor: { + default: "#000000" + }, + colorMap: { + default: function(){ + return { + 'region':'#bdbdbd', // greyLighten + 'gene':'#757575', // greyDarken + 'cds': '#000000', // black + 'rRNA': '#795548', // brown + 'tRNA': '#4caf50', // green + 'ncRNA': '#ff9800' // orange + } + } + }, + }, + computed:{ + stops(){ + return this.featureData.map(f => f.end) + }, + starts(){ + return this.featureData.map(f => f.start) + }, + genomeStart(){ + return Math.min(...this.starts) + }, + genomeStop(){ + return Math.max(...this.stops) + }, + axisStart(){ + return this.genomeStart - this.tickSize + }, + axisStop(){ + return this.genomeStop + this.tickSize + }, + genome_size(){}, + length(){ + if(this.genomeStats.start < this.genomeStats.end){ + return this.genomeStop - this.genomeStart + }else{ + // TODO: if genome is circular + } + }, + one_height(){ + return this.height/(1 + 2 * this.lanes.length) + }, + tickSize(){ + return Math.pow(10,Math.floor(Math.log10(this.length))-1) + }, + }, + mounted() { + var svg_el = this.$refs.genomeVuer.getBoundingClientRect() + this.width = svg_el.width + this.height = svg_el.height + //this.height / length([axis and lanes * 2]) + // lanes are twize as big as the axis + // so height / (1 + no_of_lanes * 2) + //var one_height = this.svg_size[1]/(1 + 2 * this.lanes.length) + //let svg_el = this.$refs.genomeVuer.getBoundingClientRect() + //console.log(svg_el) + ////console.log(svg_el) + //this.width = svg_el.width + //this.height = svg_el.height + ////return [svg_el.clientWidth, svg_el.clientHeight] + //this.one_height = this.height/(1 + 2 * this.lanes.length) + + }, + methods:{ + getColor(feature){ + if(feature.hasOwnProperty("color")){ + return feature.color + }else{ + if(feature.hasOwnProperty("type")){ + if(this.colorMap.hasOwnProperty(feature.type)){ + return this.colorMap[feature.type] + }else{ + return this.defaultColor + } + }else { + return this.defaultColor + } + } + }, + lane(str){ + return (str=="+")? 1 : -1 + }, + to_h(param){ + //param is a value between -n and +n, where n is the number of lanes divided by 2 + //if param is 0 => axis + //if param < 0 => lane on top + //if param > 0 => lane on bottom + let zero = this.lanes.length * this.one_height + if(param < 0){ + return zero + 2 * this.one_height * (param) + }else if(param > 0){ + return zero + this.one_height * (param) + } + return zero + }, + to_w(param){ + //param is a value between 0 and 100, where 100 is the full length of the svg + return (this.width*param)/100 + }, + genomeToPixel(pos){ + return (this.width*(pos - (this.axisStart)))/(this.length+2*this.tickSize) + }, + featureClick (featureId) { + console.log(featureId) + }, + fill_in_tooltip_template (feature, template) { + let tooltip = template + //TODO: Iterate over custom properties + for ( let property of ['name', 'description', 'start', 'end', 'strand', 'type'] ){ + tooltip = tooltip.replace( "{" + property + "}", feature[property] ) + } + return( tooltip ) + }, + get_tooltip (e){ + let element = e.currentTarget + let id = element.getAttribute( "name" ) + let feature = null + for(let entry of this.featureData){ + if(entry.name === id){ + feature = entry + } + } + console.log( this.fill_in_tooltip_template( feature, this.genomeStats.tooltip ) ) + }, }, data: function(){ return { - lanes: [-1, 1] + lanes: [-1, 1], + width: 0, + height: 0 } }, }) diff --git a/genome-vuer/src/js/lane.js b/genome-vuer/src/js/lane.js index d137cfd4dafe564f2f5f81190bb3460e563dce2f..46a2cd22b12af699ffcc1330ce2455cd7fa33597 100644 --- a/genome-vuer/src/js/lane.js +++ b/genome-vuer/src/js/lane.js @@ -1,21 +1,31 @@ Vue.component("lane",{ template: ` -
- TODO: im the lane component -
+ + + `, props: { - todoprop1: { + x: { validator (value) { return true } }, - todoprop2: { + y: { validator (value) { return true } - } + }, + height: { + validator (value) { + return true + } + }, + width: { + validator (value) { + return true + } + }, }, methods: { my_method(){ @@ -24,9 +34,18 @@ Vue.component("lane",{ }, }, computed: { - Todo(){ - return this.todo.charAt(0).toUpperCase() + this.todo.substr(1); - }, +// y() { +// return y; +// }, +// x() { +// return lib.map(0, this.o.xMin, this.o.xMax, 0, this.svg.w); +// }, +// tickXs() { +// const ticks = lib.range(this.o.xMin, this.o.xMax, 10) +// return ticks.map(tick => +// lib.map(tick, this.o.xMin, this.o.xMax, 0, this.svg.w) +// ); +// }, }, data: function(){ return {