block by pbogden 6016415

fit-to-height x-y plot

Full Screen

Simple x-y plot with axes, labels & margins (and a transition). Plot region resizes to fit window.innerHeight.

index.html

<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0">
<link rel="stylesheet" href="styles.css" type="text/css">
<script type="text/javascript" src="//d3js.org/d3.v3.min.js"></script>
</head>

<body>
<script>

var defaultWidth  = 960,  // Default width & height of plot region
    defaultHeight = 500,
    defaultMinHeight = 150,
    padding = 0.1,       // fraction to pad maximum of range for y-axis
    paddedExtent;        // padded extent that results from using padding

var outerWidth,          // dimensions of plot area
    outerHeight,
    marginWidth=50,      // margins -- the same on all sides
    strokeWidth=1;       // this should be consistent with <style>

// viewport <meta> info -- diagnostic only
var viewportMeta = document.getElementsByName("viewport").content, // <meta> "content" string
    viewportWidth = document.documentElement.clientWidth,          // *This* gets viewport width
    viewportHeight = document.documentElement.clientHeight;        // *This* gets viewport height

var width  = (window.innerWidth > 0)  ? window.innerWidth :  defaultWidth;
var height = (window.innerHeight > 0) ? window.innerHeight : defaultHeight;
outerWidth  = Math.min(defaultWidth,width);
outerHeight = Math.min(defaultHeight,height);
outerHeight = Math.max(defaultMinHeight,height);

// Note: on iPhone in portrait:  viewportWidth = window.innerWidth = screen.width = 320
//         ''  ''    landscape:  viewportWidth = window.innerWidth = 568 BUT screen.width = 320
//                  on desktop:  screen.width = 1680 > viewportWidth = window.innerWidth (= variable)

alert("viewport Width & Height:\n" + viewportWidth     + ", " + viewportHeight + "\n" +
      "window.innerWidth & innerHeight:\n" + window.innerWidth + ", " + window.innerHeight + "\n" +
      "screen.width & height:\n" + screen.width + ", " + screen.height + "\n" +
      "width & height for D3:\n" + width + ", " + height);

// More plot dimensions (computed from previous)
var marginLeft = marginWidth+strokeWidth/2,  // leftmost point inside the margins
    marginTop  = marginWidth+strokeWidth/2,  // topmost point inside the margins
    width  = outerWidth -2*marginLeft,       // width of inner plot area *and* margins
    height = outerHeight-2*marginTop;        // height of inner plot area *and* margins

// Eliminate default margin from <body> element
document.body.style.margin="0px";

// Check aspect ratio and resize accordingly
// TBD

var data = [
  {x: 0, y: 00},
  {x: 1, y: 30},
  {x: 2, y: 40},
  {x: 3, y: 20},
  {x: 4, y: 90},
  {x: 5, y: 70}
];

function xValue(d) { return d.x; }       // accessors for data
function yValue(d) { return d.y; }

var x = d3.scale.linear()                // interpolator for X axis -- inner plot region
    .domain(d3.extent(data,xValue))                // equivalent to .domain([0,1.1*5])
    .range([0,width]);                   // range is inner plot area (i.e., inside margins)

// pads extent of graph above the max y value; makes it easier to select max value w/brush
paddedExtent = d3.extent(data,yValue);
paddedExtent[1] += padding*(paddedExtent[1]-paddedExtent[0]);

var y = d3.scale.linear()                // interpolator for Y axis -- inner plot region
    .domain(paddedExtent)                // use the padded yxtent for plotting "y"
    .range([height,0]);                  // remember, (0,0) is upper left -- this reverses "y"

var svg = d3.svg;

var line = svg.line()                    // SVG line generator
    .x(function(d) { return x(d.x); } )
    .y(function(d) { return y(d.y); } );

var xAxis = svg.axis()                   // x Axis
    .scale(x)
    .ticks(5)                            // request 5 ticks on the x axis
    .orient("bottom");

var yAxis = svg.axis()                   // y Axis
    .scale(y)
    .ticks(4)
    .orient("left");

var svg = d3.select("body").append("svg");   // "svg" points to the SVG node in the DOM

svg.attr("width",  outerWidth)           // SVG domain is the outer plot area (i.e., inner area plus margins)
   .attr("height", outerHeight);         // Note: ok to leave this without units, implied "px"

var g = svg.append("g")                  // <g> element is the inner plot area (i.e., inside the margins)
    .attr("transform", "translate(" + marginLeft + "," + marginTop + ")");

g.append("g")                            // render the Y axis in the inner plot area
    .attr("class", "y axis")
    .call(yAxis);

g.append("g")                            // render the X axis in the inner plot area
    .attr("class", "x axis")
    .attr("transform", "translate(0," + height + ")")  // axis runs along lower part of graph
    .call(xAxis);

g.append("text")                         // inner x-axis label
    .attr("class", "x label") 
    .attr("text-anchor", "end") 
    .attr("x", width - 6) 
    .attr("y", height - 6) 
    .text("inner x-axis label");

g.append("text")                         // outer x-axis label
    .attr("class", "x label") 
    .attr("text-anchor", "end") 
    .attr("x", width/2) 
    .attr("y", height + 2*marginWidth/3 + 6) 
    .text("outer x-axis label");

g.append("text")                         // inner y-axis label
    .attr("class", "y label") 
    .attr("text-anchor", "end") 
    .attr("x", -6)
    .attr("y", 6)
    .attr("dy", ".75em") 
    .attr("transform", "rotate(-90)") 
    .text("inner y-axis label");

g.append("text")                         // outer y-axis label
    .attr("class", "x label") 
    .attr("text-anchor", "middle") 
    .attr("x", -height/2)
    .attr("y", -6 - marginWidth/3)
    .attr("dy", "-.75em") 
    .attr("transform", "rotate(-90)") 
    .text("outer y-axis label");

g.append("path")                         // plot the data as a line
    .datum(data)
    .attr("class", "line")
    .attr("d", line);

g.append("rect")                         // plot a rectangle that encloses the inner plot area
    .attr("width", width)
    .attr("width", width)
    .attr("height", height);

svg.append("circle")                     // plot a circle in the upper left of the SVG element
    .attr("cx", 0)
    .attr("cy", 0)
    .attr("r", 10);

svg.append("circle")                     // plot a circle in the lower right of the SVG element
    .attr("cx", outerWidth)
    .attr("cy", outerHeight)
    .attr("r", 10);

g.selectAll(".dot")                      // plot a circle at each data location
    .data(data)
  .enter().append("circle")
    .attr("class", "dot")
    .attr("cx", function(d) { return x(d.x); } )
    .attr("cy", function(d) { return y(d.y); } )
    .attr("r", 5);

svg.append("rect")                      // plot a rectangle that encloses the entire SVG element
    .attr("x", 0) 
    .attr("y", 0) 
    .attr("width", outerWidth)
    .attr("height", outerHeight);

d3.selectAll("path").transition()       // data transition
    .style("stroke", "steelblue")
    .delay(1000)
    .duration(2000);

</script>
</body>
</html>

styles.css

.line {
  fill: none;
  stroke: white;      // starts invisible, made visible with transition
  stroke-width: 1px;  // half is inside the margin, half is outside
}

rect {
  fill: none;
  stroke: black;
  stroke-width: 1px;  // half is inside the margin, half is outside
}

.axis path, .axis line {
  fill: none;
  stroke: #000;
  shape-rendering: crispEdges;
}

test.xml

<svg width="400px" height="300px" viewBox="0 0 400 300"
     xmlns="http://www.w3.org/2000/svg">
  <desc>This example uses the 'switch' element to provide a 
        fallback graphical representation of a paragraph, if 
        XHTML is not supported.</desc>

  <!-- The 'switch' element will process the first child element
       whose testing attributes evaluate to true.-->
  <switch>

    <!-- Process the embedded XHTML if the requiredExtensions attribute
         evaluates to true (i.e., the user agent supports XHTML
         embedded within SVG). -->
    <foreignObject width="100" height="50"
                   requiredExtensions="http://www.w3.org/1999/xhtml">
      <!-- XHTML content goes here -->
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>Here is a paragraph that requires word wrap</p>
      </body>
    </foreignObject>

    <!-- Else, process the following alternate SVG.
         Note that there are no testing attributes on the 'text' element.
         If no testing attributes are provided, it is as if there
         were testing attributes and they evaluated to true.-->
    <text font-size="10" font-family="Verdana">
      <tspan x="10" y="10">Here is a paragraph that</tspan>
      <tspan x="10" y="20">requires word wrap.</tspan>
    </text>
  </switch>
</svg>