import { Ease } from './Controller.js' import { delimiter, numberAndUnit, isPathLetter } 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' const getClassForType = (value) => { const type = typeof value if (type === 'number') { return SVGNumber } else if (type === 'string') { if (Color.isColor(value)) { return Color } else if (delimiter.test(value)) { return isPathLetter.test(value) ? PathArray : SVGArray } else if (numberAndUnit.test(value)) { return SVGNumber } else { return NonMorphable } } else if (morphableTypes.indexOf(value.constructor) > -1) { return value.constructor } else if (Array.isArray(value)) { return SVGArray } else if (type === 'object') { return ObjectBag } else { return NonMorphable } } 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 } 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) }) ) } done () { var complete = this._context .map(this._stepper.done) .reduce(function (last, curr) { return last && curr }, true) return complete } from (val) { if (val == null) { return this._from } this._from = this._set(val) return this } stepper (stepper) { if (stepper == null) return this._stepper this._stepper = stepper 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) { this.type(getClassForType(value)) } var result = (new this._type(value)) if (this._type === Color) { result = this._to ? result[this._to[4]]() : this._from ? result[this._from[4]]() : result } if (this._type === ObjectBag) { result = this._to ? result.align(this._to) : this._from ? result.align(this._from) : result } result = result.toArray() this._morphObj = this._morphObj || new this._type() this._context = this._context || Array.apply(null, Array(result.length)) .map(Object) .map(function (o) { o.done = true return o }) return result } } export class NonMorphable { constructor (...args) { this.init(...args) } init (val) { val = Array.isArray(val) ? val[0] : val this.value = val return this } toArray () { return [ this.value ] } valueOf () { 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 } const sortByKey = (a, b) => { return (a[0] < b[0] ? -1 : (a[0] > b[0] ? 1 : 0)) } export class ObjectBag { constructor (...args) { this.init(...args) } align (other) { for (let i = 0, il = this.values.length; i < il; ++i) { if (this.values[i] === Color) { const space = other[i + 6] const color = new Color(this.values.splice(i + 2, 5))[space]().toArray() this.values.splice(i + 2, 0, ...color) } } return this } init (objOrArr) { this.values = [] if (Array.isArray(objOrArr)) { this.values = objOrArr.slice() return } objOrArr = objOrArr || {} var entries = [] for (const i in objOrArr) { const Type = getClassForType(objOrArr[i]) const val = new Type(objOrArr[i]).toArray() entries.push([ i, Type, val.length, ...val ]) } entries.sort(sortByKey) this.values = entries.reduce((last, curr) => last.concat(curr), []) return this } toArray () { return this.values } valueOf () { var obj = {} var arr = this.values // for (var i = 0, len = arr.length; i < len; i += 2) { while (arr.length) { const key = arr.shift() const Type = arr.shift() const num = arr.shift() const values = arr.splice(0, num) obj[key] = new Type(values).valueOf() } return obj } } 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 } }) }