3

I'm writing a web based front end for an engineering simulation. The back end only accepts values in non-prefixed SI units, such as meters or watts. However it would be preferable to allow the user to enter values in any unit they wish. For example, if you needed to enter a distance, you could enter:

15 inches
3.1 meter
1.4 km

but values such as:

12 seconds
5 pounds
147 watts

would be rejected. I first tried using js-quantities, but it doesn't parse derived units in the most intuitive way. It requires a space to be placed between each multiplied unit. For example, to enter an amount of charge in amp hours, 100 Ah is invalid, but 100 A h is acceptable. Additionally, js-quantities does not support units of torque or temperature (only temperature difference, you can't convert Fahrenheit to Celsius for example)

I then tried to use the google calculator API to do unit conversions, but it produces hard to parse results for small numbers:

Convert 5 nm to meters

request:

http://www.google.com/ig/calculator?hl=en&q=5%20nm=?m

response:

{lhs: "5 nanometers",rhs: "5.0 \x26#215; 10\x3csup\x3e-9\x3c/sup\x3e meters",error: "",icc: false}
charliehorse55
  • 1,940
  • 5
  • 24
  • 38
  • 1
    The conversions you have mentioned don't *really* need to be farmed out to google calc. They are just static so you should do them in the browser. Something like the answer in this question: http://stackoverflow.com/questions/865590/unit-of-measure-conversion-library – olan Sep 23 '13 at 12:45
  • Yes, preferably they would be done in the browser. I'm just looking for a library OR service that can parse units in this way. I've seen the question you linked, but it doesn't handle the actual parsing. Additionally, I'm not sure I could easily create an exhaustive list of valid units. – charliehorse55 Sep 23 '13 at 13:11
  • Hi @charliehorse55. I am the author of js-quantities. I would be glad to fix the issues if possible (especially Ah parsing). Nevertheless, I tried tempF to tempC conversion and torque quantities but it works as expected ((new Qty('100 tempF').to('tempC')), new Qty('N*m')). – gentooboontoo Mar 05 '14 at 08:10

3 Answers3

2

It seems to me that modifying js-quantities would be fairly easy.

You simply edit the function parse(val) function. You try to parse and after failing you simply insert spaces as required by very simple ruleset. You go trough the string from left to right and identify units and split the string.

However I would probably go with another solution where you split it already when the user inputs it (by the same kind of rules). That way when the user inputs a value it can show "using amp hours" for Ah and the user can see that everything is the way he meant for it to be. That way you can offer the user to chose from a list (or more advanced builder) if it is not what he meant.

Rickard Liljeberg
  • 966
  • 1
  • 12
  • 39
  • Upon further analysis, it appears that it will not be possible to modify js-quantities to do what I need. Because of overlapping unit names, queries such as `80 F` could either be interpreted as 80 Farads or 80 Fahrenheit. I am probably going to end up writing my own library that allows the user to pass in a desired output unit, to resolve these ambiguities. – charliehorse55 Oct 11 '13 at 09:05
  • I think, no matter the library underneath I would have done a layer with the unit-name rules. So that the user can see when writing that it is 80Farads not Farenheit. and allow him to switch between them (and maybe search or build what he needs unitwise). This way you could still use the logic of some pre built library you just need to tack on an extra layer to interface with it and your user. – Rickard Liljeberg Oct 11 '13 at 09:37
  • If the user is entering into a field (labelled "Environment Temperature" for ex), it would make no sense to ask them if they meant Farads or Fahrenheit. – charliehorse55 Oct 11 '13 at 19:37
  • I suppose you can add support in your layer for different types of data. And upon choosing one your ui only shows the user the filtered list. Maybe I'm this case since it's much more likely that only one unit match you might want to only alert the user when there is collisions or a need. – Rickard Liljeberg Oct 12 '13 at 05:37
  • For js-quantities, you could try adding a `Qty.kinds()` function (returns an array of all known `kind` values `["force", "weight", "length"...]`) and a `Qty.getUnits(kind)` function (returns a list of all known unit types for a given `kind` `["meter", "inch", "foot"...]`). – Shadow Man May 28 '14 at 21:10
0

The Google calculator output doesn't seem too difficult to parse.

I would do something like this:

//Parse JSON output to JS variables
    ret = JSON.parse(JSON.stringify({lhs: "5 nanometers",rhs: "5.0 \x26#215; 10\x3csup\x3e-9\x3c/sup\x3e meters",error: "",icc: false} ));

  //ret = Object {lhs: "5 nanometers", rhs: "5.0 &#215; 10<sup>-9</sup> meters", error: "", icc: false}
  var lhs = new Object();
  //Check if lhs has exp notation 
  if (ret.lhs.search("&#215; ")!==-1) {
  //If so, conversion is a bit harder...but not much
  temp = ret.lhs.split("&#215; ");  
  lhs.base = temp[0]

  temp = temp[1].split("<sup>")[1].split("</sup>");
  lhs.exp = temp[0];
  lhs.unit = temp[1];
  lhs.num = parseFloat(lhs.base)*Math.pow(10,parseFloat(lhs.exp));
} else {
  //If no, piece of cake
  temp = ret.lhs.split(" ");  
  lhs.num = parseFloat(temp[0]);
  lhs.unit = temp[1];
}

//Exactly the same for rhs
var rhs = new Object();    
if (ret.rhs.search("&#215; ")!==-1) {

  temp = ret.rhs.split("&#215; ");  
  rhs.base = temp[0]

  temp = temp[1].split("<sup>")[1].split("</sup>");
  rhs.exp = temp[0];
  rhs.unit = temp[1];
  rhs.num = parseFloat(rhs.base)*Math.pow(10,parseFloat(rhs.exp));

} else {
  temp = ret.lhs.split(" ");  
  lhs.num = parseFloat(temp[0]);
  lhs.unit = temp[1];
}

console.log("Converted",lhs.num,lhs.unit,"to",rhs.num,rhs.unit);

Output : Converted 5 nanometers to 5e-9 meters

Since you now have both lhs and rhs as numeric javascript variables and their units as strings, you can format/process them as much as you like.

vinaut
  • 2,416
  • 15
  • 13
0

Have you looked at mathjs?

http://mathjs.org/

It doesn't have derived units yet (I don't believe) but they are working on it. Other than that it's probably the closest thing to what you want.

If you need more functionality specific to your industry of engineering, you'll need to extend a library at some point.

Mike H.
  • 1,731
  • 9
  • 31
  • While this looks promising, it doesn't handle temperatures/degrees very well. Try doing math on temperatures: `2 degC * 2` results in something like `((2 degC in degK) * 2) in degC` rather than `4 degC` and `2 degC - 2 degF` results in something far different from a `2 degF` drop from `2 degC`. It seems to translate all temperatures into a 0-kelvin relative value before doing the math and converting back. – Shadow Man May 28 '14 at 21:30