Last active
December 19, 2015 08:19
-
-
Save straypacket/5924557 to your computer and use it in GitHub Desktop.
Tornado websocket server and html client
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import tornado.httpserver | |
import tornado.websocket | |
import tornado.ioloop | |
import tornado.web | |
import time | |
import random | |
# Preload data | |
# ... use from previous gists | |
#import numpy as np | |
#a = kk_df[['DATE_REGISTERED','URL']].sort(['DATE_REGISTERED']) | |
class WSHandler(tornado.websocket.WebSocketHandler): | |
def open(self): | |
print 'new connection' | |
#self.write_message("Hello World") | |
parse_data(self) | |
def on_message(self, message): | |
print 'message received: %s' % message | |
def on_close(self): | |
print 'connection closed' | |
application = tornado.web.Application([ | |
(r'/', WSHandler), | |
]) | |
def parse_data(self): | |
prev_date = a['DATE_REGISTERED'].iloc[0] | |
c = [] | |
for x in range(len(a)): | |
now = a['DATE_REGISTERED'].iloc[x] | |
time.sleep((now - prev_date).seconds/100.0) | |
prev_date = now | |
# Make request | |
print "[%s] %s [%d]" % (now, a['URL'].iloc[x], len(c)) | |
path = a['URL'].iloc[x].split('/') | |
if len(path) > 2: | |
root = path[:-1][1] | |
if root not in c: | |
c.append(root) | |
msg = '{"type": "bubble", "color": %d, "radius": %d}' % (c.index(root)+1,5) | |
self.write_message(msg) | |
else: | |
msg = '{"type": "bubble", "color": %d, "radius": %d}' % (0,5) | |
self.write_message(msg) | |
def random_data(self): | |
sleep = 0.1 | |
while 1: | |
if random.random() > 1.5: | |
msg = '{"type": "bar", "id": %d, "markers": [%d], "measures": [%d,%d], "ranges": [%d,%d,%d]}' % (random.randrange(0, 4, 1),random.randrange(100, 200, 1),random.randrange(100, 200, 1),random.randrange(100, 200, 1),random.randrange(100, 200, 1),random.randrange(100, 200, 1),random.randrange(100, 200, 1)) | |
else: | |
msg = '{"type": "bubble", "color": %d, "radius": %d}' % (random.randrange(0, 4, 1),random.randrange(4, 40, 1)) | |
self.write_message(msg) | |
time.sleep(sleep) | |
if __name__ == "__main__": | |
http_server = tornado.httpserver.HTTPServer(application) | |
http_server.listen(8888) | |
tornado.ioloop.IOLoop.instance().start() |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html> | |
<head> | |
<meta charset="utf-8" /> | |
<title>Live demo</title> | |
<style> | |
body { | |
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; | |
margin: auto; | |
padding-top: 40px; | |
position: relative; | |
width: 960px; | |
} | |
button { | |
position: absolute; | |
right: 10px; | |
top: 10px; | |
} | |
.bullet { font: 10px sans-serif; } | |
.bullet .marker { stroke: #000; stroke-width: 2px; } | |
.bullet .axis line, .bullet .axis path { stroke: #666; stroke-width: .5px; fill: none; } | |
.bullet .range.s0 { fill: #eee; } | |
.bullet .range.s1 { fill: #ddd; } | |
.bullet .range.s2 { fill: #ccc; } | |
.bullet .measure.s0 { fill: lightsteelblue; } | |
.bullet .measure.s1 { fill: steelblue; } | |
.bullet .title { font-size: 14px; font-weight: bold; } | |
.bullet .subtitle { fill: #999; } | |
rect{ | |
fill: white; | |
} | |
circle { | |
stroke: #000; | |
stroke-opacity: .5; | |
} | |
</style> | |
</head> | |
<body> | |
<div id="body"> | |
<div id="chart"></div> | |
</div> | |
<script src="http://d3js.org/d3.v3.min.js"></script> | |
<script src="bullet.js"></script> | |
<script> | |
var margin = {top: 5, right: 40, bottom: 50, left: 120}, | |
width = 192 - margin.left - margin.right, | |
height = 450 - margin.top - margin.bottom; | |
var chart = d3.bullet() | |
.orient("bottom") | |
.width(width) | |
.height(height); | |
var svg_bar; | |
d3.json("bullets.json", function(error, data) { | |
svg_bar = d3.select("body").selectAll("svg") | |
.data(data) | |
.enter().append("svg") | |
.attr("class", "bullet") | |
.attr("width", width + margin.left + margin.right) | |
.attr("height", height + margin.top + margin.bottom) | |
.append("g") | |
.attr("transform", "translate(" + margin.left + "," + margin.top + ")") | |
.call(chart); | |
var title = svg_bar.append("g") | |
.style("text-anchor", "end") | |
.attr("transform", "translate(" + width + "," + (height + 20) + ")"); | |
title.append("text") | |
.attr("class", "title") | |
.text(function(d) { return d.title; }); | |
title.append("text") | |
.attr("class", "subtitle") | |
.attr("dy", "1em") | |
.text(function(d) { return d.subtitle; }); | |
}); | |
function randomize(d) { | |
if (!d.randomizer) d.randomizer = randomizer(d); | |
d.ranges = d.ranges.map(d.randomizer); | |
d.markers = d.markers.map(d.randomizer); | |
d.measures = d.measures.map(d.randomizer); | |
return d; | |
} | |
function randomizer(d) { | |
var k = d3.max(d.ranges) * .2; | |
return function(d) { | |
return Math.max(0, d + k * (Math.random() - .5)); | |
}; | |
} | |
// ========== | |
// Websockets | |
// ========== | |
var wsUri = "ws://127.0.0.1:8888/"; | |
var output; | |
function init() { | |
output = document.getElementById("output"); | |
testWebSocket(); | |
} | |
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) { | |
console.log("CONNECTED"); | |
//doSend("WebSocket rocks"); | |
} | |
function onClose(evt) { | |
console.log("DISCONNECTED"); | |
} | |
function onMessage(evt) { | |
//console.log('GOT DATA: ' + evt.data); | |
var new_data = JSON.parse(evt.data); | |
console.log(new_data); | |
if (new_data['type'] == "bubble") { | |
makeNode(new_data['radius'],new_data['color']); | |
} | |
else { | |
var id = new_data['id']; | |
svg_bar.data()[id].ranges = new_data['ranges']; | |
svg_bar.data()[id].markers = new_data['markers']; | |
svg_bar.data()[id].measures = new_data['measures']; | |
svg_bar.transition().duration(1000).call(chart); | |
} | |
} | |
function onError(evt) { | |
console.log('ERROR: ' + evt.data); | |
} | |
function doSend(message) { | |
console.log("SENT: " + message); websocket.send(message); | |
} | |
window.addEventListener("load", init, false); | |
// ======== | |
// Floaters | |
// ======== | |
var w = 960, | |
h = 500; | |
var nodes = d3.range(30).map(function(i) { | |
if (i < 15) { | |
console.log("Low"); | |
return {radius: 15, | |
fixed:true, | |
type:i, | |
x: (i+1) * (w / 16), | |
y: (h/2)-(h/4)}; | |
} | |
else { | |
console.log("High"); | |
return {radius: 15, | |
fixed:true, | |
type:i, | |
x: (i+1-15) * (w / 16), | |
y: (h/2)+(h/4)}; | |
} | |
}), | |
color = d3.scale.category20(); | |
var force = d3.layout.force() | |
.gravity(0) | |
.charge(0) | |
.nodes(nodes) | |
.size([w, h]); | |
force.start(); | |
var svg = d3.select("#chart").append("svg:svg") | |
.attr("width", w) | |
.attr("height", h); | |
svg.append("svg:rect") | |
.attr("width", w) | |
.attr("height", h); | |
svg.selectAll("circle") | |
.data(nodes) | |
.enter().append("svg:circle") | |
.attr("r", function(d) { return d.radius - 2; }) | |
.style("fill", function(d, i) { return color(d.type); }); | |
force.on("tick", function(e) { | |
var q = d3.geom.quadtree(nodes), | |
k = e.alpha * .1, | |
i = 0, | |
n = nodes.length, | |
o; | |
while (++i < n) { | |
o = nodes[i]; | |
if (o.fixed) continue; | |
c = nodes[o.type]; | |
o.x += (c.x - o.x) * k; | |
o.y += (c.y - o.y) * k; | |
q.visit(collide(o)); | |
} | |
svg.selectAll("circle") | |
.attr("cx", function(d) { return d.x; }) | |
.attr("cy", function(d) { return d.y; }); | |
}); | |
function makeNode(radius,type) { | |
var p1 = [w/2,10], | |
node = {radius: radius, type: type, x: p1[0], y: p1[1], px: w/2, py: 10}; | |
svg.append("svg:circle") | |
.data([node]) | |
.attr("cx", function(d) { return d.x; }) | |
.attr("cy", function(d) { return d.y; }) | |
.attr("r", function(d) { return d.radius - 2; }) | |
.style("fill", function(d) {return color(d.type);}) | |
.transition() | |
.delay(3000) | |
.attr("r", 1e-6) | |
.each("end", function() { nodes.splice(31, 1); }) | |
.remove(); | |
nodes.push(node); | |
force.resume(); | |
}; | |
function collide(node) { | |
var r = node.radius + 4, | |
nx1 = node.x - r, | |
nx2 = node.x + r, | |
ny1 = node.y - r, | |
ny2 = node.y + r; | |
return function(quad, x1, y1, x2, y2) { | |
if (quad.point && (quad.point !== node)) { | |
var x = node.x - quad.point.x, | |
y = node.y - quad.point.y, | |
l = Math.sqrt(x * x + y * y), | |
r = node.radius + quad.point.radius; | |
if (l < r) { | |
l = (l - r) / l * .5; | |
node.px += x * l; | |
node.py += y * l; | |
} | |
} | |
return x1 > nx2 | |
|| x2 < nx1 | |
|| y1 > ny2 | |
|| y2 < ny1; | |
}; | |
} | |
</script> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment