http://git-wip-us.apache.org/repos/asf/incubator-senssoft/blob/6b90be61/images/incubator-logo.png
----------------------------------------------------------------------
diff --git a/images/incubator-logo.png b/images/incubator-logo.png
new file mode 100644
index 0000000..c04e70d
Binary files /dev/null and b/images/incubator-logo.png differ

http://git-wip-us.apache.org/repos/asf/incubator-senssoft/blob/6b90be61/images/stout.png
----------------------------------------------------------------------
diff --git a/images/stout.png b/images/stout.png
new file mode 100644
index 0000000..29ec1de
Binary files /dev/null and b/images/stout.png differ

http://git-wip-us.apache.org/repos/asf/incubator-senssoft/blob/6b90be61/images/stout_inverted.png
----------------------------------------------------------------------
diff --git a/images/stout_inverted.png b/images/stout_inverted.png
new file mode 100644
index 0000000..597c819
Binary files /dev/null and b/images/stout_inverted.png differ

http://git-wip-us.apache.org/repos/asf/incubator-senssoft/blob/6b90be61/images/system.png
----------------------------------------------------------------------
diff --git a/images/system.png b/images/system.png
new file mode 100644
index 0000000..6849d34
Binary files /dev/null and b/images/system.png differ

http://git-wip-us.apache.org/repos/asf/incubator-senssoft/blob/6b90be61/images/tap.png
----------------------------------------------------------------------
diff --git a/images/tap.png b/images/tap.png
new file mode 100644
index 0000000..82b4991
Binary files /dev/null and b/images/tap.png differ

http://git-wip-us.apache.org/repos/asf/incubator-senssoft/blob/6b90be61/images/tap_inverted.png
----------------------------------------------------------------------
diff --git a/images/tap_inverted.png b/images/tap_inverted.png
new file mode 100644
index 0000000..dd1b363
Binary files /dev/null and b/images/tap_inverted.png differ

http://git-wip-us.apache.org/repos/asf/incubator-senssoft/blob/6b90be61/images/userale.png
----------------------------------------------------------------------
diff --git a/images/userale.png b/images/userale.png
new file mode 100644
index 0000000..d3267e5
Binary files /dev/null and b/images/userale.png differ

http://git-wip-us.apache.org/repos/asf/incubator-senssoft/blob/6b90be61/images/userale_inverted.png
----------------------------------------------------------------------
diff --git a/images/userale_inverted.png b/images/userale_inverted.png
new file mode 100644
index 0000000..c873912
Binary files /dev/null and b/images/userale_inverted.png differ

http://git-wip-us.apache.org/repos/asf/incubator-senssoft/blob/6b90be61/index.html
----------------------------------------------------------------------
diff --git a/index.html b/index.html
new file mode 100644
index 0000000..cfb9152
--- /dev/null
+++ b/index.html
@@ -0,0 +1,103 @@
+---
+layout: default
+---
+
+<div id="main-masthead" class="ui masthead padded center aligned inverted 
vertical segment">
+
+  <h1 class="ui header">Apache SensSoft</h1>
+  <h2 class="ui header">Instrument Software. &nbsp; Understand Humans.</h2>
+
+</div>
+
+<div class="ui very padded vertical segment">
+  <div class="ui center aligned text container">
+    <p>
+      Apache Software as a Sensor™ (SensSoft) incorporates a number of 
components that work together to provide user-experience researchers, project 
managers and software developers insights about how web applications are used. 
Each of the components of Apache SensSoft is made available through its own 
repository, allowing its distinctive capabilities to grow organically. A 
simplified system architecture ensures that the components will continue to 
share data and work together efficiently throughout their evolution.
+    </p>
+
+    <br>
+
+    <a class="ui big red button" href="{{ '/system' | prepend: site.baseurl 
}}">
+      Learn More
+    </a>
+    <a class="ui big blue button" href="{{ '/releases' | prepend: site.baseurl 
}}">
+      Download SensSoft
+    </a>
+    <a class="ui big yellow button" 
href="mailto:users-subscr...@senssoft.incubator.apache.org";>
+      Sign Up For News
+    </a>
+  </div>
+</div>
+
+<div class="ui inverted grey very padded vertical segment">
+  <div class="ui text container">
+    <div class="ui two column middle aligned grid">
+      <div class="column">
+        With a single line of code, capture all of your users’ behavior on 
your web page with enough resolution and granularity for advanced behavioral 
modeling. Apache UserALE is a free, open-source application for standard user 
event tracking, but is specially tailored for capturing behavior in web 
applications build for productivity—data analysis, logistics, system 
monitoring, and service provisioning.
+      </div>
+      <div class="center aligned column">
+        <a href="{{ '/userale' | prepend: site.baseurl }}">
+          <img class="component-image" src="/images/userale_inverted.png">
+        </a>
+      </div>
+    </div>
+  </div>
+</div>
+
+{% include useralejsDemo.html inverted=false %}
+
+<div class="ui inverted grey very padded vertical segment">
+  <div class="ui text container">
+    <div class="ui two column middle aligned grid">
+      <div class="center aligned column">
+        <a href="{{ '/distill' | prepend: site.baseurl }}">
+          <img class="component-image" src="/images/distill_inverted.png">
+        </a>
+      </div>
+      <div class="column">
+        Process and control your own user event data. Apache Distill is a 
scalable, customizable analytics stack built in Python that allows you to 
segment your user data and generate both simple usage statistics on different 
features of your application and complex graph models of user workflow. Distill 
provides an easy access point into databases storing your user event data and 
packages data for discovery through visual analytics.
+      </div>
+    </div>
+  </div>
+</div>
+
+<div class="ui very padded vertical segment">
+  <div class="ui text container">
+    <div class="ui two column middle aligned grid">
+      <div class="column">
+        Explore your users’ behavior and discover trends through visual 
analytics. Apache TAP is a customizable visual analytics application that 
allows you to see trends in usage across users of different types, usage trends 
across different versions of your application, and rich visualizations of 
users’ workflow. Tailor visual analytics to your needs customizing TAP with 
your favorite D3 visualizations.
+      </div>
+      <div class="center aligned column">
+        <a href="{{ '/tap' | prepend: site.baseurl }}">
+          <img class="component-image" src="/images/tap.png">
+        </a>
+      </div>
+    </div>
+  </div>
+</div>
+
+{% include tapDemo.html inverted=true %}
+
+<div class="ui very padded vertical segment">
+  <div class="ui text container">
+    <div class="ui two column middle aligned grid">
+      <div class="center aligned column">
+        <a href="{{ '/stout' | prepend: site.baseurl }}">
+          <img class="component-image" src="/images/stout.png">
+        </a>
+      </div>
+      <div class="column">
+        Stage systematic user research on the web. Apache STOUT provides 
everyone the ability to perform user research on the web. Track research 
participants through different tasks with your web applications, or track them 
through different versions of the same web application. Apache STOUT allows you 
to manage user research participants and data collected through Apache UserALE 
and 3rd party form data services.
+      </div>
+    </div>
+  </div>
+</div>
+
+<div class="ui inverted grey very padded vertical segment">
+  <div class="ui text container">
+    <h2 class="ui inverted header">About the Project</h2>
+    <p>
+      Apache SensSoft is a user activity logging and analytics system that 
enables developers to instrument and extract design and user insights from 
their applications.  It was originally developed at Draper for DARPA's XDATA 
program as a means of evaluating and improving tools for big data analysis and 
exploration.  Commercially available as Draper's Software as a Sensor™, 
Apache SensSoft aims to provide a more complete and customizable user analytics 
platform.
+    </p>
+  </div>
+</div>

http://git-wip-us.apache.org/repos/asf/incubator-senssoft/blob/6b90be61/js/bowiePlot.js
----------------------------------------------------------------------
diff --git a/js/bowiePlot.js b/js/bowiePlot.js
new file mode 100644
index 0000000..b36d740
--- /dev/null
+++ b/js/bowiePlot.js
@@ -0,0 +1,408 @@
+var Bowie = (function () {
+  // Set up module variables
+  var element = '#bowie';
+  var data;
+  var metric;
+
+
+  // Grab data for this static case
+  d3.json('/js/graphData.json', function (error, response) {
+    if (error) throw error;
+    data = response;
+
+    if (typeof metric !== 'undefined') {
+      update(metric);
+    }
+  });
+
+
+  // Set up D3 variables
+  var svg;
+  var tooltip;
+  var arcs;
+  var chords;
+  var circles;
+  var margin = {
+    top : 20,
+    right : 20,
+    bottom : 20,
+    left : 20,
+  };
+  var fullWidth = 600;
+  var fullHeight = 400;
+  var width = fullWidth - margin.left - margin.right;
+  var height = fullHeight - margin.top - margin.bottom;
+  var mainRadius = 280;
+
+  var color = d3.scaleOrdinal()
+    .range([
+      '#E24614',
+      '#DBA915',
+      '#BFD02C',
+      '#38A6D8',
+      '#852EB7'
+    ]);
+
+  var arc = d3.arc()
+    .innerRadius(mainRadius - 50)
+    .outerRadius(mainRadius);
+
+  var ribbon = d3.ribbon();
+
+  var graphLayout = graphFlow()
+    .radius(mainRadius - 50)
+    .innerRadius(mainRadius - 150);
+
+
+  // Define bowie layout function
+  function graphFlow() {
+    var tau = Math.PI * 2;
+
+    var padAngle = 0;
+    var spaceAngle = tau / 4;
+    var radius = 0;
+    var innerRadius = 0;
+
+    function layout(data) {
+      var result = {};
+
+      result.in = arrayToObj(data.in);
+      result.out = arrayToObj(data.out);
+      result.blt = arrayToObj(circleLayout(data.blt, innerRadius));
+
+      var arcAngle = (tau - (spaceAngle * 2)) / 2;
+      var inStart = (tau + spaceAngle) / 2;
+      var outStart = spaceAngle / 2;
+
+      var inSide = sideLayout(data.inMatrix, result.blt, inStart, arcAngle, 
padAngle, radius, 'in');
+      var outSide = sideLayout(data.outMatrix, result.blt, outStart, arcAngle, 
padAngle, radius, 'out');
+
+      result.inArcs = inSide[0];
+      result.inChords = inSide[1];
+      result.outArcs = outSide[0];
+      result.outChords = outSide[1];
+
+      return result;
+    }
+
+    layout.padAngle = function (value) {
+      return value ? (padAngle = value, layout) : padAngle;
+    };
+
+    layout.spaceAngle = function (value) {
+      return value ? (spaceAngle = value, layout) : spaceAngle;
+    };
+
+    layout.radius = function (value) {
+      return value ? (radius = value, layout) : radius;
+    };
+
+    layout.innerRadius = function (value) {
+      return value ? (innerRadius = value, layout) : innerRadius;
+    };
+
+    return layout;
+  }
+
+  function sideLayout(matrix, circles, startAngle, angle, padAngle, radius, 
type) {
+    var n = matrix.length;
+    var m = matrix[0].length;
+    var groupSums = [];
+    var total = 0;
+    var arcs = new Array(n);
+    var chordTemp = new Array(n * m);
+    var chords = [];
+    var k;
+    var dx;
+    var x;
+    var x0;
+    var i;
+    var j;
+
+    matrix.forEach(function (group) {
+      groupSums.push(group.reduce(function (prev, curr) { return prev + curr; 
}));
+    });
+
+    total = groupSums.reduce(function (prev, curr) { return prev + curr; });
+
+    k = Math.max(0, angle - padAngle * n) / total;
+    dx = k ? padAngle : angle / n;
+
+    x = startAngle;
+    i = -1;
+
+    while(++i < n) {
+      x0 = x;
+      j = -1;
+
+      while(++j < n) {
+        var v = matrix[i][j];
+        var a0 = x;
+        var a1 = x += v * k;
+
+        chordTemp[j + (n * i)] = {
+          index : i,
+          subindex : j,
+          startAngle : a0,
+          endAngle : a1,
+          value : v,
+        };
+      }
+
+      arcs[i] = {
+        index : i,
+        type : type,
+        startAngle : x0,
+        endAngle : x,
+        value : groupSums[i],
+      };
+
+      x += dx;
+    }
+
+    chordTemp.forEach(function (chord) {
+      if (chord.value > 0) {
+        var circle = circles[chord.subindex];
+
+        chords.push({
+          index : chord.index,
+          subindex : chord.subindex,
+          type : type,
+          source : {
+            startAngle : chord.startAngle,
+            endAngle : chord.endAngle,
+            radius : radius,
+          },
+          target : {
+            startAngle : circle.theta - 0.001,
+            endAngle : circle.theta + 0.001,
+            radius : circle.radius,
+          },
+        });
+      }
+    });
+
+    return [arcs, chords];
+  }
+
+  function circleLayout(circles, innerRadius) {
+    circles.forEach(function (d) {
+      d.r = d.value;
+    });
+
+    d3.packSiblings(circles);
+    var enclose = d3.packEnclose(circles);
+    var k = innerRadius / enclose.r;
+
+    circles.forEach(function (d) {
+      d.r = d.r * k;
+      d.x = d.x * k;
+      d.y = d.y * k;
+
+      var rSq = Math.pow(d.x, 2) + Math.pow(d.y, 2);
+      d.radius = Math.sqrt(rSq);
+      d.theta = Math.atan2(d.y, d.x) + (Math.PI / 2);
+    });
+
+    return circles;
+  }
+
+  function arrayToObj(a) {
+    var o = {};
+
+    a.forEach(function (d) {
+      o[d.index] = d;
+    });
+
+    return o;
+  }
+
+  // Initial full build of bowie
+  function create() {
+    svg = d3.select(element).append('svg')
+      .attr('width', fullWidth)
+      .attr('height', fullHeight)
+      .append('g')
+      .attr('transform', 'translate(' + ((width / 2) + margin.left) + ',' + 
((height / 2) + margin.top) + ')');
+
+    tooltip = d3.select('body').append('div')
+      .attr('class', 'tooltip')
+      .style('opacity', 0);
+  }
+
+
+  // Actually render bowie
+  function update(m) {
+    metric = m;
+    if (typeof data === 'undefined') {
+      return false;
+    }
+
+    var currentData = data[metric];
+    var layout = graphLayout(currentData);
+
+    var t = d3.transition()
+      .duration(500);
+
+    arcs = svg.selectAll('.arc')
+      .data(layout.inArcs.concat(layout.outArcs), function (d) {
+        return d.type + d.index;
+      });
+
+    arcs.exit()
+      .attr('class', 'exit')
+      .transition(t)
+      .style('fill-opacity', 0)
+      .remove();
+
+    arcs = arcs.enter()
+      .append('path')
+      .attr('class', 'arc')
+      .merge(arcs);
+
+    arcs
+      .on('mouseover', function (d) {
+        highlight(d, 'arc');
+        showTooltip(currentData.in[d.index], d3.event.pageX, d3.event.pageY);
+      })
+      .on('mouseout', function (d) {
+        restore();
+        hideTooltip();
+      })
+      .transition(t)
+      // TODO: add arc tweens
+      .attr('d', arc)
+      .style('fill', function (d) { return 
color(currentData.in[d.index].elementGroup); });
+
+    chords = svg.selectAll('.chord')
+      .data(layout.inChords.concat(layout.outChords), function (d) {
+        return d.index + d.type + d.subindex;
+      });
+
+    chords.exit()
+      .attr('class', 'exit')
+      .transition(t)
+      .style('fill-opacity', 0)
+      .remove();
+
+    chords = chords.enter()
+      .append('path')
+      .attr('class', 'chord')
+      .style('fill', '#B0B9BE')
+      .merge(chords);
+
+    chords
+      .transition(t)
+      .attr('d', ribbon)
+      .style('fill-opacity', 0.5);
+
+    circles = svg.selectAll('.node')
+      .data($.map(layout.blt, function (val) { return val; }), function (d) { 
return d.index; });
+
+    circles.exit()
+      .attr('class', 'exit')
+      .transition(t)
+      .attr('r', 0)
+      .remove();
+
+    circles = circles.enter()
+      .append('circle')
+      .attr('class', 'node')
+      .merge(circles);
+
+    circles
+      .on('mouseover', function (d) {
+        highlight(d, 'circle');
+        showTooltip(currentData.in[d.index], d3.event.pageX, d3.event.pageY);
+      })
+      .on('mouseout', function (d) {
+        restore();
+        hideTooltip();
+      })
+      .transition(t)
+      .attr('r', function (d) { return d.r; })
+      .attr('cx', function (d) { return d.x; })
+      .attr('cy', function (d) { return d.y; })
+      .style('fill', function (d) {
+        return color(currentData.in[d.index].elementGroup)
+      })
+      .style('fill-opacity', 0.75);
+  }
+
+
+  // Helper functions for mouse behaviors
+  function hideTooltip() {
+    tooltip.transition()
+      .duration(350)
+      .style('opacity', 0);
+  }
+
+  function showTooltip(activity, x, y) {
+    tooltip.transition()
+      .duration(350)
+      .style('opacity', 0.9);
+
+    tooltip
+      .style('left', (x + 6) + 'px')
+      .style('top', (y - 28) + 'px')
+      .html('Action: ' + activity.action + '<br>Id: ' + activity.elementId + 
'<br>Group: ' + activity.elementGroup);
+  }
+
+  function highlight(d, type) {
+    var indices = [];
+
+    if (type === 'arc') {
+      chords
+        .style('fill-opacity', function (c) {
+          if (c.index !== d.index || c.type !== d.type) {
+            return 0.1;
+          } else {
+            indices.push(c.subindex);
+            return 0.5;
+          }
+        });
+
+      circles
+        .style('fill-opacity', function (c) {
+          return indices.includes(c.index) ? 0.75 : 0.1;
+        });
+
+      arcs
+        .style('fill-opacity', function (c) {
+          return c === d ? 1 : 0.25;
+        });
+    } else if (type === 'circle') {
+      chords
+        .style('fill-opacity', function (c) {
+          if (c.subindex !== d.index) {
+            return 0.1;
+          } else {
+            indices.push(c.index);
+            return 0.5;
+          }
+        });
+
+      circles
+        .style('fill-opacity', function (c) {
+          return c === d ? 0.75 : 0.25;
+        });
+
+      arcs
+        .style('fill-opacity', function (c) {
+          return indices.includes(c.index) ? 1 : 0.1;
+        });
+    }
+  }
+
+  function restore() {
+    chords.style('fill-opacity', 0.5);
+    circles.style('fill-opacity', 0.75);
+    arcs.style('fill-opacity', 1);
+  }
+
+  // Return API
+  return {
+    create: create,
+    update: update
+  };
+})();

Reply via email to