From 31a2fc66015dcc5be7aa6fba5806f5b1237a81d1 Mon Sep 17 00:00:00 2001 From: Dennis Hergaarden Date: Wed, 13 Dec 2023 09:40:56 +0100 Subject: [PATCH 1/4] Use javascript functions to parse CSSStyle values and remove regex --- src/tweenjs/plugins/CSSPlugin.js | 196 ++++++++++++------------------- 1 file changed, 73 insertions(+), 123 deletions(-) diff --git a/src/tweenjs/plugins/CSSPlugin.js b/src/tweenjs/plugins/CSSPlugin.js index d2f53b1..09f18f2 100644 --- a/src/tweenjs/plugins/CSSPlugin.js +++ b/src/tweenjs/plugins/CSSPlugin.js @@ -30,9 +30,9 @@ * @module TweenJS */ -this.createjs = this.createjs||{}; +this.createjs = this.createjs || {}; -(function() { +(function () { "use strict"; /** @@ -74,18 +74,18 @@ this.createjs = this.createjs||{}; * @constructor **/ function CSSPlugin() { - throw("CSSPlugin cannot be instantiated.") + throw ("CSSPlugin cannot be instantiated.") } var s = CSSPlugin; -// static properties + // static properties /** * @property priority * @protected * @static **/ s.priority = 100; // high priority, should read first and write last - + /** * READ-ONLY. A unique identifying string for this plugin. Used by TweenJS to ensure duplicate plugins are not installed on a tween. * @property ID @@ -94,22 +94,8 @@ this.createjs = this.createjs||{}; * @readonly **/ s.ID = "CSS"; - - /** - * READ-ONLY. - * @property VALUE_RE - * @type {RegExp} - * @static - * @readonly - */ - s.VALUE_RE = /^(-?[\d.]+)([a-z%]*)$/; // extracts the numeric value and suffix from a single CSS value - - s.TRANSFORM_VALUE_RE = /(?:^| |,)(-?[\d.]+)([a-z%]*)/g; // extracts the numeric value and suffix from comma delimited lists - - s.TRANSFORM_RE = /(\w+?)\(([^)]+)\)|(?:^| )(\*)(?:$| )/g; // extracts the components of a transform - - - + + /** * By default, CSSPlugin uses only inline styles on the target element (ie. set via the style attribute, `style` property, or `cssText`) * to determine which properties should be tweened via CSS, and what units to use. @@ -139,13 +125,13 @@ this.createjs = this.createjs||{}; s.compute = false; -// static methods + // static methods /** * Installs this plugin for use with TweenJS. Call this once after TweenJS is loaded to enable this plugin. * @method install * @static **/ - s.install = function() { + s.install = function () { createjs.Tween._installPlugin(CSSPlugin); }; @@ -159,31 +145,36 @@ this.createjs = this.createjs||{}; * @return {any} * @static **/ - s.init = function(tween, prop, value) { + s.init = function (tween, prop, value) { var data = tween.pluginData; if (data.CSS_disabled || !(tween.target instanceof HTMLElement)) { return; } - var initVal = value||getStyle(tween.target, prop, data.CSS_compute); - if (initVal === undefined) { return; } - + var initVal = value || getStyle(tween.target, prop, data.CSS_compute); + + + if (initVal === undefined) { return; } + tween._addPlugin(CSSPlugin); var cssData = data.CSS || (data.CSS = {}); if (prop === "transform") { cssData[prop] = "_t"; return parseTransform(initVal); } - - var result = s.VALUE_RE.exec(initVal); + + let result = null; + if (initVal) + result = CSSNumericValue.parse(initVal); + if (result === null) { // a string we can't handle numerically, so add it to the CSSData without a suffix. cssData[prop] = ""; return initVal; } else { - cssData[prop] = result[2]; - return parseFloat(result[1]); + cssData[prop] = result.unit; + return result.value; } }; - + /** * Called when a new step is added to a tween (ie. a new "to" action is added to a tween). * See {{#crossLink "SamplePlugin/step"}}{{/crossLink}} for more info. @@ -193,7 +184,7 @@ this.createjs = this.createjs||{}; * @param {Object} props * @static **/ - s.step = function(tween, step, props) { + s.step = function (tween, step, props) { if (props.transform) { step.props.transform = parseTransform(step.props.transform, step.prev.props.transform); } @@ -212,7 +203,7 @@ this.createjs = this.createjs||{}; * @return {any} * @static **/ - s.change = function(tween, step, prop, value, ratio, end) { + s.change = function (tween, step, prop, value, ratio, end) { var sfx = tween.pluginData.CSS[prop]; if (sfx === undefined) { return; } if (prop === "transform") { @@ -223,9 +214,9 @@ this.createjs = this.createjs||{}; tween.target.style[prop] = value; return createjs.Tween.IGNORE; }; - - -// private helper methods: + + + // private helper methods: function getStyle(target, prop, compute) { if (compute || (compute == null && s.compute)) { return window.getComputedStyle(target)[prop]; @@ -234,104 +225,63 @@ this.createjs = this.createjs||{}; } } - function parseTransform(str, compare) { - var result, list = [false, str]; - do { - // pull out the next "component" of the transform (ex. "translate(10px, 20px)") - result = s.TRANSFORM_RE.exec(str); - if (!result) { break; } - if (result[3] === "*") { - // reuse previous value: - list.push(compare[list.length]); - continue; - } - var component = [result[1]], compareComp = compare && compare[list.length]; - - // check that the operation type matches (ex. "translate" vs "rotate"): - if (compare && (!compareComp || component[0] !== compareComp[0])) { - console.log("transforms don't match: ", component[0], compareComp&&compareComp[0]); - compare=null; - } // component doesn't match - - parseMulti(result[2], compareComp, component); + const parseTransform = (str, compare) => { + let list = [false]; + let result = CSSStyleValue.parse("transform", str); + list.push(result); - list.push(component); - } while(true); + if (compare && compare.length === result.length) { + for (let i = 0; i < result.length; i++) { + if (compare[1][i].constructor !== result[i].constructor) { + console.log("transforms don't match: ", result[0].constructor.name, compare[1][i].constructor.name); + compare = null; + } // component doesn't match + } + } + // Return false when compare is undefined/null list[0] = !!compare; - return list; - } - - // this was separated so that it can be used for other multi element styles in the future - // ex. transform-origin, border, etc. - function parseMulti(str, compare, arr) { - // TODO: add logic to deal with "0" values? Troublesome because the browser automatically appends a unit for some 0 values. - do { - // pull out the next value (ex. "20px", "12.4rad"): - var result = s.TRANSFORM_VALUE_RE.exec(str); - if (!result) { return arr; } - if (!arr) { arr = []; } - arr.push(+result[1], result[2]); - - // check that the units match (ex. "px" vs "em"): - if (compare && (compare[arr.length-1] !== result[2])) { console.log("transform units don't match: ",arr[0], compare[arr.length-1], result[2]); compare=null; } // unit doesn't match - } while(true); + return (list); } function writeTransform(list0, list1, ratio) { // check if we should just use the original transform strings: - if (ratio === 1) { return list1[1]; } - if (ratio === 0 || !list1[0]) { return list0[1]; } + if (ratio === 1) { return list1[1].toString(); } + if (ratio === 0 || !list1[0]) { return list0[1].toString(); } // they match, we want to apply the ratio: - var str = "", l=list0.length, i, j, jl; - for (i=2; i Date: Wed, 13 Dec 2023 10:08:16 +0100 Subject: [PATCH 2/4] Break on unequal list and better variable naming --- src/tweenjs/plugins/CSSPlugin.js | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/src/tweenjs/plugins/CSSPlugin.js b/src/tweenjs/plugins/CSSPlugin.js index 09f18f2..c04d810 100644 --- a/src/tweenjs/plugins/CSSPlugin.js +++ b/src/tweenjs/plugins/CSSPlugin.js @@ -235,6 +235,7 @@ this.createjs = this.createjs || {}; if (compare[1][i].constructor !== result[i].constructor) { console.log("transforms don't match: ", result[0].constructor.name, compare[1][i].constructor.name); compare = null; + break; } // component doesn't match } } @@ -250,36 +251,36 @@ this.createjs = this.createjs || {}; if (ratio === 0 || !list1[0]) { return list0[1].toString(); } // they match, we want to apply the ratio: - let original = list0[1]; - let modifiedValue = CSSStyleValue.parse("transform", original.toString()); - let newValue = list1[1]; + let startValue = list0[1]; + let newValue = CSSStyleValue.parse("transform", startValue.toString()); + let endValue = list1[1]; // Only works for rotate, scale and translate, skew or metrix do not have x,y,z - for (let i = 0; i < original.length; i++) { - switch (original[i].constructor) { + for (let i = 0; i < startValue.length; i++) { + switch (startValue[i].constructor) { case CSSRotate: - modifiedValue[i].angle.value += (newValue[i].angle.value - original[i].angle.value) * ratio; + newValue[i].angle.value += (endValue[i].angle.value - startValue[i].angle.value) * ratio; // Fall down to CSSScale to set x,y,z case CSSTranslate: // Fall down to CSSScale to set x,y,z case CSSScale: - modifiedValue[i].x.value += (newValue[i].x.value - original[i].x.value) * ratio; - modifiedValue[i].y.value += (newValue[i].y.value - original[i].y.value) * ratio; - modifiedValue[i].z.value += (newValue[i].z.value - original[i].z.value) * ratio; + newValue[i].x.value += (endValue[i].x.value - startValue[i].x.value) * ratio; + newValue[i].y.value += (endValue[i].y.value - startValue[i].y.value) * ratio; + newValue[i].z.value += (endValue[i].z.value - startValue[i].z.value) * ratio; break; case CSSSkew: - modifiedValue[i].ax.value += (newValue[i].ax.value - original[i].ax.value) * ratio; - modifiedValue[i].ay.value += (newValue[i].ay.value - original[i].ay.value) * ratio; + newValue[i].ax.value += (endValue[i].ax.value - startValue[i].ax.value) * ratio; + newValue[i].ay.value += (endValue[i].ay.value - startValue[i].ay.value) * ratio; break; case CSSSkewX: - modifiedValue[i].ax.value += (newValue[i].ax.value - original[i].ax.value) * ratio; + newValue[i].ax.value += (endValue[i].ax.value - startValue[i].ax.value) * ratio; break; case CSSSkewY: - modifiedValue[i].ay.value += (newValue[i].ay.value - original[i].ay.value) * ratio; + newValue[i].ay.value += (endValue[i].ay.value - startValue[i].ay.value) * ratio; break; } } - return modifiedValue.toString(); + return newValue.toString(); } createjs.CSSPlugin = s; From 14c4ae7d0327ffeeb66cdb37b4177b60dbc483ae Mon Sep 17 00:00:00 2001 From: Dennis Hergaarden Date: Fri, 15 Dec 2023 10:05:51 +0100 Subject: [PATCH 3/4] fix values without unit --- src/tweenjs/plugins/CSSPlugin.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/tweenjs/plugins/CSSPlugin.js b/src/tweenjs/plugins/CSSPlugin.js index c04d810..477d2a4 100644 --- a/src/tweenjs/plugins/CSSPlugin.js +++ b/src/tweenjs/plugins/CSSPlugin.js @@ -169,7 +169,11 @@ this.createjs = this.createjs || {}; cssData[prop] = ""; return initVal; } else { - cssData[prop] = result.unit; + if (result.unit == 'number') + cssData[prop] = ''; + else + cssData[prop] = result.unit; + return result.value; } }; From dc992028dc8979d559a2b7817345518bb7e56129 Mon Sep 17 00:00:00 2001 From: Dennis Hergaarden Date: Mon, 18 Dec 2023 08:34:09 +0100 Subject: [PATCH 4/4] add example for CSS plugin --- examples/CSSPlugin_square.html | 36 ++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 examples/CSSPlugin_square.html diff --git a/examples/CSSPlugin_square.html b/examples/CSSPlugin_square.html new file mode 100644 index 0000000..9613259 --- /dev/null +++ b/examples/CSSPlugin_square.html @@ -0,0 +1,36 @@ + + + + + + + + + + + + + \ No newline at end of file