This is a version of cubism.js written by Patrick Thompson to use cubism tracking for discrete events that occur in real time.
Cubism is a library written by Mike Bostock.
For more information about cubism.js go here.
This is a version of cubism.js written by Patrick Thompson to use cubism tracking for discrete events that occur in real time.
Cubism is a library written by Mike Bostock.
For more information about cubism.js go here.
html { | |
min-width: 1040px; | |
} | |
body { | |
font-family:"Helvetica Neue", Helvetica, sans-serif; | |
margin: auto; | |
margin-top: 40px; | |
margin-bottom: 4em; | |
width: 800px; | |
position:relative; | |
} | |
#body { | |
position: left; | |
} | |
footer { | |
font-size: small; | |
margin-top: 8em; | |
} | |
aside { | |
font-size: small; | |
left: 780px; | |
position: absolute; | |
width: 180px; | |
} | |
#body > p, li > p { | |
line-height: 1.5em; | |
} | |
#body > p { | |
width: 720px; | |
} | |
#body > blockquote { | |
width: 640px; | |
} | |
li { | |
width: 680px; | |
} | |
a { | |
color: steelblue; | |
} | |
a:not(:hover) { | |
text-decoration: none; | |
} | |
pre, code, textarea { | |
font-family:"Menlo", monospace; | |
} | |
code { | |
line-height: 1em; | |
} | |
textarea { | |
font-size: 100%; | |
} | |
#body > pre { | |
border-left: solid 2px #ccc; | |
padding-left: 18px; | |
margin: 2em 0 2em -20px; | |
} | |
.html .value, .javascript .string, .javascript .regexp { | |
color: #756bb1; | |
} | |
.html .tag, .css .tag, .javascript .keyword { | |
color: #3182bd; | |
} | |
.comment { | |
color: #636363; | |
} | |
.html .doctype, .javascript .number { | |
color: #31a354; | |
} | |
.html .attribute, .css .attribute, .javascript .class, .javascript .special { | |
color: #e6550d; | |
} | |
svg { | |
font: 10px sans-serif; | |
} | |
.axis path, .axis line { | |
fill: none; | |
stroke: #000; | |
shape-rendering: crispEdges; | |
} | |
sup, sub { | |
line-height: 0; | |
} | |
q:before, blockquote:before { | |
content:"“"; | |
} | |
q:after, blockquote:after { | |
content:"”"; | |
} | |
blockquote:before { | |
position: absolute; | |
left: 2em; | |
} | |
blockquote:after { | |
position: absolute; | |
} | |
h1 { | |
font-size: 96px; | |
margin-top: .3em; | |
margin-bottom: 0; | |
} | |
h1 + h2 { | |
margin-top: 0; | |
} | |
h2 { | |
font-weight: 400; | |
font-size: 28px; | |
} | |
h1, h2 { | |
font-family:"Yanone Kaffeesatz"; | |
text-rendering: optimizeLegibility; | |
} | |
#logo { | |
width: 122px; | |
height: 31px; | |
} | |
#fork { | |
position: absolute; | |
top: 0; | |
right: 0; | |
} | |
.axis { | |
font: 10px sans-serif; | |
} | |
.axis text { | |
-webkit-transition: fill-opacity 250ms linear; | |
} | |
.axis path { | |
display: none; | |
} | |
.axis line { | |
stroke: #000; | |
shape-rendering: crispEdges; | |
} | |
.horizon { | |
border-bottom: solid 1px #000; | |
overflow: hidden; | |
position: relative; | |
} | |
.horizon { | |
border-top: solid 0px #000; | |
border-bottom: solid 1px #000; | |
} | |
.horizon + .horizon { | |
border-top: none; | |
} | |
.horizon canvas { | |
display: block; | |
} | |
.horizon .title, .horizon .value { | |
bottom: 0; | |
line-height: 30px; | |
margin: 0 6px; | |
position: absolute; | |
text-shadow: 0 1px 0 rgba(255, 255, 255, .5); | |
white-space: nowrap; | |
} | |
.horizon .title { | |
left: 0; | |
} | |
.horizon .value { | |
right: 0; | |
} | |
.line { | |
background: #000; | |
opacity: .2; | |
z-index: 2; | |
} |
////////////////////////////////////////////////// | |
//DISCRETE CUBISM.JS | |
////////////////////////////////////////////////// | |
//This is a version of cubism.js written by Patrick Thompson | |
//to use cubism tracking for discrete events | |
//that occur in real time | |
//////////////////////////////////////////////////// | |
//Cubism is a library written by Mike Bostock | |
//For more information about cubism go to | |
//https://square.github.io/cubism/ | |
////////////////////////////////////////////////// | |
//(Note:this is written in the user/event paradigm) | |
//but can be translated into any system that has discrete events | |
////////////////////////////////////////////////// | |
//TODO | |
//1. Add block colors (I do not fully understand how to add colors to cubism.js yet) | |
//2. Add a line above the first user (just haven't gotten around to it yet | |
//3. Add "delete user" and "delete event" input (not really necessary to demonstrate) | |
var AllUsers = []; //Create an array that will contain all users | |
var Users = [{ //Create the first template user | |
name: "User1", | |
event: 1, | |
newevent: false | |
}]; | |
var events = [{ //Create the New event notification | |
name: "New Event!", | |
value: "20" | |
}] | |
events.push({ //Create the default event notification | |
name: "No Events", | |
value: "0.0" | |
}); | |
events.push({ //Create a couple of events | |
name: "Home Page", | |
value: "5.0" | |
}); | |
events.push({ //Create a couple of events | |
name: "Subject View", | |
value: "-5.0" | |
}); | |
////////////////////////////////////////////////// | |
//BEGIN CUBISM FUNCTIONS ///////////////////////// | |
////////////////////////////////////////////////// | |
////////////////////////////////////////////////// | |
//Add the cubism context ///////////////////////// | |
//Required for cubism to work //////////////////// | |
////////////////////////////////////////////////// | |
var context = cubism.context() // set the cubism context | |
.serverDelay(0) // No server delay | |
.clientDelay(0) // No client delay | |
.step(1e3) // step once ever second | |
.size(800); // and make the horizon div 960 px wide. | |
////////////////////////////////////////////////// | |
//Execute when AddNewEvent button pressed //////// | |
//Adds a new event to the event list ///////////// | |
////////////////////////////////////////////////// | |
d3.select("#example1").call(function (div) { | |
AddAllUsers(); | |
div.append("div") | |
.attr("class", "axis") | |
.call(context.axis().orient("top")); | |
RunData(); | |
div.append("div") | |
.attr("class", "rule") | |
.call(context.rule()); | |
RefreshUsers(); | |
RefreshEvents(); | |
RefreshRule(); | |
}); | |
////////////////////////////////////////////////// | |
//Execute when AddAllUsers button pressed //////// | |
//Adds a new user to the AllUsers list ///////////// | |
////////////////////////////////////////////////// | |
function AddAllUsers() { | |
for (var i = 0; i < Users.length; i++) { | |
var myuser = random(Users[i].name); | |
AllUsers.push(myuser); | |
} | |
} | |
////////////////////////////////////////////////// | |
//Execute RunData function //////// | |
//Adds all horizons to cubism div ///////////// | |
////////////////////////////////////////////////// | |
function RunData() { | |
d3.select("#example1").selectAll(".horizon") | |
.data(AllUsers) | |
.enter().append("div") | |
.attr("class", "horizon") | |
.call(context.horizon().extent([-20, 20])); | |
} | |
///////////////////////////////////////////////////////////////////// | |
//Execute the running process (heart of the code)//////////////////// | |
//This is also executed each time a user is added//////////////////// | |
///////////////////////////////////////////////////////////////////// | |
function random(name) { | |
var value = 0, | |
values = [], | |
area = [], | |
i = 0, | |
last; | |
return context.metric(function (start, stop, step, callback) { | |
start = +start, stop = +stop; | |
if (isNaN(last)) last = start; | |
while (last < stop) { | |
last += step; | |
for (var j = 0; j < Users.length; j++) { //For all users | |
if (Users[j].name == name) { //If the user name in the loop matches the current user name | |
if (Users[j].newevent) { //If the user has a new event | |
value = parseInt(events[0].value); //Show a "blip" in event zero | |
Users[j].newevent = false; //And switch newevent OFF | |
} else { //Otherwise | |
value = parseFloat(events[Users[j].event].value); //Write the value of the current user | |
} | |
values.push(value); //And add it to the values array | |
} | |
} | |
} | |
callback(null, values = values.slice((start - stop) / step)); //And execute the callback function | |
}, name); | |
} | |
////////////////////////////////////////////////// | |
//Execute when AddNewEvent button pressed //////// | |
//Adds a new event to the event list ///////////// | |
////////////////////////////////////////////////// | |
function UpdateRule(i) { | |
d3.selectAll(".value").each(function (index, d, k) { | |
for (l = 0; l < events.length; l++) { | |
//console.log($(this).text().replace("−", "-")); | |
if ($(this).text().replace("−", "-") == events[l].value) { | |
$(this).text(events[l].name); | |
} | |
} | |
}).style("right", i == null ? null : context.size() - i + 10 + "px"); | |
} | |
////////////////////////////////////////////////// | |
//BEGIN INPUT FUNCTIONS //////// | |
////////////////////////////////////////////////// | |
////////////////////////////////////////////////// | |
//Execute when AddNewEvent button pressed //////// | |
//Adds a new event to the event list ///////////// | |
////////////////////////////////////////////////// | |
function addNewEvent() { | |
var prefixstring = ""; | |
var suffixstring = ""; | |
if (events.length + 4 < 10) { | |
suffixstring = ".0" | |
} | |
if (events.length % 2 == 0) { | |
prefixstring = "-" | |
} | |
events.push({ | |
name: $("#NewEventName").val(), | |
value: prefixstring + (events.length + 4).toString() + suffixstring | |
}); | |
$(NewEventName).val(''); | |
RefreshEvents(); | |
}; | |
///////////////////////////////////////////////////////////////////// | |
//Execute when AddEvent button pressed ////////////////////////////// | |
//Adds event to the selected user ////////////////////////////////// | |
///////////////////////////////////////////////////////////////////// | |
function addEvent() { | |
Users[$("#UserList").val()].newevent = true; | |
Users[$("#UserList").val()].event = $("#EventList").val(); | |
} | |
////////////////////////////////////////////////// | |
//Execute when AddUser button pressed //////// | |
//Adds a new user to the user list ///////////// | |
////////////////////////////////////////////////// | |
function addUser() { //Add a user function (executed by pressing add user button) | |
totalusers = Users.length + 1; //a variable for total users | |
Users.push({ //add a user to the users object | |
name: $("#UserName").val(), //name equals username text field value | |
event: 1, //default event of 1 | |
newevent: false //the event for this user has not been created yet, so keep the newevent false | |
}); | |
$("#UserName").val(''); //clear the username field | |
RefreshUsers(); //execute the refreshusers function | |
myuser = random(Users[totalusers - 1].name); // | |
AllUsers.push(myuser); //push the user onto the AllUsers array of users | |
RunData(); //Run the data with the new user | |
RefreshRule(); //Refresh the rule for all users (will not refresh new user rule if not invoked) | |
} | |
////////////////////////////////////////////////// | |
//BEGIN SELECT OPTION UPDATE FUNCTIONS //////// | |
////////////////////////////////////////////////// | |
////////////////////////////////////////////////// | |
//Execute RefreshUsers function //////// | |
//Clears and populates the user select option list ///////////// | |
////////////////////////////////////////////////// | |
function RefreshUsers() { | |
$('#UserList') | |
.find('option') | |
.remove(); | |
for (i = 0; i < Users.length; i++) { | |
$('#UserList').append('<option value="' + i + '">' + Users[i].name + '</option>'); | |
} | |
}; | |
////////////////////////////////////////////////// | |
//Execute the RefreshEvents function //////// | |
//Clears and populates the event select option list ///////////// | |
////////////////////////////////////////////////// | |
function RefreshEvents() { | |
$('#EventList') | |
.find('option') | |
.remove(); | |
for (i = 2; i < events.length; i++) { | |
$('#EventList').append('<option value="' + i + '">' + events[i].name + '</option>'); | |
} | |
}; | |
////////////////////////////////////////////////// | |
//Execute the RefreshRule function //////// | |
//Refreshes the horizontal rule on mouse context focus | |
////////////////////////////////////////////////// | |
function RefreshRule() { | |
// On mousemove, reposition the chart values to match the rule. | |
context.on("focus", function (i) { | |
UpdateRule(i) | |
}); | |
} | |
<HTML><HEAD></HEAD><BODY> | |
<link rel="stylesheet" type="text/css" href="discrete-cubism.css"> | |
<div id="example1"></div> | |
<br/>Step 1: Add a user by the name of | |
<input id="UserName" /> | |
<button id="AddUser" onClick="javascript:addUser();">Go!</button> | |
<br/>Step 2: Add a new event by the name of | |
<input id="NewEventName" /> | |
<button id="AddNewEvent" onClick="javascript:addNewEvent();">Go!</button> | |
<br/>Step 3: Add event | |
<select id="EventList"></select>to user | |
<select id="UserList"></select> | |
<button id="AddEvent" onClick="javascript:addEvent();">Go!</button> | |
<br/> | |
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js"></script> | |
<script src="http://square.github.io/cubism/d3.v2.js"></script> | |
<script src="http://square.github.io/cubism/cubism.v1.js"></script> | |
<script src="http://square.github.io/cubism/highlight.min.js"></script> | |
<script src="discrete-cubism.js"></script> | |
</BODY></HTML> | |