bitcoin-liveblock/js/liveblock.js

342 lines
9.0 KiB
JavaScript
Raw Permalink Normal View History

2018-01-04 15:24:35 -06:00
var graphics = Viva.Graph.View.webglGraphics();
var isWebgl = graphics.isSupported();
if (!isWebgl) {
alert("Turn on webgl or use modern browser");
}
var graph = Viva.Graph.graph(),
layout = Viva.Graph.Layout.forceDirected(graph, {
springLength : 80,
springCoeff : 0.0002,
dragCoeff : 0.009,
gravity : -30,
theta : 0.7
}),
minNodeSize = 0.1,
maxNodeSize = 100,
txCount1=0,
txCount10=0,
txCount50=0,
txCount100=0,
txCount1000=0,
totalBTC=0;
function log10(val) {
return Math.log(val) / Math.LN10;
}
function log2(val) {
return Math.log(val) / Math.LN2;
}
var scaleType = "LOG"; // LINEAR
var getNodeColor = function(node) {
// here different colors for tx, input, output, mixed and txconfirmed
if(node.data && node.data.t && node.data.t == "i"){
return 0x00FF00;
}else if(node.data && node.data.t && node.data.t == "o"){
return 0xFF0000;
}
return 0x008ED2;
},
getNodeSize = function(node){
if(! node.data || !node.data.s){
return 25;
}
var rmin = 20;
var rmax = 96;
// linear normalization to a range rmin,rmax
if(scaleType == "LINEAR"){
return rmin + (rmax - rmin) * ( (node.data.s - minNodeSize)/(maxNodeSize - minNodeSize) ) ;
}else{
// log normalization to a range rmin,rmax
var min = log2(minNodeSize);
var max = log2(maxNodeSize);
var val = log2( node.data.s );
// linear scaling from min.max -> rmin rmax
return rmin + (rmax - rmin) * ( (val - min)/(max - min) ) ;
}
},
getNodeDetails = function(node){
//
// http://blockchain.info/rawtx/$tx_index?format=json
var label = "transaction";
var id = node.id;
if(node.data && node.data.t){
if(node.data.t == "i"){
// input node
label = "input";
}else if(node.data.t == "o"){
// output node
label = "output";
}else if(node.data.t == "io"){
// node which is both input and output
label = "input to output";
}
else if(node.data.t == "oi"){
// node which is both input and output
label = "output to input";
}
// for addresses infor cors not enabled :-(
// enabled for blocks
var balance = 0;
balance=node.data.s;
//lets get balance
document.getElementById("info").innerHTML = label+"<br/>"+id+"<br/>balance: "+balance +" BTC";
}else{
// transaction node
document.getElementById("info").innerHTML = label+"<br/>"+id;
}
};
// need to get these 2 from yavis.reddit.min.js
graphics.setLinkProgram(Viva.Graph.View.webglDualColorLinkProgram());
graphics.setNodeProgram(Viva.Graph.View.webglCustomNodeProgram());
graphics
.node(function(node){
var img = Viva.Graph.View.webglSquare(getNodeSize(node), getNodeColor(node));
return img;
})
.link(function(link){
var fromColor, toColor;
fromColor = toColor = 0x808080;
var line = Viva.Graph.View.webglDualColorLine(fromColor, toColor);
line.oldStart = fromColor;
line.oldEnd = toColor;
return line;
});
var renderer = Viva.Graph.View.renderer(graph,{
layout : layout,
graphics : graphics,
container : document.getElementById('g')
//prerender : 10
});
var events = Viva.Graph.webglInputEvents(graphics, graph),
lastHovered = null,
colorLinks = function(node, color) {
if (node && node.id) {
graph.forEachLinkedNode(node.id, function(node, link){
if (color) {
link.ui.start = link.ui.end = color;
} else {
//link.ui.start = link.ui.oldStart;
//link.ui.end =link.ui.oldEnd;
link.ui.start = link.ui.end = 0x80808040;
}
});
}
};
events.mouseEnter(function(node){
getNodeDetails(node);
colorLinks(lastHovered);
lastHovered = node;
graph.forEachLinkedNode(node.id, function(node, link){
link.ui.start = link.ui.end = 0xffffffff;
graphics.bringLinkToFront(link.ui);
});
renderer.rerender();
}).mouseLeave(function(node) {
colorLinks(lastHovered);
lastHovered = null;
colorLinks(node);
renderer.rerender();
});
// pause rendere on spacebar
var paused = false;
$(window).keydown(function(e) {
if (e.keyCode === 32) { // toggle on spacebar;
e.preventDefault();
paused = !paused;
if (paused) { renderer.pause(); }
else { renderer.resume(); }
}
});
var width = $("#g").width(),
height= $("#g").height();
renderer.run();
graphics.scale(0.15, {x : width/2, y : height/2});
// websockets part
var linksBuffer = [];
var wsUri = "wss://ws.blockchain.info/inv";
if (document.location.protocol.indexOf("https") === 0) {
wsUri = "wss://ws.blockchain.info/inv";
}
var output;
function init() {
output = document.getElementById("output");
testWebSocket();
}
var colorNodes = function(node, color) {
if (node && node.id) {
graph.forEachNode(function(node){
if (color) {
node.ui.color = color;
}
});
}
};
function addNodes(link){
if(link.t == "i"){
var node = graph.getNode(link.from);
if( !node ){
graph.addNode(link.from,{s:link.value,t:link.t});
} else {
// such a node already exists
if(node.data && node.data.t && node.data.t == "o" ){
node.data.t = "io";
node.ui.color = 0xFFFFFF;
renderer.rerender();
}
}
} else if(link.t == "o"){
var node = graph.getNode(link.to);
if( ! node){
graph.addNode(link.to,{s:link.value,t:link.t});
} else {
// such a node alredy exists.
if(node.data && node.data.t && node.data.t == "i"){
node.data.t = "oi";
node.ui.color = 0x9932CC;
renderer.rerender();
}
}
}
}
function testWebSocket() {
websocket = new WebSocket(wsUri);
websocket.onopen = function(evt) { onOpen(evt) };
websocket.onclose = function(evt) { onClose(evt) };
websocket.onmessage = function(evt) { onMessage(evt) };
websocket.onerror = function(evt) { onError(evt) }; }
function onOpen(evt) {
writeToScreen("CONNECTED");
doSend({"op":"unconfirmed_sub"});
}
function onClose(evt) { writeToScreen("DISCONNECTED"); }
function onMessage(evt) {
// parse message
var msg = JSON.parse(evt.data);
var txHash = msg.x.hash;
if(msg.op == "utx"){
// uncorfimed transactions
var inputs = msg.x.inputs;
var outputs = msg.x.out;
// generate from to
var links = [];
var txValue=0;
for(var i=0;i<inputs.length;i++){
var input = inputs[i];
links.push({
from: input.prev_out.addr,
to: txHash,
value: input.prev_out.value/100000000,
t:"i"
});
txValue+=input.prev_out.value/100000000;
}
for(var j=0;j<outputs.length;j++){
var output = outputs[j];
links.push({
from: txHash,
to: output.addr,
value: output.value/100000000,
t:"o"
});
}
totalBTC+=txValue;
if(txValue<1){txCount1++; }
else if(txValue>=1&&txValue<10){txCount10++; }
else if(txValue>=10&&txValue<50){txCount50++;}
else if(txValue50>=50&&txValue<100){txCount100++; }
else if(txValue>=100){txCount1000++; }
document.getElementById("output2").innerHTML = "Total:"+totalBTC+"<br/>BTC 0-1: "+txCount1+"<br/>BTC 1-10: "+txCount10+"<br/>BTC 10-50: "+txCount50+"<br/>BTC 50-100: "+txCount100+"<br/>BTC 100+: "+txCount1000;
}
for(var i=0;i<links.length;i++){
var link = links[i];
if (! paused) {
addNodes(link);
graph.addLink(link.from,link.to);
}
//writeToScreen('<span style="color: blue;">from: ' + link.from+' to ' +link.to+' value: '+ (link.value/100000000)+'</span>');
}
//websocket.close();
}
function onError(evt) {
writeToScreen('<span style="color: red;">ERROR:</span> ' + evt.data);
}
function doSend(message) {
//writeToScreen("SENT: " + JSON.stringify(message));
websocket.send(JSON.stringify(message));
}
function writeToScreen(message) {
var pre = document.createElement("p");
pre.style.wordWrap = "break-word";
pre.innerHTML = message;
output.appendChild(pre);
}
window.addEventListener("load", init, false);
window.l = layout;
window.g = graph;
window.r = renderer;
$("input[name='scaleType']").change(function(){
scaleType = this.value;
graph.forEachNode(function(node){
node.ui.size = getNodeSize(node);
})
});