Skip to content

Instantly share code, notes, and snippets.

@powersparks
Last active March 12, 2017 01:17
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/b28097508b11f4b167130684beab5f8c to your computer and use it in GitHub Desktop.
Save powersparks/b28097508b11f4b167130684beab5f8c to your computer and use it in GitHub Desktop.
Brush first, Zoom same element - Brushing and Zoom works, but not Pan.
Display the source blob
Display the rendered blob
Raw
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
<!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: 30, left: 40},
margin2 = {top: 60, 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).tickSizeInner(height-5).tickSizeOuter( height).tickPadding(-height *0.2),
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);
// 4.1) Setup Brush for time filter
var brush_sensor = d3.brushX()
.extent([[0, 0], [width, height]])
.on("brush end", focus_brush_feedback );
// 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");
d3.xml("blog.svg").mimeType("image/svg+xml").get(function(error, xml) {
if (error) throw error;
document.body.appendChild(xml.documentElement);
});
focus.selectAll("image")
.data(data).enter().append("image")
.attr('xlink:href','blog.svg')
.attr('class', 'icon')
.attr('height', '22')
.attr('width', '22')
.attr('y', '0')
.attr('transform', "translate(" + -11+ "," + 22+ ")" )
.attr('x', function(d){return x(d.date); })
;
// 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("g")
.attr("class", "zoom brush")
.attr("width", width)
.attr("height", height)
//.attr("transform", "translate(" + 0 + "," + 0 + ")")
// .call(drag)
.call(brush_sensor)
.call(brush_sensor.move, [width - Math.floor(width / 2) - ( width / 5), width - Math.floor( width / 2) + (width / 5)])
//.on("drag", function() { d3.event.stopImmediatePropagation(); });
.call(zoom);
/*focus.select('.brush')
.on('mousedown', function(){
brush_elm = svg.select(".selection").node();
new_click_event = new Event('mousedown');
new_click_event.pageX = d3.event.pageX;
new_click_event.clientX = d3.event.clientX;
new_click_event.pageY = d3.event.pageY;
new_click_event.clientY = d3.event.clientY;
brush_elm.dispatchEvent(new_click_event);
});
*/
//.on("brush", function() { d3.event.stopImmediatePropagation(); });
focus.selectAll('.tick line')
.attr("y1", function(d){
return -height;
});
}); //end of data call
function focus_brush_feedback(){
if(!d3.event.select)return;
console.info("slave_feedback");
console.info(d3.event.select);
}
// 8) Method for zooming
function zoomed() {
if(d3.event.select)return;
// 8.1) confirm the right events are used
if (d3.event.sourceEvent == null || d3.event.sourceEvent.type == null || d3.event.sourceEvent.type === '') 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);
focus.selectAll('.icon')
.attr('x', function(d){return x(d.date); });
/*
focus.selectAll(".icon")
.attr("transform", function(d) {
return "translate(" + 0 + "," + d.x + ")"
});
*/
// 8.5) Select the Chart's axis--x class, call xAxis to reset it(how?)
focus.select(".axis--x").call(xAxis);
focus.selectAll('.tick line')
.attr("y1", function(d){
return -height;
});
}
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
Jul 2009 1040.45
Feb 2010 1340.45
Apr 2016 1140.45
Mar 2017 1240.45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment