|
<!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> |