block by alanmclean 5852582

Run Pace Viz experiment #10

Full Screen

index.html

<html>
<body>
  <link rel="stylesheet" type="text/css" href="normalize.css">
<style type="text/css">
.avgPaceLabel,
.avgPaceLabel2,
.runTimeLabel,
.runTimeLabel2{

  font-family:arial,sans-serif;
  font-size:11px;
  fill:#666;
  /*font-weight:bold;*/
}
.avgPaceLabel2,.runTimeLabel2{
 font-weight:bold;
 font-size:13px;
 fill:rgb(60,146,186);
}
.paceBar{
  stroke:rgba(0,0,0,.2);
  stroke-width:1px;
  shape-rendering:crispEdges;
  stroke-dashArray: 2,4;
  display:none;
}
.paceLabel{
  font-family:arial,sans-serif;
  font-size:11px;
  fill:#aaa;
}
.mileMarkerText{
  /*font-weight:bold;*/
  font-family:arial,sans-serif;
  font-size:11px;
  fill:#777;
  /*font-weight:bold;*/
}
.mileMarker{
  stroke:rgba(0,0,0,.3);
  stroke-width:1px;
  shape-rendering:crispEdges;
  stroke-dashArray: 2,4;
}
 .block{
  /*fill:#fff;*/
 }
.positionCircle{
  fill:#999;
}
#container{
  width:1000px;
  margin: 20px auto;
  position:relative;
  /*height:500px;*/
}
.paceline{
  stroke:rgba(0,0,100,0);
  stroke-width:1.5px;
  /*fill:none;*/
  /*opacity:0;*/
  /*stroke:#000;*/
}
.avg{
  stroke: rgb(163,210,225);
  opacity:.9;
  /*stroke-dashArray: 2,4;*/
  shape-rendering:crispEdges;
  /*fill:none;*/
  stroke-width:1px;
  fill:none;
}
.goal{
  stroke:#f9a7a8;
  opacity:1;
  /*stroke-dashArray: 2,4;*/
  shape-rendering:crispEdges;
  /*fill:none;*/
  stroke-width:1px;
  fill:none;
}
.area.above {
  fill: rgb(163,210,225);
  fill-opacity:.7;
}

.area.below {
  fill: #f9a7a8;
  fill-opacity:.8;
}
.elevationGraph{
  fill: #ccc;
  fill-opacity:.3;
}
.paceline-above{
  stroke:#900;
}
.hed{
  font-size:25px;
  text-align:center;
  margin-left:-85px;
  font-family: "HelveticaNeue-Light", "Helvetica Neue Light", "Helvetica Neue", Helvetica, Arial, "Lucida Grande", sans-serif;
   font-weight: 300;
}
#faster{
font-size: 11px;
color: #999;
width: 50px;
height: 38px;
position: absolute;
z-index: 100;
background: url(arrowbottom.gif) no-repeat 20px top;
left: 53px;
top: 269px;
padding-top: 21px;
text-align: center;
text-transform:uppercase;
display:none;
}
#slower{
font-size: 11px;
color: #999;
width: 50px;
height: 38px;
position: absolute;
z-index: 100;
background: url(arrowtop.gif) no-repeat 20px bottom;
left: 53px;
top: 210px;
padding-top: 21px;
text-align: center;
text-transform:uppercase;
display:none;

}

.boxRight{
  height:40px;
  width:4px;
  border:1px solid #ddd;
  border-right:none;
  position:absolute;
}
.boxLeft{
  height:50px;
  width:10px;
  border:1px solid #ddd;
  border-left:none;
  position:absolute;
}
.altitude{
  fill:#999;
  fill-opacity:.7;
}
</style>

<div id="container">
  <h3 class="hed">Race Pace Analysis</h3>
  <div id="chart"></div>
  <div id="faster">Faster</div>
  <div id="slower">Slower</div>
</div>

<script src="//d3js.org/d3.v3.min.js"></script>
<script type="text/javascript" src="streams.js"></script>

<script>

  // fastestPaceDataMetersPerSec = d3.max(paceData, function(d){ return d.y })
  // slowestPaceDataMetersPerSec = d3.min(paceData, function(d){ return d.y })

var margin = {top: 20, right: 156, bottom: 150, left: 100 },
    width = 900 - margin.left - margin.right,
    height = 400 - margin.top - margin.bottom;


 var chart = d3.select("#container").append("svg")
    .attr('xml:space', "preserve")
    .attr("width", width + margin.left + margin.right)
    .attr("height", height + margin.top + margin.bottom)
  .append("g")
    .attr("transform", "translate(" + margin.left + "," + margin.top + ")");


  var x = d3.scale.linear().range([0, width]).domain(d3.extent(desiredStream, function(d){ return d.x }))
  var y = d3.scale.linear().range([height, 40]).domain(d3.extent(desiredStream, function(d){ return d.y }))
  var xDistance = d3.scale.linear().range([0, width]).domain(d3.extent(distanceStream, function(d){ return d }))
  var avg     = d3.mean(desiredStream, function(d){ return d.y });
  var goal     = 480;

  var altX = d3.scale.linear().range([0, width]).domain(d3.extent(elevationStream, function(d){ return d.x }))
  var altY = d3.scale.linear().range([height, 70]).domain(d3.extent(elevationStream, function(d){ return d.y }))

// chart.append('text')

chart.selectAll('.mileMarker')
    .data([1,2,3,4,5,6,7,8]).enter()
    .append('line')
      .attr('class', 'mileMarker')
      .style('opacity',0)
      .attr('x1', function(d){ return xDistance(d) })
      .attr('x2', function(d){ return xDistance(d) })
      .attr('y1', 0)
      .attr('y2', height)
      .attr('clip-path', 'url(#clip-above)')
    .transition()
      .delay(function(d, i) { return i / 8  * 700; })
       .style('opacity',1)

chart.selectAll('.mileMarkerText')
    .data([1,2,3,4,5,6,7,8]).enter()
    .append('text')
      .attr('class', 'mileMarkerText')
      .style('opacity',0)
      .attr('x', function(d){ return xDistance(d) })
      .attr('dx', -3)
      .attr('dy', -6)
      .attr('y', 0)
      .text(function(d){ if(d !== 1){ return d+'mi.' }else{ return d+'mile'} })
    .transition()
      .delay(function(d, i) { return i / 8  * 700; })
       .style('opacity',1)

var desiredPaces = [8,10,12,14],
    maxln = d3.max(desiredPaces),
    paddingDesiredPaces = desiredPaces.map(function(d){ return (" " + d).slice((-2)) })

chart.selectAll('.avgPaceLabel')
  .data([avg])
  .enter()
  .append('text')
  .attr('class','avgPaceLabel')
  .attr('text-anchor','start')
  .attr('x',width+11)
  .attr('dy',-16)
  .attr('y',function(d){ return y(d) })
  .text('AVG. PACE')

chart.selectAll('.avgPaceLabel2')
  .data([avg])
  .enter()
  .append('text')
  .attr('class','avgPaceLabel2')
  .attr('text-anchor','start')
  .attr('x',width+11)

  .attr('y',function(d){ return y(d) })
  .attr('dy',1)
  .text('9:07min/mile')

  chart.selectAll('.runTimeLabel')
  .data([goal])
  .enter()
  .append('text')
  .attr('class','avgPaceLabel')
  .attr('text-anchor','end')
  .attr('x',0)
  .attr('dx',-10)
  .attr('y',function(d){ return y(d) })
  .attr('dy',19)
  .text('GOAL PACE')

chart.selectAll('.runTimeLabel2')
  .data([goal])
  .enter()
  .append('text')
  .attr('class','avgPaceLabel2')
  .attr('text-anchor','end')
  .attr('x',0)
  .attr('dx',-10)
  .attr('y',function(d){ return y(d) })
  .attr('dy',5)
  .text('8:15min/mi')

// chart.selectAll('.paceLabel')
//     .data(desiredPaces).enter()
//     .append('text')
//       .attr('class', 'paceLabel')
//       .style('opacity',0)
//       .attr('x', 0)
//       .attr('dx',-10)
//       .attr('text-anchor','end')
//       .attr('y', function(d){ return y(d * 60) })
//       .text(function(d,i){ return (paddingDesiredPaces[i])+' min/mi' })
//     .transition()
//       .delay(function(d, i) { return i / 8  * 700; })
//        .style('opacity',1)


chart.selectAll('.paceBar')
    .data(desiredPaces).enter()
    .append('line')
      .attr('class', 'paceBar')
      // .style('opacity',0)
      .attr('x1', 0)
      .attr('x2', width)
      .attr('y1', function(d){ return y(d * 60) })
      .attr('y2', function(d){ return y(d * 60) })
      // .text(function(d,i){ return (paddingDesiredPaces[i])+' min/mi' })
    // .transition()
    //   .delay(function(d, i) { return i / 8  * 700; })
    //    .style('opacity',1)

  // initalT = chart.transition().duration(700);

  var line = d3.svg.area()
    .interpolate("basis")
    .x(function(d) { return x(d.x); })
    .y(function(d) { return y(d.y); });

  var area = d3.svg.area()
    .interpolate("basis")
    .x(function(d) { return x(d.x); })
    .y1(function(d) { return y(goal); });


  var altLine = d3.svg.area()
    .interpolate("basis")
    .x(function(d) { return altX(d.x); })
    .y(function(d) { return altY(d.y); });

  var altArea = d3.svg.area()
    .interpolate("basis")
    .x(function(d) { return altX(d.x); })
    .y0(function(d) { return y(goal); })
    .y1(function(d) { return altY(d.y); });


// var tempArea = d3.svg.area()
//     .interpolate("basis")
//     .x(function(d) { return x(d.x); })
//     .y0(function(d) { return y(goal); });



  var meanData = desiredStream.map(function(d){ return { x: d.x, y: goal }; })
  var startData = desiredStream.map(function(d){ return { x: paceData[0].x, y: goal }; })

  // startData[startData.length-1].x = paceData[startData.length-1].x
  // chart.datum(meanData)




  var t0 = chart.transition().duration(600)

  var pline = chart.append("path")
        .datum(startData)
        .attr("class", "paceline animateMe")
        .attr("d", line)
        .style('opacity',0)

  var avgLine = d3.select('svg').append("svg:line")
    .attr("x1", margin.left)
    .attr("x2", 0)
    .attr('class', 'avg animateMe')
    .attr("y1", y(avg)+margin.top + 1)
    .attr("y2", y(avg)+margin.top + 1)
    .style('opacity',0)
      .transition()
      .duration(600)
    .style('opacity',1)
    .attr('x2',width + margin.left)

var avgLine = d3.select('svg').append("svg:line")
    .attr("x1", margin.left)
    .attr("x2", 0)
    .attr('class', 'goal animateMe')
    .attr("y1", y(goal)+margin.top)
    .attr("y2", y(goal)+margin.top)
    .style('opacity',0)
      .transition()
      .duration(600)
    .style('opacity',1)
    .attr('x2',width + margin.left)



  // var l = pline.node().getTotalLength();

  // pline.attr("stroke-dasharray", l + " " + l);
  // t0.selectAll('.startPaceline').attr("stroke-dashoffset", 0);


  pline.datum(meanData);
  var t1 = chart.transition().duration(900).delay(200)

  t1.selectAll('.paceline').attr('d',line).style('opacity',1)

 var altGraph = chart.append("path")
    .datum(elevationStream)
      .attr("id", "elevationGraph")
      .attr("class", "elevationGraph")
      .attr("d", altArea);

  var c1_clip = chart.append("clipPath")
     .datum(meanData)
      .attr("id", "clip-above")
    .append("path")
      .attr("d", area.y0(0));

 var c1_clip2 = chart.append("path")
    .datum(meanData)
      .attr("id", "area-above")
      .attr("class", "area above")
      .attr("clip-path", "url(#clip-above)")
      .attr("d", area.y0(function(d) { return y(d.y); }));

  var c3 = chart.append("path")
      .datum(meanData)
      .attr("class", "area below")
      .attr("clip-path", "url(#clip-below)")
      .attr("d", area);

  var c4 = chart.append("clipPath")
      .datum(meanData)
      .attr("id", "clip-below")
    .append("path")
      .attr("d", area.y1(height))


  pline.datum(desiredStream);
  c1_clip.datum(desiredStream);
  c1_clip2.datum(desiredStream);


  var t2 = t1.transition()



  t2.selectAll('.paceline').attr('d',line);
  t2.selectAll('#clip-above').attr("d", area.y0(0));
  t2.selectAll('#area-above').attr("d", area.y0(function(d) { return y(d.y); }));
  c3.datum(desiredStream);
  c4.datum(desiredStream);
  t2.selectAll('#clip-below').attr("d", area.y1(height - margin.top - margin.bottom));
  t2.selectAll('.area.below').attr("d", area);

  d3.select('#container').append('div')
     .attr('class','boxRight')
     .attr('style','left:'+(margin.left + width + 3)+'px; top: '+(margin.top+y(avg) + 21)+'px;')

      // pline.datum(paceData)
      //   .transition()
      //    .duration(1000)
      // .attr('d',line)
      // pline
      //   .attr("d", line)

  // chart.datum(paceData)
  // pline.datum(paceData)
  // pline.attr('d', line)

  // d3.select('.area.below').transition().attr('d',area)

  // d3.select('#clip-below').attr('d',area.y1(height - margin.top - margin.bottom))

  // chart.append("path")
  //   .attr("class", "area below")
  //   .attr("clip-path", "url(#clip-below)")
  //   .attr("d", area);

  // var pline = chart.append('svg:path').attr([0,0]).enter()
  // var line = "M"+paceData[0].x + " " + paceData[0].y

  // var avgLine = chart.append("svg:line")
  //   .attr("x1", 0)
  //   .attr("x2", 0)
  //   .attr('class', 'avg animateMe')
  //   .attr("y1", y(avg))
  //   .attr("y2", y(avg))


  // avgLine.attr('x2', width)
  // pline.attr("stroke-dashoffset", 0);

// var gradient = chart.append("svg:defs")
//   .append("svg:linearGradient")
//     .attr("id", "gradient")
//     .attr("x1", "0%")
//     .attr("y1", "0%")
//     .attr("x2", "100%")
//     .attr("y2", "0%")
//     .attr("spreadMethod", "pad");

// gradient.append("svg:stop")
//     .attr("offset", "10")
//     .attr("stop-color", "rgb(255,255,255)")
//     .attr("stop-opacity", .7);

// gradient.append("svg:stop")
//     .attr("offset", "100%")
//     .attr("stop-color", "rgba(255,255,255,1)")
//     .attr("stop-opacity", 1);

// var circle = chart.append("circle")
//     .attr('class','positionCircle')
//     .attr("r", 5)
//     .attr("transform", "translate(" + x(paceData[0].x) + "," + y(paceData[0].y) + ")");


// // circle.transition()
// //       .duration(4000)
// //       .each("end", function(d,i){ if(d.y !== paceData[paceData.length-1].y) { transition() })
//   var block= chart.append('svg:rect').style('fill','url(#gradient)').attr('class','block').attr('x',0).attr('y',0).attr('height',height).attr('width',width);

//   transition()

// // block.transition().ease('linear').duration(4000).attr('x',width)

//   function transition() {
//     circle.transition()
//       .duration(10010)
//       .ease('linear')
//       .delay(function(d){ return d })
//       .attrTween("transform", translateAlong(pline.node()))

//     block.transition()
//       .duration(10000)
//       .ease('linear')
//       .attrTween("transform", translateAlong2(pline.node()))
//       // .each("end", function(d,i){ console.log('d'); })
//   }
// // Returns an attrTween for translating along the specified path element.
//   function translateAlong(path) {
//     var pl = path.getTotalLength();

//     return function(d, i, a) {

//       return function(t) {
//         if(t >= 0.5) {
//           circle.remove()
//           // return "translate(" + p.x + "," + p.y + ")";
//         }else{
//           var p = path.getPointAtLength(t * pl);
//           return "translate(" + p.x + "," + p.y + ")";
//         }


//     };
//   };
// }
//   function translateAlong2(path) {
//     var pl = path.getTotalLength();

//     return function(d, i, a) {

//       return function(t) {
//         if(t >= 0.5) {
//           block.remove()
//         }else{
//           var p = path.getPointAtLength(t * pl);
//           return "translate(" + (p.x) + ",0)";
//         }


//     };
//   };
// }
  // var transitionMe = function(transition){

  //   if(this.attr('class','avg') === true){
  //     transition
  //       .duration(4000)
  //       .ease("linear")
  //       .attr('x2', width);

  //   }else{
  //     transition
  //       .duration(4000)
  //       .ease("linear")
  //       .attr("stroke-dashoffset", 0);
  //   }
  // };

  // d3.selectAll('.animateMe').transition().call(transitionMe);


  // var pline2 = chart.append("path")
  //       // .attr("class", "paceline-above")
  //       .attr("d", line)
  //       .attr("clip-path", "url(#clip-below)")





  // fastestPaceDataMetersPerSec = d3.max([fast.y, fastestPaceDataMetersPerSec])
  // slowestPaceDataMetersPerSec = d3.min([slow.y, slowestPaceDataMetersPerSec])

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