diff --git a/README.md b/README.md
index 9fa9ce7..70b3833 100644
--- a/README.md
+++ b/README.md
@@ -5,7 +5,7 @@ The name **rAF** is a common abbreviation for the core JavaScript animation func
It is a solo open source project about to be released in its first public version 1.0. Hopefully others will contribute in the future.
## Getting started
-If you want to skip the formalities and jump right in, the best place to start are the 3 Apps (latest code on GitHub Pages) that test & demonstrate the library and generate starting-point JavaScript code. They are also available in a more stable form on my homepage.
+If you want to skip the formalities and jump right in, the best place to start are the 3 Apps (latest code on GitHub Pages) that test & demonstrate the library and generate starting-point JavaScript code. They are also available in a more sta(b)le form on my homepage.
There are also animation examples in these collections on CodePen:
@@ -14,7 +14,7 @@ There are also animation examples in these collections on CodePen:
Properties and Methods by Class catalogs classes and constants you might want to use. The current state of documentation is skeletal. Hopefully the examples, apps, and app instructions will help to fill to fill things in.
## Setup
-**rAF** is modular. There are currently no packages or minified file. Should be coming your way soon after v1.0. For most users, `raf.js` provides all the exports you need. Here is a typical import statement:
+**rAF** is modular. There are currently no packages and no transpiled or minified file. Coming your way soon as part of v1.0. For most users, `raf.js` provides all the exports you need. Here is a typical import statement:
```
import {E, Ez, F, P, Easy, Easies, AFrame, rAFInit} from "https://sidewayss.com/raf/src/raf.js";
```
@@ -28,13 +28,13 @@ It initializes constants that are used internally, many of which you will use to
**rAF** provides a flexible, structured, and compact way to create and execute CSS or SVG animations of two types:
- Gradual value changes controlled by timing patterns
- Cue-based animations, where timing cues trigger animation events that can span elements and properties
-It also provides an alternate paradigm for setting properties/attributes where the property sets the value on the element, not the other way around. There are advantages.
+- An alternate paradigm for setting properties/attributes, where the property sets the value on the element, not the other way around. There are advantages.
Features CSS doesn't have:
-- Multiple timing patterns for a single property, within and across functions
+- Multiple timing patterns for a single property, by argument, within and across functions
- Eased steps, for timing and values separately
- Max and min limits by argument by element
-- Animate the same property differently across elements in a single animation
+- Animate the same property differently across elements in a single animation, sharing the timing function or not
- Color.js integration
- For two-legged easings:
- Not just `inOut`, there are `outIn`, `inIn`, and `outOut` settings
@@ -48,7 +48,7 @@ Goals, Assumptions, and Approach:
- Allow for the animation of every property/attribute and function in full detail
- Create a minimal syntax that is both flexible and forgiving
- Make it fully object-oriented within the confines of JavaScript
-- Assume a “modern browser” that supports ES6*
+- Assume a “modern browser” that supports ES6*, but transpile back to wherever is plausible
- Build in callbacks for flexibility and the ability to meet as-yet-unknown requirements
- Create a way to test user GPU power and develop methods for handling low-end vs high-end GPUs
diff --git a/apps/color/_load.js b/apps/color/_load.js
index 8efa97d..e6ac1f8 100644
--- a/apps/color/_load.js
+++ b/apps/color/_load.js
@@ -110,7 +110,6 @@ function load(_, hasVisited) {
clone.id = sib.id // dummy element contains id and keeps the grid
elms[sib.id] = clone; // from reflowing via replaceWith().
clone.style.marginLeft = sib.style.marginLeft;
- g.disables.splice(g.disables.indexOf(sib), 1, clone);
sib.replaceWith(clone);
// initialize elms:
[EASY_, MEASER_].forEach((v, i) => elms.type.options[i].value = v);
diff --git a/apps/common.css b/apps/common.css
index e58750c..f09f020 100644
--- a/apps/common.css
+++ b/apps/common.css
@@ -91,8 +91,8 @@ select, input[type=number] {
background-color:var(--sidebar-white);
border:var(--border-gray);
}
-input[type=text] {
- caret-color:black;
+input[type=text], input-num {
+ caret-color:auto;
}
input.invalid {
background-color:rgb(139 0 0 / 0.1); /* background-opacity does not exist */
@@ -184,8 +184,7 @@ check-box, check-tri {
}
check-box[disabled], check-box[disabled][checked],
check-tri[disabled], check-tri[disabled][checked],
-label[disabled],
-select:disabled {
+label[disabled], select:disabled {
stroke:var(--medium-gray);
color: var(--medium-gray);
}
diff --git a/apps/easings/_load.js b/apps/easings/_load.js
index e5659e1..396a330 100644
--- a/apps/easings/_load.js
+++ b/apps/easings/_load.js
@@ -124,7 +124,7 @@ function getEasies(_, json) {
ease = Ease.ease[0][id], // default CSS "ease" as bezier array
size = ease.length;
- for (i = 1; i < size; i++) // clone sub-
+ for (i = 1; i < size; i++) // clone bezier sub-
divs.push(div.appendChild(elm.cloneNode(true)));
const titles = json.titles;
diff --git a/apps/easings/index.css b/apps/easings/index.css
index 63c608a..11932cb 100644
--- a/apps/easings/index.css
+++ b/apps/easings/index.css
@@ -63,13 +63,6 @@ p.hi { font-weight:500; }
padding-top:var(--8th);
}
-/* Numeric inputs are messy */
-input[type=number] {
- text-align:right;
- padding-left: 0;
- padding-right:0;
- caret-color:black;
-}
#v0, #v1, #v2 {
width:calc(3ch + 1.75rem);
}
@@ -291,24 +284,8 @@ circle {
.w5ch { width:5.35ch; } /* .35 for #mid alignment at font-size:100% */
.w6ch { width:6.5ch; }
.w7ch { width:7.5ch; }
- input[type=number].secs {
- text-align:left;
- padding-left:0.3125rem;
- }
- input[type=number].secs:not(:hover, :focus) {
- -moz-appearance:textfield;
- }
}
@supports (hanging-punctuation:first) and (font:-apple-system-body)
and (-webkit-appearance:none) {
- input[type=number].secs {
- text-align:left;
- padding-left:0.3125rem;
- }
- input[type=number].secs:not(:hover, :focus)::-webkit-outer-spin-button,
- input[type=number].secs:not(:hover, :focus)::-webkit-inner-spin-button {
- -webkit-appearance: none;
- margin: 0;
- }
.clear { font-weight:normal; }
}
\ No newline at end of file
diff --git a/apps/easings/msg.js b/apps/easings/msg.js
index 3046614..670cd4a 100644
--- a/apps/easings/msg.js
+++ b/apps/easings/msg.js
@@ -6,6 +6,7 @@ export const MSG = ["mid","split","gap"];
import {Ez, P} from "../../src/raf.js";
import {msecs, secs} from "../update.js";
+import {abled} from "../named.js";
import {MILLI, BUTTON, DIV, CLICK, CHANGE, elms, addEventToElms,
addEventsByElm, addEventByClass, boolToString}
from "../common.js";
@@ -152,8 +153,7 @@ function setSplitGap(time = msecs,
// disableClear() helps changeMSG() and clickClear(), also called by
// easingFromObj(), returns a factor/divisor.
function disableClear(elm, n, isDefN) {
- elm.clear.disabled = !isDefN || n == elm.default();
- elm.clear.dataset.enabled = boolToString(!elm.clear.disabled);
+ abled(elm.clear, !isDefN || n == elm.default())
}
// isUnlocked() helps clickLock() and setSplitGap();
function isUnlocked(elm) { // not exported
diff --git a/apps/easings/tio-pow.js b/apps/easings/tio-pow.js
index c663009..6b6cb63 100644
--- a/apps/easings/tio-pow.js
+++ b/apps/easings/tio-pow.js
@@ -31,7 +31,6 @@ function loadTIOPow() {
elms[sel.id] = sel;
elms.divType2.appendChild(sel);
- g.disables.push(sel);
for ([id, evt] of [[TYPE, INPUT], [POW, CHANGE]]) {
two = [elms[id], elms[id + TWO]];
diff --git a/apps/load.js b/apps/load.js
index c00687c..d07a24f 100644
--- a/apps/load.js
+++ b/apps/load.js
@@ -45,7 +45,7 @@ function loadCommon() {
arr = byTag[2].splice(-3, 3); // break out
* display-p3 and rec2020 use RGB nomenclature
diff --git a/docs/raf.xlsx b/docs/raf.xlsx
index 2dc1c38..dbabf33 100644
Binary files a/docs/raf.xlsx and b/docs/raf.xlsx differ
diff --git a/src/alt/easy-steps.js b/src/alt/easy-steps.js
new file mode 100644
index 0000000..3eeb63a
--- /dev/null
+++ b/src/alt/easy-steps.js
@@ -0,0 +1,105 @@
+// Not exported by raf.js
+export {stepsToLegs};
+
+import {legUnit} from "./easy-construct.js"
+
+import {E} from "../globals.js";
+import {Ez} from "../ez.js";
+import {Easy} from "../easy/easy.js";
+
+//==============================================================================
+// stepsToLegs() helps _finishLegs() turn 1 leg into >1 legs for _calc()
+function stepsToLegs(o, leg, legDist, dist, idx, last, keys) {
+ let ends, waits;
+ const t = "timing"; // not "time"
+ if (leg.timingReady) // leg.timing is an array of wait times
+ waits = leg[t];
+ else if (leg[t]) // leg.timing is an Easy instance
+ waits = easeSteps(leg[t], leg.waits, 1, 0, leg.time, t, true);
+ else // leg.timing is undefined
+ waits = leg.waits.map(v => v * leg.time);
+ // leg.waits is 0-1, portion of time
+ let l = waits.length;
+ const LENGTH = {length:l};
+ if (leg.stepsReady) // leg.steps is already an array of step values
+ ends = leg.steps;
+ else if (leg.easy) // generate eased steps
+ ends = easeSteps(leg.easy, waits, leg.time, leg.start, legDist, "easy");
+ else {
+ const d = legDist / l; // generate linear steps
+ ends = Array.from(LENGTH, (_, i) => leg.start + (d * (i + 1)));
+ }
+ // transform the steps into legs:
+ const
+ start = o.start,
+ legs = Array.from(LENGTH, () => new Object);
+ legs.forEach((lg, i) => {
+ lg.type = E.steps;
+ lg.io = E.in; // must be defined
+ lg.end = ends[i]; // the step value
+ legUnit(lg, start, dist, keys);
+ lg.prev = legs[i - 1];
+ lg.next = legs[i + 1];
+ lg.time = 0; // steps don't have a duration
+ lg.wait = waits[i] - (i ? waits[i - 1] : 0);
+ });
+ if (leg.wait)
+ legs[0].wait += leg.wait;
+
+ const obj = {};
+ if (idx == 0) // _firstLeg
+ obj.firstLeg = legs[0];
+ else { // replace leg in the linked list
+ legs[0].prev = leg.prev;
+ leg.prev.next = legs[0];
+ }
+ --l;
+ const leftover = leg.time - waits[l];
+ legs[l].leftover = leftover;
+ if (idx == last) { // #lastLeg
+ o.end = legs[l].end;
+ //!!o.time -= leftover;
+ obj.lastLeg = legs[l];
+ }
+ else { // continue to replace leg in the list
+ legs[l].next = leg.next;
+ leg.next.prev = legs[l];
+ leg.next.wait += leftover;
+ }
+ return obj;
+}
+// easeSteps() helps stepsToLegs() use an Easy to set the timing or
+// values for E.steps. ez cannot be E.increment here because it has
+// either no end, or no duration; and its legs cannot be E.steps, to
+// avoid infinite easeSteps loops and because not-eased is linear or
+// fixed values, which is pointless.
+// For eased values, jump:E.start has no effect because time=0 produces
+// value=0. So E.start is the same as E.none, E.end same as E.both.
+function easeSteps(ez, nows, time, start, dist, name, isTiming) {
+ Easy._validate(ez, name); // phase 1 validation
+ if (ez.isIncremental) // phase 2: can't be E.increment
+ Ez._cantBeErr(name, "class Incremental");
+ //------------------------------------------
+ let leg = ez._firstLeg;
+ const ezDown = ez.end < ez.start;
+ do { // for each leg:
+ if (leg.type == E.steps) // phase 3: can't be E.steps
+ Ez._cantBeErr(name, "type:E.steps");
+ if (isTiming && (ezDown != leg.end < leg.start
+ || (leg.type >= E.back && leg.type <= E.bounce)
+ || (leg.type == E.bezier && Ez.unitOutOfBounds(leg.bezier.array))))
+ Ez._cantBeErr( // phase 4: can't mix directions
+ name,
+ "an Easy that changes direction. Time only moves in one direction",
+ {cause:"reverse time"} // better *not* as string...
+ );
+ } while((leg = leg.next));
+ //------------------------------------------// validation complete
+ ez._zeroOut(0); // prep for pseudo-animation
+ const d = time / ez.time; // d for divisor
+ const prop = ezDown ? E.comp : E.unit; // nows always ascends
+ return nows.map(v => {
+ ez._easeMe(v / d);
+ return start + (ez.e[prop] * dist);
+ });
+}
\ No newline at end of file