Built with blockbuilder.org
forked from chloerulesok's block: Scatter plot/Colour/Timeline/Filtering
license: mit |
Built with blockbuilder.org
forked from chloerulesok's block: Scatter plot/Colour/Timeline/Filtering
<!DOCTYPE html> | |
<head> | |
<meta charset="utf-8"> | |
<script src="https://d3js.org/d3.v4.min.js"></script> | |
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.6/angular.min.js"></script> | |
<style> | |
body { margin:0;position:fixed;top:0;right:0;bottom:0;left:0; } | |
div.tooltip { | |
position: absolute; | |
text-align: center; | |
width: 150px; | |
height: 28px; | |
padding: 2px; | |
font: 12px sans-serif; | |
background: lightsteelblue; | |
border: 0px; | |
border-radius: 8px; | |
pointer-events: none; | |
} | |
</style> | |
</head> | |
<body ng-app="app" ng-controller="ctrl"> | |
Regexable filter: (e.g. "aa" or (aa|bb)) | |
<input type="text" ng-model="filteringSelection" ng-change="updateFilter()"> | |
<div id="chart"></div> | |
</body> | |
<script> | |
// *** This page uses angular as the way it interacts with the user input | |
angular.module("app", []) | |
.controller("ctrl", function($scope) { | |
// *** Create random data set | |
var fullData = []; | |
var items = ['aaa', 'bbb', 'ccc']; | |
for(var i = 0; i < 50; i++){ | |
var obj = {}; | |
var date = new Date(+(new Date()) - Math.floor(Math.random()*10000000000)); | |
obj.date = date.getDate() + '/' + (date.getMonth() + 1) + '/' + date.getFullYear(); | |
obj.time = date.getHours() + ':' + date.getMinutes() + ':' + date.getSeconds(); | |
obj.pivot = items[Math.floor(Math.random()*items.length)]; | |
fullData.push(obj); | |
} | |
// *** Set the dimensions and margins of the chart | |
var margin = {top: 20, right: 20, bottom: 100, left: 50}, | |
width = 960 - margin.left - margin.right, | |
height = 500 - margin.top - margin.bottom; | |
// *** Set the axis ranges | |
var x = d3.scaleTime().range([0, width-margin.left]); | |
var y = d3.scaleTime().range([height, 0]); | |
// *** Tool tip | |
var tooltip = d3.select("#chart").append("div") | |
.attr("class", "tooltip") | |
.style("opacity", 0); | |
// append the svg obgect to the body of the page | |
// appends a 'group' element to 'svg' | |
// moves the 'group' element to the top left margin | |
var svg = d3.select("#chart").append("svg") | |
.attr("width", width + margin.left + margin.right) | |
.attr("height", height + margin.top + margin.bottom) | |
.append("g") | |
.attr("transform", | |
"translate(" + margin.left + "," + margin.top + ")"); | |
// Get th | |
// parse the date / time | |
var parseDate = d3.timeParse("%e/%m/%Y"); | |
var formatDate = d3.timeFormat("%e/%m/%Y"); | |
var parseTime = d3.timeParse("%H:%M:%S"); | |
var formatTime = d3.timeFormat("%H:%M:%S"); | |
// format the data | |
fullData.forEach(function(d) { | |
d.date = parseDate(d.date); | |
d.time = parseTime(d.time); | |
}); | |
var earliestDate = d3.min(fullData, function(d) { return d.date; }); | |
var latestDate = d3.max(fullData, function(d) { return d.date; }); | |
// Scale the range of the data | |
x.domain([earliestDate, latestDate]); | |
y.domain([parseTime("00:00:00"),parseTime("23:59:59")]); | |
// Add the X Axis | |
svg.append("g") | |
.attr("class", "axis") | |
.attr("transform", "translate(" + margin.left + "," + height + ")") | |
.call(d3.axisBottom(x) | |
.tickFormat(d3.timeFormat("%Y-%m-%d"))) | |
.selectAll("text") | |
.style("text-anchor", "end") | |
.attr("dx", "-.8em") | |
.attr("dy", ".15em") | |
.attr("transform", "rotate(-65)"); | |
svg.append("g") | |
.attr("class", "yaxis") | |
.attr("transform", "translate(" + margin.left + ",0)") | |
.call(d3.axisLeft(y) | |
.tickFormat(d3.timeFormat("%H:%M:%S"))) | |
.selectAll("text") | |
.style("text-anchor", "end") | |
.attr("dx", "-.8em") | |
.attr("dy", ".15em"); | |
var colour = d3.scaleOrdinal() | |
.domain(d3.map(fullData, function(d){return d.pivot;}).keys()) | |
.range(d3.schemeCategory10); | |
plotData(fullData); | |
// Add the scatterplot | |
function plotData(data){ | |
svg.selectAll("circle").remove(); | |
svg.selectAll("circle").data(data) | |
.enter().append("circle") | |
.attr("r", 5) | |
.attr("cx", function(d) { return x(d.date); }) | |
.attr("cy", function(d) { return y(d.time); }) | |
.attr("transform", "translate(" + margin.left + ",0)") | |
.style("fill", function(d) { return colour(d.pivot); }) | |
.on("mouseover", function(d) { | |
tooltip.transition() | |
.duration(200) | |
.style("opacity", .9); | |
tooltip.html(formatDate(d.date) + " " + formatTime(d.time) + "<br/>" + d.pivot) | |
.style("left", (d3.event.pageX) + "px") | |
.style("top", (d3.event.pageY - 28) + "px"); | |
}) | |
.on("mouseout", function(d) { | |
tooltip.transition() | |
.duration(500) | |
.style("opacity", 0); | |
}); | |
} | |
$scope.updateFilter = function(){ | |
var pivotKeys = d3.map(fullData, function(d){return d.pivot;}).keys(); | |
var filteredPivotArr = pivotKeys.filter(function(dataItem){ | |
var re = new RegExp($scope.filteringSelection, "i"); | |
var result = dataItem.match(re); | |
if(result != null){ | |
return true; | |
} else { | |
return false; | |
} | |
}); | |
var filteredPivotObj = []; | |
for(var k in fullData){ | |
if(filteredPivotArr.includes(fullData[k].pivot)){ | |
filteredPivotObj.push(fullData[k]); | |
} | |
} | |
plotData(filteredPivotObj); | |
} | |
}); | |
</script> | |