Skip to content

Instantly share code, notes, and snippets.

@powersparks
Last active March 8, 2017 11:46
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 powersparks/736290ffbe10829735ecbfe7a6bade4c to your computer and use it in GitHub Desktop.
Save powersparks/736290ffbe10829735ecbfe7a6bade4c to your computer and use it in GitHub Desktop.
zooming & panning
<!DOCTYPE html>
<meta charset="utf-8">
<style>
.area { fill: steelblue; /* clip-path: url("/~powersparks/bz.html#clip");*/ }
.axis--grid .domain { fill: #ddd; stroke: none; }
.axis--grid .tick--minor line { stroke-opacity: .5; }
.axis--x .domain, .axis--grid .tick line { stroke: #333; }
.axis--x, .axis--y, .tick, .domain, .axis--grid .tick { shape-rendering: crispEdges; border: thin; border-color:black; }
.brush .brush-sensor { shape-rendering: crispEdges; border: thin; border-color:black; }
.brush .handle{ shape-rendering: crispEdges; fill: steelblue; }
.line{ border: solid 1px steelblue; margin: 4px; padding: 4px; background-color: #eeeeec; fill: none;}
.timeline-container{ margin: 0px; padding: 0px ; border:1px solid blue ; }
.zoom { cursor: move; fill: none; pointer-events: all; }
rect.zoom{ cursor:ns-resize; }
</style>
<div id="timelineContainerDivId" width="100%" height="90px" class="timeline-container">
<svg id="timeFilterId" viewBox="0 0 800 80" preserveAspectRatio="xMidYMid"></svg>
</div>
<!--svg id="timeFilterId" viewBox="0 0 960 500" preserveAspectRatio="xMidYMid"></svg-->
<script src="https://d3js.org/d3.v4.min.js"></script>
<script>
var divWidth = document.getElementById('timelineContainerDivId').clientWidth-10;
// 1) ESTABLISH LAYOUT SETTINGS
var svg = d3.select("svg").attr("viewBox","0 0 " + divWidth +" 80"),
h = 80, w = divWidth,
rwidth = svg.attr("width") ? svg.attr("width") : w,
rheight = svg.attr("height") ? svg.attr("height") : h,
margin = {top: 11, right: 20, bottom: 50, left: 40},
margin2 = {top: 50, right: 20, bottom: 20, left: 40},
width = w - margin.left - margin.right - 10,
height = h - margin.top - margin.bottom,
height2 = (svg.attr("height") ? + svg.attr("height") : h) - margin2.top - margin2.bottom;
//https://github.com/d3/d3-drag
//https://github.com/d3/d3-zoom
// 2) SCALE TIME RANGE on x and y
var x = d3.scaleTime().range([0, width]),
x2 = d3.scaleTime().range([0, width]),
y = d3.scaleLinear().range([height, 0]),
y2 = d3.scaleLinear().range([height2, 0]);
// 3) AXIS ORIENTATION and TICKS
var xAxis = d3.axisTop(x).tickSize([height]),
yAxis = d3.axisRight(y).ticks(0).tickSize(width);
// 4) INSTANTIATE d3 ZOOM
var zoom = d3.zoom()
.scaleExtent([1, Infinity])
.translateExtent([[0, 0], [width, height]])
.extent([[0, 0], [width, height]])
.on("zoom", zoomed);
// 5) APPEND FOCUS g element as the TIMELINE
var focus = svg.append("g")
.attr("class", "focus")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
// 6) PARSE TIME FORMAT
var parseDate = d3.timeParse("%b %Y");
// 7) SETUP DATA WITH CALLBACK AND FORMAT DATE TYPE
d3.csv("sp500_2.csv", type, function(error, data) {
if (error) throw error;
// 7.1) append culling to be used for a clip area.
svg.append("defs").append("clipPath")
.attr("id", "clip")
.append("rect")
.attr("width", width)
.attr("height", height);
// 7.2) STARTING DOMAIN of x and y axis
x.domain(d3.extent(data, function(d) { return d.date; }));
y.domain([0, d3.max(data, function(d) { return d.price; })]);
// 7.3) STARING DOMAIN FOR ALTERNATE axis
x2.domain(x.domain());
y2.domain(y.domain());
// 7.4) APPEND x-axis
focus.append("g")
.attr("class", "axis axis--x")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
// 7.5) APPEND y-axis
focus.append("g")
.attr("class", "axis axis--y")
.call(yAxis);
// 7.6) Select all the circle's within the Chart
focus.selectAll("circle")
.data(data).enter().append("circle")
.attr("clip-path", "url('#clip')")
.attr("class","dot")
.attr("r", 3.5)
.attr("opacity", 0.7)
.style("fill", "steelblue");
// 7.7) Select class dot and apply anyomous function
focus.selectAll(".dot")
.attr('cx', function(d) { return x(d.date); })
.attr('cy', height * 0.5);
// 7.8) APPEND rect to use as a zoom interface
focus.append("rect")
.attr("class", "zoom")
.attr("width", width)
.attr("height", height)
.attr("transform", "translate(" + /*margin.left*/0 + "," + /*margin.top*/0 + ")")
.call(zoom)
.on("wheel", function() { d3.event.preventDefault(); });
}); //end of data call
// 8) Method for zooming
function zoomed() {
// 8.1) confirm the right events are used
if(d3.event.sourceEvent == null || d3.event.sourceEvent.type == null/* || d3.event.sourceEvent.type === 'mousemove'*/) return;
if (d3.event.sourceEvent && d3.event.sourceEvent.type === "brush") return;
// 8.2) INSTANTIATE d3 transform event
var t = d3.event.transform;
// 8.3) RESET the X DOMAIN using the Transform, Rescale X based on the x2 domain
x.domain(t.rescaleX(x2).domain());
// 8.4) Select the Chart's element to rescale.
focus.selectAll(".dot")
.attr('cx', function(d) { return x(d.date); })
.attr('cy', height * 0.5);
// 8.5) Select the Chart's axis--x class, call xAxis to reset it(how?)
focus.select(".axis--x").call(xAxis);
}
function type(d) {
d.date = parseDate(d.date);
//d.price = +d.close;
d.price = +d.price;
return d;
}
</script>
date price
Jan 2000 1394.46
Mar 2010 1140.45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment