| <% |
| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| %> |
| |
| <!DOCTYPE html> |
| <html> |
| <head> |
| <meta charset="utf-8"> |
| |
| <% |
| // d3js.org rendering of a destination's stats |
| // based on the http://bl.ocks.org/mbostock/3943967 example |
| |
| var title = resource.path.replace(/.*\/(.*)/g,"$1") |
| %> |
| |
| <title><%= title %></title> |
| |
| <style> |
| |
| body { |
| font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; |
| margin: auto; |
| position: relative; |
| width: 960px; |
| } |
| |
| text { |
| font: 10px sans-serif; |
| } |
| |
| .axis path, |
| .axis line { |
| fill: none; |
| stroke: #000; |
| shape-rendering: crispEdges; |
| } |
| |
| form { |
| position: absolute; |
| right: 10px; |
| top: 10px; |
| } |
| |
| </style> |
| |
| <script src="http://d3js.org/d3.v3.min.js"></script> |
| </head> |
| |
| <body> |
| <h1><%= title %></h1> |
| <form> |
| <label><input type="radio" name="mode" value="grouped"> Grouped</label> |
| <label><input type="radio" name="mode" value="stacked" checked> Stacked</label> |
| </form> |
| <div id="graph"/> |
| |
| <script> |
| <% sling.include(resource.path + ".statsdata.json"); %> |
| </script> |
| |
| <script> |
| |
| // number of layers and samples per layer |
| var n = layers.length; |
| var m = statsData.length; |
| |
| var stack = d3.layout.stack(), |
| layers = stack(d3.range(n).map(function(n) { return layerData(m, n); })), |
| yGroupMax = d3.max(layers, function(layer) { return d3.max(layer, function(d) { return d.y; }); }), |
| yStackMax = d3.max(layers, function(layer) { return d3.max(layer, function(d) { return d.y0 + d.y; }); }); |
| |
| var margin = {top: 40, right: 10, bottom: 20, left: 10}, |
| width = 960 - margin.left - margin.right, |
| height = 500 - margin.top - margin.bottom; |
| |
| var x = d3.scale.ordinal() |
| .domain(d3.range(m)) |
| .rangeRoundBands([0, width], .08); |
| |
| var y = d3.scale.linear() |
| .domain([0, yStackMax]) |
| .range([height, 0]); |
| |
| var color = d3.scale.linear() |
| .domain([0, n - 1]) |
| .range(["#aad", "#556"]); |
| |
| var xAxis = d3.svg.axis() |
| .scale(x) |
| .tickSize(0) |
| .tickPadding(6) |
| .orient("bottom") |
| .tickFormat(xTickFormat); |
| |
| var svg = d3.select("#graph").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 + ")"); |
| |
| var layer = svg.selectAll(".layer") |
| .data(layers) |
| .enter().append("g") |
| .attr("class", "layer") |
| .style("fill", function(d, i) { return color(i); }); |
| |
| var rect = layer.selectAll("rect") |
| .data(function(d) { return d; }) |
| .enter().append("rect") |
| .attr("x", function(d) { return x(d.x); }) |
| .attr("y", height) |
| .attr("width", x.rangeBand()) |
| .attr("height", 0); |
| |
| rect.transition() |
| .delay(function(d, i) { return i * 10; }) |
| .attr("y", function(d) { return y(d.y0 + d.y); }) |
| .attr("height", function(d) { return y(d.y0) - y(d.y0 + d.y); }); |
| |
| svg.append("g") |
| .attr("class", "x axis") |
| .attr("transform", "translate(0," + height + ")") |
| .call(xAxis); |
| |
| d3.selectAll("input").on("change", change); |
| |
| var timeout = setTimeout(function() { |
| d3.select("input[value=\"grouped\"]").property("checked", true).each(change); |
| }, 2000); |
| |
| function change() { |
| clearTimeout(timeout); |
| if (this.value === "grouped") transitionGrouped(); |
| else transitionStacked(); |
| } |
| |
| function transitionGrouped() { |
| y.domain([0, yGroupMax]); |
| |
| rect.transition() |
| .duration(500) |
| .delay(function(d, i) { return i * 10; }) |
| .attr("x", function(d, i, j) { return x(d.x) + x.rangeBand() / n * j; }) |
| .attr("width", x.rangeBand() / n) |
| .transition() |
| .attr("y", function(d) { return y(d.y); }) |
| .attr("height", function(d) { return height - y(d.y); }); |
| } |
| |
| function transitionStacked() { |
| y.domain([0, yStackMax]); |
| |
| rect.transition() |
| .duration(500) |
| .delay(function(d, i) { return i * 10; }) |
| .attr("y", function(d) { return y(d.y0 + d.y); }) |
| .attr("height", function(d) { return y(d.y0) - y(d.y0 + d.y); }) |
| .transition() |
| .attr("x", function(d) { return x(d.x); }) |
| .attr("width", x.rangeBand()); |
| } |
| |
| // Format our tick values |
| function xTickFormat(index) { |
| return statsData[index].period; |
| } |
| |
| function layerValue(layerIndex, itemIndex) { |
| var layerName = layers[layerIndex]; |
| var senders = statsData[itemIndex].senders; |
| if(senders[layerName]) { |
| return senders[layerName]; |
| } |
| return -1; |
| } |
| |
| // Generate the data of a given layer |
| function layerData(nElements, layerIndex) { |
| var a = []; |
| for (i = 0; i < nElements; ++i) a[i] = i; |
| return a.map(function(d,i) { return { x:i, y: layerValue(layerIndex,i) }}); |
| } |
| |
| </script> |
| </body> |