aboutsummaryrefslogtreecommitdiffstats
path: root/src/animation/Morphable.js
diff options
context:
space:
mode:
Diffstat (limited to 'src/animation/Morphable.js')
-rw-r--r--src/animation/Morphable.js260
1 files changed, 260 insertions, 0 deletions
diff --git a/src/animation/Morphable.js b/src/animation/Morphable.js
new file mode 100644
index 0000000..56ffe95
--- /dev/null
+++ b/src/animation/Morphable.js
@@ -0,0 +1,260 @@
+import { Ease } from './Controller.js'
+import {
+ delimiter,
+ numberAndUnit,
+ pathLetters
+} from '../modules/core/regex.js'
+import { extend } from '../utils/adopter.js'
+import Color from '../types/Color.js'
+import PathArray from '../types/PathArray.js'
+import SVGArray from '../types/SVGArray.js'
+import SVGNumber from '../types/SVGNumber.js'
+
+export default class Morphable {
+ constructor (stepper) {
+ this._stepper = stepper || new Ease('-')
+
+ this._from = null
+ this._to = null
+ this._type = null
+ this._context = null
+ this._morphObj = null
+ }
+
+ from (val) {
+ if (val == null) {
+ return this._from
+ }
+
+ this._from = this._set(val)
+ return this
+ }
+
+ to (val) {
+ if (val == null) {
+ return this._to
+ }
+
+ this._to = this._set(val)
+ return this
+ }
+
+ type (type) {
+ // getter
+ if (type == null) {
+ return this._type
+ }
+
+ // setter
+ this._type = type
+ return this
+ }
+
+ _set (value) {
+ if (!this._type) {
+ var type = typeof value
+
+ if (type === 'number') {
+ this.type(SVGNumber)
+ } else if (type === 'string') {
+ if (Color.isColor(value)) {
+ this.type(Color)
+ } else if (delimiter.test(value)) {
+ this.type(pathLetters.test(value)
+ ? PathArray
+ : SVGArray
+ )
+ } else if (numberAndUnit.test(value)) {
+ this.type(SVGNumber)
+ } else {
+ this.type(NonMorphable)
+ }
+ } else if (morphableTypes.indexOf(value.constructor) > -1) {
+ this.type(value.constructor)
+ } else if (Array.isArray(value)) {
+ this.type(SVGArray)
+ } else if (type === 'object') {
+ this.type(ObjectBag)
+ } else {
+ this.type(NonMorphable)
+ }
+ }
+
+ var result = (new this._type(value))
+ if (this._type === Color) {
+ result = this._to ? result[this._to[4]]()
+ : this._from ? result[this._from[4]]()
+ : result
+ }
+ result = result.toArray()
+
+ this._morphObj = this._morphObj || new this._type()
+ this._context = this._context
+ || Array.apply(null, Array(result.length)).map(Object)
+ return result
+ }
+
+ stepper (stepper) {
+ if (stepper == null) return this._stepper
+ this._stepper = stepper
+ return this
+ }
+
+ done () {
+ var complete = this._context
+ .map(this._stepper.done)
+ .reduce(function (last, curr) {
+ return last && curr
+ }, true)
+ return complete
+ }
+
+ at (pos) {
+ var _this = this
+
+ return this._morphObj.fromArray(
+ this._from.map(function (i, index) {
+ return _this._stepper.step(i, _this._to[index], pos, _this._context[index], _this._context)
+ })
+ )
+ }
+}
+
+export class NonMorphable {
+ constructor (...args) {
+ this.init(...args)
+ }
+
+ init (val) {
+ val = Array.isArray(val) ? val[0] : val
+ this.value = val
+ return this
+ }
+
+ valueOf () {
+ return this.value
+ }
+
+ toArray () {
+ return [ this.value ]
+ }
+}
+
+export class TransformBag {
+ constructor (...args) {
+ this.init(...args)
+ }
+
+ init (obj) {
+ if (Array.isArray(obj)) {
+ obj = {
+ scaleX: obj[0],
+ scaleY: obj[1],
+ shear: obj[2],
+ rotate: obj[3],
+ translateX: obj[4],
+ translateY: obj[5],
+ originX: obj[6],
+ originY: obj[7]
+ }
+ }
+
+ Object.assign(this, TransformBag.defaults, obj)
+ return this
+ }
+
+ toArray () {
+ var v = this
+
+ return [
+ v.scaleX,
+ v.scaleY,
+ v.shear,
+ v.rotate,
+ v.translateX,
+ v.translateY,
+ v.originX,
+ v.originY
+ ]
+ }
+}
+
+TransformBag.defaults = {
+ scaleX: 1,
+ scaleY: 1,
+ shear: 0,
+ rotate: 0,
+ translateX: 0,
+ translateY: 0,
+ originX: 0,
+ originY: 0
+}
+
+export class ObjectBag {
+ constructor (...args) {
+ this.init(...args)
+ }
+
+ init (objOrArr) {
+ this.values = []
+
+ if (Array.isArray(objOrArr)) {
+ this.values = objOrArr
+ return
+ }
+
+ objOrArr = objOrArr || {}
+ var entries = []
+
+ for (let i in objOrArr) {
+ entries.push([i, objOrArr[i]])
+ }
+
+ entries.sort((a, b) => {
+ return a[0] - b[0]
+ })
+
+ this.values = entries.reduce((last, curr) => last.concat(curr), [])
+ return this
+ }
+
+ valueOf () {
+ var obj = {}
+ var arr = this.values
+
+ for (var i = 0, len = arr.length; i < len; i += 2) {
+ obj[arr[i]] = arr[i + 1]
+ }
+
+ return obj
+ }
+
+ toArray () {
+ return this.values
+ }
+}
+
+const morphableTypes = [
+ NonMorphable,
+ TransformBag,
+ ObjectBag
+]
+
+export function registerMorphableType (type = []) {
+ morphableTypes.push(...[].concat(type))
+}
+
+export function makeMorphable () {
+ extend(morphableTypes, {
+ to (val) {
+ return new Morphable()
+ .type(this.constructor)
+ .from(this.valueOf())
+ .to(val)
+ },
+ fromArray (arr) {
+ this.init(arr)
+ return this
+ }
+ })
+}