React/ReactJS: Multi-Color Progress Bar
In this tutorial, we will learn how to create a multi-color progress bar as a ReactJS component.
Creating the Component
We first create a kind of template for the component which we will
call MultiColorProgressBar. It consists
of the wrapper
<div className="multicolor-bar">
which contains four child
<div> elements. The values (in
percentages) will go inside
<div className="values">, the
vertical graduations inside
<div className="scale">, the
coloured bars inside
<div className="bars"> and the
legends inside
<div className="legends">.
class MultiColorProgressBar extends Component {
constructor(props) {
super(props);
}
render() {
return (
<div className="multicolor-bar">
<div className="values">
</div>
<div className="scale">
</div>
<div className="bars">
</div>
<div className="legends">
</div>
</div>
);
}
}
export default MultiColorProgressBar;
This component will be passed the following data (props),
let readings = [
{
name: 'Apples',
value: 60,
color: '#eb4d4b'
},
{
name: 'Blueberries',
value: 7,
color: '#22a6b3'
},
{
name: 'Guavas',
value: 23,
color: '#6ab04c'
},
{
name: 'Grapes',
value: 10,
color: '#e056fd'
}
]
with which we will be forming our multi-color progress bar. The
passed data, which is within this.props,
is assigned to the const named
parent inside the
render() function. Below, we show how to
generate an array of divs using the
map() function, which will display the
percentages on the top row.
render() {
const parent = this.props;
let values = parent.readings && parent.readings.length && parent.readings.map(function(item, i) {
if(item.value > 0) {
return (
<div className="value" style={{'color': item.color, 'width': item.value + '%'}} key={i}>
<span>{item.value}%</span>
</div>
)
}
}, this);
}
These generated divs are assigned to the variable
values which will be rendered inside the
<div className="values">, enclosed
as the expression {values}.
return (
<div className="multicolor-bar">
<div className="values">
{values}
</div>
</div>
);
To avoid displaying 0 while fetching values asynchronously, we modify our expression above to display nothing till the values are available.
return (
<div className="multicolor-bar">
<div className="values">
{values == ''?'':values}
</div>
</div>
);
We do the same for the scale, the colored bars and the legends as shown below —
class MultiColorProgressBar extends Component {
constructor(props) {
super(props);
}
render() {
const parent = this.props;
let values = parent.readings && parent.readings.length && parent.readings.map(function(item, i) {
if(item.value > 0) {
return (
<div className="value" style={{'color': item.color, 'width': item.value + '%'}} key={i}>
<span>{item.value}%</span>
</div>
)
}
}, this);
let calibrations = parent.readings && parent.readings.length && parent.readings.map(function(item, i) {
if(item.value > 0) {
return (
<div className="graduation" style={{'color': item.color, 'width': item.value + '%'}} key={i}>
<span>|</span>
</div>
)
}
}, this);
let bars = parent.readings && parent.readings.length && parent.readings.map(function(item, i) {
if(item.value > 0) {
return (
<div className="bar" style={{'backgroundColor': item.color, 'width': item.value + '%'}} key={i}>
</div>
)
}
}, this);
let legends = parent.readings && parent.readings.length && parent.readings.map(function(item, i) {
if(item.value > 0) {
return (
<div className="legend" key={i}>
<span className="dot" style={{'color': item.color}}>●</span>
<span className="label">{item.name}</span>
</div>
)
}
}, this);
return (
<div className="multicolor-bar">
<div className="values">
{values == ''?'':values}
</div>
<div className="scale">
{calibrations == ''?'':calibrations}
</div>
<div className="bars">
{bars == ''?'':bars}
</div>
<div className="legends">
{legends == ''?'':legends}
</div>
</div>
);
}
}
export default MultiColorProgressBar;
The style for our
MultiColorProgressBar component is as
below:
.multicolor-bar {
margin: 20px 20%;
}
.multicolor-bar .values .value {
float: left;
text-align: center;
}
.multicolor-bar .scale .graduation {
float: left;
text-align: center;
}
.multicolor-bar .bars .bar {
float: left;
height: 10px;
}
.multicolor-bar .bars div.bar:first-of-type {
border-top-left-radius: 5px;
border-bottom-left-radius: 5px;
}
.multicolor-bar .bars div.bar:last-of-type {
border-top-right-radius: 5px;
border-bottom-right-radius: 5px;
}
.multicolor-bar .legends {
text-align: center;
}
.multicolor-bar .legends .legend {
display: inline-block;
margin: 0 5px;
text-align: center;
}
.multicolor-bar .legends .legend .dot {
font-size: 25px;
vertical-align: middle;
}
.multicolor-bar .legends .legend .label {
margin-left: 2px;
vertical-align: middle;
}
We import and load our component inside
index.js, passing the array
this.readings consisting of data as an
argument (props).
this.readings = [
{
name: 'Apples',
value: 60,
color: '#eb4d4b'
},
{
name: 'Blueberries',
value: 7,
color: '#22a6b3'
},
{
name: 'Guavas',
value: 23,
color: '#6ab04c'
},
{
name: 'Grapes',
value: 10,
color: '#e056fd'
}
];
ReactDOM.render(<MultiColorProgressBar readings={this.readings}/>,
document.getElementById('root'));
The full code is available on CodePen also.
See the Pen Multi-Color Progress Bar in ReactJS by Dennis Gabil (@dennisgabil) on CodePen.
We finally get our progress bar.