Reputation: 1277
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?
Upvotes: 3
Views: 1812
Reputation: 4062
I just made this pipe to support recipe portions. It is only for positive values and not comprehensive for all fractions:
import { Pipe, PipeTransform } from '@angular/core';
@Pipe({
name: 'quantity',
standalone: true,
})
export class QuantityPipe implements PipeTransform {
transform(quantity: number): string | number {
const decimal = quantity % 1;
if (!decimal) return quantity;
const whole = Math.floor(quantity);
if (approxEq(decimal, 1 / 2)) return whole ? `${whole} ½` : '½';
if (approxEq(decimal, 1 / 3)) return whole ? `${whole} ⅓` : '⅓';
if (approxEq(decimal, 2 / 3)) return whole ? `${whole} ⅔` : '⅔';
if (approxEq(decimal, 1 / 4)) return whole ? `${whole} ¼` : '¼';
if (approxEq(decimal, 3 / 4)) return whole ? `${whole} ¾` : '¾';
if (approxEq(decimal, 1 / 5)) return whole ? `${whole} ⅕` : '⅕';
if (approxEq(decimal, 2 / 5)) return whole ? `${whole} ⅖` : '⅖';
if (approxEq(decimal, 3 / 5)) return whole ? `${whole} ⅗` : '⅗';
if (approxEq(decimal, 4 / 5)) return whole ? `${whole} ⅘` : '⅘';
if (approxEq(decimal, 1 / 6)) return whole ? `${whole} ⅙` : '⅙';
if (approxEq(decimal, 5 / 6)) return whole ? `${whole} ⅚` : '⅚';
if (approxEq(decimal, 1 / 8)) return whole ? `${whole} ⅛` : '⅛';
if (approxEq(decimal, 3 / 8)) return whole ? `${whole} ⅜` : '⅜';
if (approxEq(decimal, 5 / 8)) return whole ? `${whole} ⅝` : '⅝';
if (approxEq(decimal, 7 / 8)) return whole ? `${whole} ⅞` : '⅞';
return Number(quantity.toFixed(2));
}
}
const approxEq = (v1: number, v2: number, epsilon: number = 0.005): boolean =>
Math.abs(v1 - v2) < epsilon;
Upvotes: 0
Reputation: 22
Use one way flow syntax property binding:
<!DOCTYPE html>
<html>
<style>
</style>
<body>
<p>I will display ¾</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>
Upvotes: 0
Reputation: 2349
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;
}
}
Upvotes: 1
Reputation: 12988
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);
}
}
Upvotes: 0
Reputation: 14077
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`;
}
}
Upvotes: 0