Skip to content

Commit

Permalink
explorer charts: refactor legend formatting
Browse files Browse the repository at this point in the history
  • Loading branch information
buck54321 authored and chappjc committed Nov 9, 2019
1 parent 43a63cf commit 0ff66ea
Show file tree
Hide file tree
Showing 3 changed files with 102 additions and 104 deletions.
156 changes: 73 additions & 83 deletions public/js/controllers/charts_controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,12 @@ const windowScales = ['ticket-price', 'pow-difficulty', 'missed-votes']
const lineScales = ['ticket-price']
// index 0 represents y1 and 1 represents y2 axes.
const yValueRanges = { 'ticket-price': [1] }
var chainworkUnits = ['exahash', 'zettahash', 'yottahash']
var hashrateUnits = ['Th/s', 'Ph/s', 'Eh/s']
var ticketPoolSizeTarget, premine, stakeValHeight, stakeShare
var baseSubsidy, subsidyInterval, subsidyExponent, windowSize, avgBlockTime
var rawCoinSupply, rawPoolValue
var yFormatter, legendEntry, legendMarker, legendElement

function usesWindowUnits (chart) {
return windowScales.indexOf(chart) > -1
Expand Down Expand Up @@ -57,20 +60,9 @@ function axesToRestoreYRange (chartName, origYRange, newYRange) {
return axes
}

function formatHashRate (value, displayType) {
value = parseInt(value)
if (value <= 0) return value
var shortUnits = ['Th', 'Ph', 'Eh']
var labelUnits = ['terahash/s', 'petahash/s', 'exahash/s']
for (var i = 0; i < labelUnits.length; i++) {
var quo = Math.pow(1000, i)
var max = Math.pow(1000, i + 1)
if ((value > quo && value <= max) || i + 1 === labelUnits.length) {
var data = intComma(Math.floor(value / quo))
if (displayType === 'axis') return data + '' + shortUnits[i]
return data + ' ' + labelUnits[i]
}
}
function withBigUnits (v, units) {
var i = v === 0 ? 0 : Math.floor(Math.log10(v) / 3)
return (v / Math.pow(1000, i)).toFixed(3) + ' ' + units[i]
}

function blockReward (height) {
Expand All @@ -80,74 +72,30 @@ function blockReward (height) {
return 0
}

function legendFormatter (data) {
var html = ''
if (data.x == null) {
let dashLabels = data.series.reduce((nodes, series) => {
return `${nodes} <div class="pr-2">${series.dashHTML} ${series.labelHTML}</div>`
}, '')
html = `<div class="d-flex flex-wrap justify-content-center align-items-center">
<div class="pr-3">${this.getLabels()[0]}: N/A</div>
<div class="d-flex flex-wrap">${dashLabels}</div>
</div>`
} else {
var i = data.dygraph.getOption('legendIndex')
var extraHTML = ''
// The circulation chart has an additional legend entry showing percent
// difference.
if (data.series.length === 2 && data.series[0].label.toLowerCase().includes('coin supply')) {
let inflation = data.dygraph.getOption('inflation')
if (i < inflation.length) {
let actual = data.series[0].y
let predicted = inflation[i]
let unminted = predicted - actual
let change = ((unminted / predicted) * 100).toFixed(2)
extraHTML = `<div class="pr-2">&nbsp;&nbsp;Unminted: ${intComma(unminted)} DCR (${change}%)</div>`
}
}

let yVals = data.series.reduce((nodes, series) => {
if (!series.isVisible) return nodes
let yVal = series.yHTML
switch (series.label.toLowerCase()) {
case 'ticket pool value':
case 'inflation limit':
case 'coin supply':
yVal = intComma(series.y) + ' DCR'
break

case 'total fee':
case 'ticket price':
yVal = series.y + ' DCR'
break

case 'hashrate':
yVal = formatHashRate(series.y)
break

case 'stake participation':
yVal = series.y.toFixed(4) + '%'
break
}
let result = `${nodes} <div class="pr-2">${series.dashHTML} ${series.labelHTML}: ${yVal}</div>`
function addLegendEntryFmt (div, series, fmt) {
div.appendChild(legendEntry(`${series.dashHTML} ${series.labelHTML}: ${fmt(series.y)}`))
}

if (series.label.toLowerCase() === 'stake participation' && rawCoinSupply.length === rawPoolValue.length &&
rawPoolValue.length !== 0 && i !== null) {
result += `<div class="pr-2"><div class="dygraph-legend-line"></div> Ticket Pool Value: ${intComma(rawPoolValue[i])} DCR</div>
<div class="pr-2"><div class="dygraph-legend-line"></div> Coin Supply: ${intComma(rawCoinSupply[i])} DCR</div>`
}
function addLegendEntry (div, series) {
div.appendChild(legendEntry(`${series.dashHTML} ${series.labelHTML}: ${series.yHTML}`))
}

return result
}, '')
function defaultYFormatter (div, data) {
addLegendEntry(div, data.series[0])
}

html = `<div class="d-flex flex-wrap justify-content-center align-items-center">
<div class="pr-3">${this.getLabels()[0]}: ${data.xHTML}</div>
<div class="d-flex flex-wrap"> ${yVals}</div>
</div>${extraHTML}`
}
function customYFormatter (fmt) {
return (div, data) => addLegendEntryFmt(div, data.series[0], fmt)
}

dompurify.sanitize(html, { FORBID_TAGS: ['svg', 'math'] })
return html
function legendFormatter (data) {
if (data.x == null) return legendElement.classList.add('d-hide')
legendElement.classList.remove('d-hide')
var div = document.createElement('div')
div.appendChild(legendEntry(`${data.dygraph.getLabels()[0]}: ${data.xHTML}`))
yFormatter(div, data, data.dygraph.getOption('legendIndex'))
dompurify.sanitize(div, { IN_PLACE: true, FORBID_TAGS: ['svg', 'math'] })
return div.innerHTML
}

function nightModeOptions (nightModeOn) {
Expand Down Expand Up @@ -349,7 +297,9 @@ export default class extends Controller {
'ticketsPurchase',
'ticketsPrice',
'vSelector',
'binSize'
'binSize',
'legendEntry',
'legendMarker'
]
}

Expand All @@ -364,6 +314,25 @@ export default class extends Controller {
subsidyExponent = parseFloat(this.data.get('mulSubsidy')) / parseFloat(this.data.get('divSubsidy'))
windowSize = parseInt(this.data.get('windowSize'))
avgBlockTime = parseInt(this.data.get('blockTime')) * 1000
legendElement = this.labelsTarget

// Prepare the legend element generators.
var lm = this.legendMarkerTarget
lm.remove()
lm.removeAttribute('data-target')
legendMarker = () => {
let node = document.createElement('div')
node.appendChild(lm.cloneNode())
return node.innerHTML
}
var le = this.legendEntryTarget
le.remove()
le.removeAttribute('data-target')
legendEntry = s => {
let node = le.cloneNode()
node.innerHTML = s
return node
}

this.settings = TurboQuery.nullTemplate(['chart', 'zoom', 'scale', 'bin', 'axis'])
this.query.update(this.settings)
Expand Down Expand Up @@ -405,7 +374,7 @@ export default class extends Controller {
pointSize: 0.25,
legend: 'always',
labelsSeparateLines: true,
labelsDiv: this.labelsTarget,
labelsDiv: legendElement,
legendFormatter: legendFormatter,
highlightCircleSize: 4,
ylabel: 'Ticket Price',
Expand Down Expand Up @@ -449,6 +418,7 @@ export default class extends Controller {
}
rawPoolValue = []
rawCoinSupply = []
yFormatter = defaultYFormatter
var xlabel = data.t ? 'Date' : 'Block Height'

switch (chartName) {
Expand All @@ -465,6 +435,7 @@ export default class extends Controller {
valueRange: [0, windowSize * 20 * 8],
axisLabelFormatter: (y) => Math.round(y)
}
yFormatter = customYFormatter(y => y.toFixed(8) + ' DCR')
break

case 'ticket-pool-size': // pool size graph
Expand All @@ -479,18 +450,25 @@ export default class extends Controller {
color: '#888'
}
}
yFormatter = customYFormatter(y => `${intComma(y)} tickets &nbsp;&nbsp; (network target ${intComma(ticketPoolSizeTarget)})`)
break

case 'stake-participation':
d = percentStakedFunc(data)
assign(gOptions, mapDygraphOptions(d, [xlabel, 'Stake Participation'], true,
'Stake Participation (%)', true, false))
yFormatter = (div, data, i) => {
addLegendEntryFmt(div, data.series[0], y => y.toFixed(4) + '%')
div.appendChild(legendEntry(`${legendMarker()} Ticket Pool Value: ${intComma(rawPoolValue[i])} DCR`))
div.appendChild(legendEntry(`${legendMarker()} Coin Supply: ${intComma(rawCoinSupply[i])} DCR`))
}
break

case 'ticket-pool-value': // pool value graph
d = zip2D(data, data.poolval, atomsToDCR)
assign(gOptions, mapDygraphOptions(d, [xlabel, 'Ticket Pool Value'], true,
'Ticket Pool Value (DCR)', true, false))
yFormatter = customYFormatter(y => intComma(y) + ' DCR')
break

case 'block-size': // block size graph
Expand Down Expand Up @@ -527,6 +505,16 @@ export default class extends Controller {
}
}
gOptions.inflation = d.inflation
yFormatter = (div, data, i) => {
addLegendEntryFmt(div, data.series[0], y => intComma(y) + ' DCR')
var change = 0
if (i < d.inflation.length) {
let predicted = d.inflation[i]
let unminted = predicted - data.series[0].y
change = ((unminted / predicted) * 100).toFixed(2)
div.appendChild(legendEntry(`${legendMarker()} Unminted: ${intComma(unminted)} DCR (${change}%)`))
}
}
break

case 'fees': // block fee graph
Expand All @@ -544,12 +532,14 @@ export default class extends Controller {
d = zip2D(data, data.work)
assign(gOptions, mapDygraphOptions(d, [xlabel, 'Cumulative Chainwork (exahash)'],
false, 'Cumulative Chainwork (exahash)', true, false))
yFormatter = customYFormatter(y => withBigUnits(y, chainworkUnits))
break

case 'hashrate': // Total chainwork over time
d = zip2D(data, data.rate, 1, data.offset)
assign(gOptions, mapDygraphOptions(d, [xlabel, 'Network Hashrate (terahash/s)'],
false, 'Network Hashrate (terahash/s)', true, false))
d = zip2D(data, data.rate, 1e-3, data.offset)
assign(gOptions, mapDygraphOptions(d, [xlabel, 'Network Hashrate (petahash/s)'],
false, 'Network Hashrate (petahash/s)', true, false))
yFormatter = customYFormatter(y => withBigUnits(y * 1e3, hashrateUnits))
break

case 'missed-votes':
Expand Down
40 changes: 23 additions & 17 deletions public/scss/charts.scss
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,28 @@
transform: rotate(-90deg);
}

.chartview {
width: 96%;
min-height: 73vh;
margin: 0 2%;
}

.chartview .dygraph-ylabel {
color: #2970ff;
}

body.darkBG .chartview .dygraph-ylabel {
color: #2dd8a3;
}

.chartview .dygraph-y2label {
color: #066;
}

body.darkBG .chartview .dygraph-y2label {
color: #2970ff;
}

#tickets_by_purchase_date .dygraph-ylabel {
color: #2971ff;
font-weight: bold;
Expand Down Expand Up @@ -349,7 +371,7 @@
.legend {
background: #ececec;
z-index: 10000;
padding: 0 2px 0 5px;
padding: 5px 10px 5px 20px;
font-size: 14px;
}

Expand Down Expand Up @@ -454,22 +476,6 @@ body.darkBG .customcheck input:checked ~ .tickets-bought {
background-color: #2970ff;
}

#chart .dygraph-ylabel {
color: #2970ff;
}

body.darkBG #chart .dygraph-ylabel {
color: #2dd8a3;
}

#chart .dygraph-y2label {
color: #066;
}

body.darkBG #chart .dygraph-y2label {
color: #2970ff;
}

.checkmark::after {
content: "";
position: absolute;
Expand Down
10 changes: 6 additions & 4 deletions views/charts.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -195,9 +195,9 @@


<div data-target="charts.chartWrapper" class="chart-wrapper pl-2 pr-2 mb-5">
<div id="chart"
data-target="charts.chartsView"
style="width:100%; height:73vh; margin:0 auto;">
<div
class="chartview"
data-target="charts.chartsView">
</div>
<div class="d-flex flex-wrap justify-content-center align-items-center mb-1 mt-1">
<div class="chart-control chart-control-wrapper">
Expand Down Expand Up @@ -231,7 +231,9 @@
</div>
</div>
<div class="d-flex justify-content-center legend-wrapper">
<div class="legend d-flex" data-target="charts.labels"></div>
<div class="legend d-flex align-items-center" data-target="charts.labels">
<div class="pr-3" data-target="charts.legendEntry"><div class="dygraph-legend-line" data-target="charts.legendMarker"></div></div>
</div>
</div>
</div>

Expand Down

0 comments on commit 0ff66ea

Please sign in to comment.