Last active
March 12, 2017 01:21
-
-
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
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> | |
<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> |
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
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