From 858f19e9f8b9ba26eee8d3aeb8ba8b5b5058472b Mon Sep 17 00:00:00 2001 From: Ulrich-Matthias Schäfer Date: Sat, 24 Nov 2018 11:17:13 +0100 Subject: Get rid of HTMLNode and Bare in favor of Dom - words() and element() added to Dom - svg() now returns the _parent_ of the imported element, when outerHTML is true (which means an element gets replaces) --- src/animation/Morphable.js | 246 +++++++++++++++++++++++++++++++++++++++++++++ src/animation/Runner.js | 2 +- src/elements/Bare.js | 31 ------ src/elements/Dom.js | 15 ++- src/elements/HtmlNode.js | 6 -- src/elements/Style.js | 6 +- src/main.js | 4 +- src/types/Morphable.js | 246 --------------------------------------------- src/utils/adopter.js | 11 +- 9 files changed, 269 insertions(+), 298 deletions(-) create mode 100644 src/animation/Morphable.js delete mode 100644 src/elements/Bare.js delete mode 100644 src/elements/HtmlNode.js delete mode 100644 src/types/Morphable.js (limited to 'src') diff --git a/src/animation/Morphable.js b/src/animation/Morphable.js new file mode 100644 index 0000000..a02ba31 --- /dev/null +++ b/src/animation/Morphable.js @@ -0,0 +1,246 @@ +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)).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 + } + + var entries = Object.entries(objOrArr || {}).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 + } + }) +} diff --git a/src/animation/Runner.js b/src/animation/Runner.js index 5551162..bb8d5e7 100644 --- a/src/animation/Runner.js +++ b/src/animation/Runner.js @@ -9,7 +9,7 @@ import Animator from './Animator.js' import Box from '../types/Box.js' import EventTarget from '../types/EventTarget.js' import Matrix from '../types/Matrix.js' -import Morphable, { TransformBag } from '../types/Morphable.js' +import Morphable, { TransformBag } from './Morphable.js' import Point from '../types/Point.js' import SVGNumber from '../types/SVGNumber.js' import Timeline from './Timeline.js' diff --git a/src/elements/Bare.js b/src/elements/Bare.js deleted file mode 100644 index a057634..0000000 --- a/src/elements/Bare.js +++ /dev/null @@ -1,31 +0,0 @@ -import { nodeOrNew, register, wrapWithAttrCheck } from '../utils/adopter.js' -import { registerMethods } from '../utils/methods.js' -import Container from './Container.js' -import { globals } from '../utils/window.js' - -export default class Bare extends Container { - constructor (node, attrs) { - super(nodeOrNew(node, typeof node === 'string' ? null : node), attrs) - } - - words (text) { - // remove contents - while (this.node.hasChildNodes()) { - this.node.removeChild(this.node.lastChild) - } - - // create text node - this.node.appendChild(globals.document.createTextNode(text)) - - return this - } -} - -register(Bare) - -registerMethods('Container', { - // Create an element that is not described by SVG.js - element: wrapWithAttrCheck(function (node) { - return this.put(new Bare(node)) - }) -}) diff --git a/src/elements/Dom.js b/src/elements/Dom.js index 2fcedce..5d7dbac 100644 --- a/src/elements/Dom.js +++ b/src/elements/Dom.js @@ -4,6 +4,7 @@ import { eid, extend, makeInstance, + makeNode, register } from '../utils/adopter.js' import { find } from '../modules/core/selector' @@ -88,6 +89,10 @@ export default class Dom extends EventTarget { return this } + element (nodeName) { + return this.put(new Dom(makeNode(nodeName))) + } + // Get first child first () { return adopt(this.node.firstChild) @@ -285,12 +290,20 @@ export default class Dom extends EventTarget { fragment.appendChild(well.firstElementChild) } + let parent = this.parent() + // Add the whole fragment at once return outerHTML - ? this.replace(fragment) + ? this.replace(fragment) && parent : this.add(fragment) } + words (text) { + // This is faster than removing all children and adding a new one + this.node.textContent = text + return this + } + // write svgjs data to the dom writeDataToDom () { // dump variables recursively diff --git a/src/elements/HtmlNode.js b/src/elements/HtmlNode.js deleted file mode 100644 index 009b122..0000000 --- a/src/elements/HtmlNode.js +++ /dev/null @@ -1,6 +0,0 @@ -import { register } from '../utils/adopter.js' -import Dom from './Dom.js' - -export default class HtmlNode extends Dom {} - -register(HtmlNode) diff --git a/src/elements/Style.js b/src/elements/Style.js index 50ec50e..0b1cdb7 100644 --- a/src/elements/Style.js +++ b/src/elements/Style.js @@ -23,8 +23,8 @@ export default class Style extends Element { super(nodeOrNew('style', node), node) } - words (w) { - this.node.textContent += (w || '') + addText (w = '') { + this.node.textContent += w return this } @@ -37,7 +37,7 @@ export default class Style extends Element { } rule (selector, obj) { - return this.words(cssRule(selector, obj)) + return this.addText(cssRule(selector, obj)) } } diff --git a/src/main.js b/src/main.js index 919fb25..696dfdd 100644 --- a/src/main.js +++ b/src/main.js @@ -30,7 +30,7 @@ import Morphable, { TransformBag, makeMorphable, registerMorphableType -} from './types/Morphable.js' +} from './animation/Morphable.js' import Path from './elements/Path.js' import PathArray from './types/PathArray.js' import Pattern from './elements/Pattern.js' @@ -85,7 +85,6 @@ export { default as PointArray } from './types/PointArray.js' export { default as List } from './types/List.js' /* Elements */ -export { default as Bare } from './elements/Bare.js' export { default as Circle } from './elements/Circle.js' export { default as ClipPath } from './elements/ClipPath.js' export { default as Container } from './elements/Container.js' @@ -95,7 +94,6 @@ export { default as Element } from './elements/Element.js' export { default as Ellipse } from './elements/Ellipse.js' export { default as Gradient } from './elements/Gradient.js' export { default as G } from './elements/G.js' -export { default as HtmlNode } from './elements/HtmlNode.js' export { default as A } from './elements/A.js' export { default as Image } from './elements/Image.js' export { default as Line } from './elements/Line.js' diff --git a/src/types/Morphable.js b/src/types/Morphable.js deleted file mode 100644 index 703cc00..0000000 --- a/src/types/Morphable.js +++ /dev/null @@ -1,246 +0,0 @@ -import { Ease } from '../animation/Controller.js' -import { - delimiter, - numberAndUnit, - pathLetters -} from '../modules/core/regex.js' -import { extend } from '../utils/adopter.js' -import Color from './Color.js' -import PathArray from './PathArray.js' -import SVGArray from './SVGArray.js' -import SVGNumber from './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)).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 - } - - var entries = Object.entries(objOrArr || {}).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 - } - }) -} diff --git a/src/utils/adopter.js b/src/utils/adopter.js index 6109f22..52d589e 100644 --- a/src/utils/adopter.js +++ b/src/utils/adopter.js @@ -50,19 +50,16 @@ export function adopt (node) { // make sure a node isn't already adopted if (node.instance instanceof Base) return node.instance - if (!(node instanceof globals.window.SVGElement)) { - return new elements.HtmlNode(node) - } - // initialize variables var className = capitalize(node.nodeName) + // Make sure that gradients are adopted correctly if (className === 'LinearGradient' || className === 'RadialGradient') { className = 'Gradient' - } - if (!elements[className]) { - className = 'Bare' + // Fallback to Dom if element is not known + } else if (!elements[className]) { + className = 'Dom' } return new elements[className](node) -- cgit v1.2.3