Skip to content

Instantly share code, notes, and snippets.

@karlbohlmark
Forked from stepheneb/index.html
Created May 25, 2012 15:25
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save karlbohlmark/2788770 to your computer and use it in GitHub Desktop.
Save karlbohlmark/2788770 to your computer and use it in GitHub Desktop.
D3 Example: zoom, pan, and axis rescale

This example is a mashup of the D3 Zoom-Pan example along with Ricardo Marimon's example of X-axis re-scaling by dragging.

  • Drag on the canvas to translate/pan the graph.
  • double-click on the canvas to zoom in
  • shift-double-click on the canvas to zoom out
  • Drag on one of the X or Y axis numeric labels to re-scale that axis
  • click on a data point to select it
  • drag a selected data point up or down to change it's Y value
  • enter the delete or backspace key to delete a selected data point
  • hold the ALT/Option key down and click an empty area of the graph to add a data point

Most of the UI should also work with the touch events generated by a tablet or SmartPhone.

source: gist.github.com/1182434

D3 References:

D3 Tutorials:

External D3 Tutorials

SVG Graphics

<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8">
<title>One Graph</title>
<script type="text/javascript" src="http://localhost:8999/d3.v2.js"></script>
<script type="text/javascript" src="simple-graph.js"></script>
<style type="text/css">
body { font: 13px sans-serif; }
rect { fill: #fff; }
ul {
list-style-type: none;
margin: 0.5em 0em 0.5em 0em;
width: 100%; }
ul li {
display: table-cell;
vertical-align: middle;
margin: 0em;
padding: 0em 1em; }
.axis { font-size: 1.5em; }
.chart {
width: 960px;
height: 500px; }
circle, .line {
fill: none;
stroke: steelblue;
stroke-width: 2px; }
</style>
</head>
<body>
<div id="chart1" class="chart"></div>
<script type="text/javascript">
graph = new SimpleGraph("chart1", {
"xmax": 60, "xmin": 0,
"ymax": 40, "ymin": 0,
"title": "Simple Graph1",
"xlabel": "X Axis",
"ylabel": "Y Axis"
});
</script>
</body>
</html>
registerKeyboardHandler = function(callback) {
var callback = callback;
d3.select(window).on("keydown", callback);
};
SimpleGraph = function(elemid, options) {
var self = this;
this.chart = document.getElementById(elemid);
this.cx = this.chart.clientWidth;
this.cy = this.chart.clientHeight;
this.options = options || {};
this.options.xmax = options.xmax || 30;
this.options.xmin = options.xmin || 0;
this.options.ymax = options.ymax || 10;
this.options.ymin = options.ymin || 0;
this.padding = {
"top": this.options.title ? 40 : 20,
"right": 30,
"bottom": this.options.xlabel ? 60 : 10,
"left": this.options.ylabel ? 70 : 45
};
this.size = {
"width": this.cx - this.padding.left - this.padding.right,
"height": this.cy - this.padding.top - this.padding.bottom
};
// x-scale
this.x = d3.scale.linear()
.domain([this.options.xmin, this.options.xmax])
.range([0, this.size.width]);
// drag x-axis logic
this.downx = Math.NaN;
// y-scale (inverted domain)
this.y = d3.scale.linear()
.domain([this.options.ymax, this.options.ymin])
.nice()
.range([0, this.size.height])
.nice();
// drag y-axis logic
this.downy = Math.NaN;
this.dragged = this.selected = null;
this.line = d3.svg.line()
.x(function(d, i) { return this.x(this.points[i].x); })
.y(function(d, i) { return this.y(this.points[i].y); });
var xrange = (this.options.xmax - this.options.xmin),
yrange2 = (this.options.ymax - this.options.ymin) / 2,
yrange4 = yrange2 / 2,
datacount = this.size.width/30;
this.points = d3.range(datacount).map(function(i) {
return { x: i * xrange / datacount, y: this.options.ymin + yrange4 + Math.random() * yrange2 };
}, self);
this.vis = d3.select(this.chart).append("svg")
.attr("width", this.cx)
.attr("height", this.cy)
.append("g")
.attr("transform", "translate(" + this.padding.left + "," + this.padding.top + ")");
this.plot = this.vis.append("rect")
.attr("width", this.size.width)
.attr("height", this.size.height)
.style("fill", "#EEEEEE")
.attr("pointer-events", "all")
this.plot.call(d3.behavior.zoom().x(this.x).y(this.y).on("zoom", this.redraw()));
this.vis.append("svg")
.attr("top", 0)
.attr("left", 0)
.attr("width", this.size.width)
.attr("height", this.size.height)
.attr("viewBox", "0 0 "+this.size.width+" "+this.size.height)
.attr("class", "line")
.append("path")
.attr("class", "line")
.attr("d", this.line(this.points));
// Add the x-axis label
if (this.options.xlabel) {
this.vis.append("text")
.attr("class", "axis")
.text(this.options.xlabel)
.attr("x", this.size.width/2)
.attr("y", this.size.height)
.attr("dy","2.4em")
.style("text-anchor","middle");
}
// add y-axis label
if (this.options.ylabel) {
this.vis.append("g").append("text")
.attr("class", "axis")
.text(this.options.ylabel)
.style("text-anchor","middle")
.attr("transform","translate(" + -40 + " " + this.size.height/2+") rotate(-90)");
}
this.redraw()();
};
//
// SimpleGraph methods
//
SimpleGraph.prototype.plot_drag = function() {
return function() {};
};
SimpleGraph.prototype.update = function() {
var self = this;
var lines = this.vis.select("path").attr("d", this.line(this.points));
};
SimpleGraph.prototype.mousemove = function() {
return function() {};
};
SimpleGraph.prototype.mouseup = function() {
var self = this;
return function() {};
};
SimpleGraph.prototype.redraw = function() {
var self = this;
return function() {
var tx = function(d) {
return "translate(" + self.x(d) + ",0)";
},
ty = function(d) {
return "translate(0," + self.y(d) + ")";
},
stroke = function(d) {
return d ? "#ccc" : "#666";
},
fx = self.x.tickFormat(10),
fy = self.y.tickFormat(10);
// Regenerate x-ticks…
var gx = self.vis.selectAll("g.x")
.data(self.x.ticks(10), String)
.attr("transform", tx);
gx.select("text")
.text(fx);
var gxe = gx.enter().insert("g", "a")
.attr("class", "x")
.attr("transform", tx);
gxe.append("line")
.attr("stroke", stroke)
.attr("y1", 0)
.attr("y2", self.size.height);
gxe.append("text")
.attr("class", "axis")
.attr("y", self.size.height)
.attr("dy", "1em")
.attr("text-anchor", "middle")
.text(fx)
.style("cursor", "ew-resize");
gx.exit().remove();
// Regenerate y-ticks…
var gy = self.vis.selectAll("g.y")
.data(self.y.ticks(10), String)
.attr("transform", ty);
gy.select("text")
.text(fy);
var gye = gy.enter().insert("g", "a")
.attr("class", "y")
.attr("transform", ty)
.attr("background-fill", "#FFEEB6");
gye.append("line")
.attr("stroke", stroke)
.attr("x1", 0)
.attr("x2", self.size.width);
gye.append("text")
.attr("class", "axis")
.attr("x", -3)
.attr("dy", ".35em")
.attr("text-anchor", "end")
.text(fy)
.style("cursor", "ns-resize");
gy.exit().remove();
self.plot.call(d3.behavior.zoom().x(self.x).y(self.y).on("zoom", self.redraw()));
self.update();
};
};
SimpleGraph.prototype.xaxis_drag = function() {
return function(d) {};
};
SimpleGraph.prototype.yaxis_drag = function(d) {
return function(d) {};
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment