Skip to content

Instantly share code, notes, and snippets.

@tgotwig
Last active December 5, 2017 22:59
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tgotwig/4536d70352fc1149b437f78f61361763 to your computer and use it in GitHub Desktop.
Save tgotwig/4536d70352fc1149b437f78f61361763 to your computer and use it in GitHub Desktop.
Arrows (+tooltip)
<!DOCTYPE html>
<meta charset="utf-8">
<svg width="960" height="500"
></svg>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script src="https://unpkg.com/tippy.js@2.0.2/dist/tippy.all.min.js"></script>
<link href="https://fonts.googleapis.com/css?family=Roboto+Mono" rel="stylesheet">
<script>
;(function (window, d3) {
document.addEventListener("DOMContentLoaded", function(event) {
window.draw = draw
})
let draw = (data, selector) => {
const svg = d3.select('svg')
const margin = {top: 20, right: 0, bottom: 30, left: 40}
const height = +svg.attr('height') - margin.top - margin.bottom
const width = +svg.attr('width') - margin.left - margin.right
// bar colors
const getTypeColor = function (type) {
switch (type) {
case 'feature': return 'gold'
case 'gene': return '#bdbdbd' // greyLighten
case 'cds': return '#757575' // greyDarken
case 'rrna': return '#795548' // brown
case 'trna': return '#4caf50' // green
case 'ncrna': return '#ff9800' // orange
default: return -1
}
}
// bar constants
const barHeight = height * 0.7
const peakWidth = 10
const peakMid = barHeight * 0.5
const opacity = 0.6
// x setup
const xScale = d3.scaleLinear()
.domain([data.start, data.end])
.range([0, width])
const xAxis = d3.axisBottom(xScale)
svg
.attr('width', width + margin.left + margin.right) // width + 2x padding
.attr('height', height + margin.top + margin.bottom) // height + 2x padding
.append('g')
.attr('transform', `translate(${margin.left}, ${margin.top})`)
// x axis
svg.append('g')
.attr('transform', 'translate(0,' + height + ')')
.call(xAxis)
const lineGenerator = d3.line()
svg.selectAll('.arrow')
.data(data.features)
.enter()
.append('path')
.attr('class', 'arrow')
.attr('title', d => `<div style="text-align: left; font-family: 'Roboto Mono', monospace;">
<b>name</b> ${'&nbsp;'.repeat(2)}${d.name}<br>
<b>start</b> ${'&nbsp;'.repeat(1)}${d.start}<br>
<b>end</b> ${'&nbsp;'.repeat(3)}${d.end}<br>
</div>`)
.attr('data-placement', 'bottom')
.attr('d', d => {
if (d.type === 'feature' && (d.strand === 1 || d.strand === -1)) { // draw bar
const points = [
[xScale(d.start), 0],
[xScale(d.end), 0],
[xScale(d.end), barHeight],
[xScale(d.start), barHeight]
]
return lineGenerator(points)
} else if (d.strand === 1 && getTypeColor(d.type) !== -1) { // draw right arrow
if (xScale(d.end) - xScale(d.start) <= peakWidth) {
const points = [
[xScale(d.start), 0],
[xScale(d.end), peakMid],
[xScale(d.start), barHeight]
]
return lineGenerator(points)
} else {
const points = [
[xScale(d.start), 0],
[xScale(d.end) - peakWidth, 0],
[xScale(d.end), peakMid],
[xScale(d.end) - peakWidth, barHeight],
[xScale(d.start), barHeight]
]
return lineGenerator(points)
}
} else if (d.strand === -1 && getTypeColor(d.type) !== -1) { // draw left arrow
if (xScale(d.end) - xScale(d.start) <= peakWidth) {
console.log(true)
const points = [
[xScale(d.end), 0],
[xScale(d.start), peakMid],
[xScale(d.end), barHeight]
]
return lineGenerator(points)
} else {
const points = [
[xScale(d.start), peakMid],
[xScale(d.start) + peakWidth, 0],
[xScale(d.end), 0],
[xScale(d.end), barHeight],
[xScale(d.start) + peakWidth, barHeight]
]
return lineGenerator(points)
}
} else console.log(`unknown type: "` + d.type + `" or unknown strand: "` + d.strand + `"`) // error
})
.style('fill', d => {
return getTypeColor(d.type)
})
.style('opacity', opacity)
.on('mouseover', function (element) {
this.style.opacity = 1
})
.on('mouseout', function (element) {
this.style.opacity = opacity
})
}
const data = {
'start': 1000,
'end': 20100,
'features': [
{
'name': 'A',
'desc': 'xyz in detail.',
'start': 1000,
'end': 1900,
'strand': 1,
'type': 'feature'
},
{
'name': 'B',
'desc': 'xyz in detail.',
'start': 2000,
'end': 2100,
'strand': 1,
'type': 'gene'
},
{
'name': 'C',
'desc': 'xyz in detail.',
'start': 2500,
'end': 6500,
'strand': 1,
'type': 'cds'
},
{
'name': 'D',
'desc': 'mitf',
'start': 7000,
'end': 9000,
'strand': -1,
'type': 'rrna'
},
{
'name': 'E',
'desc': 'mitf',
'start': 9000,
'end': 13000,
'strand': -1,
'type': 'trna'
},
{
'name': 'F',
'desc': 'mitf',
'start': 14000,
'end': 20000,
'strand': 1,
'type': 'ncrna'
}
]
}
draw(data, 'svg')
tippy('[title]', {
performance: true,
arrow: true,
size: 'large',
animation: 'scale',
})
}(window, window.d3))
</script>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment