Last active
August 29, 2015 14:14
-
-
Save sachams/d8621093ebb8181d50fe to your computer and use it in GitHub Desktop.
D3 panning issue - panning accelerates!
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> | |
<html> | |
<head> | |
<title></title> | |
</head> | |
<style> | |
body, html{ | |
margin: auto; | |
width: 100%; | |
height: 100%; | |
color: white; | |
background-color: black; | |
font-family: helvetica; | |
} | |
chart{ | |
display: block; | |
z-index: 0; | |
overflow: hidden; | |
font-size: 10px; | |
} | |
rect.pane { /*this transparent rectangle catches all zoom events*/ | |
opacity:0; | |
/* cursor:move; */ | |
pointer-events: all; | |
} | |
.x-axis path, | |
.x-axis line { | |
fill: none; | |
stroke: none; | |
shape-rendering: crispEdges; | |
stroke-width: 1.5px; | |
} | |
.x-axis text { | |
fill: white; | |
stroke: white; | |
font-family: sans-serif; | |
font-size: 11px; | |
} | |
.y-axis path, | |
.y-axis line { | |
fill: none; | |
stroke: none; | |
shape-rendering: crispEdges; | |
stroke-width: 1.5px; | |
} | |
.y-axis text { | |
fill: white; | |
stroke: white; | |
font-family: sans-serif; | |
font-size: 11px; | |
} | |
.line { | |
fill: none; | |
stroke: white; | |
stroke-width: 1.5px; | |
} | |
.grid .tick { | |
stroke: lightgrey; | |
opacity: 0.7; | |
} | |
.grid path { | |
stroke-width: 0; | |
} | |
.chart-1{ | |
width: 100%; | |
height: 100%; | |
float: left; | |
} | |
</style> | |
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.10/angular.min.js"></script> | |
<script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script> | |
<script src="http://d3js.org/queue.v1.min.js"></script> | |
<body ng-app="myApp" ng-controller="MainCtrl"> | |
<chart class="chart-1" data="chart_data" range="range" selected-point="selectEmployer"> </scatter> | |
</body> | |
<script> | |
var app = angular.module('myApp', []); | |
app.factory('dataService', ['$http', function ($http) { | |
var getStaticData = function(){ | |
data = [ | |
{ time: '2011-11-04 16:07:00', value: 11.9 }, | |
{ time: '2011-11-05 16:12:00', value: 11.9 }, | |
{ time: '2011-11-06 16:17:00', value: 11.8 }, | |
{ time: '2011-11-07 16:22:00', value: 11.6 }, | |
{ time: '2011-11-08 16:27:00', value: 11.5 }, | |
{ time: '2011-11-09 16:32:00', value: 11.4 }, | |
{ time: '2011-11-10 16:37:00', value: 11.2 }, | |
{ time: '2011-11-11 16:42:00', value: 10.9 }, | |
{ time: '2011-11-12 16:47:00', value: 10.8 }, | |
{ time: '2011-11-13 16:52:00', value: 10.7 } | |
]; | |
// Parse the data | |
var format = d3.time.format('%Y-%m-%d %H:%M:%S'); | |
data.forEach(function(d) { | |
d.time = format.parse(d.time); | |
}) | |
return data; | |
}; | |
function addMinutes(date, minutes) { | |
return new Date(date.getTime() + minutes*60000); | |
} | |
var getRandomData = function(){ | |
var start = new Date(2011,10,1,0,0,0,0); // month 10 is actuall Nov... | |
var end = new Date(2011,10,11,0,0,0,0); | |
var interval = 60; // interval in mins | |
var dt = start; | |
var value = 5; | |
var data = []; | |
while(dt < end) { | |
data.push({time: dt, value: value}); | |
dt = addMinutes(dt, interval); | |
value = value + (Math.random()-0.5) * 1; | |
if(value > 15) { value = 15 } // cap and floor it at 15/3, respectively. | |
if(value < 3) { value = 3 } | |
} | |
return data; | |
}; | |
var filterData = function(data, params) { | |
var filteredData = []; | |
data.forEach(function(d) { | |
if(d.time >= params.start && d.time <= params.end) { | |
filteredData.push(d) | |
} | |
}) | |
return filteredData; | |
} | |
// Public API here | |
return { | |
getData: function(params){ | |
var data = getRandomData(); | |
var filteredData = filterData(data, params); | |
return filteredData; | |
} | |
}; | |
}]); | |
app.controller('MainCtrl', function(dataService, $scope, $window){ | |
$scope.range = [new Date(2011,10,1,0,0,0,0), | |
new Date(2011,10,11,0,0,0,0)]; | |
$scope.loadData = function(range) { | |
console.log('Loading data form range ' + range) | |
var params = {start: range[0], end: range[1]}; | |
$scope.chart_data = dataService.getData(params); | |
}; | |
$scope.loadData($scope.range); | |
angular.element($window).on('resize', function(){ $scope.$apply() }) | |
}); | |
app.directive('chart', function(){ | |
function link(scope, el, attr){ | |
// Everything construction-related goes here | |
// We create objects and assign them to variables | |
// which we then reference later on | |
el = el[0]; | |
var x = d3.time.scale(); | |
var y = d3.scale.linear(); | |
var xAxis = d3.svg.axis().scale(x).orient('bottom').tickFormat(d3.time.format('%d %b %y')); | |
var yAxis = d3.svg.axis().scale(y).orient('left'); | |
var xGrid = d3.svg.axis().scale(x).orient("bottom").ticks(10).tickFormat(""); | |
var yGrid = d3.svg.axis().scale(y).orient("left").ticks(10).tickFormat(""); | |
var line = d3.svg.line().interpolate("cardinal").x(function(d) { return x(d.time); }).y(function(d) { return y(d.value); }); | |
var Zoomer = d3.behavior.zoom() | |
.x(x) | |
.on("zoom", zoomHandler); | |
var svg = d3.select(el).append('svg'); | |
var svgG = svg.append('g'); | |
var svgX = svgG.append('g'); | |
var xAxisG = svgG.append('g').attr('class', 'x-axis'); | |
var yAxisG = svgG.append('g').attr('class', 'y-axis'); | |
var xGridG = svgG.append('g').attr('class', 'grid'); | |
var yGridG = svgG.append('g').attr('class', 'grid'); | |
var path = svgG.append('path').attr('class', 'line'); | |
var xAxisText = xAxisG.append("text").attr("y", 30).attr('dx', '.71em').style("text-anchor", "middle").text("Date"); | |
var yAxisText = yAxisG.append('text').attr('transform', 'rotate(-90)').attr('y', -40).attr('dy', '.71em').style('text-anchor', 'middle').text('Value'); | |
var margin = {top: 20, right: 20, bottom: 35, left: 50}; | |
x.domain(scope.range); | |
scope.$watch(function(){ | |
width = el.clientWidth; | |
height = el.clientHeight; | |
return width + height; | |
}, resize); | |
scope.$watch('data', function(){ | |
console.log('On data change'); | |
update(); | |
}); | |
function zoomHandler() { | |
scope.range = x.domain() | |
update(); | |
} | |
function resize(){ | |
// Everything related to client sizes has to go in here | |
var width = el.clientWidth - margin.left - margin.right; | |
var height = el.clientHeight - margin.top - margin.bottom; | |
svg.attr('width', width + margin.left + margin.right) | |
.attr('height', height + margin.top + margin.bottom); | |
// Translate the whole svg *group* - this means all children of the group | |
// (like axes, etc) will also be translated | |
svgG.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')'); | |
// We have already translated our entire svg so we can ignore margins | |
// See https://gist.github.com/mbostock/3019563 | |
x.range([0, width]); | |
y.range([height, 0]); | |
xAxisText.attr("x", width/2 ); | |
yAxisText.attr('x', -height/2); | |
xGridG.attr('transform', 'translate(' + [0, height] + ')'); | |
xGrid.tickSize(-height, 0, 0); | |
yGrid.tickSize(-width, 0, 0); | |
xAxisG.attr('transform', 'translate(' + [0, height] + ')'); | |
var rect = svgX.append("svg:rect") // overlay to catch mouse zoom events | |
.attr("class", "pane") | |
.attr("width", el.clientWidth) | |
.attr("height", el.clientHeight); | |
rect.call(Zoomer); | |
update(); | |
} | |
function update(){ | |
// Everything related to data ranges has to go in here | |
// (we call this from our data watcher) | |
x.domain(scope.range); | |
y.domain(d3.extent(scope.data, function(d) { return d.value; })); | |
Zoomer.x(x) // update the zooming behavior to match the domain | |
xAxisG.call(xAxis); | |
yAxisG.call(yAxis); | |
xGridG.call(xGrid); | |
yGridG.call(yGrid); | |
// Add the line | |
path.datum(scope.data).attr('d', line); | |
} | |
} | |
return { | |
link: link, | |
restrict: 'E', | |
scope: { data: '=', selectedPoint: '=', range: '='} | |
}; | |
}); | |
</script> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment