d3-flame-graph
Version:
A d3.js library to produce flame graphs.
127 lines (110 loc) • 4.3 kB
JavaScript
import { select } from 'd3-selection'
import flamegraph from '../../flamegraph'
import { generateColorVector } from '../../colorUtils'
import { calculateColor } from '../../colorScheme'
import '../../flamegraph.css'
import './template.css'
class FlameGraphUI {
constructor (stacks, options) {
this.stacks = stacks || { name: 'Stacks were not loaded.', value: 0, children: [] }
this.options = options || {}
if (!this.options.context || this.options.context === '') {
this.options.context = 'No context information available.'
}
this.context = document.getElementById('context')
this.chart = document.getElementById('chart')
this.details = document.getElementById('details')
this.contextBtn = document.getElementById('context-button')
this.resetBtn = document.getElementById('reset-button')
this.clearBtn = document.getElementById('clear-button')
this.searchForm = document.getElementById('search-form')
this.searchInput = document.getElementById('search-input')
}
handleSearch () {
if (this.searchInput.value === '') {
this.flameGraph.clear()
} else {
this.flameGraph.search(this.searchInput.value)
}
}
toggleContextInfo () {
if (this.context.style.display === 'none') {
this.chart.style.display = 'none'
this.context.style.display = 'block'
} else {
this.context.style.display = 'none'
this.chart.style.display = 'block'
}
}
handleResetZoom () {
this.flameGraph.resetZoom()
}
handleClear () {
this.searchInput.value = ''
this.flameGraph.clear()
}
handleWindowResize () {
var width = this.chart.clientWidth
var graphs = document.getElementsByClassName('d3-flame-graph')
if (graphs.length > 0) {
graphs[0].setAttribute('width', width)
}
this.flameGraph.width(width)
this.flameGraph.resetZoom()
}
sortByValue (lhs, rhs) {
if (lhs.value === rhs.value) return 0
if (lhs.value < rhs.value) return 1
return -1
}
colorSchemeColorMapper (getName, getLibtype, d, originalColor) {
if (d.highlight) {
return '#E600E6' // purple
} else if (this.options.colorscheme === 'blue-green') {
const name = getName(d)
const libtype = getLibtype(d)
const vector = generateColorVector(name)
if (libtype === 'root') {
return 'rgb(217,75,75)'
} else if (libtype === 'kernel') {
return calculateColor('blue', vector)
} else { // userspace
return calculateColor('pastelgreen', vector)
}
} else {
return originalColor
}
}
init () {
this.flameGraph = flamegraph()
.width(this.chart.clientWidth)
.cellHeight(16)
.minFrameSize(5)
.sort(this.sortByValue)
.selfValue(true)
.resetHeightOnZoom(true)
.scrollOnZoom(true)
.setDetailsElement(this.details)
const getNameFn = this.flameGraph.getName()
const getLibtypeFn = this.flameGraph.getLibtype()
this.flameGraph.setColorMapper(this.colorSchemeColorMapper.bind(this, getNameFn, getLibtypeFn))
this.contextBtn.addEventListener('click', this.toggleContextInfo.bind(this))
this.resetBtn.addEventListener('click', this.handleResetZoom.bind(this))
this.clearBtn.addEventListener('click', this.handleClear.bind(this))
this.searchForm.addEventListener('submit', (event) => {
event.preventDefault()
this.handleSearch()
})
this.searchInput.addEventListener('blur', this.handleSearch.bind(this))
window.addEventListener('resize', this.handleWindowResize.bind(this), true)
this.context.textContent = this.options.context
this.details.textContent = ''
select(this.chart)
.datum(this.stacks)
.call(this.flameGraph)
}
}
window.flamegraph = (stacks, options) => {
const ui = new FlameGraphUI(stacks, options)
ui.init()
}