Add files via upload
This commit is contained in:
parent
287a29954b
commit
346a66d704
|
@ -0,0 +1,34 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>LiveBlock</title>
|
||||
|
||||
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
|
||||
<script type="text/javascript" src="js/vivagraph.js"></script>
|
||||
<script type="text/javascript" src="js/webgl-programs.js"></script>
|
||||
<link type="text/css" href="js/liveblock.css" rel="stylesheet" />
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<div id="g" style="background-color:black; width:100%; height:600px;"></div>
|
||||
<div id="info">Hover over nodes to view transaction details</div>
|
||||
|
||||
LEGEND:
|
||||
<span class="input-node">Green = input</span>, <span class="output-node">Red = output</span>,
|
||||
<span class="input-output-node">White = input that became output</span>,<span class="output-input-node">Purple = output that became input</span>, <span class="transaction-node">Blue = transaction</span>
|
||||
<br />
|
||||
NAVIGATION: mouse + scroll = pan/zoom, SPACE = run/pause
|
||||
<br />
|
||||
<pre>
|
||||
</pre>
|
||||
<div id="output" ></div>
|
||||
<div id="output2" ></div>
|
||||
|
||||
|
||||
|
||||
</body>
|
||||
<script type="text/javascript" src="js/liveblock.js"></script>
|
||||
|
||||
|
||||
</html>
|
|
@ -0,0 +1,28 @@
|
|||
body{
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
position: relative;
|
||||
}
|
||||
.input-node{color:green;}
|
||||
.output-node{color:red;}
|
||||
.input-output-node{color:black;}
|
||||
.output-input-node{color:purple;}
|
||||
|
||||
.transaction-node{color:blue;}
|
||||
|
||||
#output{display:none;}
|
||||
#output2{ position: absolute;
|
||||
left:4px;
|
||||
top:4px;
|
||||
width:100px;
|
||||
background-color: #ccc;
|
||||
padding:4px;}
|
||||
|
||||
#info{
|
||||
position: absolute;
|
||||
right:4px;
|
||||
top:4px;
|
||||
width:300px;
|
||||
background-color: #ccc;
|
||||
padding:4px;
|
||||
}
|
|
@ -0,0 +1,341 @@
|
|||
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);
|
||||
})
|
||||
});
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,90 @@
|
|||
// here define functions to draw points and lines
|
||||
|
||||
Viva.Graph.View.webglDualColorLine = function (t, e) {
|
||||
return {
|
||||
start: Viva.Graph.View._webglUtil.parseColor(t),
|
||||
end: Viva.Graph.View._webglUtil.parseColor(e)
|
||||
}
|
||||
}
|
||||
Viva.Graph.View.webglDualColorLinkProgram = function () {
|
||||
var t, e, r, i, n, a, o, s, u, c, d = 6,
|
||||
l = 2 * (2 * Float32Array.BYTES_PER_ELEMENT + Uint32Array.BYTES_PER_ELEMENT),
|
||||
f = ["precision mediump float;", "varying vec4 color;", "void main(void) {", " gl_FragColor = color;", "}"].join("\n"),
|
||||
p = ["attribute vec2 a_vertexPos;", "attribute vec4 a_color;", "uniform vec2 u_screenSize;", "uniform mat4 u_transform;", "varying vec4 color;", "void main(void) {", " gl_Position = u_transform * vec4(a_vertexPos/u_screenSize, 0.0, 1.0);", " color = a_color.abgr;", "}"].join("\n"),
|
||||
h = 0,
|
||||
g = new ArrayBuffer(1024 * l),
|
||||
v = new Float32Array(g),
|
||||
m = new Uint32Array(g),
|
||||
w = function () {
|
||||
if ((h + 1) * l > g.byteLength) {
|
||||
var t = new ArrayBuffer(2 * g.byteLength),
|
||||
e = new Float32Array(t),
|
||||
r = new Uint32Array(t);
|
||||
r.set(m), v = e, m = r, g = t
|
||||
}
|
||||
};
|
||||
return {
|
||||
load: function (a) {
|
||||
e = a, e.blendFunc(e.SRC_ALPHA, e.ONE_MINUS_SRC_ALPHA), e.enable(e.BLEND), i = Viva.Graph.webgl(a), t = i.createProgram(p, f), e.useProgram(t), n = i.getLocations(t, ["a_vertexPos", "a_color", "u_screenSize", "u_transform"]), e.enableVertexAttribArray(n.vertexPos), e.enableVertexAttribArray(n.color), r = e.createBuffer()
|
||||
},
|
||||
position: function (t, e, r) {
|
||||
var i = t.id,
|
||||
n = i * d;
|
||||
v[n] = e.x, v[n + 1] = e.y, m[n + 2] = t.start, v[n + 3] = r.x, v[n + 4] = r.y, m[n + 5] = t.end
|
||||
},
|
||||
createLink: function (t) {
|
||||
w(), h += 1, a = t.id
|
||||
},
|
||||
removeLink: function (t) {
|
||||
h > 0 && (h -= 1), h > t.id && h > 0 && i.copyArrayPart(m, t.id * d, h * d, d)
|
||||
},
|
||||
updateTransform: function (t) {
|
||||
c = !0, u = t
|
||||
},
|
||||
updateSize: function (t, e) {
|
||||
o = t, s = e, c = !0
|
||||
},
|
||||
render: function () {
|
||||
e.useProgram(t), e.bindBuffer(e.ARRAY_BUFFER, r), e.bufferData(e.ARRAY_BUFFER, g, e.DYNAMIC_DRAW), c && (c = !1, e.uniformMatrix4fv(n.transform, !1, u), e.uniform2f(n.screenSize, o, s)), e.vertexAttribPointer(n.vertexPos, 2, e.FLOAT, !1, 3 * Float32Array.BYTES_PER_ELEMENT, 0), e.vertexAttribPointer(n.color, 4, e.UNSIGNED_BYTE, !0, 3 * Float32Array.BYTES_PER_ELEMENT, 8), e.drawArrays(e.LINES, 0, 2 * h), a = h - 1
|
||||
},
|
||||
bringToFront: function (t) {
|
||||
a > t.id && i.swapArrayPart(m, t.id * d, a * d, d), a > 0 && (a -= 1)
|
||||
},
|
||||
getFrontLinkId: function () {
|
||||
return a
|
||||
}
|
||||
}
|
||||
}
|
||||
Viva.Graph.View.webglCustomNodeProgram = function () {
|
||||
var t, e, r, i, n, a, o, s, u, c = 4,
|
||||
d = ["precision mediump float;", "varying vec4 color;", "varying float pixelSize;", "void main(void) {", " if (gl_PointCoord.x <= pixelSize || gl_PointCoord.x >= 1.0-pixelSize || gl_PointCoord.y <= pixelSize || gl_PointCoord.y >= 1. - pixelSize) {", " gl_FragColor = vec4(color.xyz * 0.3, 1);", " } else {", " gl_FragColor = color;", " }", "}"].join("\n"),
|
||||
l = ["attribute vec2 a_vertexPos;", "attribute vec2 a_customAttributes;", "uniform vec2 u_screenSize;", "uniform mat4 u_transform;", "varying vec4 color;", "varying float pixelSize;", "void main(void) {", " gl_Position = u_transform * vec4(a_vertexPos/u_screenSize, 0, 1);", " gl_PointSize = a_customAttributes[1] * u_transform[0][0];", " float c = a_customAttributes[0];", " color.b = mod(c, 256.0); c = floor(c/256.0);", " color.g = mod(c, 256.0); c = floor(c/256.0);", " color.r = mod(c, 256.0); c = floor(c/256.0); color /= 255.0;", " color.a = 1.0;", " pixelSize = 1.0/gl_PointSize;", "}"].join("\n"),
|
||||
f = new Float32Array(64),
|
||||
p = 0;
|
||||
return {
|
||||
load: function (a) {
|
||||
e = a, n = Viva.Graph.webgl(a), t = n.createProgram(l, d), e.useProgram(t), i = n.getLocations(t, ["a_vertexPos", "a_customAttributes", "u_screenSize", "u_transform"]), e.enableVertexAttribArray(i.vertexPos), e.enableVertexAttribArray(i.customAttributes), r = e.createBuffer()
|
||||
},
|
||||
position: function (t, e) {
|
||||
var r = t.id;
|
||||
f[r * c] = e.x, f[r * c + 1] = e.y, f[r * c + 2] = t.color, f[r * c + 3] = t.size
|
||||
},
|
||||
updateTransform: function (t) {
|
||||
u = !0, s = t
|
||||
},
|
||||
updateSize: function (t, e) {
|
||||
a = t, o = e, u = !0
|
||||
},
|
||||
createNode: function () {
|
||||
f = n.extendArray(f, p, c), p += 1
|
||||
},
|
||||
removeNode: function (t) {
|
||||
p > 0 && (p -= 1), p > t.id && p > 0 && n.copyArrayPart(f, t.id * c, p * c, c)
|
||||
},
|
||||
replaceProperties: function () {},
|
||||
render: function () {
|
||||
e.useProgram(t), e.bindBuffer(e.ARRAY_BUFFER, r), e.bufferData(e.ARRAY_BUFFER, f, e.DYNAMIC_DRAW), u && (u = !1, e.uniformMatrix4fv(i.transform, !1, s), e.uniform2f(i.screenSize, a, o)), e.vertexAttribPointer(i.vertexPos, 2, e.FLOAT, !1, c * Float32Array.BYTES_PER_ELEMENT, 0), e.vertexAttribPointer(i.customAttributes, 2, e.FLOAT, !1, c * Float32Array.BYTES_PER_ELEMENT, 8), e.drawArrays(e.POINTS, 0, p)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue