Skip to content

Instantly share code, notes, and snippets.

@ceane
Created October 21, 2015 04:34
Show Gist options
  • Save ceane/3c72753577c5a199ef06 to your computer and use it in GitHub Desktop.
Save ceane/3c72753577c5a199ef06 to your computer and use it in GitHub Desktop.
Unfinished calcSizeOrPosition function (finished elsewhere...)
import ExpressionParser from "ExpressionParser";
const add = (a, b) => a + b;
const subtract = (a, b) => a - b;
const multiply = (a, b) => a * b;
const divide = (a, b) = > b == 0 ? 0 : a / b;
function calcSizeOrPosition(sizeOrPosition, child, parent) {
child = child || [0, 0];
parent = parent || [0, 0];
var cw = child[0];
var ch = child[1];
var pw = parent[0];
var ph = parent[1];
var parsed = new ExpressionParser(sizeOrPosition);
var innerWidth = window.innerWidth;
var innerHeight = window.innerHeight;
var fontSize = 16;
var vmin = innerWidth > innerHeight ? innerHeight : innerWidth;
var vmax = innerWidth > innerHeight ? innerWidth : innerHeight;
var isReversed = false;
var finalPositionOrSize = 0;
var operation = add;
for (var i = 0, len = parsed.length; i < len; i++) {
var item = parsed[i];
var axis = isReversed ? i > 1 : i < 1;
var childAxisLength = axis ? cw : ch;
var parentAxisLength = axis ? pw : ph;
switch (item.unit) {
case "-":
operation = subtractOperation;
continue;
case CSS_UNITS.ZERO:
case CSS_UNITS.PIXELS:
finalPositionOrSize = operation(item.value);
break;
case CSS_UNITS.PERCENTAGE:
finalPositionOrSize = operation(item.value / 100 * parentAxisLength);
break;
case CSS_UNITS.VW:
finalPositionOrSize = operation(item.value / 100 * innerWidth);
break;
case CSS_UNITS.VH:
finalPositionOrSize = operation(item.value / 100 * innerHeight);
break;
case CSS_UNITS.VMIN:
finalPositionOrSize = operation(item.value / 100 * vmin);
break;
case CSS_UNITS.VMAX:
finalPositionOrSize = operation(item.value / 100 * vmax);
break;
case CSS_UNITS.EMS:
finalPositionOrSize = operation(item.value * fontSize * 0.75);
break;
case CSS_UNITS.INHERIT:
finalPositionOrSize = operation(parentAxisLength);
break;
case CSS_POSITION.CENTER:
finalPositionOrSize =
operation((parentAxisLength - childAxisLength) / 2);
break;
case CSS_POSITION.RIGHT:
case CSS_POSITION.BOTTOM:
finalPositionOrSize = operation(parentAxisLength - childAxisLength);
break;
case CSS_POSITION.LEFT:
case CSS_POSITION.TOP:
finalPositionOrSize += 0;
break;
}
operation = addOperation;
}
return finalPositionOrSize;
}
// EXAMPLE
let elementSize = [100, 100];
let elementParentSize = [200, 200];
let size = calcSizeOrPosition("calc(100vw - 20px) 500px", elementSize, elementParentSize);
let position = calcSizeOrPosition("center center", size, elementParentSize);
function actual(l, r, o) {
switch(r) {
case "px":
return l;
case "vw":
case "%":
return (l / 100) * window.innerWidth;
case "vh":
return (l / 100) * window.innerHeight;
}
}
var testExpression = new ExpressionParser("calc(100vw - (-10px) * 500px)", actual);
for (var val of testExpression) console.log(val);
// Remove default params and destructuring and add "use strict" to test in Chrome 46
const toFloat = (lhs) => parseFloat(lhs.replace(/[^-\d.]+/, ""));
export default class ExpressionParser {
constructor(str, fn = toFloat, _depth = 0) {
Object.assign(this, { _depth, fn, str });
}
*[Symbol.iterator]() {
var match;
var { _depth, fn, str } = this;
const depth = _depth;
while (match = ExpressionParser.VALUE_DELIMITER.exec(this.str)) {
let [a] = match;
if (a && a.length === 1 && ExpressionParser.SKIPPED_TOKENS.test(a)) {
continue;
}
/*if (skip && a && skip.test(a)) {
ops = { value: a, depth: this.depth };
continue;
} else if (/[^(]+\(/.test(a)) {
ops = Object.assign(ops, { type: a.replace(/\([^(]+/, "") });
}*/
let externalLhs = ExpressionParser.EXPRESSION_EXTERNAL_LHS.test(a) && {
expressionType: a.replace(/\([^(]+/g, "")
};
let cleaned = a.replace(ExpressionParser.EXPRESSION_INNER, "");
if (ExpressionParser.IS_EXPRESSION.test(a)) {
yield* new ExpressionParser(cleaned, fn, _depth++);
} else {
var [lhs, rhs] = cleaned.split(ExpressionParser.LHS_DELIMITER);
let valueOf = fn.bind(null, lhs, rhs, externalLhs); // Is this name a good idea?
yield { lhs, rhs, depth, valueOf };
}
}
}
}
ExpressionParser.SKIPPED_TOKENS = /[\*\+\-\/]/;
ExpressionParser.IS_EXPRESSION = /\(.+\).*/;
ExpressionParser.VALUE_DELIMITER = /\S+/g;
ExpressionParser.LHS_DELIMITER = /('[^']*'|"[^"]*"|[^-\d.]+)/;
ExpressionParser.EXPRESSION_INNER = /(^[^(]*\()|([\)]+[^)]*$)/g;
ExpressionParser.EXPRESSION_EXTERNAL_LHS = /(?:[^(]+)\([^(]+/;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment