@itwin/core-quantity 4.0.0-dev.7 → 4.0.0-dev.70
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +11 -1
- package/lib/cjs/Constants.d.ts +27 -27
- package/lib/cjs/Constants.js +52 -52
- package/lib/cjs/Constants.js.map +1 -1
- package/lib/cjs/Exception.d.ts +26 -26
- package/lib/cjs/Exception.js +38 -38
- package/lib/cjs/Formatter/Format.d.ts +91 -91
- package/lib/cjs/Formatter/Format.js +328 -329
- package/lib/cjs/Formatter/Format.js.map +1 -1
- package/lib/cjs/Formatter/FormatEnums.d.ts +133 -133
- package/lib/cjs/Formatter/FormatEnums.js +318 -318
- package/lib/cjs/Formatter/Formatter.d.ts +44 -44
- package/lib/cjs/Formatter/Formatter.js +371 -371
- package/lib/cjs/Formatter/Formatter.js.map +1 -1
- package/lib/cjs/Formatter/FormatterSpec.d.ts +39 -39
- package/lib/cjs/Formatter/FormatterSpec.js +101 -101
- package/lib/cjs/Formatter/Interfaces.d.ts +62 -62
- package/lib/cjs/Formatter/Interfaces.js +17 -17
- package/lib/cjs/Interfaces.d.ts +86 -86
- package/lib/cjs/Interfaces.d.ts.map +1 -1
- package/lib/cjs/Interfaces.js +9 -9
- package/lib/cjs/Parser.d.ts +93 -93
- package/lib/cjs/Parser.d.ts.map +1 -1
- package/lib/cjs/Parser.js +592 -592
- package/lib/cjs/Parser.js.map +1 -1
- package/lib/cjs/ParserSpec.d.ts +34 -34
- package/lib/cjs/ParserSpec.js +47 -47
- package/lib/cjs/Quantity.d.ts +27 -27
- package/lib/cjs/Quantity.js +46 -46
- package/lib/cjs/Quantity.js.map +1 -1
- package/lib/cjs/Unit.d.ts +25 -25
- package/lib/cjs/Unit.js +44 -44
- package/lib/cjs/core-quantity.d.ts +19 -19
- package/lib/cjs/core-quantity.js +39 -35
- package/lib/cjs/core-quantity.js.map +1 -1
- package/lib/esm/Constants.d.ts +27 -27
- package/lib/esm/Constants.js +49 -48
- package/lib/esm/Constants.js.map +1 -1
- package/lib/esm/Exception.d.ts +26 -26
- package/lib/esm/Exception.js +34 -34
- package/lib/esm/Formatter/Format.d.ts +91 -91
- package/lib/esm/Formatter/Format.js +323 -324
- package/lib/esm/Formatter/Format.js.map +1 -1
- package/lib/esm/Formatter/FormatEnums.d.ts +133 -133
- package/lib/esm/Formatter/FormatEnums.js +302 -302
- package/lib/esm/Formatter/Formatter.d.ts +44 -44
- package/lib/esm/Formatter/Formatter.js +368 -367
- package/lib/esm/Formatter/Formatter.js.map +1 -1
- package/lib/esm/Formatter/FormatterSpec.d.ts +39 -39
- package/lib/esm/Formatter/FormatterSpec.js +97 -97
- package/lib/esm/Formatter/Interfaces.d.ts +62 -62
- package/lib/esm/Formatter/Interfaces.js +13 -13
- package/lib/esm/Interfaces.d.ts +86 -86
- package/lib/esm/Interfaces.d.ts.map +1 -1
- package/lib/esm/Interfaces.js +8 -8
- package/lib/esm/Parser.d.ts +93 -93
- package/lib/esm/Parser.d.ts.map +1 -1
- package/lib/esm/Parser.js +589 -588
- package/lib/esm/Parser.js.map +1 -1
- package/lib/esm/ParserSpec.d.ts +34 -34
- package/lib/esm/ParserSpec.js +43 -43
- package/lib/esm/Quantity.d.ts +27 -27
- package/lib/esm/Quantity.js +42 -42
- package/lib/esm/Quantity.js.map +1 -1
- package/lib/esm/Unit.d.ts +25 -25
- package/lib/esm/Unit.js +39 -39
- package/lib/esm/core-quantity.d.ts +19 -19
- package/lib/esm/core-quantity.js +23 -23
- package/package.json +10 -10
|
@@ -1,372 +1,372 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/*---------------------------------------------------------------------------------------------
|
|
3
|
-
* Copyright (c) Bentley Systems, Incorporated. All rights reserved.
|
|
4
|
-
* See LICENSE.md in the project root for license terms and full copyright notice.
|
|
5
|
-
*--------------------------------------------------------------------------------------------*/
|
|
6
|
-
/** @packageDocumentation
|
|
7
|
-
* @module Quantity
|
|
8
|
-
*/
|
|
9
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
-
exports.Formatter = void 0;
|
|
11
|
-
const Constants_1 = require("../Constants");
|
|
12
|
-
const Exception_1 = require("../Exception");
|
|
13
|
-
const FormatEnums_1 = require("./FormatEnums");
|
|
14
|
-
/** rounding additive
|
|
15
|
-
* @internal
|
|
16
|
-
*/
|
|
17
|
-
const FPV_ROUNDFACTOR = 0.50000000001;
|
|
18
|
-
/** A private helper class used to format fraction part of value into a numerator and denominator.
|
|
19
|
-
* @internal
|
|
20
|
-
*/
|
|
21
|
-
class FractionalNumeric {
|
|
22
|
-
constructor(value, precision, reduce) {
|
|
23
|
-
this._integral = 0;
|
|
24
|
-
this._numerator = 0;
|
|
25
|
-
this._denominator = 1;
|
|
26
|
-
this._greatestCommonFactor = 1;
|
|
27
|
-
this._textParts = [];
|
|
28
|
-
this.calculate(value, precision);
|
|
29
|
-
this.formTextParts(reduce);
|
|
30
|
-
}
|
|
31
|
-
calculate(value, denominator) {
|
|
32
|
-
const positiveValue = Math.abs(value);
|
|
33
|
-
this._denominator = denominator;
|
|
34
|
-
this._integral = Math.floor(positiveValue);
|
|
35
|
-
const fractionPart = positiveValue - this._integral;
|
|
36
|
-
this._numerator = Math.floor(fractionPart * this._denominator + FPV_ROUNDFACTOR);
|
|
37
|
-
if (0 !== denominator && (this._numerator / this._denominator) === 1) {
|
|
38
|
-
this._numerator = 0;
|
|
39
|
-
this._integral += 1;
|
|
40
|
-
}
|
|
41
|
-
else {
|
|
42
|
-
this._greatestCommonFactor = this.getGreatestCommonFactor(this._numerator, this._denominator);
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
/** Determine the GCD given two values. This value can be used to reduce a fraction.
|
|
46
|
-
* See algorithm description http://en.wikipedia.org/wiki/Euclidean_algorithm
|
|
47
|
-
*/
|
|
48
|
-
getGreatestCommonFactor(numerator, denominator) {
|
|
49
|
-
let r;
|
|
50
|
-
while (denominator !== 0) {
|
|
51
|
-
r = numerator % denominator;
|
|
52
|
-
numerator = denominator;
|
|
53
|
-
denominator = r;
|
|
54
|
-
}
|
|
55
|
-
return (numerator < 0) ? -numerator : numerator;
|
|
56
|
-
}
|
|
57
|
-
get greatestCommonFactor() { return this._greatestCommonFactor; }
|
|
58
|
-
get hasFractionPart() { return this._textParts.length > 0; }
|
|
59
|
-
get isZero() { return 0 === this._numerator; }
|
|
60
|
-
getIntegralString() {
|
|
61
|
-
if (this._textParts.length > 0)
|
|
62
|
-
return this._textParts[0];
|
|
63
|
-
return "";
|
|
64
|
-
}
|
|
65
|
-
getNumeratorString() {
|
|
66
|
-
if (this._textParts.length >= 3)
|
|
67
|
-
return this._textParts[1];
|
|
68
|
-
return "";
|
|
69
|
-
}
|
|
70
|
-
getDenominatorString() {
|
|
71
|
-
if (this._textParts.length >= 3)
|
|
72
|
-
return this._textParts[2];
|
|
73
|
-
return "";
|
|
74
|
-
}
|
|
75
|
-
formTextParts(reduce) {
|
|
76
|
-
let numerator = this._numerator;
|
|
77
|
-
let denominator = this._denominator;
|
|
78
|
-
if (reduce && this._greatestCommonFactor > 1) {
|
|
79
|
-
numerator /= this.greatestCommonFactor;
|
|
80
|
-
denominator /= this.greatestCommonFactor;
|
|
81
|
-
}
|
|
82
|
-
this._textParts.push(this._integral.toFixed(0));
|
|
83
|
-
if (numerator > 0) {
|
|
84
|
-
this._textParts.push(numerator.toFixed(0));
|
|
85
|
-
this._textParts.push(denominator.toFixed(0));
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
/** A helper class that contains methods used to format quantity values based on a format that are defined via the Format class.
|
|
90
|
-
* @beta
|
|
91
|
-
*/
|
|
92
|
-
class Formatter {
|
|
93
|
-
static isNegligible(value) { return (Math.abs(value) < Formatter.FPV_MINTHRESHOLD); }
|
|
94
|
-
/** Return floating point value rounded by specific rounding factor.
|
|
95
|
-
* @param value Value to be rounded.
|
|
96
|
-
* @param roundTo Rounding factor.
|
|
97
|
-
*/
|
|
98
|
-
static roundDouble(value, roundTo) {
|
|
99
|
-
if (Formatter.isNegligible(roundTo))
|
|
100
|
-
return value;
|
|
101
|
-
roundTo = Math.abs(roundTo);
|
|
102
|
-
let rnd = FPV_ROUNDFACTOR + (value / roundTo);
|
|
103
|
-
const iVal = Math.floor(rnd);
|
|
104
|
-
rnd = iVal * roundTo;
|
|
105
|
-
return (value < 0.0) ? -rnd : rnd;
|
|
106
|
-
}
|
|
107
|
-
/** Generate a formatted text string integer value insert 1000 separators if appropriate.
|
|
108
|
-
* @param wholePart Integer value to be formatted.
|
|
109
|
-
*/
|
|
110
|
-
static integerPartToText(wholePart, spec) {
|
|
111
|
-
// build invariant string represent wholePart
|
|
112
|
-
let formattedValue = wholePart.toFixed(0);
|
|
113
|
-
if ((formattedValue.length > 3) && (spec.format.hasFormatTraitSet(FormatEnums_1.FormatTraits.Use1000Separator) && (spec.format.thousandSeparator.length > 0))) {
|
|
114
|
-
let numSeparators = Math.floor(formattedValue.length / 3);
|
|
115
|
-
let groupLength = formattedValue.length % 3;
|
|
116
|
-
if (groupLength === 0) {
|
|
117
|
-
numSeparators = numSeparators - 1;
|
|
118
|
-
groupLength = groupLength + 3;
|
|
119
|
-
}
|
|
120
|
-
let outString = formattedValue.
|
|
121
|
-
for (let i = 1; i <= numSeparators; i += 1) {
|
|
122
|
-
outString = outString + spec.format.thousandSeparator + formattedValue.
|
|
123
|
-
groupLength = groupLength + 3;
|
|
124
|
-
}
|
|
125
|
-
formattedValue = outString;
|
|
126
|
-
}
|
|
127
|
-
return formattedValue;
|
|
128
|
-
}
|
|
129
|
-
/** Trim trailing "0" from the text that represent the fractional part of a floating point value.
|
|
130
|
-
* @param strVal The value string.
|
|
131
|
-
*/
|
|
132
|
-
static trimTrailingZeroes(strVal) {
|
|
133
|
-
let lastNonZeroCharIndex = -1;
|
|
134
|
-
for (let i = strVal.length - 1; i >= 0; i--) {
|
|
135
|
-
if (strVal.charCodeAt(i) !== Constants_1.QuantityConstants.CHAR_DIGIT_ZERO) {
|
|
136
|
-
lastNonZeroCharIndex = i;
|
|
137
|
-
break;
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
if (lastNonZeroCharIndex >= 0)
|
|
141
|
-
return strVal.
|
|
142
|
-
return "";
|
|
143
|
-
}
|
|
144
|
-
/** Format a quantity value into a composite format such as ft-in or deg-min-sec.
|
|
145
|
-
* @param compositeValue The value for this part of the composite
|
|
146
|
-
* @param isLastPart If false the composite value should be a whole value, if true then the value should be formatted as a floating point value.
|
|
147
|
-
* @param label Label for this part of the composite. This will be either the default unit label or a custom label specified the format specification.
|
|
148
|
-
*/
|
|
149
|
-
static formatCompositePart(compositeValue, isLastPart, label, spec) {
|
|
150
|
-
let componentText = "";
|
|
151
|
-
if (!isLastPart) {
|
|
152
|
-
componentText = Formatter.integerPartToText(compositeValue, spec);
|
|
153
|
-
}
|
|
154
|
-
else {
|
|
155
|
-
componentText = Formatter.formatMagnitude(compositeValue, spec);
|
|
156
|
-
}
|
|
157
|
-
if (spec.format.hasFormatTraitSet(FormatEnums_1.FormatTraits.ShowUnitLabel)) {
|
|
158
|
-
componentText = componentText + spec.format.uomSeparator + label;
|
|
159
|
-
}
|
|
160
|
-
else {
|
|
161
|
-
if (!isLastPart)
|
|
162
|
-
componentText = `${componentText}:`;
|
|
163
|
-
}
|
|
164
|
-
return componentText;
|
|
165
|
-
}
|
|
166
|
-
/** Format a quantity value into a composite format such as ft-in or deg-min-sec.
|
|
167
|
-
* @param magnitude quantity value
|
|
168
|
-
* @param fromUnit quantity unit
|
|
169
|
-
*/
|
|
170
|
-
static formatComposite(magnitude, spec) {
|
|
171
|
-
const compositeStrings = [];
|
|
172
|
-
// Caller will deal with appending +||-||() value sign as specified by formatting options so just format positive value
|
|
173
|
-
let posMagnitude = Math.abs(magnitude);
|
|
174
|
-
// eslint-disable-next-line @typescript-eslint/prefer-for-of
|
|
175
|
-
for (let i = 0; i < spec.unitConversions.length; i++) {
|
|
176
|
-
const currentLabel = spec.unitConversions[i].label;
|
|
177
|
-
const unitConversion = spec.unitConversions[i].conversion;
|
|
178
|
-
if (i > 0 && unitConversion.factor < 1.0)
|
|
179
|
-
throw new Exception_1.QuantityError(Exception_1.QuantityStatus.InvalidCompositeFormat, `The Format ${spec.format.name} has a invalid unit specification..`);
|
|
180
|
-
if (i > 0 && unitConversion.offset !== 0)
|
|
181
|
-
throw new Exception_1.QuantityError(Exception_1.QuantityStatus.InvalidCompositeFormat, `The Format ${spec.format.name} has a invalid unit specification..`);
|
|
182
|
-
let unitValue = (posMagnitude * unitConversion.factor) + unitConversion.offset + Formatter.FPV_MINTHRESHOLD; // offset should only ever be defined for major unit
|
|
183
|
-
if (0 === i) {
|
|
184
|
-
const precisionScale = Math.pow(10, 8); // use a fixed round off precision of 8 to avoid loss of precision in actual magnitude
|
|
185
|
-
unitValue = Math.floor(unitValue * precisionScale + FPV_ROUNDFACTOR) / precisionScale;
|
|
186
|
-
if ((Math.abs(unitValue) < 0.0001) && spec.format.hasFormatTraitSet(FormatEnums_1.FormatTraits.ZeroEmpty))
|
|
187
|
-
return "";
|
|
188
|
-
}
|
|
189
|
-
if (i < spec.format.units.length - 1) {
|
|
190
|
-
const wholePart = Math.floor(unitValue);
|
|
191
|
-
const componentText = Formatter.formatCompositePart(wholePart, false, currentLabel, spec);
|
|
192
|
-
posMagnitude = unitValue - wholePart;
|
|
193
|
-
compositeStrings.push(componentText);
|
|
194
|
-
}
|
|
195
|
-
else {
|
|
196
|
-
const componentText = Formatter.formatCompositePart(unitValue, true, currentLabel, spec);
|
|
197
|
-
compositeStrings.push(componentText);
|
|
198
|
-
}
|
|
199
|
-
}
|
|
200
|
-
return compositeStrings.join(spec.format.spacer ? spec.format.spacer : "");
|
|
201
|
-
}
|
|
202
|
-
/** Format a quantity value into a single text string. Imitate how formatting done by server method NumericFormatSpec::FormatDouble.
|
|
203
|
-
* @param magnitude quantity value
|
|
204
|
-
*/
|
|
205
|
-
static formatMagnitude(magnitude, spec) {
|
|
206
|
-
let posMagnitude = Math.abs(magnitude);
|
|
207
|
-
if ((Math.abs(posMagnitude) < 0.0001) && spec.format.hasFormatTraitSet(FormatEnums_1.FormatTraits.ZeroEmpty))
|
|
208
|
-
return "";
|
|
209
|
-
if (spec.format.hasFormatTraitSet(FormatEnums_1.FormatTraits.ApplyRounding))
|
|
210
|
-
posMagnitude = Math.abs(Formatter.roundDouble(magnitude, spec.format.roundFactor));
|
|
211
|
-
const isSci = ((posMagnitude > 1.0e12) || spec.format.type === FormatEnums_1.FormatType.Scientific);
|
|
212
|
-
const isDecimal = (isSci || spec.format.type === FormatEnums_1.FormatType.Decimal);
|
|
213
|
-
const isFractional = (!isDecimal && spec.format.type === FormatEnums_1.FormatType.Fractional);
|
|
214
|
-
/* const usesStops = spec.format.type === FormatType.Station; */
|
|
215
|
-
const isPrecisionZero = spec.format.precision === FormatEnums_1.DecimalPrecision.Zero;
|
|
216
|
-
const isKeepSingleZero = spec.format.hasFormatTraitSet(FormatEnums_1.FormatTraits.KeepSingleZero);
|
|
217
|
-
const precisionScale = Math.pow(10.0, spec.format.precision);
|
|
218
|
-
const isKeepTrailingZeroes = spec.format.hasFormatTraitSet(FormatEnums_1.FormatTraits.TrailZeroes);
|
|
219
|
-
let expInt = 0.0;
|
|
220
|
-
if (isSci && (posMagnitude !== 0.0)) {
|
|
221
|
-
let exp = Math.log10(posMagnitude);
|
|
222
|
-
let negativeExp = false;
|
|
223
|
-
if (exp < 0.0) {
|
|
224
|
-
exp = -exp;
|
|
225
|
-
negativeExp = true;
|
|
226
|
-
}
|
|
227
|
-
expInt = Math.floor(exp);
|
|
228
|
-
if (spec.format.type === FormatEnums_1.FormatType.Scientific) {
|
|
229
|
-
if (spec.format.scientificType === FormatEnums_1.ScientificType.ZeroNormalized && posMagnitude > 1.0)
|
|
230
|
-
expInt += 1.0;
|
|
231
|
-
else if (spec.format.scientificType === FormatEnums_1.ScientificType.Normalized && posMagnitude < 1.0)
|
|
232
|
-
expInt += 1.0;
|
|
233
|
-
if (negativeExp)
|
|
234
|
-
expInt = -expInt;
|
|
235
|
-
}
|
|
236
|
-
const factor = Math.pow(10.0, -expInt);
|
|
237
|
-
posMagnitude *= factor;
|
|
238
|
-
}
|
|
239
|
-
let formattedValue = "";
|
|
240
|
-
if (isDecimal) {
|
|
241
|
-
const actualVal = isPrecisionZero ? posMagnitude + FPV_ROUNDFACTOR : posMagnitude + Formatter.FPV_MINTHRESHOLD;
|
|
242
|
-
let wholePart = Math.floor(actualVal);
|
|
243
|
-
let fractionPart = actualVal - wholePart;
|
|
244
|
-
if (!isPrecisionZero) {
|
|
245
|
-
fractionPart = Math.abs(fractionPart) * precisionScale + FPV_ROUNDFACTOR;
|
|
246
|
-
if (fractionPart >= precisionScale) {
|
|
247
|
-
wholePart += 1;
|
|
248
|
-
fractionPart -= precisionScale;
|
|
249
|
-
}
|
|
250
|
-
}
|
|
251
|
-
formattedValue = Formatter.integerPartToText(wholePart, spec);
|
|
252
|
-
if (isPrecisionZero) {
|
|
253
|
-
if (spec.format.hasFormatTraitSet(FormatEnums_1.FormatTraits.KeepDecimalPoint) && !isKeepSingleZero)
|
|
254
|
-
formattedValue = formattedValue + spec.format.decimalSeparator;
|
|
255
|
-
else if (isKeepSingleZero)
|
|
256
|
-
formattedValue = `${formattedValue + spec.format.decimalSeparator}0`;
|
|
257
|
-
}
|
|
258
|
-
else {
|
|
259
|
-
fractionPart = Math.floor(fractionPart) / precisionScale;
|
|
260
|
-
let fractionString = fractionPart.toFixed(spec.format.precision);
|
|
261
|
-
// remove leading "0."
|
|
262
|
-
fractionString = fractionString.
|
|
263
|
-
if (!isKeepTrailingZeroes)
|
|
264
|
-
fractionString = Formatter.trimTrailingZeroes(fractionString);
|
|
265
|
-
if (fractionString.length > 0)
|
|
266
|
-
formattedValue = formattedValue + spec.format.decimalSeparator + fractionString;
|
|
267
|
-
else {
|
|
268
|
-
if (spec.format.hasFormatTraitSet(FormatEnums_1.FormatTraits.KeepDecimalPoint))
|
|
269
|
-
formattedValue = formattedValue + spec.format.decimalSeparator;
|
|
270
|
-
}
|
|
271
|
-
}
|
|
272
|
-
if (isSci) {
|
|
273
|
-
const expString = `e${expInt.toFixed(0)}`;
|
|
274
|
-
formattedValue = formattedValue + expString;
|
|
275
|
-
}
|
|
276
|
-
}
|
|
277
|
-
else if (isFractional) {
|
|
278
|
-
const fn = new FractionalNumeric(posMagnitude, spec.format.precision, true);
|
|
279
|
-
formattedValue = fn.getIntegralString();
|
|
280
|
-
if (!fn.isZero && fn.hasFractionPart) {
|
|
281
|
-
const wholeFractionSeparator = spec.format.hasFormatTraitSet(FormatEnums_1.FormatTraits.FractionDash) ? "-" : " ";
|
|
282
|
-
const fractionString = `${fn.getNumeratorString()}/${fn.getDenominatorString()}`;
|
|
283
|
-
formattedValue = formattedValue + wholeFractionSeparator + fractionString;
|
|
284
|
-
}
|
|
285
|
-
}
|
|
286
|
-
else /* if (usesStops)*/ {
|
|
287
|
-
// we assume that stopping value is always positive
|
|
288
|
-
posMagnitude = Math.floor(posMagnitude * precisionScale + FPV_ROUNDFACTOR) / precisionScale;
|
|
289
|
-
const denominator = (Math.pow(10, spec.format.stationOffsetSize));
|
|
290
|
-
const tVal = Math.floor(posMagnitude); // this is the integer part only
|
|
291
|
-
const hiPart = Math.floor(tVal / denominator);
|
|
292
|
-
const lowPart = tVal - hiPart * denominator;
|
|
293
|
-
const fract = posMagnitude - tVal;
|
|
294
|
-
const fractionPart = Math.floor(fract * precisionScale + FPV_ROUNDFACTOR);
|
|
295
|
-
const stationString = hiPart.toFixed(0) + spec.format.stationSeparator + lowPart.toFixed(0).padStart(spec.format.stationOffsetSize, "0");
|
|
296
|
-
let fractionString = "";
|
|
297
|
-
if (fractionPart > 0) {
|
|
298
|
-
fractionString = (fractionPart / precisionScale).toFixed(spec.format.precision);
|
|
299
|
-
// remove leading "0."
|
|
300
|
-
fractionString = fractionString.
|
|
301
|
-
if (!isKeepTrailingZeroes)
|
|
302
|
-
fractionString = Formatter.trimTrailingZeroes(fractionString);
|
|
303
|
-
formattedValue = stationString + spec.format.decimalSeparator + fractionString;
|
|
304
|
-
}
|
|
305
|
-
else {
|
|
306
|
-
if (isKeepTrailingZeroes)
|
|
307
|
-
fractionString = spec.format.decimalSeparator + "".padEnd(spec.format.precision, "0");
|
|
308
|
-
else if (spec.format.hasFormatTraitSet(FormatEnums_1.FormatTraits.KeepDecimalPoint))
|
|
309
|
-
fractionString = spec.format.decimalSeparator;
|
|
310
|
-
formattedValue = stationString + fractionString;
|
|
311
|
-
}
|
|
312
|
-
}
|
|
313
|
-
return formattedValue;
|
|
314
|
-
}
|
|
315
|
-
/** Format a quantity value into a single text string based on the current format specification of this class.
|
|
316
|
-
* @param magnitude defines the value to spec.format.
|
|
317
|
-
* @param spec A FormatterSpec object the defines specification for the magnitude and unit conversions for the formatter.
|
|
318
|
-
*/
|
|
319
|
-
static formatQuantity(magnitude, spec) {
|
|
320
|
-
const valueIsNegative = magnitude < 0.0;
|
|
321
|
-
let prefix = "";
|
|
322
|
-
let suffix = "";
|
|
323
|
-
let formattedValue = "";
|
|
324
|
-
switch (spec.format.showSignOption) {
|
|
325
|
-
case FormatEnums_1.ShowSignOption.NegativeParentheses:
|
|
326
|
-
if (valueIsNegative) {
|
|
327
|
-
prefix = "(";
|
|
328
|
-
suffix = ")";
|
|
329
|
-
}
|
|
330
|
-
break;
|
|
331
|
-
case FormatEnums_1.ShowSignOption.OnlyNegative:
|
|
332
|
-
if (valueIsNegative)
|
|
333
|
-
prefix = "-";
|
|
334
|
-
break;
|
|
335
|
-
case FormatEnums_1.ShowSignOption.SignAlways:
|
|
336
|
-
if (valueIsNegative)
|
|
337
|
-
prefix = "-";
|
|
338
|
-
else
|
|
339
|
-
prefix = "+";
|
|
340
|
-
break;
|
|
341
|
-
case FormatEnums_1.ShowSignOption.NoSign:
|
|
342
|
-
default:
|
|
343
|
-
break;
|
|
344
|
-
}
|
|
345
|
-
let formattedMagnitude = "";
|
|
346
|
-
if (spec.format.hasUnits) {
|
|
347
|
-
formattedMagnitude = Formatter.formatComposite(magnitude, spec);
|
|
348
|
-
}
|
|
349
|
-
else {
|
|
350
|
-
// unitless quantity
|
|
351
|
-
formattedMagnitude = Formatter.formatMagnitude(magnitude, spec);
|
|
352
|
-
if (formattedMagnitude.length > 0 && spec.unitConversions.length > 0 && spec.format.hasFormatTraitSet(FormatEnums_1.FormatTraits.ShowUnitLabel)) {
|
|
353
|
-
if (spec.format.hasFormatTraitSet(FormatEnums_1.FormatTraits.PrependUnitLabel))
|
|
354
|
-
formattedMagnitude = spec.unitConversions[0].label + spec.format.uomSeparator + formattedMagnitude;
|
|
355
|
-
else
|
|
356
|
-
formattedMagnitude = formattedMagnitude + spec.format.uomSeparator + spec.unitConversions[0].label;
|
|
357
|
-
}
|
|
358
|
-
}
|
|
359
|
-
// add Sign prefix and suffix as necessary
|
|
360
|
-
if ((prefix.length > 0 || suffix.length > 0) && formattedMagnitude.length > 0)
|
|
361
|
-
formattedValue = prefix + formattedMagnitude + suffix;
|
|
362
|
-
else
|
|
363
|
-
formattedValue = formattedMagnitude;
|
|
364
|
-
if (spec.format.minWidth && spec.format.minWidth < formattedValue.length)
|
|
365
|
-
formattedValue.padStart(spec.format.minWidth, " ");
|
|
366
|
-
return formattedValue;
|
|
367
|
-
}
|
|
368
|
-
}
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
Formatter
|
|
1
|
+
"use strict";
|
|
2
|
+
/*---------------------------------------------------------------------------------------------
|
|
3
|
+
* Copyright (c) Bentley Systems, Incorporated. All rights reserved.
|
|
4
|
+
* See LICENSE.md in the project root for license terms and full copyright notice.
|
|
5
|
+
*--------------------------------------------------------------------------------------------*/
|
|
6
|
+
/** @packageDocumentation
|
|
7
|
+
* @module Quantity
|
|
8
|
+
*/
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.Formatter = void 0;
|
|
11
|
+
const Constants_1 = require("../Constants");
|
|
12
|
+
const Exception_1 = require("../Exception");
|
|
13
|
+
const FormatEnums_1 = require("./FormatEnums");
|
|
14
|
+
/** rounding additive
|
|
15
|
+
* @internal
|
|
16
|
+
*/
|
|
17
|
+
const FPV_ROUNDFACTOR = 0.50000000001;
|
|
18
|
+
/** A private helper class used to format fraction part of value into a numerator and denominator.
|
|
19
|
+
* @internal
|
|
20
|
+
*/
|
|
21
|
+
class FractionalNumeric {
|
|
22
|
+
constructor(value, precision, reduce) {
|
|
23
|
+
this._integral = 0;
|
|
24
|
+
this._numerator = 0;
|
|
25
|
+
this._denominator = 1;
|
|
26
|
+
this._greatestCommonFactor = 1;
|
|
27
|
+
this._textParts = [];
|
|
28
|
+
this.calculate(value, precision);
|
|
29
|
+
this.formTextParts(reduce);
|
|
30
|
+
}
|
|
31
|
+
calculate(value, denominator) {
|
|
32
|
+
const positiveValue = Math.abs(value);
|
|
33
|
+
this._denominator = denominator;
|
|
34
|
+
this._integral = Math.floor(positiveValue);
|
|
35
|
+
const fractionPart = positiveValue - this._integral;
|
|
36
|
+
this._numerator = Math.floor(fractionPart * this._denominator + FPV_ROUNDFACTOR);
|
|
37
|
+
if (0 !== denominator && (this._numerator / this._denominator) === 1) {
|
|
38
|
+
this._numerator = 0;
|
|
39
|
+
this._integral += 1;
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
this._greatestCommonFactor = this.getGreatestCommonFactor(this._numerator, this._denominator);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
/** Determine the GCD given two values. This value can be used to reduce a fraction.
|
|
46
|
+
* See algorithm description http://en.wikipedia.org/wiki/Euclidean_algorithm
|
|
47
|
+
*/
|
|
48
|
+
getGreatestCommonFactor(numerator, denominator) {
|
|
49
|
+
let r;
|
|
50
|
+
while (denominator !== 0) {
|
|
51
|
+
r = numerator % denominator;
|
|
52
|
+
numerator = denominator;
|
|
53
|
+
denominator = r;
|
|
54
|
+
}
|
|
55
|
+
return (numerator < 0) ? -numerator : numerator;
|
|
56
|
+
}
|
|
57
|
+
get greatestCommonFactor() { return this._greatestCommonFactor; }
|
|
58
|
+
get hasFractionPart() { return this._textParts.length > 0; }
|
|
59
|
+
get isZero() { return 0 === this._numerator; }
|
|
60
|
+
getIntegralString() {
|
|
61
|
+
if (this._textParts.length > 0)
|
|
62
|
+
return this._textParts[0];
|
|
63
|
+
return "";
|
|
64
|
+
}
|
|
65
|
+
getNumeratorString() {
|
|
66
|
+
if (this._textParts.length >= 3)
|
|
67
|
+
return this._textParts[1];
|
|
68
|
+
return "";
|
|
69
|
+
}
|
|
70
|
+
getDenominatorString() {
|
|
71
|
+
if (this._textParts.length >= 3)
|
|
72
|
+
return this._textParts[2];
|
|
73
|
+
return "";
|
|
74
|
+
}
|
|
75
|
+
formTextParts(reduce) {
|
|
76
|
+
let numerator = this._numerator;
|
|
77
|
+
let denominator = this._denominator;
|
|
78
|
+
if (reduce && this._greatestCommonFactor > 1) {
|
|
79
|
+
numerator /= this.greatestCommonFactor;
|
|
80
|
+
denominator /= this.greatestCommonFactor;
|
|
81
|
+
}
|
|
82
|
+
this._textParts.push(this._integral.toFixed(0));
|
|
83
|
+
if (numerator > 0) {
|
|
84
|
+
this._textParts.push(numerator.toFixed(0));
|
|
85
|
+
this._textParts.push(denominator.toFixed(0));
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
/** A helper class that contains methods used to format quantity values based on a format that are defined via the Format class.
|
|
90
|
+
* @beta
|
|
91
|
+
*/
|
|
92
|
+
class Formatter {
|
|
93
|
+
static isNegligible(value) { return (Math.abs(value) < Formatter.FPV_MINTHRESHOLD); }
|
|
94
|
+
/** Return floating point value rounded by specific rounding factor.
|
|
95
|
+
* @param value Value to be rounded.
|
|
96
|
+
* @param roundTo Rounding factor.
|
|
97
|
+
*/
|
|
98
|
+
static roundDouble(value, roundTo) {
|
|
99
|
+
if (Formatter.isNegligible(roundTo))
|
|
100
|
+
return value;
|
|
101
|
+
roundTo = Math.abs(roundTo);
|
|
102
|
+
let rnd = FPV_ROUNDFACTOR + (value / roundTo);
|
|
103
|
+
const iVal = Math.floor(rnd);
|
|
104
|
+
rnd = iVal * roundTo;
|
|
105
|
+
return (value < 0.0) ? -rnd : rnd;
|
|
106
|
+
}
|
|
107
|
+
/** Generate a formatted text string integer value insert 1000 separators if appropriate.
|
|
108
|
+
* @param wholePart Integer value to be formatted.
|
|
109
|
+
*/
|
|
110
|
+
static integerPartToText(wholePart, spec) {
|
|
111
|
+
// build invariant string represent wholePart
|
|
112
|
+
let formattedValue = wholePart.toFixed(0);
|
|
113
|
+
if ((formattedValue.length > 3) && (spec.format.hasFormatTraitSet(FormatEnums_1.FormatTraits.Use1000Separator) && (spec.format.thousandSeparator.length > 0))) {
|
|
114
|
+
let numSeparators = Math.floor(formattedValue.length / 3);
|
|
115
|
+
let groupLength = formattedValue.length % 3;
|
|
116
|
+
if (groupLength === 0) {
|
|
117
|
+
numSeparators = numSeparators - 1;
|
|
118
|
+
groupLength = groupLength + 3;
|
|
119
|
+
}
|
|
120
|
+
let outString = formattedValue.substring(0, groupLength);
|
|
121
|
+
for (let i = 1; i <= numSeparators; i += 1) {
|
|
122
|
+
outString = outString + spec.format.thousandSeparator + formattedValue.substring(groupLength, groupLength + 3);
|
|
123
|
+
groupLength = groupLength + 3;
|
|
124
|
+
}
|
|
125
|
+
formattedValue = outString;
|
|
126
|
+
}
|
|
127
|
+
return formattedValue;
|
|
128
|
+
}
|
|
129
|
+
/** Trim trailing "0" from the text that represent the fractional part of a floating point value.
|
|
130
|
+
* @param strVal The value string.
|
|
131
|
+
*/
|
|
132
|
+
static trimTrailingZeroes(strVal) {
|
|
133
|
+
let lastNonZeroCharIndex = -1;
|
|
134
|
+
for (let i = strVal.length - 1; i >= 0; i--) {
|
|
135
|
+
if (strVal.charCodeAt(i) !== Constants_1.QuantityConstants.CHAR_DIGIT_ZERO) {
|
|
136
|
+
lastNonZeroCharIndex = i;
|
|
137
|
+
break;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
if (lastNonZeroCharIndex >= 0)
|
|
141
|
+
return strVal.substring(0, lastNonZeroCharIndex + 1);
|
|
142
|
+
return "";
|
|
143
|
+
}
|
|
144
|
+
/** Format a quantity value into a composite format such as ft-in or deg-min-sec.
|
|
145
|
+
* @param compositeValue The value for this part of the composite
|
|
146
|
+
* @param isLastPart If false the composite value should be a whole value, if true then the value should be formatted as a floating point value.
|
|
147
|
+
* @param label Label for this part of the composite. This will be either the default unit label or a custom label specified the format specification.
|
|
148
|
+
*/
|
|
149
|
+
static formatCompositePart(compositeValue, isLastPart, label, spec) {
|
|
150
|
+
let componentText = "";
|
|
151
|
+
if (!isLastPart) {
|
|
152
|
+
componentText = Formatter.integerPartToText(compositeValue, spec);
|
|
153
|
+
}
|
|
154
|
+
else {
|
|
155
|
+
componentText = Formatter.formatMagnitude(compositeValue, spec);
|
|
156
|
+
}
|
|
157
|
+
if (spec.format.hasFormatTraitSet(FormatEnums_1.FormatTraits.ShowUnitLabel)) {
|
|
158
|
+
componentText = componentText + spec.format.uomSeparator + label;
|
|
159
|
+
}
|
|
160
|
+
else {
|
|
161
|
+
if (!isLastPart)
|
|
162
|
+
componentText = `${componentText}:`;
|
|
163
|
+
}
|
|
164
|
+
return componentText;
|
|
165
|
+
}
|
|
166
|
+
/** Format a quantity value into a composite format such as ft-in or deg-min-sec.
|
|
167
|
+
* @param magnitude quantity value
|
|
168
|
+
* @param fromUnit quantity unit
|
|
169
|
+
*/
|
|
170
|
+
static formatComposite(magnitude, spec) {
|
|
171
|
+
const compositeStrings = [];
|
|
172
|
+
// Caller will deal with appending +||-||() value sign as specified by formatting options so just format positive value
|
|
173
|
+
let posMagnitude = Math.abs(magnitude);
|
|
174
|
+
// eslint-disable-next-line @typescript-eslint/prefer-for-of
|
|
175
|
+
for (let i = 0; i < spec.unitConversions.length; i++) {
|
|
176
|
+
const currentLabel = spec.unitConversions[i].label;
|
|
177
|
+
const unitConversion = spec.unitConversions[i].conversion;
|
|
178
|
+
if (i > 0 && unitConversion.factor < 1.0)
|
|
179
|
+
throw new Exception_1.QuantityError(Exception_1.QuantityStatus.InvalidCompositeFormat, `The Format ${spec.format.name} has a invalid unit specification..`);
|
|
180
|
+
if (i > 0 && unitConversion.offset !== 0)
|
|
181
|
+
throw new Exception_1.QuantityError(Exception_1.QuantityStatus.InvalidCompositeFormat, `The Format ${spec.format.name} has a invalid unit specification..`);
|
|
182
|
+
let unitValue = (posMagnitude * unitConversion.factor) + unitConversion.offset + Formatter.FPV_MINTHRESHOLD; // offset should only ever be defined for major unit
|
|
183
|
+
if (0 === i) {
|
|
184
|
+
const precisionScale = Math.pow(10, 8); // use a fixed round off precision of 8 to avoid loss of precision in actual magnitude
|
|
185
|
+
unitValue = Math.floor(unitValue * precisionScale + FPV_ROUNDFACTOR) / precisionScale;
|
|
186
|
+
if ((Math.abs(unitValue) < 0.0001) && spec.format.hasFormatTraitSet(FormatEnums_1.FormatTraits.ZeroEmpty))
|
|
187
|
+
return "";
|
|
188
|
+
}
|
|
189
|
+
if (i < spec.format.units.length - 1) {
|
|
190
|
+
const wholePart = Math.floor(unitValue);
|
|
191
|
+
const componentText = Formatter.formatCompositePart(wholePart, false, currentLabel, spec);
|
|
192
|
+
posMagnitude = unitValue - wholePart;
|
|
193
|
+
compositeStrings.push(componentText);
|
|
194
|
+
}
|
|
195
|
+
else {
|
|
196
|
+
const componentText = Formatter.formatCompositePart(unitValue, true, currentLabel, spec);
|
|
197
|
+
compositeStrings.push(componentText);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
return compositeStrings.join(spec.format.spacer ? spec.format.spacer : "");
|
|
201
|
+
}
|
|
202
|
+
/** Format a quantity value into a single text string. Imitate how formatting done by server method NumericFormatSpec::FormatDouble.
|
|
203
|
+
* @param magnitude quantity value
|
|
204
|
+
*/
|
|
205
|
+
static formatMagnitude(magnitude, spec) {
|
|
206
|
+
let posMagnitude = Math.abs(magnitude);
|
|
207
|
+
if ((Math.abs(posMagnitude) < 0.0001) && spec.format.hasFormatTraitSet(FormatEnums_1.FormatTraits.ZeroEmpty))
|
|
208
|
+
return "";
|
|
209
|
+
if (spec.format.hasFormatTraitSet(FormatEnums_1.FormatTraits.ApplyRounding))
|
|
210
|
+
posMagnitude = Math.abs(Formatter.roundDouble(magnitude, spec.format.roundFactor));
|
|
211
|
+
const isSci = ((posMagnitude > 1.0e12) || spec.format.type === FormatEnums_1.FormatType.Scientific);
|
|
212
|
+
const isDecimal = (isSci || spec.format.type === FormatEnums_1.FormatType.Decimal);
|
|
213
|
+
const isFractional = (!isDecimal && spec.format.type === FormatEnums_1.FormatType.Fractional);
|
|
214
|
+
/* const usesStops = spec.format.type === FormatType.Station; */
|
|
215
|
+
const isPrecisionZero = spec.format.precision === FormatEnums_1.DecimalPrecision.Zero;
|
|
216
|
+
const isKeepSingleZero = spec.format.hasFormatTraitSet(FormatEnums_1.FormatTraits.KeepSingleZero);
|
|
217
|
+
const precisionScale = Math.pow(10.0, spec.format.precision);
|
|
218
|
+
const isKeepTrailingZeroes = spec.format.hasFormatTraitSet(FormatEnums_1.FormatTraits.TrailZeroes);
|
|
219
|
+
let expInt = 0.0;
|
|
220
|
+
if (isSci && (posMagnitude !== 0.0)) {
|
|
221
|
+
let exp = Math.log10(posMagnitude);
|
|
222
|
+
let negativeExp = false;
|
|
223
|
+
if (exp < 0.0) {
|
|
224
|
+
exp = -exp;
|
|
225
|
+
negativeExp = true;
|
|
226
|
+
}
|
|
227
|
+
expInt = Math.floor(exp);
|
|
228
|
+
if (spec.format.type === FormatEnums_1.FormatType.Scientific) {
|
|
229
|
+
if (spec.format.scientificType === FormatEnums_1.ScientificType.ZeroNormalized && posMagnitude > 1.0)
|
|
230
|
+
expInt += 1.0;
|
|
231
|
+
else if (spec.format.scientificType === FormatEnums_1.ScientificType.Normalized && posMagnitude < 1.0)
|
|
232
|
+
expInt += 1.0;
|
|
233
|
+
if (negativeExp)
|
|
234
|
+
expInt = -expInt;
|
|
235
|
+
}
|
|
236
|
+
const factor = Math.pow(10.0, -expInt);
|
|
237
|
+
posMagnitude *= factor;
|
|
238
|
+
}
|
|
239
|
+
let formattedValue = "";
|
|
240
|
+
if (isDecimal) {
|
|
241
|
+
const actualVal = isPrecisionZero ? posMagnitude + FPV_ROUNDFACTOR : posMagnitude + Formatter.FPV_MINTHRESHOLD;
|
|
242
|
+
let wholePart = Math.floor(actualVal);
|
|
243
|
+
let fractionPart = actualVal - wholePart;
|
|
244
|
+
if (!isPrecisionZero) {
|
|
245
|
+
fractionPart = Math.abs(fractionPart) * precisionScale + FPV_ROUNDFACTOR;
|
|
246
|
+
if (fractionPart >= precisionScale) {
|
|
247
|
+
wholePart += 1;
|
|
248
|
+
fractionPart -= precisionScale;
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
formattedValue = Formatter.integerPartToText(wholePart, spec);
|
|
252
|
+
if (isPrecisionZero) {
|
|
253
|
+
if (spec.format.hasFormatTraitSet(FormatEnums_1.FormatTraits.KeepDecimalPoint) && !isKeepSingleZero)
|
|
254
|
+
formattedValue = formattedValue + spec.format.decimalSeparator;
|
|
255
|
+
else if (isKeepSingleZero)
|
|
256
|
+
formattedValue = `${formattedValue + spec.format.decimalSeparator}0`;
|
|
257
|
+
}
|
|
258
|
+
else {
|
|
259
|
+
fractionPart = Math.floor(fractionPart) / precisionScale;
|
|
260
|
+
let fractionString = fractionPart.toFixed(spec.format.precision);
|
|
261
|
+
// remove leading "0."
|
|
262
|
+
fractionString = fractionString.substring(2).padEnd(spec.format.precision, "0");
|
|
263
|
+
if (!isKeepTrailingZeroes)
|
|
264
|
+
fractionString = Formatter.trimTrailingZeroes(fractionString);
|
|
265
|
+
if (fractionString.length > 0)
|
|
266
|
+
formattedValue = formattedValue + spec.format.decimalSeparator + fractionString;
|
|
267
|
+
else {
|
|
268
|
+
if (spec.format.hasFormatTraitSet(FormatEnums_1.FormatTraits.KeepDecimalPoint))
|
|
269
|
+
formattedValue = formattedValue + spec.format.decimalSeparator + (isKeepSingleZero ? "0" : "");
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
if (isSci) {
|
|
273
|
+
const expString = `e${expInt.toFixed(0)}`;
|
|
274
|
+
formattedValue = formattedValue + expString;
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
else if (isFractional) {
|
|
278
|
+
const fn = new FractionalNumeric(posMagnitude, spec.format.precision, true);
|
|
279
|
+
formattedValue = fn.getIntegralString();
|
|
280
|
+
if (!fn.isZero && fn.hasFractionPart) {
|
|
281
|
+
const wholeFractionSeparator = spec.format.hasFormatTraitSet(FormatEnums_1.FormatTraits.FractionDash) ? "-" : " ";
|
|
282
|
+
const fractionString = `${fn.getNumeratorString()}/${fn.getDenominatorString()}`;
|
|
283
|
+
formattedValue = formattedValue + wholeFractionSeparator + fractionString;
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
else /* if (usesStops)*/ {
|
|
287
|
+
// we assume that stopping value is always positive
|
|
288
|
+
posMagnitude = Math.floor(posMagnitude * precisionScale + FPV_ROUNDFACTOR) / precisionScale;
|
|
289
|
+
const denominator = (Math.pow(10, spec.format.stationOffsetSize));
|
|
290
|
+
const tVal = Math.floor(posMagnitude); // this is the integer part only
|
|
291
|
+
const hiPart = Math.floor(tVal / denominator);
|
|
292
|
+
const lowPart = tVal - hiPart * denominator;
|
|
293
|
+
const fract = posMagnitude - tVal;
|
|
294
|
+
const fractionPart = Math.floor(fract * precisionScale + FPV_ROUNDFACTOR);
|
|
295
|
+
const stationString = hiPart.toFixed(0) + spec.format.stationSeparator + lowPart.toFixed(0).padStart(spec.format.stationOffsetSize, "0");
|
|
296
|
+
let fractionString = "";
|
|
297
|
+
if (fractionPart > 0) {
|
|
298
|
+
fractionString = (fractionPart / precisionScale).toFixed(spec.format.precision);
|
|
299
|
+
// remove leading "0."
|
|
300
|
+
fractionString = fractionString.substring(2).padEnd(spec.format.precision, "0");
|
|
301
|
+
if (!isKeepTrailingZeroes)
|
|
302
|
+
fractionString = Formatter.trimTrailingZeroes(fractionString);
|
|
303
|
+
formattedValue = stationString + spec.format.decimalSeparator + fractionString;
|
|
304
|
+
}
|
|
305
|
+
else {
|
|
306
|
+
if (isKeepTrailingZeroes)
|
|
307
|
+
fractionString = spec.format.decimalSeparator + "".padEnd(spec.format.precision, "0");
|
|
308
|
+
else if (spec.format.hasFormatTraitSet(FormatEnums_1.FormatTraits.KeepDecimalPoint))
|
|
309
|
+
fractionString = spec.format.decimalSeparator;
|
|
310
|
+
formattedValue = stationString + fractionString;
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
return formattedValue;
|
|
314
|
+
}
|
|
315
|
+
/** Format a quantity value into a single text string based on the current format specification of this class.
|
|
316
|
+
* @param magnitude defines the value to spec.format.
|
|
317
|
+
* @param spec A FormatterSpec object the defines specification for the magnitude and unit conversions for the formatter.
|
|
318
|
+
*/
|
|
319
|
+
static formatQuantity(magnitude, spec) {
|
|
320
|
+
const valueIsNegative = magnitude < 0.0;
|
|
321
|
+
let prefix = "";
|
|
322
|
+
let suffix = "";
|
|
323
|
+
let formattedValue = "";
|
|
324
|
+
switch (spec.format.showSignOption) {
|
|
325
|
+
case FormatEnums_1.ShowSignOption.NegativeParentheses:
|
|
326
|
+
if (valueIsNegative) {
|
|
327
|
+
prefix = "(";
|
|
328
|
+
suffix = ")";
|
|
329
|
+
}
|
|
330
|
+
break;
|
|
331
|
+
case FormatEnums_1.ShowSignOption.OnlyNegative:
|
|
332
|
+
if (valueIsNegative)
|
|
333
|
+
prefix = "-";
|
|
334
|
+
break;
|
|
335
|
+
case FormatEnums_1.ShowSignOption.SignAlways:
|
|
336
|
+
if (valueIsNegative)
|
|
337
|
+
prefix = "-";
|
|
338
|
+
else
|
|
339
|
+
prefix = "+";
|
|
340
|
+
break;
|
|
341
|
+
case FormatEnums_1.ShowSignOption.NoSign:
|
|
342
|
+
default:
|
|
343
|
+
break;
|
|
344
|
+
}
|
|
345
|
+
let formattedMagnitude = "";
|
|
346
|
+
if (spec.format.hasUnits) {
|
|
347
|
+
formattedMagnitude = Formatter.formatComposite(magnitude, spec);
|
|
348
|
+
}
|
|
349
|
+
else {
|
|
350
|
+
// unitless quantity
|
|
351
|
+
formattedMagnitude = Formatter.formatMagnitude(magnitude, spec);
|
|
352
|
+
if (formattedMagnitude.length > 0 && spec.unitConversions.length > 0 && spec.format.hasFormatTraitSet(FormatEnums_1.FormatTraits.ShowUnitLabel)) {
|
|
353
|
+
if (spec.format.hasFormatTraitSet(FormatEnums_1.FormatTraits.PrependUnitLabel))
|
|
354
|
+
formattedMagnitude = spec.unitConversions[0].label + spec.format.uomSeparator + formattedMagnitude;
|
|
355
|
+
else
|
|
356
|
+
formattedMagnitude = formattedMagnitude + spec.format.uomSeparator + spec.unitConversions[0].label;
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
// add Sign prefix and suffix as necessary
|
|
360
|
+
if ((prefix.length > 0 || suffix.length > 0) && formattedMagnitude.length > 0)
|
|
361
|
+
formattedValue = prefix + formattedMagnitude + suffix;
|
|
362
|
+
else
|
|
363
|
+
formattedValue = formattedMagnitude;
|
|
364
|
+
if (spec.format.minWidth && spec.format.minWidth < formattedValue.length)
|
|
365
|
+
formattedValue.padStart(spec.format.minWidth, " ");
|
|
366
|
+
return formattedValue;
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
370
|
+
Formatter.FPV_MINTHRESHOLD = 1.0e-14;
|
|
371
|
+
exports.Formatter = Formatter;
|
|
372
372
|
//# sourceMappingURL=Formatter.js.map
|