skip to Main Content

I want to fill the background of a cell in a Material table with color. The cell should be filled in a way that it represents the cells value. It would kind of look like a bar chart in the end.

I got a good start from here: Set div background color based on a percent (like progress bar)

The problem is that this doesn’t fill the cell. It’s height is a high as the font is.
The following image shows how it currently is. Currently I’m using a static width, but I’ll change that later to the cells value.
The bar starts from the middle because some other columns might be negative.

Table with color bars

Is there a way to either make the div height fit the parent cell or apply the same behavior directly to the cell without using divs?
I prefer the last one more, but I don’t even know if that is possible.

I took the current table from the Angular Material examples.

HTML:

<ng-container *transloco="let t; read: 'dashboard'">
  <div class="card-container">
    // other cards

    <table mat-table [dataSource]="dataSource" class="mat-elevation-z8">
      <ng-container [matColumnDef]="column" *ngFor="let column of displayedColumns">
        <th mat-header-cell *matHeaderCellDef> {{column}} </th>
        <td mat-cell *matCellDef="let element">
          <div class="progressbar-wrapper">
            {{element[column]}}
            <div class="progressbar" style="width: 28%"></div>
            <div class="progressbar2" style="width: 28%"></div>
          </div></td>
      </ng-container>
      <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
      <tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
    </table>
  </div>
</ng-container>

CSS:

.card-container {
    width: 85vw;
    height: 90vh;
    display: flex;
    flex-wrap: wrap;
    flex-direction: column;
    justify-content: space-evenly;
}

.overview-card {
    width: 40%;
    height: fit-content;
    // height: 46%;
}

.overview-content {
    display: flex;
    flex-direction: row;
    flex-wrap: wrap;
    justify-content: space-between;
}

.overview-item {
    margin: 10px;
    margin-top: 0px;
}

.make-gold {
  background-color: gold
}

.progressbar-wrapper {
    position: relative;
    z-index: 1;
}

.progressbar {
    position: absolute;
    top: 0;
    bottom: 0;
    left: 50%;
    background-color: #dcf3dd;
    z-index: -1;
}
.progressbar2 {
    position: absolute;
    top: 0;
    bottom: 0;
    left: 22%;
    background-color: #1ccb25;
    z-index: -1;
}

.table-card {
    width: 44%;
    height: 46%;
}

.value-card {
    width: 20%;
    height: 20%;
}

Typescript:

import { Component, OnInit } from "@angular/core";
import { MatTableDataSource } from "@angular/material/table";

@Component({
  selector: "app-dashboard-page",
  templateUrl: "./dashboard-page.component.html",
  styleUrls: ["./dashboard-page.component.scss"],
})
export class DashboardPageComponent implements OnInit {
  displayedColumns: string[] = ["name", "status", "windDirection", "windSpeed", "power"];
  dataSource = new MatTableDataSource(ELEMENT_DATA);

  constructor() {}

  ngOnInit(): void {}

}

export interface PeriodicElement {
  name: string;
  status: string;
  windDirection: number;
  windSpeed: number;
  power: number;
}

const ELEMENT_DATA: PeriodicElement[] = [
  {
    name: "Hydrogen",
    status: "ok",
    windDirection: 180.0,
    windSpeed: 8.2,
    power: 900,
  },
  {
    name: "Helium",
    status: "ok",
    windDirection: 180.0,
    windSpeed: 8.2,
    power: 900,
  },
  {
    name: "Lithium",
    status: "ok",
    windDirection: 180.0,
    windSpeed: 8.2,
    power: 900,
  },
  {
    name: "Beryllium",
    status: "ok",
    windDirection: 180.0,
    windSpeed: 8.2,
    power: 900,
  },
  {
    name: "Boron",
    status: "ok",
    windDirection: 180.0,
    windSpeed: 8.2,
    power: 900,
  },
  {
    name: "Carbon",
    status: "ok",
    windDirection: 180.0,
    windSpeed: 8.2,
    power: 900,
  },
  {
    name: "Nitrogen",
    status: "ok",
    windDirection: 180.0,
    windSpeed: 8.2,
    power: 900,
  },
  {
    name: "Oxygen",
    status: "ok",
    windDirection: 180.0,
    windSpeed: 8.2,
    power: 900,
  },
  {
    name: "Fluorine",
    status: "ok",
    windDirection: 180.0,
    power: 900,
  },
  {
    name: "Neon",
    status: "ok",
    windDirection: 180.0,
    windSpeed: 8.2,
    power: 900,
  },
];

2

Answers


  1. Chosen as BEST ANSWER

    I found a way for the divs to fill up the space of the cells.

    I added the min-height property to the wrapper:

    .progressbar-wrapper {
        position: relative;
        min-height: inherit;
        text-align: center;
        width: 100%;
        z-index: 1;
    }
    

    Then the value sticks to the top of a cell. To vertically center it again I put it in a p tag:

    <mat-cell *matCellDef="let element" class="number-column">
      <div class="progressbar-wrapper">
        <p>{{ element[column] }}</p>
        <div
          *ngIf="element[column] >= 0"
          class="bargraph-green"
          [style.width]="getBarWidth(column, element[column]) + '%'"
        ></div>
        <div
          *ngIf="element[column] < 0"
          class="bargraph-red"
          [style.width]="getBarWidth(column, element[column]) + '%'"
          [style.left]="barScale - getBarWidth(column, element[column]) + '%'"
        ></div>
      </div>
    </mat-cell>
    

  2. You can use style binding to set a dynamic width percentage of both your progress bars. Then you just need to calculate this percentage, store in a property of your component and use on your .progressbar and .progressbar2 something like:

    <div *ngFor="let element of elements; index as i">    
        <div class="progressbar" [style.width]="percentFilled[i]+'%'"></div>
        <div class="progressbar2" [style.width]="percentEmpty[i]+'%'"></div>
    </div>
    

    Edit: off-topic answer, sorry. I thought we were talking about the width.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search