-
-
Notifications
You must be signed in to change notification settings - Fork 16
/
main.coffee
139 lines (124 loc) · 5.13 KB
/
main.coffee
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
currencies =
btc: new BTC()
eth: new ETH()
ltc: new LTC()
xrp: new XRP()
nano: new NANO()
prices = {}
stats = {}
currencyFormat =
style: 'currency'
currency: 'USD'
minimumFractionDigits: 0
maximumFractionDigits:0
# render TX
showTx = (engine, currency, tx) ->
value = tx.amount * (prices[currency] or 1)
fee = tx.fee * (prices[currency] or 1)
engine.addMeteor
speed: if fee then 2 + 4 * Math.min(2, Math.log10(1+fee))/2 else 6
hue: if value then 220 - 220 * Math.min(6, Math.log10(1+value))/6 else 220
thickness: Math.max(5, Math.log10(1+value) * 10)
length: Math.min(3, Math.log10(1 + fee))/3 * 250
link: tx.link
donation: tx.donation
updateStats currency, value, fee
# render block
showBlock = (engine, currency, block) ->
engine.addBlock Math.min(250, block.count / 4)
stats[currency].count = Math.max(0, stats[currency].count - block.count) if stats[currency]?
# get current price
updatePrices = (currencies) ->
currencyAPI = 'https://min-api.cryptocompare.com/data/price?fsym=USD&tsyms='
$.get currencyAPI + currencies.join(',').toUpperCase(), (data) ->
if data
for currency, price of data
currency = currency.toLowerCase()
prices[currency] = Math.round(1/price*100)/100
$(".#{currency} .price").text prices[currency].toLocaleString(undefined, { style: 'currency', currency: 'USD' })
marketcapAPI = 'https://api.coinlore.com/api/global/'
$.get marketcapAPI, (data) ->
if data
$(".marketcap").text JSON.parse(data)[0].total_mcap.toLocaleString(undefined, currencyFormat)
setTimeout updatePrices.bind(null, currencies), 10*1000
# update stats for a currency, called whenever there is a new TX
# to do that, keep a log of the last 60 seconds of tx
updateStats = (currency, value = 0, fee = 0) ->
stats[currency] = {last: [], count: 0} unless stats[currency]?
# increase number of unverified TX
stats[currency].count++ unless currencies[currency].noBlocks
# calculate stats for last 60s
last = stats[currency].last
timestamp = new Date().getTime()
last.push {timestamp, value, fee}
i = last.length
last.splice(i, 1) while i-- when timestamp - last[i].timestamp > 60*1000
duration = Math.max(last[last.length - 1].timestamp - last[0].timestamp, 1) / 1000
txPerSecond = Math.round(last.length / duration * 10)/10
#valuePerSecond = Math.round(stat.reduce(((a, b) -> a + b.value), 0) / duration)
valuePerTx = Math.round(last.reduce(((a, b) -> a + b.value), 0) / last.length)
#feePerSecond = Math.round(stat.reduce(((a, b) -> a + b.fee), 0) / duration * 100)/100
feePerTx = Math.round(last.reduce(((a, b) -> a + b.fee), 0) / last.length * 100)/100
$(".#{currency} .stats").text """
#{txPerSecond.toLocaleString()} tx/s (#{stats[currency].count} unconfirmed)
#{valuePerTx.toLocaleString(undefined, currencyFormat)} value/tx
#{feePerTx.toLocaleString(undefined, { style: 'currency', currency: 'USD' })} fee/tx
"""
# set up a lane
initialize = (currency) ->
if currencies[currency]? and $(".#{currency}")
container = $(".#{currency}")
container.css 'background-image', "url('img/#{currency}.png')"
container.find("canvas").remove()
canvas = $ '<canvas></canvas>'
container.append canvas
engine = new CanvasRenderer canvas.get(0)
canvas.data 'engine', engine
engine.start() if container.is ':visible'
currencies[currency].start showTx.bind(null, engine, currency), showBlock.bind(null, engine, currency)
# donation links
if currencies[currency].donationAddress
container.find('.donate').on 'click', =>
$('.overlay .donation').show().siblings().hide()
$('.overlay').fadeToggle()
.find('.address').text currencies[currency].donationAddress
.end().find('.donation img').attr 'src', "img/#{currency}-qr.png"
else
container.find('.donate').remove()
# update lane rendering (for resizing and lane toggling
updateLanes = ->
$(".currencies > div").each ->
container = $(@)
engine = container.find('canvas').data 'engine'
if container.is ':visible'
engine.resize container.find('canvas').get(0)
engine.start()
else
engine.stop()
showHelp = ->
$('.overlay .help').show().siblings().hide()
$('.overlay').fadeIn()
# start everything
$ ->
# load prices
updatePrices Object.keys(currencies)
# set up overlay
$('.overlay').on 'click', (e) ->
if $('.overlay .help').is(':visible') # don't show help at the beginning after closing
document.cookie = "nohelp=true; expires=#{new Date(Date.now()+1000*60*60*24*365).toString()}; path=/"
$(this).fadeOut() if $(e.target).is('.overlay, .help')
$('.overlay').hide() if !!document.cookie.match(/nohelp/) or !!location.hash.match(/nohelp/i)
$('nav').hide() if !!location.hash.match(/nohelp/i)
# initialize coins
$('.currencies > div').each -> initialize $(@).attr 'class'
# listen to resizing
$(window).resize updateLanes
# set up nav
$ 'nav'
.on 'click', '.help', showHelp
.on 'click', '.right', ->
$(".currencies").append($(".currencies > div").first())
updateLanes()
.on 'click', '.left', ->
$(".currencies").prepend($(".currencies > div").last())
updateLanes()