Created
January 13, 2013 19:28
-
-
Save theon/4525788 to your computer and use it in GitHub Desktop.
Example of a cubism chart used to chart moisture levels from an arduino plant watering system that writes plant moisture levels to a cube server. See: http://theon.github.com/plant-watering-with-arduino.html
This file contains 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
<html> | |
<head> | |
<script type="text/javascript" src="https://raw.github.com/mbostock/d3/master/d3.min.js"></script> | |
<script type="text/javascript" src="https://raw.github.com/square/cubism/master/cubism.v1.min.js"></script> | |
<style> | |
.time-series { | |
font-family: "Helvetica Neue", Helvetica, sans-serif; | |
margin: 30px auto; | |
width: 800px; | |
position: relative; | |
} | |
.time-series .axis { | |
font: 10px sans-serif; | |
pointer-events: none; | |
z-index: 2; | |
} | |
.time-series .axis text { | |
-webkit-transition: fill-opacity 250ms linear; | |
} | |
.time-series .axis path { | |
display: none; | |
} | |
.time-series .axis line { | |
stroke: #000; | |
shape-rendering: crispEdges; | |
} | |
.time-series .axis.top { | |
background-image: linear-gradient(top, #fff 0%, rgba(255,255,255,0) 100%); | |
background-image: -o-linear-gradient(top, #fff 0%, rgba(255,255,255,0) 100%); | |
background-image: -moz-linear-gradient(top, #fff 0%, rgba(255,255,255,0) 100%); | |
background-image: -webkit-linear-gradient(top, #fff 0%, rgba(255,255,255,0) 100%); | |
background-image: -ms-linear-gradient(top, #fff 0%, rgba(255,255,255,0) 100%); | |
top: 0px; | |
} | |
.time-series .axis.bottom { | |
background-image: linear-gradient(bottom, #fff 0%, rgba(255,255,255,0) 100%); | |
background-image: -o-linear-gradient(bottom, #fff 0%, rgba(255,255,255,0) 100%); | |
background-image: -moz-linear-gradient(bottom, #fff 0%, rgba(255,255,255,0) 100%); | |
background-image: -webkit-linear-gradient(bottom, #fff 0%, rgba(255,255,255,0) 100%); | |
background-image: -ms-linear-gradient(bottom, #fff 0%, rgba(255,255,255,0) 100%); | |
bottom: 0px; | |
} | |
.time-series .horizon { | |
border-bottom: solid 1px #000; | |
overflow: hidden; | |
position: relative; | |
} | |
.time-series .horizon { | |
border-top: solid 1px #000; | |
border-bottom: solid 1px #000; | |
} | |
.time-series .horizon + .horizon { | |
border-top: none; | |
} | |
.time-series .horizon canvas { | |
display: block; | |
} | |
.time-series .horizon .title, | |
.time-series .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; | |
font-size: 120%; | |
} | |
.time-series .horizon .title { | |
left: 0; | |
} | |
.time-series .horizon .value { | |
right: 0; | |
} | |
.time-series .line { | |
background: #000; | |
opacity: .2; | |
z-index: 2; | |
} | |
@media all and (max-width: 1439px) { | |
.time-series { margin: 0px auto; } | |
.time-series .axis { position: static; } | |
.time-series .axis.top, .time-series .axis.bottom { padding: 0; } | |
} | |
</style> | |
<script type="text/javascript"> | |
var contexts = []; | |
var moistureHeight = 300; | |
var moistureExtent = 1023; | |
function renderTimeSeries(expression, title, container, extent, step, colours) { | |
var context = cubism.context() | |
.serverDelay(0) | |
.clientDelay(0) | |
.step(step) //3e5 5 minute | |
.size(800); | |
// 1e4 - 10-second | |
// 6e4 - 1-minute | |
// 3e5 - 5-minute | |
// 36e5 - 1-hour | |
// 864e5 - 1-day | |
contexts.push(context); | |
var horizon = context.horizon(); | |
horizon.height(moistureHeight); | |
horizon.title(title); | |
horizon.extent(extent); | |
horizon.colors(colours); | |
var cube = context.cube("http://54.247.0.0"); | |
var metric = cube.metric(expression); | |
var metrics = [ | |
metric | |
]; | |
d3.select(container).selectAll(".axis") | |
.data(["top", "bottom"]) | |
.enter().append("div") | |
.attr("class", function(d) { return d + " axis"; }) | |
.each(function(d) { d3.select(this).call(context.axis().ticks(12).orient(d)); }); | |
d3.select(container).selectAll(".horizon") | |
.data(metrics) | |
.enter().insert("div", ".bottom") | |
.attr("class", "horizon") | |
.call(horizon); | |
context.on("focus", function(i) { | |
d3.selectAll(container + " .value").style("right", i == null ? null : context.size() - i + "px"); | |
var val = parseInt(metric.valueAt(parseInt(i))); | |
if(!isNaN(val)) { | |
d3.selectAll(container + " .value").text(val); | |
} | |
}); | |
} | |
function addRules() { | |
for(var i=0; i<contexts.length; i++) { | |
d3.selectAll(".time-series").append("div") | |
.attr("class", "rule") | |
.call(contexts[i].rule()); | |
} | |
} | |
function drawWaterLine() { | |
var canvas = document.getElementById("moisture-time-series").getElementsByTagName("canvas")[0]; | |
var ctx = canvas.getContext("2d"); | |
ctx.strokeStyle = "#F66"; | |
ctx.lineWidth = 1; | |
var amount = (moistureExtent - 350) * (moistureHeight / moistureExtent); | |
ctx.moveTo(0, amount); | |
ctx.lineTo(1000, amount); | |
ctx.stroke(); | |
} | |
</script> | |
</head> | |
<body> | |
<div id="moisture-time-series" class="time-series"> | |
<script type="text/javascript"> | |
renderTimeSeries("1023 - (sum(moisture(moisture)) / sum(moisture))", "Soil Moisture", "#moisture-time-series", [0, moistureExtent], 3e5, ["#31a354", "#E9967A"]); | |
</script> | |
</div> | |
<div id="watering-time-series" class="time-series"> | |
<script type="text/javascript"> | |
renderTimeSeries("max(moisture(watered))", "Watering Events", "#watering-time-series", [0, 1], 3e5, ["#08519c", "#6baed6"]); | |
</script> | |
</div> | |
<script type="text/javascript"> | |
addRules(); | |
setTimeout(drawWaterLine, 1000); | |
</script> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment