Skip to content
Snippets Groups Projects
Select Git revision
  • 6012a87d4464cdbf65ba46cb5c98d6113b5d7aea
  • master default protected
  • v0.10.0
  • v0.10.0-rc2
  • v0.10.0-rc1
  • v0.9.0
  • v0.9.0-rc1
  • v0.8.0
  • v0.8.0-rc2
  • v0.8.0-rc1
  • v0.7.0
  • v0.7.0-rc2
  • v0.7.0-rc1
  • v0.6.1
  • v0.6.0
  • v0.6.0-rc2
  • v0.6.0-rc1
  • v0.5.0
  • v0.5.0-rc2
  • v0.5.0-rc1
  • v0.4.0
  • v0.4.0-rc2
22 results

NEWS-0.9.0

Blame
  • To find the state of this project's repository at the time of any of these versions, check out the tags.
    index.html 15.39 KiB
    <!-- simbit visualizer frontend for in-browser simulation -->
    <!doctype html>
    <html>
    	<head>
    		<title>simbit</title>
    		<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    		<style>
    		body {
    			font: 10px sans-serif;	
    		}
    
    			.network {
    			  border: 1px solid #DEDEDE;
    			  display:block;
    			  margin:auto;
    			}
    
    			svg {
    			  margin: auto;
    			  display:block;
    			}
    
    			rect {
    			  fill: none;
    			  pointer-events: all;
    			}
    
    			.node {
    			  fill: #000;
    			}
    
    			.link {
    			  stroke: #999;
    			}
    
    			input[type="number"] {
    				width: 50px;
    			}
    
    			path {
    				stroke: steelblue;
    				stroke-width: 2;
    				fill: none;
    			}
    
    			path.diff {
    				stroke: red;
    			}
    
    			path.avShort {
    				stroke: green;
    			}
    
    			.axis path,
    			.axis line {
    				fill: none;
    				stroke: grey;
    				stroke-width: 1;
    				shape-rendering: crispEdges;
    			}
    		</style>
    
    		<script type="text/javascript" src="d3.v3.min.js"></script>
    		<script type="text/javascript" src="jquery.min.js"></script>
    		<script type="text/javascript" src="require.js"></script>
    		<script src="graph.js"></script>
    		<script src="goog/base.js"></script>
    		<script>
    		goog.require("goog.structs.PriorityQueue")
    		</script>
    	</head>
    	<body>
    		<table>
    			<tr>
    				<td id="buttonparent">
    					<div style="float:left">
    						<input id="disable" type="button" value="Disable Visualizer">
    					</div>
    				</td>
    				<td id="optionparent">
    					<div id="graphwindows" style="display:none">
    						&nbsp;&nbsp;Short window:
    						<input id="shortwindow" type="number" min=1 value=10>
    						&nbsp;&nbsp;Long window:
    						<input id="longwindow" type="number" min=10 step=10 value=100>
    					</div>
    				</td>
    			</tr>
    			<tr>
    				<td id="networkparent">
    					<div class="network" style="width: 700px; height: 500px"></div>
    				</td>
    				<td id="graphparent" style="display:none">
    					<div class="graph" style="width: 700px; height: 500px"></div>
    				</td>
    				<td id="logs" valign="top">
    					
    				</td>
    			</tr>
    			<tr>
    				<td valign="top">
    					<div style="float:right">
    					Elapsed: <span id="elapsed">0 seconds</span>&nbsp;&nbsp;
    					<input id="play" type="button" value="Play">&nbsp;&nbsp;
    					<input id="pause" type="button" value="Pause">&nbsp;&nbsp;
    					</div>
    					
    					<div style="float:left">
    					Speed: <input id="slower" type="button" value="⇠"><input id="defaultspeed" type="button" value="Default"><input id="faster" type="button" value="⇢">
    					&nbsp;&nbsp;<span id="relspeed">(1.00x)</span>
    					</div>
    				</td>
    				<td id="timeBetweenBlocks" style="display:none" valign="top">
    					<center>
    					<h1>time between each block</h1>
    					</center>
    					<div class='scatter'>
    			          <!-- /the chart goes here -->
    			        </div>
    				</td>
    			</tr>
    		</table>
    
    
    		<script type="text/javascript">
    			// make it so that net.run() doesn't actually run
    			var DELAY_RUN = {net:false};
    
    			function Visualizer(div) {
    				this.nindex = 0;
    				this.svg = null;
    				this.divname = div;
    				this.force = null;
    				this.nodes = null;
    				this.links = null;
    				this.slink = null;
    				this.snode = null;
    				this.edges = {};
    				this.inodes = [];
    				this.lastmsgs = [];
    				this.updated = false;
    				this.colormap = {};
    				this.colormap_u = false;
    				this.link_colormap = {};
    				this.link_colormap_last = 0;
    			}
    
    			Visualizer.prototype = {
    				width: 700,
    				height: 500,
    				linkDistance: 30,
    				charge: -150,
    				gravity: .5,
    
    				drawGraph: function(data) {
    					var maxx = d3.max(data, function(d) { return d[0]; })
    					var maxdiff = d3.max(data, function(d) { return d[1]; })
    					var mintime = d3.min(data, function(d) { return d[2]; })
    					var maxtime = d3.max(data, function(d) { return d[2]; })
    
    					var margin = {top: 20, right: 60, bottom: 60, left: 60},
    						width = 700 - margin.left - margin.right,
    						height = 500 - margin.top - margin.bottom;
    
    					var x = d3.scale.linear()
    						.domain([0, maxx])
    						.range([ 0, width]);
    
    					var diff = d3.scale.linear()
    						.domain([0, maxdiff])
    						.range([ height, 0 ]);
    
    					var time = d3.scale.linear()
    						.domain([mintime, maxtime])
    						.range([ height, 0 ]);
    
    					 $("#graphparent").css('display', 'block')
    					 $("#graphwindows").css('display', 'inline')
    					 $(".graph").html("")
    
    					var chart = d3.select('.graph')
    						.append('svg:svg')
    						.attr('width', width + margin.right + margin.left)
    						.attr('height', height + margin.top + margin.bottom)
    						.attr('class', 'chart')
    
    					var main = chart.append('g')
    						.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')')
    						.attr('width', width)
    						.attr('height', height)
    						.attr('class', 'main')
    
    					// draw the x axis
    					var xAxis = d3.svg.axis()
    						.scale(x)
    						.orient('bottom');
    
    					main.append('g')
    						.attr('transform', 'translate(0,' + height + ')')
    						.attr('class', 'main axis date')
    						.call(xAxis)
    						.append("text")
    						.attr("dx", ".71em")
    						.attr("x", 420)
    						.attr("y", -6)
    						.style("text-anchor", "end")
    						.text("Block");
    
    					// draw the d axis
    					var diffAxis = d3.svg.axis()
    						.scale(diff)
    						.orient('left');
    
    					main.append('g')
    						.attr('transform', 'translate(0,0)')
    						.attr('class', 'main axis date')
    						.call(diffAxis)
    						.append("text")
    						.attr("transform", "rotate(-90)")
    						.attr("y", 6)
    						.attr("dy", ".71em")
    						.style("text-anchor", "end")
    						.text("Difficulty");
    
    					// draw the t axis
    					var timeAxis = d3.svg.axis()
    						.scale(time)
    						.orient('right');
    
    					main.append('g')
    						.attr('transform', 'translate(' + width + ',0)')
    						.attr('class', 'main axis date')
    						.call(timeAxis)
    						.append("text")
    						.attr("transform", "rotate(-90)")
    						.attr("y", -10)
    						.attr("dy", ".71em")
    						.style("text-anchor", "end")
    						.text("Block time");
    
    					var dline = d3.svg.line()
    						.x(function(d) { return x(d[0]); })
    						.y(function(d) { return diff(d[1]); });
    
    					var tsline = d3.svg.line()
    						.x(function(d) { return x(d[0]); })
    						.y(function(d) { return time(d[2]); });
    
    					var tlline = d3.svg.line()
    						.x(function(d) { return x(d[0]); })
    						.y(function(d) { return time(d[3]); });
    
    					var g = main.append("svg:g");
    
    					g.append("path")
    						.attr("class", "line diff" )
    						.attr("d", dline(data) );
    
    					g.append("path")
    						.attr("class", "line avShort" )
    						.attr("d", tsline(data) );
    
    					g.append("path")
    						.attr("class", "line" )
    						.attr("d", tlline(data) );
    				},
    
    				drawScatter: function(data) {
    					var maxy = d3.max(data, function(d) { return d[1]; })
    					var maxx = d3.max(data, function(d) { return d[0]; })
    
    					var margin = {top: 20, right: 15, bottom: 60, left: 60}
    				      , width = 500 - margin.left - margin.right
    				      , height = 300 - margin.top - margin.bottom;
    				    
    				    var x = d3.scale.linear()
    				              .domain([0, 1200])
    				              .range([ 0, width]);
    				    
    				    var y = d3.scale.linear()
    				            .domain([0, maxy])
    				            .range([ height, 0 ]);
    
    				     $("#timeBetweenBlocks").css('display', 'block')
    				     $(".scatter").html("")
    
    				    var chart = d3.select('.scatter')
    				  .append('svg:svg')
    				  .attr('width', width + margin.right + margin.left)
    				  .attr('height', height + margin.top + margin.bottom)
    				  .attr('class', 'chart')
    
    				    var main = chart.append('g')
    				  .attr('transform', 'translate(' + margin.left + ',' + margin.top + ')')
    				  .attr('width', width)
    				  .attr('height', height)
    				  .attr('class', 'main')   
    				        
    				    // draw the x axis
    				    var xAxis = d3.svg.axis()
    				  .scale(x)
    				  .orient('bottom');
    
    				    main.append('g')
    				  .attr('transform', 'translate(0,' + height + ')')
    				  .attr('class', 'main axis date')
    				  .call(xAxis)
    				  .append("text")
    				  .attr("dx", ".71em")
    				  .attr("x", 420)
    				  .attr("y", -6)
    				  .style("text-anchor", "end")
    				  .text("Time between blocks (in seconds)");
    
    				    // draw the y axis
    				    var yAxis = d3.svg.axis()
    				  .scale(y)
    				  .orient('left');
    
    				    main.append('g')
    				  .attr('transform', 'translate(0,0)')
    				  .attr('class', 'main axis date')
    				  .call(yAxis)
    				  .append("text")
    				  .attr("transform", "rotate(-90)")
    				  .attr("y", 6)
    				  .attr("dy", ".71em")
    				  .style("text-anchor", "end")
    				  .text("Blocks");
    
    				    var g = main.append("svg:g"); 
    				    
    				    g.selectAll("scatter-dots")
    				      .data(data)
    				      .enter().append("svg:circle")
    				          .attr("cx", function (d,i) { return x(d[0]); } )
    				          .attr("cy", function (d) { return y(d[1]); } )
    				          .attr("r", 2);
    				},
    
    				init: function() {
    					// init the network layout/svg
    					$(this.divname).css('width', this.width);
    					$(this.divname).css('height', this.height);
    
    					this.force = d3.layout.force()
    						.size([this.width,this.height])
    						.nodes([]) // no nodes
    						.friction(0.5)
    						.linkDistance(function(link) {
    							return link.linkDistance;
    						})
    						.charge(this.charge)
    						.gravity(this.gravity);
    
    					this.svg = d3.select(this.divname).append("svg")
    				    	.attr("width", this.width)
    				    	.attr("height", this.height);
    
    				   	this.svg.append("rect")
    					    .attr("width", this.width)
    					    .attr("height", this.height);
    
    					this.nodes = this.force.nodes();
    					this.links = this.force.links();
    					this.slink = this.svg.selectAll(".link");
    					this.snode = this.svg.selectAll(".node");
    
    					this.force = this.force.on("tick", this.tick());
    
    					this.updated = true;
    					this.rehash(0);
    				},
    
    				log: function(msg) {
    					this.lastmsgs.push(msg);
    					if (this.lastmsgs.length > 35)
    						this.lastmsgs.shift();
    
    					var newlogs = "";
    
    					this.lastmsgs.forEach(function(e) {
    						newlogs += e + "<br />";
    					})
    
    					$("#logs").html(newlogs);
    				},
    
    				setColor: function(p, color) {
    					this.colormap_u = true;
    					this.colormap[p] = color;
    				},
    
    				setLinkActivity: function(p, now) {
    					this.link_colormap[p] = now;
    					this.link_colormap_last = 0;
    				},
    
    				getRandomLink: function() {
    					var result;
    					var count=1;
    					for (var prop in this.edges) {
    						if (Math.random() < 1/++count)
    							result = prop;
    					}
    					if (!result)
    						return -1;
    					var e = result.split("-");
    					return [parseInt(e[0]), parseInt(e[1])];
    				},
    
    				getRandomNode: function() {
    					return this.inodes[Math.floor(Math.random()*this.inodes.length)];
    				},
    
    				getKeyForID: function(id) {
    					return this.inodes.indexOf(id);
    				},
    
    				incCharge: function(amt) {
    					this.force.charge(this.force.charge() - amt);
    					this.updated = true;
    					///////////this.rehash();
    				},
    
    				addNode: function() {
    					// add a node, return the index
    					this.nodes.push({id:"n"+this.nindex});
    					this.inodes.push(this.nindex);
    					this.updated = true;
    					/////////////this.rehash();
    
    					this.nindex++;
    					return this.nindex-1;
    				},
    
    				connect: function(a, b, latency) {
    					if (this.edges.hasOwnProperty(a + '-' + b) || this.edges.hasOwnProperty(b + '-' + a))
    						return false; // we're already connected
    
    					if (a==b)
    						return false; // can't connect to ourself silly!
    
    					this.edges[a + '-' + b] = {source:this.nodes[this.getKeyForID(a)],target:this.nodes[this.getKeyForID(b)],linkDistance:latency};
    					this.links.push(this.edges[a + '-' + b]);
    
    					this.updated = true;
    					//////this.rehash();
    				},
    
    				disconnect: function(a, b) {
    					if (!this.edges.hasOwnProperty(a + '-' + b) && !this.edges.hasOwnProperty(b + '-' + a))
    						return false; // we're already disconnected
    
    					var i = this.links.indexOf(this.edges[a + '-' + b]);
    					if (i<0)
    						i = this.links.indexOf(this.edges[b + '-' + a]);
    
    					delete this.edges[a + '-' + b];
    					delete this.edges[b + '-' + a];
    
    					this.links.splice(i, 1); // remove the link
    
    					this.updated = true;
    					//////this.rehash();
    				},
    
    				removeNode: function(index) {
    					// remove a node at index
    					var i = this.getKeyForID(index);
    					if (i < 0)
    						return false; // this one has already been removed
    
    					this.nodes.splice(i, 1);
    					this.inodes.splice(i, 1);
    					this.updated = true;
    					///////////////////this.rehash();
    				},
    
    				tick: function() {
    					var svg = this.svg;
    					return function() {
    						svg.selectAll(".link").attr("x1", function(d) { return d.source.x; })
    							.attr("y1", function(d) { return d.source.y; })
    							.attr("x2", function(d) { return d.target.x; })
    							.attr("y2", function(d) { return d.target.y; })
    							.attr("id", function(d) {return "l-" + d.source.id + "-" + d.target.id;});
    
    						svg.selectAll(".node").attr("cx", function(d) { return d.x; })
    							.attr("cy", function(d) { return d.y; });
    					}
    				},
    
    				rehash: function(now) {
    					/***** COLORMAP *****/
    					if (this.colormap_u) {
    						for (var p in this.colormap) {
    							$(".n" + p).css('fill', this.colormap[p]);
    						}
    						this.colormap_u = false;
    					}
    
    					if (this.link_colormap_last < (now-100)) {
    						this.link_colormap_last = now;
    						for (var p in this.link_colormap) {
    							if (this.link_colormap[p] + 100 > now) {
    								$("#l-" + p).css('stroke', "black")
    							} else {
    								$("#l-" + p).css('stroke', "#999")
    								delete this.link_colormap[p];
    							}
    						}
    					}
    
    					if (!this.updated)
    						return;
    
    					this.slink = this.slink.data(this.force.links(), function(d) { return d.source.id + "-" + d.target.id; });
    					this.slink.enter().insert("line", ".node")
    						.attr("class", "link");
    					this.slink.exit().remove();
    
    					this.snode = this.snode.data(this.force.nodes(), function(d) {return d.id;});
    					this.snode.enter().append("circle").attr("class", function (d) {return "node " + d.id;})
    						.attr("r", 3)
    					//	.call(this.force.drag);
    					this.snode.exit().remove();
    
    					this.force.start();
    
    					this.updated = false;
    				}
    			};
    
    			$("#network").html("");
    			var VISUALIZER = new Visualizer(".network");
    			VISUALIZER.init();
    		</script>
    		<script type="text/javascript" src="sim.js"></script>
    		<script type="text/javascript">
    			var amt = 10;
    			var play = false;
    
    			$("#play").click(function() {
    				play = true;
    			})
    
    			$("#pause").click(function() {
    				play = false;
    			})
    
    			$("#slower").click(function() {
    				amt = amt / 2;
    				$("#relspeed").html("(" + (amt / 10).toFixed(2) + "x)");
    			})
    
    			$("#faster").click(function() {
    				amt = amt * 2;
    				$("#relspeed").html("(" + (amt / 10).toFixed(2) + "x)");
    			})
    
    			$("#defaultspeed").click(function() {
    				amt = 10;
    				$("#relspeed").html("(" + (amt / 10).toFixed(2) + "x)");
    			})
    
    			$("#disable").click(function() {
    				VISUALIZER.rehash = function() {return;}
    				VISUALIZER.force.stop();
    				$("#disable").prop("disabled", true);
    			})
    			$("#disable").prop("disabled", false);
    
    			setInterval(function() {
    				if (play && DELAY_RUN.net) {
    					DELAY_RUN.net._run(amt);
    					VISUALIZER.rehash(DELAY_RUN.net.now);
    					$("#elapsed").html((DELAY_RUN.net.now / 1000).toFixed(2) + " seconds")
    				}
    			}, 10);
    		</script>
    	</body>
    </html>