UI: Refactoring units models; Add new units acceleration, angle, area, angular-acceleration
This commit is contained in:
parent
6d2d07da24
commit
cfcb16a61b
@ -21,12 +21,11 @@ import { isDefinedAndNotNull, isUndefinedOrNull } from '@core/utils';
|
|||||||
|
|
||||||
export interface Conversion<
|
export interface Conversion<
|
||||||
TMeasures extends string,
|
TMeasures extends string,
|
||||||
TSystems extends string,
|
|
||||||
TUnits extends string,
|
TUnits extends string,
|
||||||
> {
|
> {
|
||||||
abbr: TUnits;
|
abbr: TUnits;
|
||||||
measure: TMeasures;
|
measure: TMeasures;
|
||||||
system: TSystems;
|
system: UnitSystem;
|
||||||
unit: Unit;
|
unit: Unit;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -39,10 +38,10 @@ export interface Conversion<
|
|||||||
|
|
||||||
type Entries<T, S extends keyof T> = [S, T[keyof T]];
|
type Entries<T, S extends keyof T> = [S, T[keyof T]];
|
||||||
|
|
||||||
export type UnitCache<TMeasures, TSystems, TUnits> = Map<
|
export type UnitCache<TMeasures, TUnits> = Map<
|
||||||
string,
|
string,
|
||||||
{
|
{
|
||||||
system: TSystems;
|
system: UnitSystem;
|
||||||
measure: TMeasures;
|
measure: TMeasures;
|
||||||
unit: Unit;
|
unit: Unit;
|
||||||
abbr: TUnits;
|
abbr: TUnits;
|
||||||
@ -51,14 +50,13 @@ export type UnitCache<TMeasures, TSystems, TUnits> = Map<
|
|||||||
|
|
||||||
export class Converter<
|
export class Converter<
|
||||||
TMeasures extends AllMeasures,
|
TMeasures extends AllMeasures,
|
||||||
TSystems extends UnitSystem,
|
|
||||||
TUnits extends string,
|
TUnits extends string,
|
||||||
> {
|
> {
|
||||||
private measureData: Record<TMeasures, TbMeasure<TSystems, TUnits>>;
|
private readonly measureData: Record<TMeasures, TbMeasure<TUnits>>;
|
||||||
private unitCache: Map<
|
private unitCache: Map<
|
||||||
string,
|
string,
|
||||||
{
|
{
|
||||||
system: TSystems;
|
system: UnitSystem;
|
||||||
measure: TMeasures;
|
measure: TMeasures;
|
||||||
unit: Unit;
|
unit: Unit;
|
||||||
abbr: TUnits;
|
abbr: TUnits;
|
||||||
@ -66,8 +64,8 @@ export class Converter<
|
|||||||
>;
|
>;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
measures: Record<TMeasures, TbMeasure<TSystems, TUnits>>,
|
measures: Record<TMeasures, TbMeasure<TUnits>>,
|
||||||
unitCache: UnitCache<TMeasures, TSystems, TUnits>
|
unitCache: UnitCache<TMeasures, TUnits>
|
||||||
) {
|
) {
|
||||||
this.measureData = measures;
|
this.measureData = measures;
|
||||||
this.unitCache = unitCache;
|
this.unitCache = unitCache;
|
||||||
@ -96,18 +94,8 @@ export class Converter<
|
|||||||
|
|
||||||
if (origin.system !== destination.system) {
|
if (origin.system !== destination.system) {
|
||||||
const measure = this.measureData[origin.measure];
|
const measure = this.measureData[origin.measure];
|
||||||
const anchors = measure.anchors;
|
const transform = measure[origin.system]?.transform;
|
||||||
if (!anchors) {
|
const ratio = measure[origin.system]?.ratio;
|
||||||
throw Error(`Unable to convert units. Anchors are missing for "${origin.measure}" and "${destination.measure}" measures.`);
|
|
||||||
}
|
|
||||||
|
|
||||||
const anchor = anchors[origin.system];
|
|
||||||
if (!anchor) {
|
|
||||||
throw Error(`Unable to convert units. Anchors are missing for "${origin.measure}" and "${destination.measure}" measures.`);
|
|
||||||
}
|
|
||||||
|
|
||||||
const transform = anchor[destination.system]?.transform;
|
|
||||||
const ratio = anchor[destination.system]?.ratio;
|
|
||||||
|
|
||||||
if (typeof transform === 'function') {
|
if (typeof transform === 'function') {
|
||||||
result = transform(result);
|
result = transform(result);
|
||||||
@ -146,16 +134,8 @@ export class Converter<
|
|||||||
}
|
}
|
||||||
if (origin.system !== destination.system) {
|
if (origin.system !== destination.system) {
|
||||||
const measure = this.measureData[origin.measure];
|
const measure = this.measureData[origin.measure];
|
||||||
const anchors = measure.anchors;
|
const transform = measure[origin.system]?.transform;
|
||||||
if (!anchors) {
|
const ratio = measure[origin.system]?.ratio;
|
||||||
throw Error(`Unable to convert units. Anchors are missing for "${origin.measure}" and "${destination.measure}" measures.`);
|
|
||||||
}
|
|
||||||
const anchor = anchors[origin.system];
|
|
||||||
if (!anchor) {
|
|
||||||
throw Error(`Unable to convert units. Anchors are missing for "${origin.measure}" and "${destination.measure}" measures.`);
|
|
||||||
}
|
|
||||||
const transform = anchor[destination.system]?.transform;
|
|
||||||
const ratio = anchor[destination.system]?.ratio;
|
|
||||||
if (typeof transform === 'function') {
|
if (typeof transform === 'function') {
|
||||||
result = transform(result);
|
result = transform(result);
|
||||||
} else if (typeof ratio === 'number') {
|
} else if (typeof ratio === 'number') {
|
||||||
@ -234,7 +214,7 @@ export class Converter<
|
|||||||
// return best;
|
// return best;
|
||||||
// }
|
// }
|
||||||
|
|
||||||
getUnit(abbr: TUnits | (string & {})): Conversion<TMeasures, TSystems, TUnits> | null {
|
getUnit(abbr: TUnits | (string & {})): Conversion<TMeasures, TUnits> | null {
|
||||||
return this.unitCache.get(abbr) ?? null;
|
return this.unitCache.get(abbr) ?? null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -247,7 +227,7 @@ export class Converter<
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private describeUnit(unit: Conversion<TMeasures, TSystems, TUnits>): UnitDescription {
|
private describeUnit(unit: Conversion<TMeasures, TUnits>): UnitDescription {
|
||||||
return {
|
return {
|
||||||
abbr: unit.abbr,
|
abbr: unit.abbr,
|
||||||
measure: unit.measure,
|
measure: unit.measure,
|
||||||
@ -268,11 +248,11 @@ export class Converter<
|
|||||||
const measure = this.measureData[measureName];
|
const measure = this.measureData[measureName];
|
||||||
if (isDefinedAndNotNull(unitSystem)) {
|
if (isDefinedAndNotNull(unitSystem)) {
|
||||||
let currentUnitSystem = unitSystem;
|
let currentUnitSystem = unitSystem;
|
||||||
let units = measure.systems[currentUnitSystem];
|
let units = measure[currentUnitSystem];
|
||||||
if (isUndefinedOrNull(units)) {
|
if (isUndefinedOrNull(units)) {
|
||||||
if (currentUnitSystem === UnitSystem.IMPERIAL) {
|
if (currentUnitSystem === UnitSystem.IMPERIAL) {
|
||||||
currentUnitSystem = UnitSystem.METRIC;
|
currentUnitSystem = UnitSystem.METRIC;
|
||||||
units = measure.systems[currentUnitSystem];
|
units = measure[currentUnitSystem];
|
||||||
}
|
}
|
||||||
if (!units) {
|
if (!units) {
|
||||||
console.log(`Measure "${measureName}" in ${currentUnitSystem} system is not found.`);
|
console.log(`Measure "${measureName}" in ${currentUnitSystem} system is not found.`);
|
||||||
@ -280,29 +260,29 @@ export class Converter<
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (const [abbr, unit] of Object.entries(
|
for (const [abbr, unit] of Object.entries(
|
||||||
units
|
units.units
|
||||||
)) {
|
)) {
|
||||||
list.push(
|
list.push(
|
||||||
this.describeUnit({
|
this.describeUnit({
|
||||||
abbr: abbr as TUnits,
|
abbr: abbr as TUnits,
|
||||||
measure: measureName as TMeasures,
|
measure: measureName as TMeasures,
|
||||||
system: currentUnitSystem as TSystems,
|
system: currentUnitSystem,
|
||||||
unit: unit as Unit,
|
unit: unit as Unit,
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for (const [systemName, units] of Object.entries(
|
for (const [systemName, units] of Object.entries(
|
||||||
(measure as TbMeasure<TSystems, TUnits>).systems
|
measure
|
||||||
)) {
|
) as Entries<TbMeasure<TUnits>, UnitSystem>[]) {
|
||||||
for (const [abbr, unit] of Object.entries(
|
for (const [abbr, unit] of Object.entries(
|
||||||
units as Partial<Record<TUnits, Unit>>
|
units.units as Partial<Record<TUnits, Unit>>
|
||||||
)) {
|
)) {
|
||||||
list.push(
|
list.push(
|
||||||
this.describeUnit({
|
this.describeUnit({
|
||||||
abbr: abbr as TUnits,
|
abbr: abbr as TUnits,
|
||||||
measure: measureName as TMeasures,
|
measure: measureName as TMeasures,
|
||||||
system: systemName as TSystems,
|
system: systemName,
|
||||||
unit: unit as Unit,
|
unit: unit as Unit,
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
@ -313,11 +293,11 @@ export class Converter<
|
|||||||
for (const [name, measure] of Object.entries(this.measureData)) {
|
for (const [name, measure] of Object.entries(this.measureData)) {
|
||||||
if (isDefinedAndNotNull(unitSystem)) {
|
if (isDefinedAndNotNull(unitSystem)) {
|
||||||
let currentUnitSystem = unitSystem;
|
let currentUnitSystem = unitSystem;
|
||||||
let units = (measure as TbMeasure<TSystems, TUnits>).systems[currentUnitSystem];
|
let units = (measure as TbMeasure<TUnits>)[currentUnitSystem]?.units;
|
||||||
if (isUndefinedOrNull(units)) {
|
if (isUndefinedOrNull(units)) {
|
||||||
if (currentUnitSystem === UnitSystem.IMPERIAL) {
|
if (currentUnitSystem === UnitSystem.IMPERIAL) {
|
||||||
currentUnitSystem = UnitSystem.METRIC;
|
currentUnitSystem = UnitSystem.METRIC;
|
||||||
units = (measure as TbMeasure<TSystems, TUnits>).systems[currentUnitSystem];
|
units = (measure as TbMeasure<TUnits>)[currentUnitSystem]?.units;
|
||||||
}
|
}
|
||||||
if (!units) {
|
if (!units) {
|
||||||
console.log(`Measure "${measureName}" in ${currentUnitSystem} system is not found.`);
|
console.log(`Measure "${measureName}" in ${currentUnitSystem} system is not found.`);
|
||||||
@ -331,23 +311,23 @@ export class Converter<
|
|||||||
this.describeUnit({
|
this.describeUnit({
|
||||||
abbr: abbr as TUnits,
|
abbr: abbr as TUnits,
|
||||||
measure: name as TMeasures,
|
measure: name as TMeasures,
|
||||||
system: currentUnitSystem as TSystems,
|
system: currentUnitSystem,
|
||||||
unit: unit as Unit,
|
unit: unit as Unit,
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for (const [systemName, units] of Object.entries(
|
for (const [systemName, units] of Object.entries(
|
||||||
(measure as TbMeasure<TSystems, TUnits>).systems
|
measure
|
||||||
)) {
|
) as Entries<TbMeasure<TUnits>, UnitSystem>[]) {
|
||||||
for (const [abbr, unit] of Object.entries(
|
for (const [abbr, unit] of Object.entries(
|
||||||
units as Partial<Record<TUnits, Unit>>
|
units.units as Partial<Record<TUnits, Unit>>
|
||||||
)) {
|
)) {
|
||||||
list.push(
|
list.push(
|
||||||
this.describeUnit({
|
this.describeUnit({
|
||||||
abbr: abbr as TUnits,
|
abbr: abbr as TUnits,
|
||||||
measure: name as TMeasures,
|
measure: name as TMeasures,
|
||||||
system: systemName as TSystems,
|
system: systemName,
|
||||||
unit: unit as Unit,
|
unit: unit as Unit,
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
@ -397,21 +377,20 @@ export class Converter<
|
|||||||
|
|
||||||
export function buildUnitCache<
|
export function buildUnitCache<
|
||||||
TMeasures extends string,
|
TMeasures extends string,
|
||||||
TSystems extends UnitSystem,
|
|
||||||
TUnits extends string,
|
TUnits extends string,
|
||||||
>(measures: Record<TMeasures, TbMeasure<TSystems, TUnits>>,
|
>(measures: Record<TMeasures, TbMeasure<TUnits>>,
|
||||||
translate: TranslateService
|
translate: TranslateService
|
||||||
) {
|
) {
|
||||||
const unitCache: UnitCache<TMeasures, TSystems, TUnits> = new Map();
|
const unitCache: UnitCache<TMeasures, TUnits> = new Map();
|
||||||
for (const [measureName, measure] of Object.entries(measures) as Entries<
|
for (const [measureName, measure] of Object.entries(measures) as Entries<
|
||||||
typeof measures,
|
typeof measures,
|
||||||
TMeasures
|
TMeasures
|
||||||
>[]) {
|
>[]) {
|
||||||
for (const [systemName, system] of Object.entries(
|
for (const [systemName, system] of Object.entries(
|
||||||
measure.systems
|
measure
|
||||||
) as Entries<Record<TSystems, Record<TUnits, Unit>>, TSystems>[]) {
|
) as Entries<TbMeasure<TUnits>, UnitSystem>[]) {
|
||||||
for (const [testAbbr, unit] of Object.entries(system) as Entries<
|
for (const [testAbbr, unit] of Object.entries(system.units) as Entries<
|
||||||
typeof system,
|
Record<TUnits, Unit>,
|
||||||
TUnits
|
TUnits
|
||||||
>[]) {
|
>[]) {
|
||||||
unit.name = translate.instant(unit.name);
|
unit.name = translate.instant(unit.name);
|
||||||
@ -429,16 +408,15 @@ export function buildUnitCache<
|
|||||||
|
|
||||||
export function configureMeasurements<
|
export function configureMeasurements<
|
||||||
TMeasures extends AllMeasures,
|
TMeasures extends AllMeasures,
|
||||||
TSystems extends UnitSystem,
|
|
||||||
TUnits extends string,
|
TUnits extends string,
|
||||||
>(
|
>(
|
||||||
measures: Record<TMeasures, TbMeasure<TSystems, TUnits>>,
|
measures: Record<TMeasures, TbMeasure<TUnits>>,
|
||||||
translate: TranslateService
|
translate: TranslateService
|
||||||
): Converter<TMeasures, TSystems, TUnits> {
|
): Converter<TMeasures, TUnits> {
|
||||||
if (typeof measures !== 'object') {
|
if (typeof measures !== 'object') {
|
||||||
throw new TypeError('The measures argument needs to be an object');
|
throw new TypeError('The measures argument needs to be an object');
|
||||||
}
|
}
|
||||||
|
|
||||||
const unitCache = buildUnitCache(measures, translate);
|
const unitCache = buildUnitCache(measures, translate);
|
||||||
return new Converter<TMeasures, TSystems, TUnits>(measures, unitCache);
|
return new Converter<TMeasures, TUnits>(measures, unitCache);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,66 @@
|
|||||||
|
///
|
||||||
|
/// Copyright © 2016-2025 The Thingsboard Authors
|
||||||
|
///
|
||||||
|
/// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
/// you may not use this file except in compliance with the License.
|
||||||
|
/// You may obtain a copy of the License at
|
||||||
|
///
|
||||||
|
/// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
///
|
||||||
|
/// Unless required by applicable law or agreed to in writing, software
|
||||||
|
/// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
/// See the License for the specific language governing permissions and
|
||||||
|
/// limitations under the License.
|
||||||
|
///
|
||||||
|
|
||||||
|
import { TbMeasure, TbMeasureUnits } from '@shared/models/unit.models';
|
||||||
|
|
||||||
|
export type AccelerationMetricUnits = 'G' | 'm/s²' | 'km/h²' | 'Gal';
|
||||||
|
export type AccelerationImperialUnits = 'ft/s²';
|
||||||
|
|
||||||
|
export type AccelerationUnits = AccelerationMetricUnits | AccelerationImperialUnits;
|
||||||
|
|
||||||
|
const METRIC: TbMeasureUnits<AccelerationMetricUnits> = {
|
||||||
|
ratio: 3.28084,
|
||||||
|
units: {
|
||||||
|
'G': {
|
||||||
|
name: 'unit.g-force',
|
||||||
|
tags: ['acceleration', 'gravity', 'g-force', 'load', 'G'],
|
||||||
|
to_anchor: 9.80665,
|
||||||
|
},
|
||||||
|
'm/s²': {
|
||||||
|
name: 'unit.meters-per-second-squared',
|
||||||
|
tags: ['peak', 'peak to peak', 'root mean square (RMS)', 'vibration', 'meters per second squared', 'm/s²'],
|
||||||
|
to_anchor: 1,
|
||||||
|
},
|
||||||
|
'Gal': {
|
||||||
|
name: 'unit.gal',
|
||||||
|
tags: ['acceleration', 'gravity', 'g-force', 'Gal'],
|
||||||
|
to_anchor: 1,
|
||||||
|
},
|
||||||
|
'km/h²': {
|
||||||
|
name: 'unit.kilometer-per-hour-squared',
|
||||||
|
tags: ['acceleration', 'rate of change of velocity', 'kilometer per hour squared', 'km/h²'],
|
||||||
|
to_anchor: 1 / 12960,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const IMPERIAL: TbMeasureUnits<AccelerationImperialUnits> = {
|
||||||
|
ratio: 1 / 3.28084,
|
||||||
|
units: {
|
||||||
|
'ft/s²': {
|
||||||
|
name: 'unit.foot-per-second-squared',
|
||||||
|
tags: ['acceleration', 'rate of change of velocity', 'foot per second squared', 'ft/s²'],
|
||||||
|
to_anchor: 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const measure: TbMeasure<AccelerationUnits> = {
|
||||||
|
METRIC,
|
||||||
|
IMPERIAL
|
||||||
|
};
|
||||||
|
|
||||||
|
export default measure;
|
||||||
@ -14,24 +14,38 @@
|
|||||||
/// limitations under the License.
|
/// limitations under the License.
|
||||||
///
|
///
|
||||||
|
|
||||||
import temperature, {
|
import { TbMeasure } from '@shared/models/unit.models';
|
||||||
TemperatureUnits,
|
import acceleration, { AccelerationUnits } from '@core/services/unit/definitions/acceleration';
|
||||||
} from './temperature';
|
import angle, { AngleUnits } from '@core/services/unit/definitions/angle';
|
||||||
|
import angularAcceleration, { AngularAccelerationUnits } from '@core/services/unit/definitions/angular-acceleration';
|
||||||
|
import area, { AreaUnits } from '@core/services/unit/definitions/area';
|
||||||
|
import temperature, { TemperatureUnits } from './temperature';
|
||||||
import time, { TimeUnits } from './time';
|
import time, { TimeUnits } from './time';
|
||||||
import { TbMeasure, UnitSystem } from '@shared/models/unit.models';
|
|
||||||
|
|
||||||
export type AllMeasuresUnits =
|
export type AllMeasuresUnits =
|
||||||
|
| AccelerationUnits
|
||||||
|
| AngleUnits
|
||||||
|
| AngularAccelerationUnits
|
||||||
|
| AreaUnits
|
||||||
| TemperatureUnits
|
| TemperatureUnits
|
||||||
| TimeUnits;
|
| TimeUnits;
|
||||||
|
|
||||||
export type AllMeasures =
|
export type AllMeasures =
|
||||||
|
| 'acceleration'
|
||||||
|
| 'angle'
|
||||||
|
| 'angularAcceleration'
|
||||||
|
| 'area'
|
||||||
| 'temperature'
|
| 'temperature'
|
||||||
| 'time';
|
| 'time';
|
||||||
|
|
||||||
const allMeasures: Record<
|
const allMeasures: Record<
|
||||||
AllMeasures,
|
AllMeasures,
|
||||||
TbMeasure<UnitSystem, AllMeasuresUnits>
|
TbMeasure<AllMeasuresUnits>
|
||||||
> = {
|
> = {
|
||||||
|
acceleration,
|
||||||
|
angle,
|
||||||
|
angularAcceleration,
|
||||||
|
area,
|
||||||
temperature,
|
temperature,
|
||||||
time,
|
time,
|
||||||
};
|
};
|
||||||
|
|||||||
67
ui-ngx/src/app/core/services/unit/definitions/angle.ts
Normal file
67
ui-ngx/src/app/core/services/unit/definitions/angle.ts
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
///
|
||||||
|
/// Copyright © 2016-2025 The Thingsboard Authors
|
||||||
|
///
|
||||||
|
/// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
/// you may not use this file except in compliance with the License.
|
||||||
|
/// You may obtain a copy of the License at
|
||||||
|
///
|
||||||
|
/// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
///
|
||||||
|
/// Unless required by applicable law or agreed to in writing, software
|
||||||
|
/// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
/// See the License for the specific language governing permissions and
|
||||||
|
/// limitations under the License.
|
||||||
|
///
|
||||||
|
|
||||||
|
import { TbMeasure, TbMeasureUnits } from '@shared/models/unit.models';
|
||||||
|
|
||||||
|
export type AngleUnits = AngleSIUnits;
|
||||||
|
|
||||||
|
export type AngleSIUnits = 'rad' | 'deg' | 'grad' | 'arcmin' | 'arcsec' | 'mil' | 'rev';
|
||||||
|
|
||||||
|
const METRIC: TbMeasureUnits<AngleSIUnits> = {
|
||||||
|
units: {
|
||||||
|
rad: {
|
||||||
|
name: 'unit.rad',
|
||||||
|
tags: ['angle', 'radian', 'radians', 'rad'],
|
||||||
|
to_anchor: 180 / Math.PI,
|
||||||
|
},
|
||||||
|
deg: {
|
||||||
|
name: 'unit.degree',
|
||||||
|
tags: ['angle', 'degree', 'degrees', 'deg'],
|
||||||
|
to_anchor: 1,
|
||||||
|
},
|
||||||
|
grad: {
|
||||||
|
name: 'unit.gradian',
|
||||||
|
tags: ['angle', 'gradian', 'grades', 'grad'],
|
||||||
|
to_anchor: 9 / 10,
|
||||||
|
},
|
||||||
|
arcmin: {
|
||||||
|
name: 'unit.arcminute',
|
||||||
|
tags: ['angle', 'arcminute', 'arcminutes', 'arcmin'],
|
||||||
|
to_anchor: 1 / 60
|
||||||
|
},
|
||||||
|
arcsec: {
|
||||||
|
name: 'unit.arcsecond',
|
||||||
|
tags: ['angle', 'arcsecond', 'arcseconds', 'arcsec'],
|
||||||
|
to_anchor: 1 / 3600
|
||||||
|
},
|
||||||
|
mil: {
|
||||||
|
name: 'unit.mil',
|
||||||
|
tags: ['angle', 'military angle', 'angular mil', 'mil'],
|
||||||
|
to_anchor: 9 / (50 * Math.PI),
|
||||||
|
},
|
||||||
|
rev: {
|
||||||
|
name: 'revolution',
|
||||||
|
tags: ['angle', 'revolution', 'full circle', 'complete turn', 'rev'],
|
||||||
|
to_anchor: 360,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const measure: TbMeasure<AngleUnits> = {
|
||||||
|
METRIC,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default measure;
|
||||||
@ -0,0 +1,51 @@
|
|||||||
|
///
|
||||||
|
/// Copyright © 2016-2025 The Thingsboard Authors
|
||||||
|
///
|
||||||
|
/// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
/// you may not use this file except in compliance with the License.
|
||||||
|
/// You may obtain a copy of the License at
|
||||||
|
///
|
||||||
|
/// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
///
|
||||||
|
/// Unless required by applicable law or agreed to in writing, software
|
||||||
|
/// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
/// See the License for the specific language governing permissions and
|
||||||
|
/// limitations under the License.
|
||||||
|
///
|
||||||
|
|
||||||
|
import { TbMeasure, TbMeasureUnits } from '@shared/models/unit.models';
|
||||||
|
|
||||||
|
export type AngularAccelerationMetricUnits = 'rad/s²';
|
||||||
|
export type AngularAccelerationImperialUnits = 'rpm/s';
|
||||||
|
|
||||||
|
export type AngularAccelerationUnits = AngularAccelerationMetricUnits | AngularAccelerationImperialUnits;
|
||||||
|
|
||||||
|
const METRIC: TbMeasureUnits<AngularAccelerationMetricUnits> = {
|
||||||
|
ratio: 30 / Math.PI,
|
||||||
|
units: {
|
||||||
|
'rad/s²': {
|
||||||
|
name: 'unit.radian-per-second-squared',
|
||||||
|
tags: ['angular acceleration', 'rotation rate of change', 'rad/s²'],
|
||||||
|
to_anchor: 1,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const IMPERIAL: TbMeasureUnits<AngularAccelerationImperialUnits> = {
|
||||||
|
ratio: Math.PI / 30,
|
||||||
|
units: {
|
||||||
|
'rpm/s': {
|
||||||
|
name: 'unit.revolutions-per-minute-per-second',
|
||||||
|
tags: ['angular acceleration', 'rotation rate of change', 'rpm/s'],
|
||||||
|
to_anchor: 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const measure: TbMeasure<AngularAccelerationUnits> = {
|
||||||
|
METRIC,
|
||||||
|
IMPERIAL
|
||||||
|
};
|
||||||
|
|
||||||
|
export default measure;
|
||||||
101
ui-ngx/src/app/core/services/unit/definitions/area.ts
Normal file
101
ui-ngx/src/app/core/services/unit/definitions/area.ts
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
///
|
||||||
|
/// Copyright © 2016-2025 The Thingsboard Authors
|
||||||
|
///
|
||||||
|
/// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
/// you may not use this file except in compliance with the License.
|
||||||
|
/// You may obtain a copy of the License at
|
||||||
|
///
|
||||||
|
/// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
///
|
||||||
|
/// Unless required by applicable law or agreed to in writing, software
|
||||||
|
/// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
/// See the License for the specific language governing permissions and
|
||||||
|
/// limitations under the License.
|
||||||
|
///
|
||||||
|
|
||||||
|
import { TbMeasure, TbMeasureUnits } from '@shared/models/unit.models';
|
||||||
|
|
||||||
|
export type AreaMetricUnits = 'mm²' | 'cm²' | 'm²' | 'a' | 'ha' | 'km²';
|
||||||
|
export type AreaImperialUnits = 'in²' | 'yd²' | 'ft²' | 'ac' | 'ml²' | 'cin';
|
||||||
|
|
||||||
|
export type AreaUnits = AreaMetricUnits | AreaImperialUnits;
|
||||||
|
|
||||||
|
const METRIC: TbMeasureUnits<AreaMetricUnits> = {
|
||||||
|
ratio: 10.7639,
|
||||||
|
units: {
|
||||||
|
'mm²': {
|
||||||
|
name: 'unit.square-millimeter',
|
||||||
|
tags: ['area','lot','zone','space','region','square millimeter','square millimeters','mm²','sq-mm'],
|
||||||
|
to_anchor: 1 / 1000000,
|
||||||
|
},
|
||||||
|
'cm²': {
|
||||||
|
name: 'unit.square-centimeter',
|
||||||
|
tags: ['area','lot','zone','space','region','square centimeter','square centimeters','cm²','sq-cm'],
|
||||||
|
to_anchor: 1 / 10000,
|
||||||
|
},
|
||||||
|
'm²': {
|
||||||
|
name: 'unit.square-meter',
|
||||||
|
tags: ['area','lot','zone','space','region','square meter','square meters','m²','sq-m'],
|
||||||
|
to_anchor: 1,
|
||||||
|
},
|
||||||
|
a: {
|
||||||
|
name: 'unit.are',
|
||||||
|
tags: ['area','land measurement','are'],
|
||||||
|
to_anchor: 100,
|
||||||
|
},
|
||||||
|
ha: {
|
||||||
|
name: 'unit.hectare',
|
||||||
|
tags: ['area','lot','zone','space','region','hectare','hectares','ha'],
|
||||||
|
to_anchor: 10000,
|
||||||
|
},
|
||||||
|
'km²': {
|
||||||
|
name: 'unit.square-kilometer',
|
||||||
|
tags: ['area','lot','zone','space','region','square kilometer','square kilometers','km²','sq-km'],
|
||||||
|
to_anchor: 1000000,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const IMPERIAL: TbMeasureUnits<AreaImperialUnits> = {
|
||||||
|
ratio: 1 / 10.7639,
|
||||||
|
units: {
|
||||||
|
'in²': {
|
||||||
|
name: 'unit.square-inch',
|
||||||
|
tags: ['area','lot','zone','space','region','square inch','square inches','in²','sq-in'],
|
||||||
|
to_anchor: 1 / 144,
|
||||||
|
},
|
||||||
|
'yd²': {
|
||||||
|
name: 'unit.square-yard',
|
||||||
|
tags: ['area','lot','zone','space','region','square yard','square yards','yd²','sq-yd'],
|
||||||
|
to_anchor: 9,
|
||||||
|
},
|
||||||
|
'ft²': {
|
||||||
|
name: 'unit.square-foot',
|
||||||
|
tags: ['area','lot','zone','space','region','square foot','square feet','ft²','sq-ft'],
|
||||||
|
to_anchor: 1,
|
||||||
|
},
|
||||||
|
ac: {
|
||||||
|
name: 'unit.acre',
|
||||||
|
tags: ['area','lot','zone','space','region','acre','acres','a'],
|
||||||
|
to_anchor: 43560,
|
||||||
|
},
|
||||||
|
'ml²': {
|
||||||
|
name: 'unit.square-mile',
|
||||||
|
tags: ['area','lot','zone','space','region','square mile','square miles','ml²','sq-mi'],
|
||||||
|
to_anchor: 27878400,
|
||||||
|
},
|
||||||
|
cin: {
|
||||||
|
name: 'unit.circular-inch',
|
||||||
|
tags: ['area','circular measurement','circular inch','circin'],
|
||||||
|
to_anchor: Math.PI / 576
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const measure: TbMeasure<AreaUnits> = {
|
||||||
|
METRIC,
|
||||||
|
IMPERIAL
|
||||||
|
};
|
||||||
|
|
||||||
|
export default measure;
|
||||||
@ -14,7 +14,7 @@
|
|||||||
/// limitations under the License.
|
/// limitations under the License.
|
||||||
///
|
///
|
||||||
|
|
||||||
import { TbMeasure, Unit, UnitSystem } from '@shared/models/unit.models';
|
import { TbMeasure, TbMeasureUnits } from '@shared/models/unit.models';
|
||||||
|
|
||||||
export type TemperatureMetricUnits = '°C' | 'K';
|
export type TemperatureMetricUnits = '°C' | 'K';
|
||||||
export type TemperatureImperialUnits = '°F' | '°R';
|
export type TemperatureImperialUnits = '°F' | '°R';
|
||||||
@ -23,55 +23,43 @@ export type TemperatureUnits =
|
|||||||
| TemperatureMetricUnits
|
| TemperatureMetricUnits
|
||||||
| TemperatureImperialUnits;
|
| TemperatureImperialUnits;
|
||||||
|
|
||||||
const METRIC: Record<TemperatureMetricUnits, Unit> = {
|
const METRIC: TbMeasureUnits<TemperatureMetricUnits> = {
|
||||||
|
transform: (C) => C / (5 / 9) + 32,
|
||||||
|
units: {
|
||||||
'°C': {
|
'°C': {
|
||||||
name: 'unit.celsius',
|
name: 'unit.celsius',
|
||||||
tags: ['temperature','heat','cold','warmth','degrees','celsius','shipment condition','°C'],
|
tags: ['temperature', 'heat', 'cold', 'warmth', 'degrees', 'celsius', 'shipment condition', '°C'],
|
||||||
to_anchor: 1,
|
to_anchor: 1,
|
||||||
},
|
},
|
||||||
K: {
|
K: {
|
||||||
name: 'unit.kelvin',
|
name: 'unit.kelvin',
|
||||||
tags: ['temperature','heat','cold','warmth','degrees','kelvin','K','color quality','white balance','color temperature'],
|
tags: ['temperature', 'heat', 'cold', 'warmth', 'degrees', 'kelvin', 'K', 'color quality', 'white balance', 'color temperature'],
|
||||||
to_anchor: 1,
|
to_anchor: 1,
|
||||||
anchor_shift: 273.15,
|
anchor_shift: 273.15,
|
||||||
},
|
},
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const IMPERIAL: Record<TemperatureImperialUnits, Unit> = {
|
const IMPERIAL: TbMeasureUnits<TemperatureImperialUnits> = {
|
||||||
|
transform: (F) => (F - 32) * (5 / 9),
|
||||||
|
units: {
|
||||||
'°F': {
|
'°F': {
|
||||||
name: 'unit.fahrenheit',
|
name: 'unit.fahrenheit',
|
||||||
tags: ['temperature','heat','cold','warmth','degrees','fahrenheit','°F'],
|
tags: ['temperature', 'heat', 'cold', 'warmth', 'degrees', 'fahrenheit', '°F'],
|
||||||
to_anchor: 1,
|
to_anchor: 1,
|
||||||
},
|
},
|
||||||
'°R': {
|
'°R': {
|
||||||
name: 'unit.rankine',
|
name: 'unit.rankine',
|
||||||
tags: ['temperature','heat','cold','warmth','Rankine','°R'],
|
tags: ['temperature', 'heat', 'cold', 'warmth', 'Rankine', '°R'],
|
||||||
to_anchor: 1,
|
to_anchor: 1,
|
||||||
anchor_shift: 459.67,
|
anchor_shift: 459.67,
|
||||||
},
|
},
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const measure: TbMeasure<UnitSystem, TemperatureUnits> = {
|
const measure: TbMeasure<TemperatureUnits> = {
|
||||||
systems: {
|
|
||||||
METRIC,
|
METRIC,
|
||||||
IMPERIAL,
|
IMPERIAL
|
||||||
},
|
|
||||||
anchors: {
|
|
||||||
METRIC: {
|
|
||||||
IMPERIAL: {
|
|
||||||
transform: function (C: number): number {
|
|
||||||
return C / (5 / 9) + 32;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
IMPERIAL: {
|
|
||||||
METRIC: {
|
|
||||||
transform: function (F: number): number {
|
|
||||||
return (F - 32) * (5 / 9);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default measure;
|
export default measure;
|
||||||
|
|||||||
@ -14,11 +14,14 @@
|
|||||||
/// limitations under the License.
|
/// limitations under the License.
|
||||||
///
|
///
|
||||||
|
|
||||||
import { TbMeasure, Unit, UnitSystem } from '@shared/models/unit.models';
|
import { TbMeasure, TbMeasureUnits } from '@shared/models/unit.models';
|
||||||
|
|
||||||
export type TimeUnits = TimeSIUnits;
|
export type TimeUnits = TimeSIUnits;
|
||||||
|
|
||||||
export type TimeSIUnits =
|
export type TimeSIUnits =
|
||||||
|
| 'ns'
|
||||||
|
| 'μs'
|
||||||
|
| 'ms'
|
||||||
| 's'
|
| 's'
|
||||||
| 'min'
|
| 'min'
|
||||||
| 'h'
|
| 'h'
|
||||||
@ -29,48 +32,63 @@ export type TimeSIUnits =
|
|||||||
|
|
||||||
const daysInYear = 365.25;
|
const daysInYear = 365.25;
|
||||||
|
|
||||||
const METRIC: Record<TimeSIUnits, Unit> = {
|
const METRIC: TbMeasureUnits<TimeSIUnits> = {
|
||||||
|
units: {
|
||||||
|
ns: {
|
||||||
|
name: 'unit.nanosecond',
|
||||||
|
tags: ['time', 'duration', 'interval', 'ns'],
|
||||||
|
to_anchor: 1 / 1000000000
|
||||||
|
},
|
||||||
|
'μs': {
|
||||||
|
name: 'unit.microsecond',
|
||||||
|
tags: ['time', 'duration', 'interval', 'h'],
|
||||||
|
to_anchor: 1 / 1000000
|
||||||
|
},
|
||||||
|
ms: {
|
||||||
|
name: 'unit.millisecond',
|
||||||
|
tags: ['time', 'duration', 'interval', 'ms'],
|
||||||
|
to_anchor: 1 / 1000
|
||||||
|
},
|
||||||
s: {
|
s: {
|
||||||
name: 'unit.second',
|
name: 'unit.second',
|
||||||
tags: ["time","duration","interval","angle","second","arcsecond","sec"],
|
tags: ['time', 'duration', 'interval', 'second', 'sec'],
|
||||||
to_anchor: 1,
|
to_anchor: 1,
|
||||||
},
|
},
|
||||||
min: {
|
min: {
|
||||||
name: 'unit.minute',
|
name: 'unit.minute',
|
||||||
tags: ["time","duration","interval","angle","minute","arcminute","min"],
|
tags: ['time', 'duration', 'interval', 'minute', 'min'],
|
||||||
to_anchor: 60,
|
to_anchor: 60,
|
||||||
},
|
},
|
||||||
h: {
|
h: {
|
||||||
name: 'unit.hour',
|
name: 'unit.hour',
|
||||||
tags: ["time","duration","interval","h"],
|
tags: ['time', 'duration', 'interval', 'h'],
|
||||||
to_anchor: 60 * 60,
|
to_anchor: 60 * 60,
|
||||||
},
|
},
|
||||||
d: {
|
d: {
|
||||||
name: 'unit.day',
|
name: 'unit.day',
|
||||||
tags: ["time","duration","interval","d"],
|
tags: ['time', 'duration', 'interval', 'd'],
|
||||||
to_anchor: 60 * 60 * 24,
|
to_anchor: 60 * 60 * 24,
|
||||||
},
|
},
|
||||||
wk: {
|
wk: {
|
||||||
name: 'unit.week',
|
name: 'unit.week',
|
||||||
tags: ["time","duration","interval","wk"],
|
tags: ['time', 'duration', 'interval', 'wk'],
|
||||||
to_anchor: 60 * 60 * 24 * 7,
|
to_anchor: 60 * 60 * 24 * 7,
|
||||||
},
|
},
|
||||||
mo: {
|
mo: {
|
||||||
name: 'unit.month',
|
name: 'unit.month',
|
||||||
tags: ["time","duration","interval","mo"],
|
tags: ['time', 'duration', 'interval', 'mo'],
|
||||||
to_anchor: (60 * 60 * 24 * daysInYear) / 12,
|
to_anchor: (60 * 60 * 24 * daysInYear) / 12,
|
||||||
},
|
},
|
||||||
yr: {
|
yr: {
|
||||||
name: 'unit.year',
|
name: 'unit.year',
|
||||||
tags: ["time","duration","interval","yr"],
|
tags: ['time', 'duration', 'interval', 'yr'],
|
||||||
to_anchor: 60 * 60 * 24 * daysInYear,
|
to_anchor: 60 * 60 * 24 * daysInYear,
|
||||||
},
|
},
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const measure: TbMeasure<UnitSystem, TimeUnits> = {
|
const measure: TbMeasure<TimeUnits> = {
|
||||||
systems: {
|
|
||||||
METRIC,
|
METRIC,
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default measure;
|
export default measure;
|
||||||
|
|||||||
@ -31,14 +31,14 @@ import { AppState } from '@core/core.state';
|
|||||||
export class UnitService {
|
export class UnitService {
|
||||||
|
|
||||||
private currentUnitSystem: UnitSystem = UnitSystem.METRIC;
|
private currentUnitSystem: UnitSystem = UnitSystem.METRIC;
|
||||||
private converter: Converter<AllMeasures, UnitSystem, AllMeasuresUnits>;
|
private converter: Converter<AllMeasures, AllMeasuresUnits>;
|
||||||
|
|
||||||
constructor(private store: Store<AppState>,
|
constructor(private store: Store<AppState>,
|
||||||
private translate: TranslateService) {
|
private translate: TranslateService) {
|
||||||
this.translate.onLangChange.pipe(
|
this.translate.onLangChange.pipe(
|
||||||
takeUntilDestroyed()
|
takeUntilDestroyed()
|
||||||
).subscribe(() => {
|
).subscribe(() => {
|
||||||
this.converter = configureMeasurements<AllMeasures, UnitSystem, AllMeasuresUnits>(allMeasures, this.translate);
|
this.converter = configureMeasurements<AllMeasures, AllMeasuresUnits>(allMeasures, this.translate);
|
||||||
console.warn(this.converter?.list());
|
console.warn(this.converter?.list());
|
||||||
console.warn(this.converter?.list('temperature'));
|
console.warn(this.converter?.list('temperature'));
|
||||||
console.warn(this.converter?.list('temperature', UnitSystem.METRIC));
|
console.warn(this.converter?.list('temperature', UnitSystem.METRIC));
|
||||||
|
|||||||
@ -57,14 +57,12 @@ export interface TbUnitMapping {
|
|||||||
HYBRID: string;
|
HYBRID: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface TbAnchor {
|
export type TbMeasure<TUnits extends string> = Partial<Record<UnitSystem, TbMeasureUnits<TUnits>>>;
|
||||||
|
|
||||||
|
export interface TbMeasureUnits<TUnits extends string> {
|
||||||
ratio?: number;
|
ratio?: number;
|
||||||
transform?: (value: number) => number;
|
transform?: (value: number) => number;
|
||||||
}
|
units?: Partial<Record<TUnits, Unit>>;
|
||||||
|
|
||||||
export interface TbMeasure<TSystems extends UnitSystem, TUnits extends string> {
|
|
||||||
systems: Partial<Record<TSystems, Partial<Record<TUnits, Unit>>>>;
|
|
||||||
anchors?: Partial<Record<TSystems, Partial<Record<TSystems, TbAnchor>>>>;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const searchUnitTags = (unit: UnitDescription, searchText: string): boolean =>
|
const searchUnitTags = (unit: UnitDescription, searchText: string): boolean =>
|
||||||
|
|||||||
@ -6160,6 +6160,9 @@
|
|||||||
"millibars": "Millibars",
|
"millibars": "Millibars",
|
||||||
"inch-of-mercury": "One inch of mercury",
|
"inch-of-mercury": "One inch of mercury",
|
||||||
"richter-scale": "Richter Scale",
|
"richter-scale": "Richter Scale",
|
||||||
|
"nanosecond": "Nanosecond",
|
||||||
|
"microsecond": "Microsecond",
|
||||||
|
"millisecond": "Millisecond",
|
||||||
"second": "Second",
|
"second": "Second",
|
||||||
"minute": "Minute",
|
"minute": "Minute",
|
||||||
"hour": "Hour",
|
"hour": "Hour",
|
||||||
@ -6197,6 +6200,8 @@
|
|||||||
"degree": "Degree",
|
"degree": "Degree",
|
||||||
"radian": "Radian",
|
"radian": "Radian",
|
||||||
"gradian": "Gradian",
|
"gradian": "Gradian",
|
||||||
|
"arcminute": "Arcminute",
|
||||||
|
"arcsecond": "Arcsecond",
|
||||||
"mil": "Mil",
|
"mil": "Mil",
|
||||||
"revolution": "Revolution",
|
"revolution": "Revolution",
|
||||||
"siemens": "Siemens",
|
"siemens": "Siemens",
|
||||||
@ -6267,7 +6272,6 @@
|
|||||||
"radian-per-second": "Radian per second",
|
"radian-per-second": "Radian per second",
|
||||||
"radian-per-second-squared": "Radian per second squared",
|
"radian-per-second-squared": "Radian per second squared",
|
||||||
"revolutions-per-minute-per-second": "Angular acceleration",
|
"revolutions-per-minute-per-second": "Angular acceleration",
|
||||||
"revolutions-per-minute-per-second-squared": "Angular Acceleration",
|
|
||||||
"deg-per-second": "deg/s",
|
"deg-per-second": "deg/s",
|
||||||
"degrees-brix": "Degrees Brix",
|
"degrees-brix": "Degrees Brix",
|
||||||
"katal": "Katal",
|
"katal": "Katal",
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user