Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

DataTables conditional formatting bars

I develop the app that uses datatables to visualize certain statistics data.

I receive from API the data in the following format:

{
    "data": [{
        "companyName": "company1",
        "growth": 15
    },
    {
        "companyName": "company2",
        "growth": -8
    },
    {
        "companyName": "company3",
        "growth": 23
    }]
}

Which is essentially a company name and its year over year revenue growth figure (%).

What I would like to implement is an MS Excel-like conditional formatting feature that displays colored bars inside percentage cells (color of the bar is red for negative and green for positive values and its size is normalized to minimal/maximal value and column width).

So far, my HTML is:

<link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/1.10.19/css/jquery.dataTables.css">
<script type="text/javascript" src="https://code.jquery.com/jquery-3.4.1.min.js" charset="utf8"></script>  
<script type="text/javascript" charset="utf8" src="https://cdn.datatables.net/1.10.19/js/jquery.dataTables.js"></script>
<table id="revenue-growth"></table>

And jQuery:

$('#revenue-growth').DataTable({
    ajax: {
        url: 'https://192.168.0.1/revenue',
        method: 'GET',
        dataSrc: 'data'
    }
    dom: 'Bfrtip',
    pageLength: 50,
    order: [0, 'asc']
    columDefs: [{
            targets: 0,
            data: 'companyName',
            title: 'Company Name'
        }, {
            targets: 1,
            data: 'growth',
            title: 'YoY revenue growth, %'
        }
    ]
})

So, my question is: is there a way to implement such feature from the ground up, or, maybe, there's already plug-in that does exactly this?

I didn't find anything matching my request here, at stackoverflow, nor I was able to identify DataTables API methods that may solve my problem, so I would really appreciate that if you could point me to the right direction.

like image 571
luoxuan86 Avatar asked Oct 15 '22 13:10

luoxuan86


1 Answers

You could use the render-callback to create bars inside the cells in the growth-column.

  1. You have to find the maximum growth inside the dataset.

  2. In the render-callback:

    2.1. check if the growth is negative or positive.

    2.2. calculate bar width-% based on the growth and the maximum.

    2.3. create and append the elements based on these information.

Here is an simple example:

$(document).ready(function() {
  
  const dataSet = [
    { companyName: "Company A", growth: -12 },
    { companyName: "Company B", growth:  31 },
    { companyName: "Company C", growth:   7 },
    { companyName: "Company D", growth:   0 },
    { companyName: "Company E", growth: -29 },
    { companyName: "Company F", growth:  23 },
  ];
  
  // Get absolute maximum value of grwoth from dataset
  const maxGrowthValue = Math.max.apply(Math, dataSet.map(function(item) { return Math.abs(item.growth); }));
  
  const table = $('#example').DataTable({
    data: dataSet,
    columns: [
      {
        data: 'companyName',
        title: "Company Name",
      },
      {
        data: 'growth',
        title: "YoY revenue growth, %",
        // Custom render the cell of the growth-column
        render: (data, type, row, meta) => {
          const isPositive = (Number(data) > 0);
          const barWidth = 100 / maxGrowthValue * Math.abs(Number(data)) * 0.5;
          const $growthBarContainer = $('<div>', {
            class: "growth-bar",
          });
          const $growthBar = $('<div>', {
            class: "bar bar-" + (isPositive ? 'positive' : 'negative'),
          });
          $growthBar.css({
            width: barWidth.toFixed(2) + '%',
          });
          $growthBarContainer.append($growthBar);
          $growthNumber = $('<div>', {
            class: "growth-number",
          });
          $growthNumber.text(data + '%');
          $growthBarContainer.append($growthNumber);
          return $growthBarContainer.prop("outerHTML");
        },
      },
    ],
  });
  
});
.growth-bar {
  display: inline-block;
  width: 120px;
  height: 12px;
  position: relative;
  background-color: #eee;
  border: 1px solid #424242;
}

.growth-bar > .bar {
  width: 0%;
  height: 100%;
  position: absolute;
}

.growth-bar > .bar.bar-negative {
  right: 50%;
  background-color: red;
}

.growth-bar > .bar.bar-positive {
  left: 50%;
  background-color: green;
}

.growth-bar > .growth-number {
  position: absolute;
  top: 1px;
  right: 2px;
  color: #fff;
  /* shadow for better readability */
  text-shadow: 0px -1px 0px rgba(0,0,0,.5), 0px 1px 0px rgba(0,0,0,.5), -1px 0px 0px rgba(0,0,0,.5), 1px 0px 0px rgba(0,0,0,.5), 0px 0px 1px rgba(0,0,0,.25), 0px 0px 2px rgba(0,0,0,.5), 0px 0px 3px rgba(0,0,0,.75);
  font-size: 10px;
  line-height: 12px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<link rel="stylesheet" href="https://cdn.datatables.net/1.10.19/css/jquery.dataTables.min.css">
<script src="https://cdn.datatables.net/1.10.19/js/jquery.dataTables.min.js"></script>

<table id="example" class="display" style="width:100%"></table>
like image 133
Jan Avatar answered Oct 19 '22 00:10

Jan