Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Merge branch 'release'

  • Loading branch information...
commit 3588bbca8836bafa4e52f9352f44c3a8da0b2306 2 parents 330f547 + a2f8431
@mbostock mbostock authored
View
43 lib/cube/client/piece-area.js
@@ -25,25 +25,28 @@ cube.piece.type.area = function(board) {
var time = div.append("div")
.attr("class", "time")
- .text("Time Range:")
- .append("select")
- .on("change.area", area.edit)
- .on("focus.area", area.focus)
- .on("blur.area", area.blur);
+ .text("Time Range:");
- time.selectAll("option")
+ time.append("input");
+
+ time.append("select").selectAll("option")
.data([
- {description: "1 Day / 5-Minute", value: 864e5 + "/" + 3e5},
- {description: "3 Days / 5-Minute", value: 3 * 864e5 + "/" + 3e5},
- {description: "7 Days / Hour", value: 7 * 864e5 + "/" + 36e5},
- {description: "14 Days / Hour", value: 14 * 864e5 + "/" + 36e5},
- {description: "30 Days / Hour", value: 30 * 864e5 + "/" + 36e5},
- {description: "30 Days / Day", value: 30 * 864e5 + "/" + 864e5}
+ {description: "Seconds @ 20", value: 2e4},
+ {description: "Minutes @ 5", value: 3e5},
+ {description: "Hours", value: 36e5},
+ {description: "Days", value: 864e5},
+ {description: "Weeks", value: 6048e5},
+ {description: "Months", value: 2592e6}
])
.enter().append("option")
.property("selected", function(d, i) { return i == 1; })
.attr("value", cube_piece_areaValue)
.text(function(d) { return d.description; });
+
+ time.selectAll("input,select")
+ .on("change.area", area.edit)
+ .on("focus.area", area.focus)
+ .on("blur.area", area.blur)
} else {
var m = [6, 40, 14, 10], // top, right, bottom, left margins
socket;
@@ -86,7 +89,7 @@ cube.piece.type.area = function(board) {
.style("height", innerSize[1] - 58 + "px");
transition.select(".time select")
- .style("width", innerSize[0] - 100 + "px");
+ .style("width", innerSize[0] - 174 + "px");
} else {
var z = board.squareSize(),
@@ -147,16 +150,18 @@ cube.piece.type.area = function(board) {
}
function serialize(json) {
- var t = time.property("value").split("/");
+ var step = +time.select("select").property("value"),
+ range = time.select("input").property("value") * cube_piece_areaMultipler(step);
json.type = "area";
json.query = query.property("value");
- json.time = {range: +t[0], step: +t[1]};
+ json.time = {range: range, step: step};
}
function deserialize(json) {
if (mode == "edit") {
query.property("value", json.query);
- time.property("value", json.time.range + "/" + json.time.step);
+ time.select("input").property("value", json.time.range / cube_piece_areaMultipler(json.time.step));
+ time.select("select").property("value", json.time.step);
} else {
var dt1 = json.time.step,
t1 = new Date(Math.floor(Date.now() / dt1) * dt1),
@@ -235,6 +240,12 @@ function cube_piece_areaValue(d) {
var cube_piece_formatNumber = d3.format(".2r");
+function cube_piece_areaMultipler(step) {
+ return step / (step === 2e4 ? 20
+ : step === 3e5 ? 5
+ : 1);
+}
+
function cube_piece_format(domain) {
var prefix = d3.formatPrefix(Math.max(-domain[0], domain[1]), 2);
return function(value) {
View
37 lib/cube/client/piece-sum.js
@@ -26,25 +26,28 @@ cube.piece.type.sum = function(board) {
var time = div.append("div")
.attr("class", "time")
- .text("Time Range:")
- .append("select")
- .on("change.sum", sum.edit)
- .on("focus.sum", sum.focus)
- .on("blur.sum", sum.blur);
+ .text("Time Range:");
+
+ time.append("input");
- time.selectAll("option")
+ time.append("select").selectAll("option")
.data([
- {description: "5 Minutes / 5-Minute", value: 3e5 + "/" + 3e5},
- {description: "1 Hour / 5-Minute", value: 36e5 + "/" + 3e5},
- {description: "1 Hour / Hour", value: 36e5 + "/" + 36e5},
- {description: "1 Day / 5-Minute", value: 864e5 + "/" + 3e5},
- {description: "1 Day / Hour", value: 864e5 + "/" + 36e5},
- {description: "1 Day / Day", value: 864e5 + "/" + 864e5}
+ {description: "Seconds @ 20", value: 2e4},
+ {description: "Minutes @ 5", value: 3e5},
+ {description: "Hours", value: 36e5},
+ {description: "Days", value: 864e5},
+ {description: "Weeks", value: 6048e5},
+ {description: "Months", value: 2592e6}
])
.enter().append("option")
.property("selected", function(d, i) { return i == 1; })
.attr("value", cube_piece_areaValue)
.text(function(d) { return d.description; });
+
+ time.selectAll("input,select")
+ .on("change.sum", sum.edit)
+ .on("focus.sum", sum.focus)
+ .on("blur.sum", sum.blur)
}
function resize() {
@@ -57,7 +60,7 @@ cube.piece.type.sum = function(board) {
.style("height", innerSize[1] - 58 + "px");
transition.select(".time select")
- .style("width", innerSize[0] - 100 + "px");
+ .style("width", innerSize[0] - 174 + "px");
} else {
transition
.style("font-size", innerSize[0] / 5 + "px")
@@ -77,17 +80,19 @@ cube.piece.type.sum = function(board) {
}
function serialize(json) {
- var t = time.property("value").split("/");
+ var step = +time.select("select").property("value"),
+ range = time.select("input").property("value") * cube_piece_areaMultipler(step);
json.type = "sum";
json.query = query.property("value");
- json.time = {range: +t[0], step: +t[1]};
+ json.time = {range: range, step: step};
}
function deserialize(json) {
if (!json.time.range) json.time = {range: json.time, step: 3e5};
if (mode == "edit") {
query.property("value", json.query);
- time.property("value", json.time.range + "/" + json.time.step);
+ time.select("input").property("value", json.time.range / cube_piece_areaMultipler(json.time.step));
+ time.select("select").property("value", json.time.step);
} else {
var dt = json.time.step,
t1 = new Date(Math.floor(Date.now() / dt) * dt),
View
7 lib/cube/client/piece.css
@@ -29,7 +29,7 @@
margin: 4px;
}
-.piece textarea {
+.piece textarea, .piece input {
margin-left: 4px;
height: 20px;
border-radius: 4px;
@@ -43,6 +43,11 @@
line-height: 20px;
}
+.piece input {
+ height: 16px;
+ width: 88px;
+}
+
.piece select {
margin-right: 4px;
float: right;
View
9 lib/cube/server/metric.js
@@ -58,13 +58,12 @@ exports.getter = function(db) {
// Request any needed fields.
expression.fields(fields);
- find(start, stop, tier, callback);
+ find(start, stop, tier, reduce.pyramidal && tier.next, callback);
// The metric is computed recursively, reusing the above variables.
- function find(start, stop, tier, callback) {
+ function find(start, stop, tier, pyramidal, callback) {
var compute = group ? (group.multi ? computeGroups : computeGroup)
- : tier.next && reduce.pyramidal ? computePyramidal
- : computeFlat;
+ : pyramidal ? computePyramidal : computeFlat;
// Query for the desired metric in the cache.
type.metrics.find({
@@ -165,7 +164,7 @@ exports.getter = function(db) {
// Group metrics from the next tier.
function computePyramidal(start, stop) {
var bins = {};
- find(start, stop, tier.next, function(time, value) {
+ find(start, stop, tier.next, false, function(time, value) {
var bin = bins[time = tier.floor(time)] || (bins[time] = {size: tier.size(time), values: []});
if (bin.values.push(value) === bin.size) {
save(time, reduce(bin.values));
View
12 lib/cube/server/tiers.js
@@ -1,6 +1,7 @@
var tiers = module.exports = {};
var second = 1000,
+ second20 = 20 * second,
minute = 60 * second,
minute5 = 5 * minute,
hour = 60 * minute,
@@ -9,11 +10,20 @@ var second = 1000,
month = 30 * day,
year = 365 * day;
+tiers[second20] = {
+ key: second20,
+ floor: function(d) { return new Date(Math.floor(d / second20) * second20); },
+ ceil: tier_ceil,
+ step: function(d) { return new Date(+d + second20); }
+};
+
tiers[minute5] = {
key: minute5,
floor: function(d) { return new Date(Math.floor(d / minute5) * minute5); },
ceil: tier_ceil,
- step: function(d) { return new Date(+d + minute5); }
+ step: function(d) { return new Date(+d + minute5); },
+ next: tiers[second20],
+ size: function() { return 15; }
};
tiers[hour] = {
View
2  package.json
@@ -1,6 +1,6 @@
{
"name": "cube",
- "version": "0.0.13",
+ "version": "0.0.14",
"description": "A system for time series visualization using MongoDB, Node and D3.",
"keywords": ["time series", "visualization"],
"homepage": "http://square.github.com/cube/",
View
71 test/tiers-test.js
@@ -13,14 +13,14 @@ suite.addBatch({
keys.push(+key);
}
keys.sort(function(a, b) { return a - b; });
- assert.deepEqual(keys, [3e5, 36e5, 864e5, 6048e5, 2592e6]);
+ assert.deepEqual(keys, [2e4, 3e5, 36e5, 864e5, 6048e5, 2592e6]);
}
},
- "minute5": {
- topic: tiers[3e5],
- "has the key 3e5": function(tier) {
- assert.strictEqual(tier.key, 3e5);
+ "second20": {
+ topic: tiers[2e4],
+ "has the key 2e4": function(tier) {
+ assert.strictEqual(tier.key, 2e4);
},
"next is undefined": function(tier) {
assert.isUndefined(tier.next);
@@ -30,6 +30,67 @@ suite.addBatch({
},
"floor": {
+ "rounds down to 20-seconds": function(tier) {
+ assert.deepEqual(tier.floor(utc(2011, 08, 02, 12, 00, 20)), utc(2011, 08, 02, 12, 00, 20));
+ assert.deepEqual(tier.floor(utc(2011, 08, 02, 12, 00, 21)), utc(2011, 08, 02, 12, 00, 20));
+ assert.deepEqual(tier.floor(utc(2011, 08, 02, 12, 00, 23)), utc(2011, 08, 02, 12, 00, 20));
+ assert.deepEqual(tier.floor(utc(2011, 08, 02, 12, 00, 39)), utc(2011, 08, 02, 12, 00, 20));
+ assert.deepEqual(tier.floor(utc(2011, 08, 02, 12, 00, 40)), utc(2011, 08, 02, 12, 00, 40));
+ },
+ "does not modify the passed-in date": function(tier) {
+ var date = utc(2011, 08, 02, 12, 00, 21);
+ assert.deepEqual(tier.floor(date), utc(2011, 08, 02, 12, 00, 20));
+ assert.deepEqual(date, utc(2011, 08, 02, 12, 00, 21));
+ }
+ },
+
+ "ceil": {
+ "rounds up to 5-minutes": function(tier) {
+ assert.deepEqual(tier.ceil(utc(2011, 08, 02, 12, 00, 20)), utc(2011, 08, 02, 12, 00, 20));
+ assert.deepEqual(tier.ceil(utc(2011, 08, 02, 12, 00, 21)), utc(2011, 08, 02, 12, 00, 40));
+ assert.deepEqual(tier.ceil(utc(2011, 08, 02, 12, 00, 23)), utc(2011, 08, 02, 12, 00, 40));
+ assert.deepEqual(tier.ceil(utc(2011, 08, 02, 12, 00, 39)), utc(2011, 08, 02, 12, 00, 40));
+ assert.deepEqual(tier.ceil(utc(2011, 08, 02, 12, 00, 40)), utc(2011, 08, 02, 12, 00, 40));
+ },
+ "does not modified the specified date": function(tier) {
+ var date = utc(2011, 08, 02, 12, 00, 21);
+ assert.deepEqual(tier.ceil(date), utc(2011, 08, 02, 12, 00, 40));
+ assert.deepEqual(date, utc(2011, 08, 02, 12, 00, 21));
+ }
+ },
+
+ "step": {
+ "increments time by twenty minutes": function(tier) {
+ var date = utc(2011, 08, 02, 23, 59, 20);
+ assert.deepEqual(date = tier.step(date), utc(2011, 08, 02, 23, 59, 40));
+ assert.deepEqual(date = tier.step(date), utc(2011, 08, 03, 00, 00, 00));
+ assert.deepEqual(date = tier.step(date), utc(2011, 08, 03, 00, 00, 20));
+ assert.deepEqual(date = tier.step(date), utc(2011, 08, 03, 00, 00, 40));
+ assert.deepEqual(date = tier.step(date), utc(2011, 08, 03, 00, 01, 00));
+ },
+ "does not round the specified date": function(tier) {
+ assert.deepEqual(tier.step(utc(2011, 08, 02, 12, 21, 23)), utc(2011, 08, 02, 12, 21, 43));
+ },
+ "does not modify the specified date": function(tier) {
+ var date = utc(2011, 08, 02, 12, 20, 00);
+ assert.deepEqual(tier.step(date), utc(2011, 08, 02, 12, 20, 20));
+ assert.deepEqual(date, utc(2011, 08, 02, 12, 20, 00));
+ }
+ }
+ },
+ "minute5": {
+ topic: tiers[3e5],
+ "has the key 3e5": function(tier) {
+ assert.strictEqual(tier.key, 3e5);
+ },
+ "next is the 20-second tier": function(tier) {
+ assert.equal(tier.next, tiers[2e4]);
+ },
+ "size is 15": function(tier) {
+ assert.strictEqual(tier.size(), 15);
+ },
+
+ "floor": {
"rounds down to 5-minutes": function(tier) {
assert.deepEqual(tier.floor(utc(2011, 08, 02, 12, 20, 00)), utc(2011, 08, 02, 12, 20));
assert.deepEqual(tier.floor(utc(2011, 08, 02, 12, 20, 01)), utc(2011, 08, 02, 12, 20));
Please sign in to comment.
Something went wrong with that request. Please try again.