Demos Back to Demos

Fitness Tracker Dashboard

7 of 25

Include multiple grids on the same page, and conditionally highlight different types of information in each of them.

Result HTML CSS JS
Edit Download

Result

HTML

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>ZingGrid: Blank Grid</title>
    <script src="https://cdn.zinggrid.com/dev/zinggrid-dev.min.js" defer></script>
    <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.3.1/css/all.css" integrity="sha384-mzrmE5qonljUremFsqc01SB46JvROS7bZs3IO2EmfFsd15uHvIt+Y8vEf7N7fWAU" crossorigin="anonymous">
    <link href="https://fonts.googleapis.com/css?family=Heebo:300,400,700" rel="stylesheet">
  </head>
  <body>
    
    <div class="dashboard-container">
      <h1>Fitness Tracker Dashboard</h1>
      <p>Monitor your heart rate, calorie consumption, and activity logs in one place with a dashboard overview of your data.</p>  
      <hr>
      <div class="columns">
        <zing-grid 
          src="https://zinggrid-examples.firebaseio.com/fitness-dashboard/1/heartRateTracker" 
          layout="row"
          sort
          pager
          page-size="6"
          page-size-options="6,12,8,24"
        >
          <zg-caption>
            <i class="fas fa-heartbeat"></i> Heart Rate Tracker
          </zg-caption>
          <zg-colgroup>
            <zg-column index="date"></zg-column>
            <zg-column index="restingHeartRate">
              [[index.restingHeartRate]] bpm
            </zg-column>
            <zg-column index="timeInHeartRateZones.fatBurn" header="Fat Burn"></zg-column>
            <zg-column index="timeInHeartRateZones.cardio" header="Cardio"></zg-column>
            <zg-column index="timeInHeartRateZones.peak" header="Peak" renderer="renderPeak"></zg-column>
          </zg-colgroup>
        </zing-grid> 

        <zing-grid 
          src="https://zinggrid-examples.firebaseio.com/fitness-dashboard/2/calorieTracker" 
          layout="row"
          sort
          pager
          page-size="6"
          page-size-options="6,12,8,24"
        >
          <zg-caption>
            <i class="fas fa-burn"></i> Calorie Tracker
          </zg-caption>
          <zg-colgroup>
            <zg-column type="text" index="date"></zg-column>
            <zg-column type="number" index="breakfast">
              [[index.breakfast]] cal
            </zg-column>
            <zg-column type="number" index="lunch">
              [[index.lunch]] cal
            </zg-column>
            <zg-column type="number" index="dinner">
              [[index.dinner]] cal
            </zg-column>
            <zg-column type="number" index="snacks">
              [[index.snacks]] cal
            </zg-column>
            <zg-column type="number" index="total" renderer="renderCalorieGoal">
            </zg-column>
          </zg-colgroup>
        </zing-grid> 
      </div>

      <zing-grid 
        src="https://zinggrid-examples.firebaseio.com/fitness-dashboard/0/activityTracker" 
        row-class="_renderClassActivity"
        layout="row"
        sort
        pager
        page-size="6"
        page-size-options="6,12,8,24"
      >
        <zg-caption>
          <i class="fas fa-child"></i> Activity Tracker
        </zg-caption>
        <zg-colgroup>
        <zg-column index="date"></zg-column>
          <zg-column index="activityType" renderer="renderActivityType"></zg-column>
          <zg-column index="city"></zg-column>
          <zg-column index="state"></zg-column>
          <zg-column index="distance" header="Distance">
            [[index.distance]] mi
          </zg-column>
          <zg-column index="elapsedTime"></zg-column>
          <zg-column index="movingTime"></zg-column>
        </zg-colgroup>
      </zing-grid>
    </div>
    
  </body>
</html>

CSS

body{
  background: #F3F3F3;
  padding: 30px;
  font-family: 'Heebo', sans-serif;
}
.dashboard-container {
  max-width: 1000px;
  margin: 0 auto;
}
h1 {
  color: #606470;
  margin-bottom: 10px;
  font-weight: 300;
}
p {
  color: #606470;
  margin: 0 0 10px 0;
  font-weight: 300;
}
hr {
  display: block;
  height: 1px;
  border: 0;
  border-top: 1px solid #dddddd;
  margin: 1em 0;
  padding: 0; 
  margin: 0 0 30px 0; 
}
.columns {
  display: grid;
  grid-template-columns: 1fr 1fr;
  grid-auto-rows: 2em;
  grid-gap: 2em;
  min-height: 440px;
  width: 100%;
}
.fas { padding-right:5px; font-size:15px; }
.blue { color:#2f89fc; }
.gold { color: #f4b342; }
.green { color: #4bbb8b; }
.grey { color: #ccc; }
.red { color: #ff5759; }

/* Grid */
zing-grid {
  max-width: 1000px;
  margin: 0 auto;
  font-family: 'Heebo', sans-serif;
  font-size: 11px;
  background: #ffffff;
  border: none;
  color: #ffffff;
  --theme-color-primary: #606470;
  --zg-cell-background_sorted: #eee;
  --zg-head-cell-background_sorted: #ccc;
  --zg-icon-init-fill: #606470;
  --zg-head-cell-icon-color_sorted: #606470;
  --zg-select-arrow-color: #606470;
  box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.05), 0 6px 20px 0 rgba(0, 0, 0, 0.09);
}
zg-caption {
  border-bottom: 1px solid #efefef;
  font-weight: 400;
  background: #ffffff;
  color: #606470;
  border-radius: 8px 8px 0 0;
  -webkit-border-radius: 8px 8px 0 0;
  -moz-border-radius: 8px 8px 0 0;
}
zg-control-bar {
  display: none;
}
zg-head, zg-head-cell {
  background: #ffffff;
  color: #606470;
  font-size: 9px;
  font-weight: bold;
  text-transform: none;
}
zg-icon {
  width: 15px;
}
zg-head,
zg-body {
  border: none;
}
zg-row {
  border-bottom: 1px solid #efefef;
  background: #ffffff;
  color: #414141;
}
zg-row, zg-cell {
 padding: 0 15px; 
  height: 40px;
}
zg-body zg-row:last-child {
  border-radius: 0 0 8px 8px;
  -moz-border-radius: 0 0 8px 8px;
  -webkit-border-radius: 0 0 8px 8px;
}
zg-pager {
  background: #ffffff;
  margin-top: 0px;
  color: #606470;
  border-radius: 0 0 8px 8px;
  -webkit-border-radius: 0 0 8px 8px;
  -moz-border-radius: 0 0 8px 8px;
  font-size: 10px;
}

.bike {
  color: #2f89fc;
  font-weight: bold;
}
zg-row.outdoor-bike  {
  color: #2f89fc;
  font-weight: normal;
}
.run,
.peak {
  color: #ff5759;
  font-weight: bold;
}
zg-row.run  {
  color: #ff5759;
  font-weight: normal;
}
zg-row.peak  {
  color: #ff5759;
  font-weight: normal;
}
.sport {
  color: #4bbb8b;
  font-weight: bold;
}
zg-row.sport  {
  color: #4bbb8b;
  font-weight: normal;
}
.not-peak {
  color: #cccccc;
}
.calorie-goal {
  color: #f4b342;
  font-weight: bold;
}
.bold {
  font-weight: bold;
}
@media screen and (max-width: 650px) {
  .columns {
    display: block;
    margin-bottom: 30px;
  }
  .columns zing-grid:first-child {
    margin-bottom: 30px;
  }
}

JS

// Javascript code to execute after DOM content
ZingGrid.registerMethod(_renderClassActivity);

// Add Row Classes
function _renderClassActivity(record, $cell) {
  return record.activityType.replace(' ', '-').toLowerCase();
}

// Cell Renderers
function renderPeak(value) {
  const match = value === "00:00:00";
  const classes = match ? 'grey' : 'red';
  const peak = match ? 'not-peak' : 'peak';
  return ` ${value}`;
}
function renderCalorieGoal(value, $cellRef, cell) {
  const match = value > "2,350";
  const classes = match ? 'grey' : 'gold';
  const total = match ? 'not-peak' : 'calorie-goal';
  return ` ${value}`;
}
function renderActivityType(value) {
  let classes, type;
  switch (value) {
    case 'Run':
      classes = 'fa-shoe-prints red';
      type = 'run';
      break;
    case 'Sport':
      classes = 'fa-volleyball-ball green';
      type = 'sport';
      break;
    default:
      classes = 'fa-bicycle blue';
      type = 'bike';
  }
  return ` ${value}`;
}

Interested in this demo? Modify it to your needs in the ZingSoft Studio, our testing sandbox. It's free to sign up, and you can come back and edit at any time!

Edit in Studio