Skip to content

Instantly share code, notes, and snippets.

@birm
Last active September 14, 2017 19:27
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save birm/c429d6d120e15e0cc3bb0ccd2661f97d to your computer and use it in GitHub Desktop.
Save birm/c429d6d120e15e0cc3bb0ccd2661f97d to your computer and use it in GitHub Desktop.
{"data":[[457,"0",1,"Millet, Mr. Francis Davis","male",65,0,0,"13509",26.55,"E38","S",null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null],[7,"0",1,"McCarthy, Mr. Timothy J","male",54,0,0,"17463",51.8625,"E46","S",null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null],[22,"1",2,"Beesley, Mr. Lawrence","male",34,0,0,"248698",13,"D56","S",null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null],[873,"0",1,"Carlsson, Mr. Frans Olof","male",33,0,0,"695",5,"B51 B53 B55","S",null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null],[24,"1",1,"Sloper, Mr. William Thompson","male",28,0,0,"113788",35.5,"A6","S",null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null],[868,"0",1,"Roebling, Mr. Washington Augustus II","male",31,0,0,"PC 17590",50.4958,"A24","S",null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null],[28,"0",1,"Fortune, Mr. Charles Alexander","male",19,3,2,"19950",263,"C23 C25 C27","S",null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null],[858,"1",1,"Daly, Mr. Peter Denis ","male",51,0,0,"113055",26.55,"E17","S",null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null],[55,"0",1,"Ostby, Mr. Engelhart Cornelius","male",65,0,1,"113509",61.9792,"B30","C",null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null],[63,"0",1,"Harris, Mr. Henry Birkhardt","male",45,1,0,"36973",83.475,"C83","S",null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null]],"active":0,"state":1,"draw":"1","recordsTotal":183,"recordsFiltered":183}
body {
font-family: sans-serif;
font-size: 12px;
background: #f9f9f9;
color: #777;
margin-top: 40px;
}
body.dark {
background: #090909;
color: #ccc;
}
#wrap {
width: 960px;
margin: 0 auto;
position: relative;
}
svg {
font: 10px sans-serif;
}
canvas, svg {
position: absolute;
top: 0;
left: 0;
}
#chart {
position: relative;
}
.brush .extent {
fill: rgba(0,0,0,0.12);
stroke: rgba(255,255,255,0.6);
shape-rendering: crisp-edges;
}
.axis line, .axis path {
fill: none;
stroke: #222;
shape-rendering: crispEdges;
}
.axis text {
fill: #222;
text-shadow: 1px 1px 1px #fff, -1px -1px 1px #fff;
}
.axis text.label {
fill: #444;
font-size: 14px;
}
.axis g,
.axis path {
display: none;
}
<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8"/>
<title>Parallel Coords DataScope Test</title>
<link rel="stylesheet" type="text/css" href="pc.css">
</head>
<body>
<div id="wrap">
<div id="chart">
<canvas id="foreground"></canvas>
<svg></svg>
</div>
<p>
Rendered: <strong id="rendered-count"></strong><br/>
Selected: <strong id="selected-count"></strong><br/>
</p>
</div>
<script src="http://d3js.org/d3.v2.js"></script>
<script src="pc.js"></script>
</body>
</html>
var all_data = [];
pagnated_json = function(url_generator, callback, finalizer) {
// url_generator can be either a generator (recommended) or an iterator
try {
var xhr = new XMLHttpRequest();
xhr.open("GET", url_generator.next().value, true);
xhr.onload = function(e) {
if (xhr.readyState === 4 && xhr.responseText) {
// if it's not blank, process records and recurse
var records = JSON.parse(xhr.responseText);
if (records['data'].length > 0) {
callback(records);
// recurse and add new request
//xhr.open("GET", url_generator.next().value, true);
pagnated_json(url_generator, callback);
}
}
}
xhr.send();
} catch (e) {
console.log(e);
}
// if the url geneator is done, or response is empty, terminate
}
window.requestAnimFrame = window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.oRequestAnimationFrame ||
window.msRequestAnimationFrame ||
function(callback) {
window.setTimeout(callback, 1000 / 60);
};
var m = [60, 10, 10, 0],
w = 960 - m[1] - m[3],
h = 290 - m[0] - m[2];
var xscale = d3.scale.ordinal().rangePoints([0, w], 1),
yscale = {};
var line = d3.svg.line(),
axis = d3.svg.axis().orient("left"),
foreground,
dimensions;
d3.select("#chart")
.style("width", (w + m[1] + m[3]) + "px")
.style("height", (h + m[0] + m[2]) + "px")
d3.selectAll("canvas")
.attr("width", w)
.attr("height", h)
.style("padding", m.join("px ") + "px");
foreground = document.getElementById('foreground').getContext('2d');
foreground.strokeStyle = "rgba(0,100,160,0.1)";
foreground.lineWidth = 1.3; // avoid weird subpixel effects
function* ds_url_generator() {
var page = 0;
while (true) {
yield "http://localhost:3001/dataTable/next?dataSourceName=main&draw=1&start=" + 10 * page + "&length=10&search";
page += 1;
}
}
var ds_urls = ds_url_generator();
var draw_record = function(data) {
var svg = d3.select("svg")
.attr("width", w + m[1] + m[3])
.attr("height", h + m[0] + m[2])
.append("svg:g")
.attr("transform", "translate(" + m[3] + "," + m[0] + ")");
var brush_count = 0;
// convert datascopr data to a more standard format
names = ["a", "b", "c"]; // TODO make work with actual variable names
data = data['data']; // get the list of lists
function ll_to_obj(data, names) {
res = [];
for (i in data) {
item = {};
for (j in names) {
item[names[j]] = data[i][j];
}
res = res.concat(item);
}
return res
}
data = ll_to_obj(data, names);
data = all_data.concat(data);
all_data = data;
// Convert quantitative scales to floats
data = data.map(function(d) {
for (var k in d) {
if (k != "name" && k != "group" && k != "id")
d[k] = parseFloat(d[k]) || 0;
};
return d;
});
// Extract the list of dimensions and create a scale for each.
xscale.domain(dimensions = d3.keys(data[0]).filter(function(d) {
return d != "name" && d != "group" && d != "id" && (yscale[d] = d3.scale.linear()
.domain(d3.extent(data, function(p) {
return +p[d];
}))
.range([h, 0]));
}));
// Render full foreground
paths(data, foreground, brush_count);
// Add a group element for each dimension.
var g = svg.selectAll(".dimension")
.data(dimensions)
.enter().append("svg:g")
.attr("class", "dimension")
.attr("transform", function(d) {
return "translate(" + xscale(d) + ")";
});
// Add an axis and title.
g.append("svg:g")
.attr("class", "axis")
.each(function(d) {
d3.select(this).call(axis.scale(yscale[d]));
})
.append("svg:text")
.attr("text-anchor", "left")
.attr("y", -8)
.attr("x", -4)
.attr("transform", "rotate(-19)")
.attr("class", "label")
.text(String);
// Add and store a brush for each axis.
g.append("svg:g")
.attr("class", "brush")
.each(function(d) {
d3.select(this).call(yscale[d].brush = d3.svg.brush().y(yscale[d]).on("brush", brush));
})
.selectAll("rect")
.attr("x", -16)
.attr("width", 32)
.attr("rx", 3)
.attr("ry", 3);
// Handles a brush event, toggling the display of foreground lines.
function brush() {
brush_count++;
console.log(dimensions);
var actives = dimensions.filter(function(p) {
console.log(yscale[p]);
return !yscale[p].brush.empty();
}),
extents = actives.map(function(p) {
return yscale[p].brush.extent();
});
// Get lines within extents
var selected = [];
data.map(function(d) {
return actives.every(function(p, i) {
return extents[i][0] <= d[p] && d[p] <= extents[i][1];
}) ? selected.push(d) : null;
});
// Render selected lines
paths(selected, foreground, brush_count);
}
function paths(data, ctx, count) {
var n = data.length,
i = 0,
opacity = d3.min([2 / Math.pow(n, 0.37), 1]);
d3.select("#selected-count").text(n);
data = shuffle(data);
ctx.clearRect(0, 0, w + 1, h + 1);
function render() {
var max = d3.min([i + 12, n]);
data.slice(i, max).forEach(function(d) {
path(d, foreground, color(d.group, opacity));
});
i = max;
d3.select("#rendered-count").text(i);
};
// render all lines until finished or a new brush event
(function animloop() {
if (i >= n || count < brush_count) return;
requestAnimFrame(animloop);
render();
})();
};
}
pagnated_json(ds_urls, draw_record);
function path(d, ctx, color) {
if (color) ctx.strokeStyle = color;
ctx.beginPath();
var x0 = 0,
y0 = 0;
dimensions.map(function(p, i) {
var x = xscale(p),
y = yscale[p](d[p]);
if (i == 0) {
ctx.moveTo(x, y);
} else {
var cp1x = x - 0.85 * (x - x0);
var cp1y = y0;
var cp2x = x - 0.15 * (x - x0);
var cp2y = y;
ctx.bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y);
}
x0 = x;
y0 = y;
});
ctx.stroke();
};
function random255() {
return Math.floor(Math.random() * 255);
}
// random probably visible color (0-60)
// except really just return black
function randomVis() {
//return Math.floor(Math.random()*60);
return 0;
}
function color(d, a) {
//return ["hsla(",randomVis(),",",randomVis(),"%,",randomVis(),"%,",a,")"].join("");
return ["hsla(", randomVis(), ",", randomVis(), "%,", randomVis(), "%,", a, ")"].join("");
};
// Fisher-Yates shuffle
function shuffle(array) {
var m = array.length,
t, i;
// While there remain elements to shuffle…
while (m) {
// Pick a remaining element…
i = Math.floor(Math.random() * m--);
// And swap it with the current element.
t = array[m];
array[m] = array[i];
array[i] = t;
}
return array;
}
window.setTimeout(function() {
d3.selectAll(".axis g").style("display", "block");
d3.selectAll(".axis path").style("display", "block");
}, 200);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment