Skip to content

Instantly share code, notes, and snippets.

@nbremer
Last active June 25, 2016 17:06
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 nbremer/b1fbcc0ff00abe8893a087d85fc8005b to your computer and use it in GitHub Desktop.
Save nbremer/b1fbcc0ff00abe8893a087d85fc8005b to your computer and use it in GitHub Desktop.
Abrupt gradients - Dynamically updating gradient
height: 220
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8"/>
<title>Dynamically updating gradient</title>
<!-- D3.js -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.6/d3.min.js" charset="utf-8"></script>
<!-- Google Fonts -->
<link href='http://fonts.googleapis.com/css?family=Open+Sans:300,400' rel='stylesheet' type='text/css'>
<style>
html { font-size: 62.5%; }
body {
font-family: 'Open Sans', sans-serif;
font-weight: 400;
text-align: center;
fill: #2B2B2B;
}
.brush .extent {
fill-opacity: .125;
shape-rendering: crispEdges;
}
.resize {
display: inline !important; /* show when empty */
fill: #7A7A7A;
stroke: #7A7A7A;
stroke-width: 3px;
}
.stopText {
font-size: 2.2rem;
color: #303030;
text-anchor: middle;
stroke: none;
}
</style>
</head>
<body>
<div id = "chart"></div>
<script>
///////////////////////////////////////////////////////////////////////////
//////////////////// Set up and initiate svg containers ///////////////////
///////////////////////////////////////////////////////////////////////////
var margin = {
top: 50,
right: 30,
bottom: 50,
left: 30
};
var width = window.innerWidth - margin.left - margin.right - 20;
var height = 100;
//SVG container
var svg = d3.select('#chart')
.append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
//Reset the overall font size
var newFontSize = Math.min(62.5, width * 62.5 / 900);
d3.select("html").style("font-size", newFontSize + "%");
//////////////////////////////////////////////////////////////
////////////////////////// Scales ////////////////////////////
//////////////////////////////////////////////////////////////
var start = 0,
end = 100,
range = end - start;
var xAll = d3.scale.linear().domain([start, end]).range([0, width]),
xBrush = d3.scale.linear().domain([start, end]).range([0, width]);
//////////////////////////////////////////////////////////////
/////////////////////// Gradient /////////////////////////////
//////////////////////////////////////////////////////////////
var linearGradient = svg.append("defs").append("linearGradient")
.attr("gradientUnits", "userSpaceOnUse")
.attr("x1", 0)
.attr("y1", 0)
.attr("x2", width)
.attr("y2", 0)
.attr("id", "line-gradient");
linearGradient.append("stop").attr("class", "left").attr("offset", "40%").attr("stop-color", "#D6D6D6");
linearGradient.append("stop").attr("class", "left").attr("offset", "40%").attr("stop-color", "#BD2E86");
linearGradient.append("stop").attr("class", "right").attr("offset", "60%").attr("stop-color", "#BD2E86");
linearGradient.append("stop").attr("class", "right").attr("offset", "60%").attr("stop-color", "#D6D6D6");
//////////////////////////////////////////////////////////////
/////////////////////// Brushing /////////////////////////////
//////////////////////////////////////////////////////////////
//Taken and adjusted from: http://bl.ocks.org/mbostock/6498580
var centering = false,
alpha = 1,
center,
moveType;
var arc = d3.svg.arc()
.outerRadius(height / 4)
.startAngle(0)
.endAngle(function(d, i) { return i ? -Math.PI : Math.PI; });
var brush = d3.svg.brush()
.x(xAll)
.extent([(40*range)/100+start, (60*range)/100+start])
.on("brush", brushmove)
.on("brushend", brushend);;
//Set up the brush
var gBrush = svg.append("g")
.attr("class", "brush")
.style("opacity", 0)
.call(brush);
gBrush.selectAll(".resize").append("line")
.attr("y2", height);
gBrush.selectAll(".resize").append("path")
.attr("d", d3.svg.symbol().type("triangle-up").size(100))
.attr("transform", function(d,i) { return i ? "translate(" + -7 + "," + height / 2 + ") rotate(-90)" : "translate(" + 7 + "," + height / 2 + ") rotate(90)"; });
gBrush.selectAll("rect")
.attr("height", height);
gBrush.select(".background")
.on("mousedown.brush", brushcenter)
.on("touchstart.brush", brushcenter);
gBrush.call(brush.event);
function brushmove() {
var extent = brush.extent();
//Reset the x-axis brush domain
xBrush.domain(brush.empty() ? xAll.domain() : brush.extent());
var startOffset = (xBrush.domain()[0] - start)/range*100,
endOffset = (xBrush.domain()[1] - start)/range*100;
//Update the text below each brush handle
d3.select(".leftStopText").text(Math.round(startOffset) + "%");
d3.select(".rightStopText").text(Math.round(endOffset) + "%");
//Reset the offsets of the chart
d3.selectAll(".left").attr("offset", startOffset + "%");
d3.selectAll(".right").attr("offset", endOffset + "%");
}//brushmove
function brushend() {
if (!d3.event.sourceEvent) return; // only transition after input
d3.select(this).transition()
.call(brush.extent(brush.extent().map(function(d) { return d3.round(d, 0); })))
.call(brush.event);
}//brushend
function brushcenter() {
var self = d3.select(window),
target = d3.event.target,
extent = brush.extent(),
size = extent[1] - extent[0],
domain = xAll.domain(),
x0 = domain[0] + size / 2,
x1 = domain[1] - size / 2,
odd = Math.round(size * 10) & 1;
recenter(true);
brushmove();
if (d3.event.changedTouches) {
self.on("touchmove.brush", brushmove).on("touchend.brush", brushend);
} else {
self.on("mousemove.brush", brushmove).on("mouseup.brush", brushend);
}
function brushmove() {
d3.event.stopPropagation();
center = d3.round(Math.max(x0, Math.min(x1, xAll.invert(d3.mouse(target)[0]) + odd * .05)), 1) - odd * .05;
recenter(false);
}
function brushend() {
brushmove();
self.on(".brush", null);
}
}//brushcenter
function recenter() {
if (centering) return; // timer is active and already interpolating
centering = true;
d3.timer(function() {
var extent = brush.extent(),
size = extent[1] - extent[0],
center1 = center * alpha + (extent[0] + extent[1]) / 2 * (1 - alpha);
if (!(centering = Math.abs(center1 - center) > 1e-3)) center1 = center;
gBrush
.call(brush.extent([center1 - size / 2, center1 + size / 2]))
.call(brush.event);
return !centering;
});
}//recenter
//////////////////////////////////////////////////////////////
//////////////////////// Rectangle ///////////////////////////
//////////////////////////////////////////////////////////////
//Add the lines to context chart
svg.append("rect")
.attr("class", "exampleRect")
.attr("x", 0)
.attr("y", 0)
.attr("width", width)
.attr("height", height)
.style("fill", "url(#line-gradient)");
//////////////////////////////////////////////////////////////
//////////////////////// Locations ///////////////////////////
//////////////////////////////////////////////////////////////
//Append two texts below the brush to show at what percentage they are
d3.selectAll(".brush .resize.w").append("text")
.attr("class", "stopText leftStopText")
.attr("x", 0)
.attr("y", 140)
.style("text-anchor", "middle")
.text("40%");
d3.selectAll(".brush .resize.e").append("text")
.attr("class", "stopText rightStopText")
.attr("x", 0)
.attr("y", 140)
.style("text-anchor", "middle")
.text("60%");
//////////////////////////////////////////////////////////////
/////////////////////////// Start ////////////////////////////
//////////////////////////////////////////////////////////////
//Move selected element to the front
d3.selection.prototype.moveToFront = function() {
return this.each(function(){
this.parentNode.appendChild(this);
});
};
//Move the brush handles to the front
setTimeout(function() {
d3.selectAll(".brush")
.style("opacity", 1)
.moveToFront();
},500);
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment