Last active
March 18, 2017 16:43
-
-
Save powersparks/a4ffbd43a4f59f932d99e40d2b500095 to your computer and use it in GitHub Desktop.
d3 axis clipping works for circle, but not working for svg group element
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> | |
.axis--grid .domain { fill: #ddd; stroke: none; } | |
.axis--grid .tick--minor line { stroke-opacity: .5; } | |
.axis--x .domain, .axis--grid .tick line { stroke: #333; } | |
rect.zoom{ cursor: move;; } | |
.axis--x, .axis--y, .tick, .domain, .axis--grid .tick { shape-rendering: crispEdges; border: thin; border-color:black; } | |
.brush .selection{ cursor: ew-resize; fill:rgba(0, 0, 0, 0.75); pointer-events: all;shape-rendering: crispEdges; border: thin; stroke:none; } | |
.brush .handle{ cursor: col-resize; fill: none; } | |
.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 { fill: none; pointer-events: all; } | |
</style> | |
<div id="timelineContainerDivId" width="100%" height="90px" class="timeline-container"> | |
<svg id="timeFilterId" viewBox="0 0 800 80" preserveAspectRatio="xMidYMid"></svg> | |
</div> | |
<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; | |
// 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); | |
// 5) APPEND FOCUS g element as the TIMELINE | |
var focus = svg.append("g") | |
.attr("class", "focus") | |
.attr("transform", "translate(" + margin.left + "," + margin.top + ")"); | |
// 5.1) APPEND rect to use as a zoom interface. (see 7.8) moved out of data block. | |
focus.append("rect") | |
.attr("class", "zoom ") | |
.attr("width", width) | |
.attr("height", height * 2) | |
.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); | |
// 5.2) Setup Brush for time filter | |
var brush_sensor = d3.brushX() | |
.extent([[0, 0], [width, (height/2 + 5)]]) | |
.on("brush end", focus_brush_feedback ); | |
// 5.3) Append the brush; (see 7.9) moved out of data block | |
focus.append("g") | |
.attr("class", "brush") | |
.attr("height", height/2) | |
.attr("transform", "translate(" + 2+ "," + Math.floor( margin.top + 5) + ")") | |
// .attr("cursor", "default !important") | |
.call(brush_sensor) | |
.call(brush_sensor.move, [width - Math.floor(width / 2) - ( width / 5), width - Math.floor( width / 2) + (width / 5)]) | |
.on("wheel",function() { d3.event.preventDefault(); }); | |
// 6) PARSE TIME FORMAT | |
var parseDate = d3.timeParse("%b %Y"); | |
// 6.2) example of adding an svg as an object. | |
var xmlSvg; | |
d3.xml("blog.svg").mimeType("image/svg+xml").get(function(error, xml) { | |
if (error) throw error; | |
xmlSvg = xml.documentElement; | |
document.body.appendChild(xml.documentElement); | |
//});//xml | |
// 6.6) trying out some len's filters | |
//// create filter with id #drop-shadow | |
// height=130% so that the shadow is not clipped | |
/* | |
var filter = defs.append("filter") | |
.attr("id", "drop-shadow") | |
.attr("height", "100%"); | |
*/ | |
// SourceAlpha refers to opacity of graphic that this filter will be applied to | |
// convolve that with a Gaussian with standard deviation 3 and store result | |
// 7) SETUP DATA WITH CALLBACK AND FORMAT DATE TYPE | |
d3.csv("sp500_2.csv", type, function(error, data) { | |
if (error) throw error; | |
// 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) moved to 6.4, then moved back. | |
//revelation - if appending the axis before the domain, it will not be scaled to the new domain. | |
// 7.5) moved to 6.5, then moved back. | |
//revelation - if appending the axis before the domain, it will not be scaled to the new domain. | |
// 6.4) APPEND x-axis. (see 7.4) this was in the "data" block, but doesn't need to be. | |
focus.append("g") | |
.attr("class", "axis axis--x") | |
.attr("transform", "translate(0," + height + ")") | |
.call(xAxis); | |
// 6.5) APPEND y-axis. (see 7.5) this was in the "data" block, but doesn't need to be | |
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", 4.5) | |
.attr("opacity", 0.7) | |
.style("fill", "steelblue"); | |
var xmlSvgB = d3.select(xmlSvg).select('#b').node(); | |
var gXml = focus.selectAll(".icon") | |
.data(data ).enter().append(function(){return xmlSvgB.cloneNode(true);}) | |
.attr("clip-path", 'url("#clip2")') | |
.attr('class', 'icon') | |
.attr("opacity", 0.7) | |
.attr('id',function(d){return 'b_' + d.date.getTime();}) | |
.attr('transform', function(d){ | |
var xdate = x(d.date) - 11; | |
return "translate(" + xdate + "," + 15 + ") scale(0.8)" ;}); | |
// 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) moved to 5.1 | |
// 7.9) moved to 5.3 | |
focus.selectAll('.tick line') | |
.attr("y1", function(d){ | |
return -height; | |
}); | |
//move the brush infront of everything. | |
d3.selectAll(".brush").raise(); | |
// 6.1) append culling to be used for a clip area. | |
var defs = focus.append("defs"); | |
defs.append("clipPath") | |
.attr("id", "clip") | |
//.attr("clipPathUnits", "objectBoundingBox")//"userSpaceOnUse") | |
.append("rect") | |
.attr("x", 0) | |
.attr("y",0) | |
.attr("width", width ) | |
.attr("height", height); | |
defs.append("clipPath") | |
.attr("id", "clip2") | |
//.attr("clipPathUnits", "userSpaceOnUse") | |
.append("rect") | |
.attr("x", 0) | |
.attr("y",0) | |
.attr("width", width ) | |
.attr("height", height) | |
; | |
}); //end of data call | |
}); //end of xml call | |
function focus_brush_feedback(){ | |
if(!d3.event.select)return; | |
console.info("focus_brush_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('transform', function(d){ | |
var xdate = x(d.date) - 11; | |
return "translate(" + xdate + "," + 15 + ") scale(0.8)" ;}); | |
// 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.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