summaryrefslogtreecommitdiff
path: root/public/js/mv/connect.js
diff options
context:
space:
mode:
Diffstat (limited to 'public/js/mv/connect.js')
-rw-r--r--public/js/mv/connect.js156
1 files changed, 156 insertions, 0 deletions
diff --git a/public/js/mv/connect.js b/public/js/mv/connect.js
new file mode 100644
index 0000000..aba4c33
--- /dev/null
+++ b/public/js/mv/connect.js
@@ -0,0 +1,156 @@
+var mv = function(mv) {
+ mv.socket = {
+ connect: connect
+ };
+ /* If we're updating due to something we received, then don't broadcast back. */
+ var netrendering = false;
+ /* Our ID */
+ var id = 0;
+ /* List of all users */
+ var users = {};
+ /* The user status box */
+ var usersStatus = d3.select("#users-status");
+ /* io.socket's socket */
+ var socket;
+ function connect() {
+ socket = io.connect('http://localhost:3000');
+ socket.on("connect", function() { console.log("CONNECT", arguments); });
+ socket.on("disconnect", function() { console.log("DISCONNECT", arguments); });
+ socket.emit('login');
+ /*
+ * Protocol:
+ * selflogin -> id (I)
+ * login -> id (I), nick (S)
+ * nickset -> id (I), nick (S)
+ * users -> { id -> {nick (S), filters ({dim (S) -> filter (*)}) } }
+ * logout -> id (I)
+ */
+ socket.on('selflogin', function(d) {
+ /* Acknowledged that we logged in */
+ /* Take note of our ID. */
+ id = d.id;
+ });
+ socket.on('login', function(d) {
+ /* Someone else logging in */
+ users[d.id] = { nick: d.nick, filters: {} };
+ updateUsersStatus();
+ });
+ socket.on('users', function(d) {
+ /* We've got a list of all users. */
+ /* The server is always right. */
+ users = d.users;
+ updateUsersStatus();
+ });
+ socket.on('nickset', function(d) {
+ /* Someone, possibly us, changed their nick. */
+ users[d.id].nick = d.nick;
+ updateUsersStatus();
+ });
+ socket.on('filterset', function(d) {
+ /* Someone changed their filter */
+ users[d.id].filters = d.filters;
+ /* Use the variable netrendering to denote that we're rendering due to a change received from the network. */
+ netrendering = true;
+ setOwnFilters(d.filters);
+ netrendering = false;
+ });
+ socket.on('logout', function(d) {
+ /* Someone disconnected, take them off the list. */
+ delete users[d.id];
+ updateUsersStatus();
+ });
+ dc.renderlet(function() {
+ /* Hook a listener into dc's rendering routine. If it rerenders, broadcast the change. */
+ if (netrendering) {
+ /* If we rendered due a change we received, don't broadcast it again. That would be A Bad Thing. */
+ return;
+ }
+ socket.emit("filter", { filters: mv.charter.filters() });
+ });
+ }
+ function setOwnFilters(filters) {
+ /* See if there's any difference - if there isn't, don't update. */
+ var change = false;
+ var key;
+ /* Check for keys in the filters to apply which are not in our charts. */
+ for (key in filters) {
+ if (!(key in mv.charts))
+ continue;
+ var filter = mv.charts[key].filter();
+ if (typeof(filter) == "array") {
+ /* Crossfilter uses arrays to filter ranges. Exactly the first two elements are significant. */
+ if (filter[0] == filters[key][0] &&
+ filter[1] == filters[key][1]) {
+ continue;
+ }
+ } else if (filter == filters[key]) {
+ continue;
+ }
+ /* This filter differs. Apply it. */
+ change = true;
+ mv.charts[key].filter(filters[key]);
+ }
+ /* Check for keys in our charts which are not in the filters to apply. */
+ for (key in mv.charts) {
+ if (mv.charts[key].filter() != null) {
+ if (key in filters) {
+ /* This has already been handled above */
+ continue;
+ }
+ /* There is no longer a filter applying here, clear it. */
+ change = true;
+ mv.charts[key].filterAll();
+ }
+ }
+ if (change) {
+ dc.redrawAll();
+ }
+ }
+ function updateUsersStatus() {
+ /* Convert the user list to a form suitable for a d3 selection */
+ var data = [];
+ for (var uid in users) { users[uid].id = uid; data.push(users[uid]); }
+ /* Data join */
+ var userlist = usersStatus.selectAll(".user")
+ .data(data, function(d) { return d.id; });
+ /* Enter */
+ userlist
+ .enter().append("li").attr("class", "user")
+ ;
+ /* Update */
+ userlist
+ .each(function(d,i) {
+ var elm = d3.select(this);
+ console.log("Userlist para appending", d,i);
+ var name = elm.select(".name");
+ var nick = d.nick == null ? "Anonymous User " + d.id : d.nick;
+ if (d.id == id) {
+ /* This is us! We can edit our name. */
+ if (name.empty()) {
+ console.log("Found our entry. id:", id, "datum", d);
+ name = elm.append("input").attr("class", "name")
+ .attr("type", "text")
+ .attr("placeholder", "Enter name here")
+ .on("change", function () {
+ /* A d3 select must be dereferenced twice to access the DOM entity */
+ socket.emit("nick", { nick: name[0][0].value });
+ })
+ ;
+ }
+ name.attr("value", nick);
+ } else {
+ /* This is someone else. We can't edit their name. */
+ if (name.empty()) {
+ name = elm.append("p").attr("class", "name");
+ }
+ name.text(nick);
+ }
+ })
+ ;
+ /* Remove */
+ userlist
+ .exit().remove()
+ ;
+ }
+ return mv;
+}(mv || {});