Skip to content

Instantly share code, notes, and snippets.

@curran
Last active June 13, 2016 15:45
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save curran/6f97aa94357cae4611c54a80c11f6128 to your computer and use it in GitHub Desktop.
Save curran/6f97aa94357cae4611c54a80c11f6128 to your computer and use it in GitHub Desktop.
Responsive Axes with ReactiveModel
license: mit
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Margin Convention II with ReactiveModel</title>
<script src="//d3js.org/d3.v4.0.0-alpha.49.min.js"></script>
<script src="//datavis-tech.github.io/reactive-model/reactive-model-v0.11.0.min.js"></script>
<style>
/* Make the chart container fill the page using CSS. */
#chart-container {
position: fixed;
left: 0px;
right: 0px;
top: 0px;
bottom: 0px;
}
.axis text {
font: 16pt sans-serif;
}
.axis .label {
font: 24pt sans-serif;
}
.axis path {
display: none;
}
.tick line {
fill: none;
stroke: #000;
stroke-width: 1px;
shape-rendering: crispEdges;
}
</style>
</head>
<body>
<!-- The SVG graphics will be injected into this div. -->
<div id="chart-container"></div>
<script>
// Resizes the SVG container.
function SVG(my){
my("svg")
("width", 100)
("height", 100)
(function (svg, width, height){
svg
.attr("width", width)
.attr("height", height);
}, "svg, width, height");
}
// Encapsulates the margin convention.
function Margin(my){
my("marginTop", 50)
("marginBottom", 50)
("marginLeft", 50)
("marginRight", 50)
("innerWidth", function (width, marginLeft, marginRight){
return width - marginLeft - marginRight;
}, "width, marginLeft, marginRight")
("innerHeight", function (height, marginTop, marginBottom){
return height - marginTop - marginBottom;
}, "height, marginTop, marginBottom")
("g", function (svg){
return svg.append("g");
}, "svg")
(function (g, marginLeft, marginTop){
g.attr("transform", "translate(" + marginLeft + "," + marginTop + ")");
}, "g, marginLeft, marginTop");
}
// Adds a gray rectangle inside the margin.
function GrayRectangle(my){
my("rect", function (g){
return g.append("rect")
.attr("fill", "lightgray")
.attr("stroke", "gray");
}, "g")
(function (rect, innerWidth, innerHeight){
rect
.attr("width", innerWidth)
.attr("height", innerHeight);
}, "rect, innerWidth, innerHeight");
}
// Tracks the X scale on the model.
function XScale(my){
var scale = d3.scaleLinear();
my("xScaleDomain")
("xScaleRange", function (innerWidth){
return [0, innerWidth];
}, "innerWidth")
("xScale", function(xScaleDomain, xScaleRange){
return scale
.domain(xScaleDomain)
.range(xScaleRange);
}, "xScaleDomain, xScaleRange");
}
// Tracks the Y scale on the model.
function YScale(my){
var scale = d3.scaleLinear();
my("yScaleDomain")
("yScaleRange", function (innerHeight){
return [innerHeight, 0];
}, "innerHeight")
("yScale", function(yScaleDomain, yScaleRange){
return scale
.domain(yScaleDomain)
.range(yScaleRange);
}, "yScaleDomain, yScaleRange");
}
// Creates the X axis.
function XAxis(my){
var axis = d3.axisBottom();
// Approximate number of pixels between ticks.
my("xAxisTickSpacing", 70)
("xAxisG", function (g){
return g.append("g")
.attr("class", "x axis");
}, "g")
(function(xAxisG, innerHeight){
xAxisG.attr("transform", "translate(0," + innerHeight + ")");
}, "xAxisG, innerHeight")
("xAxisTicks", function (xAxisTickSpacing, innerWidth){
return innerWidth / xAxisTickSpacing;
}, "xAxisTickSpacing, innerWidth")
("xAxis", function(xAxisTicks, xScale){
return axis
.scale(xScale)
.ticks(xAxisTicks);
}, "xAxisTicks, xScale")
(function(xAxisG, xAxis){
xAxis(xAxisG);
}, "xAxisG, xAxis");
}
// Creates the X axis.
function YAxis(my){
var axis = d3.axisLeft();
// Approximate number of pixels between ticks.
my("yAxisTickSpacing", 40)
("yAxisG", function (g){
return g.append("g")
.attr("class", "y axis");
}, "g")
("yAxisTicks", function (yAxisTickSpacing, innerHeight){
return innerHeight / yAxisTickSpacing;
}, "yAxisTickSpacing, innerHeight")
("yAxis", function(yAxisTicks, yScale){
return axis
.scale(yScale)
.ticks(yAxisTicks);
}, "yAxisTicks, yScale")
(function(yAxisG, yAxis){
yAxis(yAxisG);
}, "yAxisG, yAxis")
}
// The constructor for an "axis visualization" component.
// Renders a gray rectangle with responsive axes.
function AxesVis(){
return ReactiveModel()
.call(SVG)
.call(Margin)
.call(XScale)
.call(XAxis)
.call(YScale)
.call(YAxis)
.call(GrayRectangle)
;
}
// Respond to resize by setting width and height from DOM element.
function Resize(my, el){
function resize(){
my.width(el.clientWidth)
.height(el.clientHeight);
}
resize();
window.addEventListener("resize", resize);
}
// The main program that uses the MarginVis component.
function main(){
// Set up the MarginVis instance.
var container = d3.select("#chart-container"),
axesVis = AxesVis()
.svg(container.append("svg"))
.call(Resize, container.node())
.xScaleDomain([0, 1000])
.yScaleDomain([0, 1000]);
// Change the margins around in a funky way.
var time = 0;
requestAnimationFrame(function updateMargin(){
time += 0.01;
axesVis
.marginLeft( (Math.sin(time ) + 1.4) * 200)
.marginRight( (Math.sin(time * 2 ) + 1.2) * 200)
.marginTop( (Math.sin(time * 3 ) + 1.5) * 100)
.marginBottom((Math.sin(time * 4 ) + 1.5) * 100);
requestAnimationFrame(updateMargin);
});
}
main();
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment