Bit Hacker Logo
Bit Hacker Logo
Barbell racking calculator with Vue.JS

Barbell racking calculator with Vue.JS

A little over a year ago I started lifting. I knew calculating what plates to put on the rack should be easy, but after a few hours of exhaustion the head gets a little foggy. Being a programmer, building my own racking calculator was the obvious next step.

With this calculator I wanted the UI to be reactive. Clicking some archaic button like "calculate" would not work for me. Vue.js seemed like an obvious choice.

Project Setup

To get started we will use vue-cli to bootstrap our project. This little tool installs a directory structure for you which includes webpack, vue and a starter template to get up and running quickly.

Install vue-cli

If you don't have it already, install the package.

npm install -g vue-cli

Create Project

To create your project cd into your desired directory and run:

npm init webpack barbell-calc

This will through you into a few questions. Below is what we are using for this project:

  • Project name barbell-calc
  • Project description Barbell racking calculator
  • Author You
  • Vue build standalone
  • Install vue-router? No
  • Use ESLint to lint your code? No
  • Set up unit tests No
  • Setup e2e tests with Nightwatch? No
  • Should we run npm install for you after the project has been created? (recommended) Yes

Getting started

cd barbell-calc
npm run dev

Open your browser to http://localhost:8080

App.vue

The cli comes preloaded with an App.vue and a demo component called HelloWord. For the sake of this app, we will not need the HellWorld component. Go ahead and remove components/HelloWorld.vue and remove the reference in App.vue

Your App.vue should look something like the following

<template>
  <div id="app">
    <h1>Barbell Racking Calculator</h1>
  </div>
</template>

<script>
export default {
  name: 'App'
}
</script>

<style>
#app {
  font-family: ua-med,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>

To calculate the weights, lets can an input on the page to receive the base value for our calculation. Add this below the h1 tag in App.vue.

<input type="number" v-model="weight" step="5" min="45" /> lbs

We are using a number input which allows us to step the values in increments of 5. Next we will need to add a weight variable to our data section to store the desired weight. Your javascript in App.vue should look something like below:

export default {
  name: 'App',
  data() {
      return {
          weight: 45
      }
  }
}

Calculating plates

Before we can calculate what plates we need to put on the bar we must first know 1) the bar weight and 2) what plates we have available. Along with the bar weight and available plates we need a place to store the calculated plate values. Lets make these variables in the data section:

data() {
    return {
        weight: 45,
        barWeight: 45,
        platesAvailable: [45, 35, 25, 10, 5, 5, 2.5, 1.25], // plates available for us
        plates: [] // holds the plates need to meet the weight
    }
}

Time for the meat. Create a new method called calculate() inside the default object with the following code:

methods: {
  calculate() {
    this.plates = [];
    var left = this.weight - this.barWeight;
    while( left > 0 ) {
        // track if we found a plate, otherwise we will spin forever
        var foundOne = false;
        for( var i = 0; i < this.platesAvailable.length; i++ ) {
            var amount = this.platesAvailable[i]*2;
            if( amount <= left ) {
                left -= amount;
                this.plates.push( this.platesAvailable[i] );
                foundOne = true;
                break;
            }
        }
        if( !foundOne ) break;
    }
  }
}

There is a bit happening here but the logic is simple. The steps are as follows;

  1. Determine the total weight (we need to keep the bar weight in mind) we are working with
  2. Loop through our available plates to see if any are less than the total weight
  3. Subtract the plate weight from what is left
  4. Do this until we have no weight left

All the weights will get added to our handy plates variable.

Output

All the "hard" work is now complete. Next we need to display the plates so we know what to rack up. Create the following html after your input:

<div class="rack">
    <div class="bar">{{barWeight}}</div>
    <div v-for="plate in plates">
        <div class="plate">{{plate}}</div>
    </div>
</div>

This will first display the bar weight before looping through the plates.

Listing everything is fine but lets spruce it up just a bit. It would be nice to see the plates resemble the size they actually are. We can do this by adjusting the width of the plate div:

:style="{width: 30+(plate*4)+'px'}"

Basing the width entirely off the weight would make it to small, so we start with a base value of 30px and multiple the plate weight by 4. I'm sure there are many formulas to use here but this suits our needs perfectly.

The CSS

Previewing will yield nothing different. We need some css! In your style tag add the following:

.rack {
  margin: 20px auto;
}
.bar {
  width: 24px;
  margin: 4px auto;
  background: #e4e4e4;
  height: 50px;
  line-height: 50px;
  border: 2px solid #c5c5c5;
  border-radius: 5px;
}
.plate {
  margin: 4px auto;
  color: #fff;
  min-width: 30px;
  border: 2px solid #283544;
  border-radius: 5px;
  background: radial-gradient(circle, #666666,#444444);
}
input {
  font-size: 18pt;
  text-align: center;
  padding: 5px;
  border-radius: 4px;
  border: 1px solid #cad3dc;
  max-width: 80px;
}

This gives our bar and plates a bit of style. There is also something extra for our input to make it a bit larger.

Rack up!

That is it! You now have a functioning barbell plate calculator that will help you get swol.

Extending

Some ideas to extend this app would be the ability to customize what plates are available for racking and switching the weight units from pounds to kg.