Angular pipe that transforms number to readable fraction

Viewed 1109

I would like to create an Angular 5 pipe that translates a more readable fraction from a number.

For example:

0,66 -> ⅔
0,25 -> ¼
1.25 -> 1 ¼

Here is what I already have, but I would like to make it more dynamic:

export class FracturePipe implements PipeTransform {
  transform(value: any, args?: any): any {
    let roundedValue = Math.round(Number(value) * 100) / 100

    if (roundedValue === 0.66) {
      return '⅔'
    }
    //..and so on, but maybe there is a better way
  }
}

Any ideas how to do that in a more dymamic way?

4 Answers

Although you can do this using external libraries this is more than possible with typescript, using the Euclidean Algorithm you can calculate the Greatest common divisor between two numbers and divide by your decimal value, where this decimal value is calculated at

const wholeNumber = Math.floor(input);
const decimal = input - wholeNumber;

The return of this pipe is a string first followed by the integer value of the number then the fraction that is calculated ( decimal divided by gcd and bottom of fraction divided by gcd )

Example : 1.3 will return 1 3/10 You then can edit the output of the pipe as your liking

 export class FracturePipe implements PipeTransform {
 transform(value: any, args?: any): any {

  if (value === parseInt(value)) {
        return value.toString();
      } else {
        let top = value.toString().includes('.') ? value.toString().replace(/\d+[.]/, '') : 0;
        const wholeNumber = Math.floor(value);
        const decimal = value - wholeNumber;
        const bottom = Math.pow(10, top.toString().replace('-', '').length);
        if (decimal >= 1) {
          top = +top + (Math.floor(decimal) * bottom);
        } else if (decimal <= -1) {
          top = +top + (Math.ceil(decimal) * bottom);
        }

        const x = Math.abs(this.gcd(top, bottom));
        if (wholeNumber === 0) {
          return (top / x) + '/' + (bottom / x);
        }
        return wholeNumber + ' ' + (top / x) + '/' + (bottom / x);
      }
}

gcd(a: number, b: number) {
    return (b) ? this.gcd(b, a % b) : a;
  }
}

I think you could use fractionjs to get it working. I haven't worked with it, but really the problem is number conversion. So if you managed to get those two working together, I think it could be something as follows:

export class FractionPipe implements PipeTransform {
    transform(value: number): string {
        const { numerator, denominator } = new Fraction(value);

        return `${numerator} and ${denominator} formatted`;
    }
}

This library might help, if you pass two values instead of the finished float: https://github.com/ben-ng/vulgarities

var characterFor = require('vulgarities/charFor')
  , vulgarities = require('vulgarities');

console.log(characterFor(1,4)); // Returns "\u00BC"

If you combine this with the answer of EvaldasBuinauskas, you get something like this:

export class FractionPipe implements PipeTransform {
    transform(value: number): string {
        const { numerator, denominator } = new Fraction(value);

        return characterFor(numerator, denominator);
    }
}

Use one way flow syntax property binding:

<!DOCTYPE html>
<html>
<style>
</style>
<body>
<p>I will display &frac34;</p>
</body>
</html>

export class AngularFractions {

  fraction: any;
  input: number;
  public dynamicFractions(input) {
    this.fraction = '&frac' + input + ';';
  }
}
<div class="row">
  <input class="form-control" (change)="dynamicFractions(input)" [(ngModel)]="input"><br>
  <p [innerHTML]="fraction"></p>
</div>

Related