Skip to content

Instantly share code, notes, and snippets.

@powersparks
Last active March 12, 2017 01:21
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/b4714906a7f83160454f7a57cbc9f1e8 to your computer and use it in GitHub Desktop.
Save powersparks/b4714906a7f83160454f7a57cbc9f1e8 to your computer and use it in GitHub Desktop.
Zoom first, and Brush on same element - Pan and Zoom works, but not brush
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(zoom)
.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(); });
;
/*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 1140.45
Feb 2010 1140.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