All examples By author By category About

timelyportfolio

work history d3v3 and R ver 2

assembled with blockbuilder.org


subtle improvements to forked from timelyportfolio's block: work history using d3v3 and R

A very unfinished little example combining d3.js and d3.layout.timeline by Elijah Meeks to render what you might use in a resume or something similar. It is partially reusable, but still needs lots of love and attention. Please do not use this as an model for how to implement a reusable component.

If you are wondering about my potential motivation for this, see post.

code in R

library(pipeR) #install.packages("pipeR")
library(timelineR) #devtools::install_github("timelyportfolio/timelineR")
library(htmltools) #install.packages("htmltools")
library(d3r) #devtools::install_github("timelyportfolio/d3r")
library(googlefontR) #devtools::install_github("timelyportfolio/googlefontR")
library(whisker) #install.packages("whisker")

dat <- data.frame(
  id = 1:4,
  company = c(
    "Company A",
    "Company A",
    "Company B",
    "Company C"
  ),
  start = c(
    "1998-08-31",
    "1999-12-31",
    "2001-05-31",
    "2011-08-31"
  ),
  end = c(
    "1999-12-31",
    "2001-05-31",
    "2011-08-31",
    "2016-12-31"
  ),
  description = c(
    "Title and all the stuff I did",
    "New Title with other sophisticated sounding items",
    "Really Important Sounding Title with all the buzzwords",
    "Even More Important Title with persuasive text"
  )
)

# based off of 
#  /emeeks/3184af35f4937d878ac0
template <- '
(function(){
  var svg = d3.select("svg#{{svgid}}");
  var width = svg.node().getBoundingClientRect().width,
    height = svg.node().getBoundingClientRect().height;

  var data = {{{data}}};
  var groups = d3.set(data.map(function(d){ return d.{{group}} })).values();

  var bandHeight = {{bandHeight}};
  var timeline = d3.layout.timeline()
    .size([width - 150 - 20, bandHeight - 10])
    .extent(["1998-01-01", "2016-12-31"])
    .padding(3)
    .maxBandHeight(bandHeight - 20);
  
  var colorScale = {{colorFun}};
  
  groups.forEach(function (type, i) {
    onlyThisType = data.filter(function(d) {return d.{{group}} === type});
    
    theseBands = timeline(onlyThisType);
    
    svg.append("g")
      .attr("transform", "translate(150," + (35 + (i * 50)) + ")")
      .selectAll("rect")
      .data(theseBands)
      .enter()
      .append("rect")
      .classed("rect-position",true)
      .attr("rx", 2)
      .attr("x", function (d) {return d.start})
      .attr("y", function (d) {return d.y})
      .attr("height", function (d) {return d.dy})
      .attr("width", function (d) {return d.end - d.start})
      .style("fill", function (d) {return colorScale(d.{{group}})})
      .style("stroke", "black")
      .style("stroke-width", 1);
    
    d3.select("svg").append("text")
      .text(type)
      .attr("y", bandHeight + (i * bandHeight))
      .attr("x", 20);

  });

  var axisScale = d3.time.scale();

  axisScale
    .domain(timeline.extent())
    .range([0, width - 150 - 20]);

  var axis = d3.svg.axis();
  axis.scale(axisScale);
  axis.tickSize(bandHeight * groups.length + 20);

  var axis_g = svg.append("g")
    .attr("class","timeline-axis")
    .attr("transform","translate(170,0)")
    .call(axis);

  // some default styles for our axis
  axis_g.selectAll("path, .tick > line")
    .style("fill","none")
    .style("stroke","black");

  svg.selectAll(".timeline-axis > path")
    .style("fill","none")
    .style("stroke","none");
  svg.selectAll(".timeline-axis .tick line")
    .style("stroke","gray")
    .attr("stroke-dasharray","5 5");
  svg.selectAll("rect")
    .style("stroke","white")
    .attr("rx",4);

  svg.attr("height", (bandHeight * groups.length + 20 + 20) + "px")

  // now render the text descriptions of each position
  var textdiv = d3.select("div#{{divid}}");
  var posdiv = textdiv.selectAll("p")
    .data(data)
    .enter()
    .append("div");

  posdiv.append("h3")
    .text(function(d){
      return d.company + " | " + d.start + " - " + d.end
    });

  posdiv.append("p")
    .text(function(d){ return d.description; });

  // add some mouseover on the rects
  svg.selectAll("rect.rect-position")
    .on("mouseover", highlightPos)
    .on("mouseout", unhighlightPos);

  function highlightPos(pos){
    posdiv.each(function(d) {
      if(d.id !== pos.id) {
        d3.select(this).style("color", "lightgray");
      }
    });
  }

  function unhighlightPos() {
    posdiv.style("color", "black")
  }
  
})();
'

tagList(
  h1("Work History"),
  tag("svg",list(id="work-timeline", width="80%", height="400px")),
  hr(),
  div(id = "work-history"),
  tags$script(
    HTML(
      whisker.render(
        template,
        list(
          svgid = "work-timeline",
          divid = "work-history",
          group = "company",
          data = jsonlite::toJSON(dat, dataframe="rows"),
          bandHeight = 50, # total height of band not the timeline rect
          colorFun = "d3.scale.category10()"
        )
      )
    )
  )
) %>>%
  gf_add_font("Titillium+Web") %>>%
  attachDependencies(
    list(
      d3r::d3_dep_v3(offline=FALSE),
      htmlwidgets:::getDependency("timeline","timelineR")[[3]]
    ),
    append = TRUE
  ) %>>%
  browsable()