All examples By author By category About

timelyportfolio

datatables with d3 axis in header


Inspired by datacomb and LineUp, I wanted to see if I could add a reference scale from d3 in the header of a datatable with marker indicating value from mouseovered row. This is the result.

Code In R

While it may seem strange, I code my JavaScript in R. Even though this was written in R, the important JavaScript parts should still be very readable to a JavaScript-er. For this to work we use the datatables callbacks headerCallback and createdRow.

library(DT)
library(d3r)
library(htmltools)

dt1 <- datatable(
  mtcars,
  options = list(
    headerCallback = htmlwidgets::JS(
"
function(row, data) {
  debugger;

  function xsc(d) {
    return d3.scaleLinear()
      .domain(d3.extent(d))
      .range([0,150])
  };

  // try to render a d3 axis in column header
  var heads = d3.select(row)
    .selectAll('th')
    .data(this.api().columns().data().toArray().map(xsc));

  heads.each(function(head, i) {
    if(i===0) {return}
    if(d3.select(this).select('svg').size() === 0) {
      d3.select(this)
        .append('div')
        .append('svg')
        .style('height', '20px')
        .style('width', '100px')
        .attr('viewBox', '0,0,150,20')
        .append('g')
        .classed('axis', true);
      d3.select(this).select('svg').append('path').classed('marker',true);
    }
    
    var ax = d3.select(this).select('svg .axis')

    ax.call(d3.axisBottom(head).ticks(4));
  })
}
"
    ),
    createdRow = htmlwidgets::JS(
"
function(row) {
  var api = this.api();
  $(row).on('mouseover', function() {
    var heads = d3.selectAll(api.columns().header());
    var data = api.row(this).data();
    heads.each(function(sc, i) {
      var ax = d3.select(this).select('svg');
      var x = sc(data[i]);
      ax.select('path.marker')
        .style('display', '')
        .style('stroke', 'red')
        .style('fill', 'none')
        .style('stroke-width', 2)
        .attr('d', d3.line()([[x,0],[x,20]]));
    })
  })

  $(row).on('mouseout', function() {
    d3.select(this).select('svg path.marker')
      .style('display','none');
  })
}
"
    )
  )
)

browsable(
  tagList(
    dt1,
    d3_dep_v4()
  )
)