-
-
Save 100ideas/4499539 to your computer and use it in GitHub Desktop.
prototype of @brewlabsf sensor dashboard
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
<!DOCTYPE html> | |
<head> | |
<!-- <link href="../src/nv.d3.css" rel="stylesheet" type="text/css"> --> | |
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script> | |
<style> | |
<!DOCTYPE html> | |
<head> | |
<!-- <link href="../src/nv.d3.css" rel="stylesheet" type="text/css"> --> | |
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script> | |
<style> | |
body { | |
overflow-y:scroll; | |
} | |
text { | |
font: 12px sans-serif; | |
} | |
svg { | |
display: block; | |
} | |
#chart svg { | |
height: 500px; | |
min-width: 100px; | |
min-height: 100px; | |
/* | |
margin: 50px; | |
Minimum height and width is a good idea to prevent negative SVG dimensions... | |
For example width should be =< margin.left + margin.right + 1, | |
of course 1 pixel for the entire chart would not be very useful, BUT should not have errors | |
*/ | |
} | |
</style> | |
</head> | |
<body> | |
<div id="chart"> | |
<svg></svg> | |
</div> | |
<script src="http://d3js.org/d3.v3.min.js"></script> | |
<script src="http://nvd3.org/nv.d3.js"></script> | |
<!-- based on example at http://nvd3.org/livecode/#codemirrorNav --> | |
<script> | |
var temps = []; | |
var sensorCount = 1; | |
for (var i=0; i < sensorCount; i++) { | |
$.getJSON('http://hq.brewlabsf.com:5984/narwhal/_design/sensor/_view/UUID?key=%22284243_'+ i + '%22&callback=?', function(data) { | |
console.log("data returned: " + data) | |
sensorNumber = parseInt(data.rows[0].key.split("_")[1]) | |
temps[sensorNumber] = parseTemps(data); | |
if (sensorNumber == (sensorCount - 1)) {visualizeIt(temps);} | |
}.bind(this)); | |
}; | |
function parseTemps (data, index){ | |
var rawdata = data.rows; | |
var values = []; | |
var colors = ['#00FF00', '#0000FF', '#0000FF', '#ff7foe'] | |
var avg_temp = 1; | |
var avg_count = 1; | |
for (var i = 0; i < rawdata.length; i++) { | |
// discard spuriously low measurements | |
if (rawdata[i].value.temperature > 16){ | |
avg_temp = avg_temp + parseInt(rawdata[i].value.temperature); | |
avg_count++; | |
} | |
// average together the last 10 measurements (that are also "good") | |
// and add the average to the graph data | |
if ( i > 1 && i%128 === 0 ){ | |
values.push({ | |
x: rawdata[i].value.time, | |
y: Math.round( (avg_temp / avg_count) * 1000 ) / 1000 // shorten decimal | |
}); | |
// console.log("\n 10th measurement, avg: " + Math.round( (avg_temp / avg_count) * 1000 ) / 1000); | |
avg_count = 1; | |
avg_temp = 1; | |
} | |
}; | |
return [{ | |
values: values, | |
key: rawdata[0].value.UUID, | |
color: colors[index] | |
}]; | |
} | |
var chart; | |
function visualizeIt(temps) { | |
console.log(temps); | |
nv.addGraph(function() { | |
chart = nv.models.lineWithFocusChart(); | |
chart.x(function(d,i) { return i }) | |
chart.xAxis | |
.axisLabel('Time (min)') | |
.tickFormat(d3.format(',r')) | |
// TODO figure out time scale | |
.scale( d3.time.scale() ); | |
chart.yAxis | |
.axisLabel('Temperature (C)') | |
.tickFormat(d3.format('.02f')); | |
chart.y2Axis | |
.tickFormat(d3.format(',.2f')); | |
for (var i = 0; i < temps.length; i++) { | |
d3.select('#chart svg') | |
.datum( temps[i] ) | |
.transition().duration(500) | |
.call(chart); | |
}; | |
nv.utils.windowResize(chart.update); | |
// chart.dispatch.on('stateChange', function(e) { nv.log('New State:', JSON.stringify(e)); }); | |
return chart; | |
}); | |
} | |
</script> | |
<style type="text/css"> | |
/******************** | |
* HTML CSS | |
*/ | |
.chartWrap { | |
margin: 0; | |
padding: 0; | |
overflow: hidden; | |
} | |
/******************** | |
* TOOLTIP CSS | |
*/ | |
.nvtooltip { | |
position: absolute; | |
background-color: rgba(255,255,255,1); | |
padding: 10px; | |
border: 1px solid #ddd; | |
z-index: 10000; | |
font-family: Arial; | |
font-size: 13px; | |
transition: opacity 500ms linear; | |
-moz-transition: opacity 500ms linear; | |
-webkit-transition: opacity 500ms linear; | |
transition-delay: 500ms; | |
-moz-transition-delay: 500ms; | |
-webkit-transition-delay: 500ms; | |
-moz-box-shadow: 4px 4px 8px rgba(0,0,0,.5); | |
-webkit-box-shadow: 4px 4px 8px rgba(0,0,0,.5); | |
box-shadow: 4px 4px 8px rgba(0,0,0,.5); | |
-moz-border-radius: 10px; | |
border-radius: 10px; | |
pointer-events: none; | |
-webkit-touch-callout: none; | |
-webkit-user-select: none; | |
-khtml-user-select: none; | |
-moz-user-select: none; | |
-ms-user-select: none; | |
user-select: none; | |
} | |
.nvtooltip h3 { | |
margin: 0; | |
padding: 0; | |
text-align: center; | |
} | |
.nvtooltip p { | |
margin: 0; | |
padding: 0; | |
text-align: center; | |
} | |
.nvtooltip span { | |
display: inline-block; | |
margin: 2px 0; | |
} | |
.nvtooltip-pending-removal { | |
position: absolute; | |
pointer-events: none; | |
} | |
/******************** | |
* SVG CSS | |
*/ | |
svg { | |
-webkit-touch-callout: none; | |
-webkit-user-select: none; | |
-khtml-user-select: none; | |
-moz-user-select: none; | |
-ms-user-select: none; | |
user-select: none; | |
/* Trying to get SVG to act like a greedy block in all browsers */ | |
display: block; | |
width:100%; | |
height:100%; | |
} | |
svg text { | |
font: normal 12px Arial; | |
} | |
svg .title { | |
font: bold 14px Arial; | |
} | |
.nvd3 .nv-background { | |
fill: white; | |
fill-opacity: 0; | |
/* | |
pointer-events: none; | |
*/ | |
} | |
.nvd3.nv-noData { | |
font-size: 18px; | |
font-weight: bolf; | |
} | |
/********** | |
* Brush | |
*/ | |
.nv-brush .extent { | |
fill-opacity: .125; | |
shape-rendering: crispEdges; | |
} | |
/********** | |
* Legend | |
*/ | |
.nvd3 .nv-legend .nv-series { | |
cursor: pointer; | |
} | |
.nvd3 .nv-legend .disabled circle { | |
fill-opacity: 0; | |
} | |
/********** | |
* Axes | |
*/ | |
.nvd3 .nv-axis path { | |
fill: none; | |
stroke: #000; | |
stroke-opacity: .75; | |
shape-rendering: crispEdges; | |
} | |
.nvd3 .nv-axis path.domain { | |
stroke-opacity: .75; | |
} | |
.nvd3 .nv-axis.nv-x path.domain { | |
stroke-opacity: 0; | |
} | |
.nvd3 .nv-axis line { | |
fill: none; | |
stroke: #000; | |
stroke-opacity: .25; | |
shape-rendering: crispEdges; | |
} | |
.nvd3 .nv-axis line.zero { | |
stroke-opacity: .75; | |
} | |
.nvd3 .nv-axis .nv-axisMaxMin text { | |
font-weight: bold; | |
} | |
.nvd3 .x .nv-axis .nv-axisMaxMin text, | |
.nvd3 .x2 .nv-axis .nv-axisMaxMin text, | |
.nvd3 .x3 .nv-axis .nv-axisMaxMin text { | |
text-anchor: middle | |
} | |
/********** | |
* Brush | |
*/ | |
.nv-brush .resize path { | |
fill: #eee; | |
stroke: #666; | |
} | |
/********** | |
* Bars | |
*/ | |
.nvd3 .nv-bars .negative rect { | |
zfill: brown; | |
} | |
.nvd3 .nv-bars rect { | |
zfill: steelblue; | |
fill-opacity: .75; | |
transition: fill-opacity 250ms linear; | |
-moz-transition: fill-opacity 250ms linear; | |
-webkit-transition: fill-opacity 250ms linear; | |
} | |
.nvd3 .nv-bars rect:hover { | |
fill-opacity: 1; | |
} | |
.nvd3 .nv-bars .hover rect { | |
fill: lightblue; | |
} | |
.nvd3 .nv-bars text { | |
fill: rgba(0,0,0,0); | |
} | |
.nvd3 .nv-bars .hover text { | |
fill: rgba(0,0,0,1); | |
} | |
/********** | |
* Bars | |
*/ | |
.nvd3 .nv-multibar .nv-groups rect, | |
.nvd3 .nv-multibarHorizontal .nv-groups rect, | |
.nvd3 .nv-discretebar .nv-groups rect { | |
stroke-opacity: 0; | |
transition: fill-opacity 250ms linear; | |
-moz-transition: fill-opacity 250ms linear; | |
-webkit-transition: fill-opacity 250ms linear; | |
} | |
.nvd3 .nv-multibar .nv-groups rect:hover, | |
.nvd3 .nv-multibarHorizontal .nv-groups rect:hover, | |
.nvd3 .nv-discretebar .nv-groups rect:hover { | |
fill-opacity: 1; | |
} | |
.nvd3 .nv-discretebar .nv-groups text, | |
.nvd3 .nv-multibarHorizontal .nv-groups text { | |
font-weight: bold; | |
fill: rgba(0,0,0,1); | |
stroke: rgba(0,0,0,0); | |
} | |
/*********** | |
* Pie Chart | |
*/ | |
.nvd3.nv-pie path { | |
stroke-opacity: 0; | |
transition: fill-opacity 250ms linear, stroke-width 250ms linear, stroke-opacity 250ms linear; | |
-moz-transition: fill-opacity 250ms linear, stroke-width 250ms linear, stroke-opacity 250ms linear; | |
-webkit-transition: fill-opacity 250ms linear, stroke-width 250ms linear, stroke-opacity 250ms linear; | |
} | |
.nvd3.nv-pie .nv-slice text { | |
stroke: #000; | |
stroke-width: 0; | |
} | |
.nvd3.nv-pie path { | |
stroke: #fff; | |
stroke-width: 1px; | |
stroke-opacity: 1; | |
} | |
.nvd3.nv-pie .hover path { | |
fill-opacity: .7; | |
/* | |
stroke-width: 6px; | |
stroke-opacity: 1; | |
*/ | |
} | |
.nvd3.nv-pie .nv-label rect { | |
fill-opacity: 0; | |
stroke-opacity: 0; | |
} | |
/********** | |
* Lines | |
*/ | |
.nvd3 .nv-groups path.nv-line { | |
fill: none; | |
stroke-width: 2.5px; | |
/* | |
stroke-linecap: round; | |
shape-rendering: geometricPrecision; | |
transition: stroke-width 250ms linear; | |
-moz-transition: stroke-width 250ms linear; | |
-webkit-transition: stroke-width 250ms linear; | |
transition-delay: 250ms | |
-moz-transition-delay: 250ms; | |
-webkit-transition-delay: 250ms; | |
*/ | |
} | |
.nvd3 .nv-groups path.nv-area { | |
stroke: none; | |
/* | |
stroke-linecap: round; | |
shape-rendering: geometricPrecision; | |
stroke-width: 2.5px; | |
transition: stroke-width 250ms linear; | |
-moz-transition: stroke-width 250ms linear; | |
-webkit-transition: stroke-width 250ms linear; | |
transition-delay: 250ms | |
-moz-transition-delay: 250ms; | |
-webkit-transition-delay: 250ms; | |
*/ | |
} | |
.nvd3 .nv-line.hover path { | |
stroke-width: 6px; | |
} | |
/* | |
.nvd3.scatter .groups .point { | |
fill-opacity: 0.1; | |
stroke-opacity: 0.1; | |
} | |
*/ | |
.nvd3.nv-line .nvd3.nv-scatter .nv-groups .nv-point { | |
fill-opacity: 0; | |
stroke-opacity: 0; | |
} | |
.nvd3.nv-scatter.nv-single-point .nv-groups .nv-point { | |
fill-opacity: .5 !important; | |
stroke-opacity: .5 !important; | |
} | |
.nvd3 .nv-groups .nv-point { | |
transition: stroke-width 250ms linear, stroke-opacity 250ms linear; | |
-moz-transition: stroke-width 250ms linear, stroke-opacity 250ms linear; | |
-webkit-transition: stroke-width 250ms linear, stroke-opacity 250ms linear; | |
} | |
.nvd3.nv-scatter .nv-groups .nv-point.hover, | |
.nvd3 .nv-groups .nv-point.hover { | |
stroke-width: 20px; | |
fill-opacity: .5 !important; | |
stroke-opacity: .5 !important; | |
} | |
.nvd3 .nv-point-paths path { | |
stroke: #aaa; | |
stroke-opacity: 0; | |
fill: #eee; | |
fill-opacity: 0; | |
} | |
.nvd3 .nv-indexLine { | |
cursor: ew-resize; | |
} | |
/********** | |
* Distribution | |
*/ | |
.nvd3 .nv-distribution { | |
pointer-events: none; | |
} | |
/********** | |
* Scatter | |
*/ | |
/* **Attempting to remove this for useVoronoi(false), need to see if it's required anywhere | |
.nvd3 .nv-groups .nv-point { | |
pointer-events: none; | |
} | |
*/ | |
.nvd3 .nv-groups .nv-point.hover { | |
stroke-width: 20px; | |
stroke-opacity: .5; | |
} | |
.nvd3 .nv-scatter .nv-point.hover { | |
fill-opacity: 1; | |
} | |
/* | |
.nv-group.hover .nv-point { | |
fill-opacity: 1; | |
} | |
*/ | |
/********** | |
* Stacked Area | |
*/ | |
.nvd3.nv-stackedarea path.nv-area { | |
fill-opacity: .7; | |
/* | |
stroke-opacity: .65; | |
fill-opacity: 1; | |
*/ | |
stroke-opacity: 0; | |
transition: fill-opacity 250ms linear, stroke-opacity 250ms linear; | |
-moz-transition: fill-opacity 250ms linear, stroke-opacity 250ms linear; | |
-webkit-transition: fill-opacity 250ms linear, stroke-opacity 250ms linear; | |
/* | |
transition-delay: 500ms; | |
-moz-transition-delay: 500ms; | |
-webkit-transition-delay: 500ms; | |
*/ | |
} | |
.nvd3.nv-stackedarea path.nv-area.hover { | |
fill-opacity: .9; | |
/* | |
stroke-opacity: .85; | |
*/ | |
} | |
/* | |
.d3stackedarea .groups path { | |
stroke-opacity: 0; | |
} | |
*/ | |
.nvd3.nv-stackedarea .nv-groups .nv-point { | |
stroke-opacity: 0; | |
fill-opacity: 0; | |
} | |
.nvd3.nv-stackedarea .nv-groups .nv-point.hover { | |
stroke-width: 20px; | |
stroke-opacity: .75; | |
fill-opacity: 1; | |
} | |
/********** | |
* Line Plus Bar | |
*/ | |
.nvd3.nv-linePlusBar .nv-bar rect { | |
fill-opacity: .75; | |
} | |
.nvd3.nv-linePlusBar .nv-bar rect:hover { | |
fill-opacity: 1; | |
} | |
/********** | |
* Bullet | |
*/ | |
.nvd3.nv-bullet { font: 10px sans-serif; } | |
.nvd3.nv-bullet .nv-measure { fill-opacity: .8; } | |
.nvd3.nv-bullet .nv-measure:hover { fill-opacity: 1; } | |
.nvd3.nv-bullet .nv-marker { stroke: #000; stroke-width: 2px; } | |
.nvd3.nv-bullet .nv-markerTriangle { stroke: #000; fill: #fff; stroke-width: 1.5px; } | |
.nvd3.nv-bullet .nv-tick line { stroke: #666; stroke-width: .5px; } | |
.nvd3.nv-bullet .nv-range.nv-s0 { fill: #eee; } | |
.nvd3.nv-bullet .nv-range.nv-s1 { fill: #ddd; } | |
.nvd3.nv-bullet .nv-range.nv-s2 { fill: #ccc; } | |
.nvd3.nv-bullet .nv-title { font-size: 14px; font-weight: bold; } | |
.nvd3.nv-bullet .nv-subtitle { fill: #999; } | |
.nvd3.nv-bullet .nv-range { | |
fill: #999; | |
fill-opacity: .4; | |
} | |
.nvd3.nv-bullet .nv-range:hover { | |
fill-opacity: .7; | |
} | |
/********** | |
* Sparkline | |
*/ | |
.nvd3.nv-sparkline path { | |
fill: none; | |
} | |
.nvd3.nv-sparklineplus g.nv-hoverValue { | |
pointer-events: none; | |
} | |
.nvd3.nv-sparklineplus .nv-hoverValue line { | |
stroke: #333; | |
stroke-width: 1.5px; | |
} | |
.nvd3.nv-sparklineplus, | |
.nvd3.nv-sparklineplus g { | |
pointer-events: all; | |
} | |
.nvd3 .nv-hoverArea { | |
fill-opacity: 0; | |
stroke-opacity: 0; | |
} | |
.nvd3.nv-sparklineplus .nv-xValue, | |
.nvd3.nv-sparklineplus .nv-yValue { | |
/* | |
stroke: #666; | |
*/ | |
stroke-width: 0; | |
font-size: .9em; | |
font-weight: normal; | |
} | |
.nvd3.nv-sparklineplus .nv-yValue { | |
stroke: #f66; | |
} | |
.nvd3.nv-sparklineplus .nv-maxValue { | |
stroke: #2ca02c; | |
fill: #2ca02c; | |
} | |
.nvd3.nv-sparklineplus .nv-minValue { | |
stroke: #d62728; | |
fill: #d62728; | |
} | |
.nvd3.nv-sparklineplus .nv-currentValue { | |
/* | |
stroke: #444; | |
fill: #000; | |
*/ | |
font-weight: bold; | |
font-size: 1.1em; | |
} | |
/********** | |
* historical stock | |
*/ | |
.nvd3.nv-ohlcBar .nv-ticks .nv-tick { | |
stroke-width: 2px; | |
} | |
.nvd3.nv-ohlcBar .nv-ticks .nv-tick.hover { | |
stroke-width: 4px; | |
} | |
.nvd3.nv-ohlcBar .nv-ticks .nv-tick.positive { | |
stroke: #2ca02c; | |
} | |
.nvd3.nv-ohlcBar .nv-ticks .nv-tick.negative { | |
stroke: #d62728; | |
} | |
.nvd3.nv-historicalStockChart .nv-axis .nv-axislabel { | |
font-weight: bold; | |
} | |
.nvd3.nv-historicalStockChart .nv-dragTarget { | |
fill-opacity: 0; | |
stroke: none; | |
cursor: move; | |
} | |
.nvd3 .nv-brush .extent { | |
/* | |
cursor: ew-resize !important; | |
*/ | |
fill-opacity: 0 !important; | |
} | |
.nvd3 .nv-brushBackground rect { | |
stroke: #000; | |
stroke-width: .4; | |
fill: #fff; | |
fill-opacity: .7; | |
} | |
/********** | |
* Indented Tree | |
*/ | |
/** | |
* TODO: the following 3 selectors are based on classes used in the example. I should either make them standard and leave them here, or move to a CSS file not included in the library | |
*/ | |
.nvd3.nv-indentedtree .name { | |
margin-left: 5px; | |
} | |
.nvd3.nv-indentedtree .clickable { | |
color: #08C; | |
cursor: pointer; | |
} | |
.nvd3.nv-indentedtree span.clickable:hover { | |
color: #005580; | |
text-decoration: underline; | |
} | |
.nvd3.nv-indentedtree .nv-childrenCount { | |
display: inline-block; | |
margin-left: 5px; | |
} | |
.nvd3.nv-indentedtree .nv-treeicon { | |
cursor: pointer; | |
/* | |
cursor: n-resize; | |
*/ | |
} | |
.nvd3.nv-indentedtree .nv-treeicon.nv-folded { | |
cursor: pointer; | |
/* | |
cursor: s-resize; | |
*/ | |
} | |
body { | |
overflow-y:scroll; | |
} | |
text { | |
font: 12px sans-serif; | |
} | |
svg { | |
display: block; | |
} | |
#chart svg { | |
height: 500px; | |
min-width: 100px; | |
min-height: 100px; | |
} | |
</style> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment