Convert css units

I am trying to return a style property in all valid units of length and percentage converted from the original value set for this property.

For example, if I have a div with style.width equal to 20%, I would like to return an object with this value in percent (of course, 20%), pixels (regardless of the actual pixel width), em, pt, ex, etc. d.

I understand that “percentage” is not a “length” value, and not all properties that accept length values ​​accept a percentage, but also want to include this.

Of course, some values ​​will depend on the specific element and, possibly, its position in the DOM (for example, to obtain the value of em, the size of the calculated size of the parent element will also be required).

I can assume that the style is explicitly set for the element - I know how to get the current calculated style of the element - I just hope not to repeat the work that someone else has already done. I also know http://www.galasoft.ch/myjavascript/WebControls/css-length.html , but it relies on style.pixelWidth or node.clientWidth and doesn’t work in Chrome (I’d assume that it doesn’t work either in Safari ... and possibly others).

I have already received color values ​​(rgb, rgba, hex, name) - this, of course, is much more straightforward. I work with values ​​that are mathematically mutable, so only the values ​​“length” and “percent” are needed (if called in a set of properties with a length, not a percentage value, for example, “font-size: large” - the function may fail or cause an error )

if they are written procedurally, something like this would be ideal:

function getUnits(target, prop){ var value = // get target computed style property value // figure out what unit is being used natively, and it values - for this eg, 100px var units = {}; units.pixel = 100; units.percent = 50; // eg, if the prop was height and the parent was 200px tall units.inch = 1.39; // presumably units.pixel / 72 would work, but i'm not positive units.point = units.inch / 72; units.pica = units.point * 12; // etc... return units; } 

I do not ask someone to write code for me, but I hope that someone has already done this before, and it is available in some open source library, in the framework, in the blog, anyway. otherwise, if someone has a clever idea on how to optimize the process, that would be great (the author of the link above created a temporary div and calculated one value to determine the coefficients for the other units - a convenient idea, but not for sale completely, and definitely one that needs additional logic to handle everything that I hope agrees on).

in advance for any information or suggestions.

+4
source share
3 answers

EDIT: updated so that the user can select the unit that needs to be returned (for example, exists as%, go back to px) - a significant performance improvement for when it is enough - can lead to its change, just to accept the unit to convert and get rid of from cycles. Thanks for eternity for his help. / EDIT

this is what I came up with - after preliminary testing it works. I borrowed a temporary idea of ​​a div from the link mentioned in the original question, but this is about everything that was taken from this other class.

if anyone has any input or improvement, I would be happy to hear that.

  (function(){ // pass to string.replace for camel to hyphen var hyphenate = function(a, b, c){ return b + "-" + c.toLowerCase(); } // get computed style property var getStyle = function(target, prop){ if(prop in target.style){ // if it explicitly assigned, just grab that if(!!(target.style[prop]) || target.style[prop] === 0){ return target.style[prop]; } } if(window.getComputedStyle){ // gecko and webkit prop = prop.replace(/([az])([AZ])/, hyphenate); // requires hyphenated, not camel return window.getComputedStyle(target, null).getPropertyValue(prop); } if(target.currentStyle){ // ie return target.currentStyle[prop]; } return null; } // get object with units var getUnits = function(target, prop, returnUnit){ var baseline = 100; // any number serves var item; // generic iterator var map = { // list of all units and their identifying string pixel : "px", percent : "%", inch : "in", cm : "cm", mm : "mm", point : "pt", pica : "pc", em : "em", ex : "ex" }; var factors = {}; // holds ratios var units = {}; // holds calculated values var value = getStyle(target, prop); // get the computed style value var numeric = value.match(/\d+/); // get the numeric component if(numeric === null) { // if match returns null, throw error... use === so 0 values are accepted throw "Invalid property value returned"; } numeric = numeric[0]; // get the string var unit = value.match(/\D+$/); // get the existing unit unit = (unit == null) ? "px" : unit[0]; // if its not set, assume px - otherwise grab string var activeMap; // a reference to the map key for the existing unit for(item in map){ if(map[item] == unit){ activeMap = item; break; } } if(!activeMap) { // if existing unit isn't in the map, throw an error throw "Unit not found in map"; } var singleUnit = false; // return object (all units) or string (one unit)? if(returnUnit && (typeof returnUnit == "string")) { // if user wants only one unit returned, delete other maps for(item in map){ if(map[item] == returnUnit){ singleUnit = item; continue; } delete map[item]; } } var temp = document.createElement("div"); // create temporary element temp.style.overflow = "hidden"; // in case baseline is set too low temp.style.visibility = "hidden"; // no need to show it target.parentNode.appendChild(temp); // insert it into the parent for em and ex for(item in map){ // set the style for each unit, then calculate it relative value against the baseline temp.style.width = baseline + map[item]; factors[item] = baseline / temp.offsetWidth; } for(item in map){ // use the ratios figured in the above loop to determine converted values units[item] = (numeric * (factors[item] * factors[activeMap])) + map[item]; } target.parentNode.removeChild(temp); // clean up if(singleUnit !== false){ // if they just want one unit back return units[singleUnit]; } return units; // returns the object with converted unit values... } // expose window.getUnits = this.getUnits = getUnits; })(); 

tyia

+4
source

Émile does this, in particular in the parse function:

 function parse(prop){ var p = parseFloat(prop), q = prop.replace(/^[\-\d\.]+/,''); return isNaN(p) ? { v: q, f: color, u: ''} : { v: p, f: interpolate, u: q }; } 

The prop argument is a computed Style for some element. The returned object has the v (value) property, the f method, which is used later for animation, and the u (unit, if necessary) property.

This does not fully answer the question, but it may be the beginning.

+1
source

Check out Units , the JavaScript library that performs these conversions.

Here's a blog post by the author describing the code.

+1
source

Source: https://habr.com/ru/post/1333121/


All Articles