summaryrefslogtreecommitdiffstats
path: root/src/types
diff options
context:
space:
mode:
authorSaivan <savian@me.com>2018-11-25 16:21:53 +1300
committerSaivan <savian@me.com>2018-11-25 16:21:53 +1300
commit62de7d0a1b994b69032a759b796b486e6bc382e3 (patch)
tree112b19f2903b4dc5b4cf61ebef0d021c6ca2f14d /src/types
parent2b37d7ba5b4267b39c86f9aba5fb14a1b376e846 (diff)
downloadsvg.js-62de7d0a1b994b69032a759b796b486e6bc382e3.tar.gz
svg.js-62de7d0a1b994b69032a759b796b486e6bc382e3.zip
Changed the esLint rules to avoid silly ternary operators, and to let code breathe!
This commit modifies some of the eslint rules, to allow our code to be a little bit more readable. This came about because we had a particularly pesky problem, where the code was indenting ternary operators. This fixes that, and makes it easy to add new rules to eslint as we please in the future. Changes ======= - Rebuilt the library with new eslint rules - Changed the eslintrc file to a yaml file by default
Diffstat (limited to 'src/types')
-rw-r--r--src/types/ArrayPolyfill.js34
-rw-r--r--src/types/Box.js152
-rw-r--r--src/types/EventTarget.js50
-rw-r--r--src/types/List.js58
-rw-r--r--src/types/Matrix.js382
-rw-r--r--src/types/Morphable.js232
-rw-r--r--src/types/PathArray.js338
-rw-r--r--src/types/Point.js36
-rw-r--r--src/types/PointArray.js104
-rw-r--r--src/types/SVGArray.js48
-rw-r--r--src/types/SVGNumber.js94
11 files changed, 1022 insertions, 506 deletions
diff --git a/src/types/ArrayPolyfill.js b/src/types/ArrayPolyfill.js
index 4d2309f..0ee29a5 100644
--- a/src/types/ArrayPolyfill.js
+++ b/src/types/ArrayPolyfill.js
@@ -1,8 +1,10 @@
/* eslint no-new-func: "off" */
-export const subClassArray = (function () {
+export const subClassArray = ( function () {
+
try {
+
// try es6 subclassing
- return Function('name', 'baseClass', '_constructor', [
+ return Function( 'name', 'baseClass', '_constructor', [
'baseClass = baseClass || Array',
'return {',
' [name]: class extends baseClass {',
@@ -12,25 +14,35 @@ export const subClassArray = (function () {
' }',
' }',
'}[name]'
- ].join('\n'))
- } catch (e) {
+ ].join( '\n' ) )
+
+ } catch ( e ) {
+
// Use es5 approach
- return (name, baseClass = Array, _constructor) => {
+ return ( name, baseClass = Array, _constructor ) => {
+
const Arr = function () {
- baseClass.apply(this, arguments)
- _constructor && _constructor.apply(this, arguments)
+
+ baseClass.apply( this, arguments )
+ _constructor && _constructor.apply( this, arguments )
+
}
- Arr.prototype = Object.create(baseClass.prototype)
+ Arr.prototype = Object.create( baseClass.prototype )
Arr.prototype.constructor = Arr
- Arr.prototype.map = function (fn) {
+ Arr.prototype.map = function ( fn ) {
+
const arr = new Arr()
- arr.push.apply(arr, Array.prototype.map.call(this, fn))
+ arr.push.apply( arr, Array.prototype.map.call( this, fn ) )
return arr
+
}
return Arr
+
}
+
}
-})()
+
+} )()
diff --git a/src/types/Box.js b/src/types/Box.js
index e55f114..2fcb923 100644
--- a/src/types/Box.js
+++ b/src/types/Box.js
@@ -4,33 +4,45 @@ import { globals } from '../utils/window.js'
import Point from './Point.js'
import parser from '../modules/core/parser.js'
-function isNulledBox (box) {
+function isNulledBox ( box ) {
+
return !box.w && !box.h && !box.x && !box.y
+
}
-function domContains (node) {
- return (globals.document.documentElement.contains || function (node) {
+function domContains ( node ) {
+
+ return ( globals.document.documentElement.contains || function ( node ) {
+
// This is IE - it does not support contains() for top-level SVGs
- while (node.parentNode) {
+ while ( node.parentNode ) {
+
node = node.parentNode
+
}
return node === document
- }).call(globals.document.documentElement, node)
+
+ } ).call( globals.document.documentElement, node )
+
}
export default class Box {
- constructor (...args) {
- this.init(...args)
+
+ constructor ( ...args ) {
+
+ this.init( ...args )
+
}
- init (source) {
- var base = [0, 0, 0, 0]
- source = typeof source === 'string' ? source.split(delimiter).map(parseFloat)
- : Array.isArray(source) ? source
- : typeof source === 'object' ? [source.left != null ? source.left
- : source.x, source.top != null ? source.top : source.y, source.width, source.height]
- : arguments.length === 4 ? [].slice.call(arguments)
- : base
+ init ( source ) {
+
+ var base = [ 0, 0, 0, 0 ]
+ source = typeof source === 'string' ? source.split( delimiter ).map( parseFloat )
+ : Array.isArray( source ) ? source
+ : typeof source === 'object' ? [ source.left != null ? source.left
+ : source.x, source.top != null ? source.top : source.y, source.width, source.height ]
+ : arguments.length === 4 ? [].slice.call( arguments )
+ : base
this.x = source[0] || 0
this.y = source[1] || 0
@@ -44,105 +56,139 @@ export default class Box {
this.cy = this.y + this.h / 2
return this
+
}
// Merge rect box with another, return a new instance
- merge (box) {
- let x = Math.min(this.x, box.x)
- let y = Math.min(this.y, box.y)
- let width = Math.max(this.x + this.width, box.x + box.width) - x
- let height = Math.max(this.y + this.height, box.y + box.height) - y
+ merge ( box ) {
+
+ let x = Math.min( this.x, box.x )
+ let y = Math.min( this.y, box.y )
+ let width = Math.max( this.x + this.width, box.x + box.width ) - x
+ let height = Math.max( this.y + this.height, box.y + box.height ) - y
+
+ return new Box( x, y, width, height )
- return new Box(x, y, width, height)
}
- transform (m) {
+ transform ( m ) {
+
let xMin = Infinity
let xMax = -Infinity
let yMin = Infinity
let yMax = -Infinity
let pts = [
- new Point(this.x, this.y),
- new Point(this.x2, this.y),
- new Point(this.x, this.y2),
- new Point(this.x2, this.y2)
+ new Point( this.x, this.y ),
+ new Point( this.x2, this.y ),
+ new Point( this.x, this.y2 ),
+ new Point( this.x2, this.y2 )
]
- pts.forEach(function (p) {
- p = p.transform(m)
- xMin = Math.min(xMin, p.x)
- xMax = Math.max(xMax, p.x)
- yMin = Math.min(yMin, p.y)
- yMax = Math.max(yMax, p.y)
- })
+ pts.forEach( function ( p ) {
+
+ p = p.transform( m )
+ xMin = Math.min( xMin, p.x )
+ xMax = Math.max( xMax, p.x )
+ yMin = Math.min( yMin, p.y )
+ yMax = Math.max( yMax, p.y )
+
+ } )
return new Box(
xMin, yMin,
xMax - xMin,
yMax - yMin
)
+
}
addOffset () {
+
// offset by window scroll position, because getBoundingClientRect changes when window is scrolled
this.x += globals.window.pageXOffset
this.y += globals.window.pageYOffset
return this
+
}
toString () {
+
return this.x + ' ' + this.y + ' ' + this.width + ' ' + this.height
+
}
toArray () {
- return [this.x, this.y, this.width, this.height]
+
+ return [ this.x, this.y, this.width, this.height ]
+
}
isNulled () {
- return isNulledBox(this)
+
+ return isNulledBox( this )
+
}
+
}
-function getBox (cb) {
+function getBox ( cb ) {
+
let box
try {
- box = cb(this.node)
- if (isNulledBox(box) && !domContains(this.node)) {
- throw new Error('Element not in the dom')
+ box = cb( this.node )
+
+ if ( isNulledBox( box ) && !domContains( this.node ) ) {
+
+ throw new Error( 'Element not in the dom' )
+
}
- } catch (e) {
+
+ } catch ( e ) {
+
try {
- let clone = this.clone().addTo(parser().svg).show()
- box = cb(clone.node)
+
+ let clone = this.clone().addTo( parser().svg ).show()
+ box = cb( clone.node )
clone.remove()
- } catch (e) {
- throw new Error('Getting a bounding box of element "' + this.node.nodeName + '" is not possible')
+
+ } catch ( e ) {
+
+ throw new Error( 'Getting a bounding box of element "' + this.node.nodeName + '" is not possible' )
+
}
+
}
return box
+
}
export function bbox () {
- return new Box(getBox.call(this, (node) => node.getBBox()))
+
+ return new Box( getBox.call( this, ( node ) => node.getBBox() ) )
+
}
-export function rbox (el) {
- let box = new Box(getBox.call(this, (node) => node.getBoundingClientRect()))
- if (el) return box.transform(el.screenCTM().inverse())
+export function rbox ( el ) {
+
+ let box = new Box( getBox.call( this, ( node ) => node.getBoundingClientRect() ) )
+ if ( el ) return box.transform( el.screenCTM().inverse() )
return box.addOffset()
+
}
-registerMethods({
+registerMethods( {
viewbox: {
- viewbox (x, y, width, height) {
+ viewbox ( x, y, width, height ) {
+
// act as getter
- if (x == null) return new Box(this.attr('viewBox'))
+ if ( x == null ) return new Box( this.attr( 'viewBox' ) )
// act as setter
- return this.attr('viewBox', new Box(x, y, width, height))
+ return this.attr( 'viewBox', new Box( x, y, width, height ) )
+
}
}
-})
+} )
diff --git a/src/types/EventTarget.js b/src/types/EventTarget.js
index 5a005fd..3d755bf 100644
--- a/src/types/EventTarget.js
+++ b/src/types/EventTarget.js
@@ -2,57 +2,79 @@ import { dispatch, off, on } from '../modules/core/event.js'
import Base from './Base.js'
export default class EventTarget extends Base {
- constructor ({ events = {} } = {}) {
+
+ constructor ( { events = {} } = {} ) {
+
super()
this.events = events
+
}
addEventListener () {}
- dispatch (event, data) {
- return dispatch(this, event, data)
+ dispatch ( event, data ) {
+
+ return dispatch( this, event, data )
+
}
- dispatchEvent (event) {
+ dispatchEvent ( event ) {
+
const bag = this.getEventHolder().events
- if (!bag) return true
+ if ( !bag ) return true
const events = bag[event.type]
- for (let i in events) {
- for (let j in events[i]) {
- events[i][j](event)
+ for ( let i in events ) {
+
+ for ( let j in events[i] ) {
+
+ events[i][j]( event )
+
}
+
}
return !event.defaultPrevented
+
}
// Fire given event
- fire (event, data) {
- this.dispatch(event, data)
+ fire ( event, data ) {
+
+ this.dispatch( event, data )
return this
+
}
getEventHolder () {
+
return this
+
}
getEventTarget () {
+
return this
+
}
// Unbind event from listener
- off (event, listener) {
- off(this, event, listener)
+ off ( event, listener ) {
+
+ off( this, event, listener )
return this
+
}
// Bind given event to listener
- on (event, listener, binding, options) {
- on(this, event, listener, binding, options)
+ on ( event, listener, binding, options ) {
+
+ on( this, event, listener, binding, options )
return this
+
}
removeEventListener () {}
+
}
diff --git a/src/types/List.js b/src/types/List.js
index 8bd3985..a2d2226 100644
--- a/src/types/List.js
+++ b/src/types/List.js
@@ -1,38 +1,62 @@
import { extend } from '../utils/adopter.js'
import { subClassArray } from './ArrayPolyfill.js'
-const List = subClassArray('List', Array, function (arr = []) {
+const List = subClassArray( 'List', Array, function ( arr = [] ) {
+
// This catches the case, that native map tries to create an array with new Array(1)
- if (typeof arr === 'number') return this
+ if ( typeof arr === 'number' ) return this
this.length = 0
- this.push(...arr)
-})
+ this.push( ...arr )
+
+} )
export default List
-extend(List, {
- each (fnOrMethodName, ...args) {
- if (typeof fnOrMethodName === 'function') {
- this.forEach((el) => { fnOrMethodName.call(el, el) })
+extend( List, {
+ each ( fnOrMethodName, ...args ) {
+
+ if ( typeof fnOrMethodName === 'function' ) {
+
+ this.forEach( ( el ) => {
+
+ fnOrMethodName.call( el, el )
+
+ } )
+
} else {
- return this.map(el => { return el[fnOrMethodName](...args) })
+
+ return this.map( el => {
+
+ return el[fnOrMethodName]( ...args )
+
+ } )
+
}
return this
+
},
toArray () {
- return Array.prototype.concat.apply([], this)
+
+ return Array.prototype.concat.apply( [], this )
+
}
-})
+} )
+
+List.extend = function ( methods ) {
+
+ methods = methods.reduce( ( obj, name ) => {
+
+ obj[name] = function ( ...attrs ) {
+
+ return this.each( name, ...attrs )
-List.extend = function (methods) {
- methods = methods.reduce((obj, name) => {
- obj[name] = function (...attrs) {
- return this.each(name, ...attrs)
}
return obj
- }, {})
- extend(List, methods)
+ }, {} )
+
+ extend( List, methods )
+
}
diff --git a/src/types/Matrix.js b/src/types/Matrix.js
index a1eb317..a9a311e 100644
--- a/src/types/Matrix.js
+++ b/src/types/Matrix.js
@@ -3,27 +3,33 @@ import { radians } from '../utils/utils.js'
import Element from '../elements/Element.js'
import Point from './Point.js'
-function closeEnough (a, b, threshold) {
- return Math.abs(b - a) < (threshold || 1e-6)
+function closeEnough ( a, b, threshold ) {
+
+ return Math.abs( b - a ) < ( threshold || 1e-6 )
+
}
export default class Matrix {
- constructor (...args) {
- this.init(...args)
+
+ constructor ( ...args ) {
+
+ this.init( ...args )
+
}
// Initialize
- init (source) {
- var base = Matrix.fromArray([1, 0, 0, 1, 0, 0])
+ init ( source ) {
+
+ var base = Matrix.fromArray( [ 1, 0, 0, 1, 0, 0 ] )
// ensure source as object
source = source instanceof Element ? source.matrixify()
- : typeof source === 'string' ? Matrix.fromArray(source.split(delimiter).map(parseFloat))
- : Array.isArray(source) ? Matrix.fromArray(source)
- : (typeof source === 'object' && Matrix.isMatrixLike(source)) ? source
- : (typeof source === 'object') ? new Matrix().transform(source)
- : arguments.length === 6 ? Matrix.fromArray([].slice.call(arguments))
- : base
+ : typeof source === 'string' ? Matrix.fromArray( source.split( delimiter ).map( parseFloat ) )
+ : Array.isArray( source ) ? Matrix.fromArray( source )
+ : ( typeof source === 'object' && Matrix.isMatrixLike( source ) ) ? source
+ : ( typeof source === 'object' ) ? new Matrix().transform( source )
+ : arguments.length === 6 ? Matrix.fromArray( [].slice.call( arguments ) )
+ : base
// Merge the source matrix with the base matrix
this.a = source.a != null ? source.a : base.a
@@ -34,56 +40,68 @@ export default class Matrix {
this.f = source.f != null ? source.f : base.f
return this
+
}
// Clones this matrix
clone () {
- return new Matrix(this)
+
+ return new Matrix( this )
+
}
// Transform a matrix into another matrix by manipulating the space
- transform (o) {
+ transform ( o ) {
+
// Check if o is a matrix and then left multiply it directly
- if (Matrix.isMatrixLike(o)) {
- var matrix = new Matrix(o)
- return matrix.multiplyO(this)
+ if ( Matrix.isMatrixLike( o ) ) {
+
+ var matrix = new Matrix( o )
+ return matrix.multiplyO( this )
+
}
// Get the proposed transformations and the current transformations
- var t = Matrix.formatTransforms(o)
+ var t = Matrix.formatTransforms( o )
var current = this
- let { x: ox, y: oy } = new Point(t.ox, t.oy).transform(current)
+ let { x: ox, y: oy } = new Point( t.ox, t.oy ).transform( current )
// Construct the resulting matrix
var transformer = new Matrix()
- .translateO(t.rx, t.ry)
- .lmultiplyO(current)
- .translateO(-ox, -oy)
- .scaleO(t.scaleX, t.scaleY)
- .skewO(t.skewX, t.skewY)
- .shearO(t.shear)
- .rotateO(t.theta)
- .translateO(ox, oy)
+ .translateO( t.rx, t.ry )
+ .lmultiplyO( current )
+ .translateO( -ox, -oy )
+ .scaleO( t.scaleX, t.scaleY )
+ .skewO( t.skewX, t.skewY )
+ .shearO( t.shear )
+ .rotateO( t.theta )
+ .translateO( ox, oy )
// If we want the origin at a particular place, we force it there
- if (isFinite(t.px) || isFinite(t.py)) {
- const origin = new Point(ox, oy).transform(transformer)
+ if ( isFinite( t.px ) || isFinite( t.py ) ) {
+
+ const origin = new Point( ox, oy ).transform( transformer )
// TODO: Replace t.px with isFinite(t.px)
const dx = t.px ? t.px - origin.x : 0
const dy = t.py ? t.py - origin.y : 0
- transformer.translateO(dx, dy)
+ transformer.translateO( dx, dy )
+
}
// Translate now after positioning
- transformer.translateO(t.tx, t.ty)
+ transformer.translateO( t.tx, t.ty )
return transformer
+
}
// Applies a matrix defined by its affine parameters
- compose (o) {
- if (o.origin) {
+ compose ( o ) {
+
+ if ( o.origin ) {
+
o.originX = o.origin[0]
o.originY = o.origin[1]
+
}
// Get the parameters
var ox = o.originX || 0
@@ -97,18 +115,20 @@ export default class Matrix {
// Apply the standard matrix
var result = new Matrix()
- .translateO(-ox, -oy)
- .scaleO(sx, sy)
- .shearO(lam)
- .rotateO(theta)
- .translateO(tx, ty)
- .lmultiplyO(this)
- .translateO(ox, oy)
+ .translateO( -ox, -oy )
+ .scaleO( sx, sy )
+ .shearO( lam )
+ .rotateO( theta )
+ .translateO( tx, ty )
+ .lmultiplyO( this )
+ .translateO( ox, oy )
return result
+
}
// Decomposes this matrix into its affine parameters
- decompose (cx = 0, cy = 0) {
+ decompose ( cx = 0, cy = 0 ) {
+
// Get the parameters from the matrix
var a = this.a
var b = this.b
@@ -123,20 +143,20 @@ export default class Matrix {
// Since we only shear in x, we can use the x basis to get the x scale
// and the rotation of the resulting matrix
- var sx = ccw * Math.sqrt(a * a + b * b)
- var thetaRad = Math.atan2(ccw * b, ccw * a)
+ var sx = ccw * Math.sqrt( a * a + b * b )
+ var thetaRad = Math.atan2( ccw * b, ccw * a )
var theta = 180 / Math.PI * thetaRad
- var ct = Math.cos(thetaRad)
- var st = Math.sin(thetaRad)
+ var ct = Math.cos( thetaRad )
+ var st = Math.sin( thetaRad )
// We can then solve the y basis vector simultaneously to get the other
// two affine parameters directly from these parameters
- var lam = (a * c + b * d) / determinant
- var sy = ((c * sx) / (lam * a - b)) || ((d * sx) / (lam * b + a))
+ var lam = ( a * c + b * d ) / determinant
+ var sy = ( ( c * sx ) / ( lam * a - b ) ) || ( ( d * sx ) / ( lam * b + a ) )
// Use the translations
- let tx = e - cx + cx * ct * sx + cy * (lam * ct * sx - st * sy)
- let ty = f - cy + cx * st * sx + cy * (lam * st * sx + ct * sy)
+ let tx = e - cx + cx * ct * sx + cy * ( lam * ct * sx - st * sy )
+ let ty = f - cy + cx * st * sx + cy * ( lam * st * sx + ct * sy )
// Construct the decomposition and return it
return {
@@ -158,38 +178,48 @@ export default class Matrix {
e: this.e,
f: this.f
}
+
}
// Left multiplies by the given matrix
- multiply (matrix) {
- return this.clone().multiplyO(matrix)
+ multiply ( matrix ) {
+
+ return this.clone().multiplyO( matrix )
+
}
- multiplyO (matrix) {
+ multiplyO ( matrix ) {
+
// Get the matrices
var l = this
var r = matrix instanceof Matrix
? matrix
- : new Matrix(matrix)
+ : new Matrix( matrix )
+
+ return Matrix.matrixMultiply( l, r, this )
- return Matrix.matrixMultiply(l, r, this)
}
- lmultiply (matrix) {
- return this.clone().lmultiplyO(matrix)
+ lmultiply ( matrix ) {
+
+ return this.clone().lmultiplyO( matrix )
+
}
- lmultiplyO (matrix) {
+ lmultiplyO ( matrix ) {
+
var r = this
var l = matrix instanceof Matrix
? matrix
- : new Matrix(matrix)
+ : new Matrix( matrix )
+
+ return Matrix.matrixMultiply( l, r, this )
- return Matrix.matrixMultiply(l, r, this)
}
// Inverses matrix
inverseO () {
+
// Get the current parameters out of the matrix
var a = this.a
var b = this.b
@@ -200,7 +230,7 @@ export default class Matrix {
// Invert the 2x2 matrix in the top left
var det = a * d - b * c
- if (!det) throw new Error('Cannot invert ' + this)
+ if ( !det ) throw new Error( 'Cannot invert ' + this )
// Calculate the top 2x2 matrix
var na = d / det
@@ -209,8 +239,8 @@ export default class Matrix {
var nd = a / det
// Apply the inverted matrix to the top right
- var ne = -(na * e + nc * f)
- var nf = -(nb * e + nd * f)
+ var ne = -( na * e + nc * f )
+ var nf = -( nb * e + nd * f )
// Construct the inverted matrix
this.a = na
@@ -221,34 +251,46 @@ export default class Matrix {
this.f = nf
return this
+
}
inverse () {
+
return this.clone().inverseO()
+
}
// Translate matrix
- translate (x, y) {
- return this.clone().translateO(x, y)
+ translate ( x, y ) {
+
+ return this.clone().translateO( x, y )
+
}
- translateO (x, y) {
+ translateO ( x, y ) {
+
this.e += x || 0
this.f += y || 0
return this
+
}
// Scale matrix
- scale (x, y, cx, cy) {
- return this.clone().scaleO(...arguments)
+ scale ( x, y, cx, cy ) {
+
+ return this.clone().scaleO( ...arguments )
+
}
- scaleO (x, y = x, cx = 0, cy = 0) {
+ scaleO ( x, y = x, cx = 0, cy = 0 ) {
+
// Support uniform scaling
- if (arguments.length === 3) {
+ if ( arguments.length === 3 ) {
+
cy = cx
cx = y
y = x
+
}
let { a, b, c, d, e, f } = this
@@ -261,19 +303,23 @@ export default class Matrix {
this.f = f * y - cy * y + cy
return this
+
}
// Rotate matrix
- rotate (r, cx, cy) {
- return this.clone().rotateO(r, cx, cy)
+ rotate ( r, cx, cy ) {
+
+ return this.clone().rotateO( r, cx, cy )
+
}
- rotateO (r, cx = 0, cy = 0) {
+ rotateO ( r, cx = 0, cy = 0 ) {
+
// Convert degrees to radians
- r = radians(r)
+ r = radians( r )
- let cos = Math.cos(r)
- let sin = Math.sin(r)
+ let cos = Math.cos( r )
+ let sin = Math.sin( r )
let { a, b, c, d, e, f } = this
@@ -285,25 +331,33 @@ export default class Matrix {
this.f = f * cos + e * sin - cx * sin - cy * cos + cy
return this
+
}
// Flip matrix on x or y, at a given offset
- flip (axis, around) {
- return this.clone().flipO(axis, around)
+ flip ( axis, around ) {
+
+ return this.clone().flipO( axis, around )
+
}
- flipO (axis, around) {
- return axis === 'x' ? this.scaleO(-1, 1, around, 0)
- : axis === 'y' ? this.scaleO(1, -1, 0, around)
- : this.scaleO(-1, -1, axis, around || axis) // Define an x, y flip point
+ flipO ( axis, around ) {
+
+ return axis === 'x' ? this.scaleO( -1, 1, around, 0 )
+ : axis === 'y' ? this.scaleO( 1, -1, 0, around )
+ : this.scaleO( -1, -1, axis, around || axis ) // Define an x, y flip point
+
}
// Shear matrix
- shear (a, cx, cy) {
- return this.clone().shearO(a, cx, cy)
+ shear ( a, cx, cy ) {
+
+ return this.clone().shearO( a, cx, cy )
+
}
- shearO (lx, cx = 0, cy = 0) {
+ shearO ( lx, cx = 0, cy = 0 ) {
+
let { a, b, c, d, e, f } = this
this.a = a + b * lx
@@ -311,27 +365,33 @@ export default class Matrix {
this.e = e + f * lx - cy * lx
return this
+
}
// Skew Matrix
- skew (x, y, cx, cy) {
- return this.clone().skewO(...arguments)
+ skew ( x, y, cx, cy ) {
+
+ return this.clone().skewO( ...arguments )
+
}
- skewO (x, y = x, cx = 0, cy = 0) {
+ skewO ( x, y = x, cx = 0, cy = 0 ) {
+
// support uniformal skew
- if (arguments.length === 3) {
+ if ( arguments.length === 3 ) {
+
cy = cx
cx = y
y = x
+
}
// Convert degrees to radians
- x = radians(x)
- y = radians(y)
+ x = radians( x )
+ y = radians( y )
- let lx = Math.tan(x)
- let ly = Math.tan(y)
+ let lx = Math.tan( x )
+ let ly = Math.tan( y )
let { a, b, c, d, e, f } = this
@@ -343,55 +403,75 @@ export default class Matrix {
this.f = f + e * ly - cx * ly
return this
+
}
// SkewX
- skewX (x, cx, cy) {
- return this.skew(x, 0, cx, cy)
+ skewX ( x, cx, cy ) {
+
+ return this.skew( x, 0, cx, cy )
+
}
- skewXO (x, cx, cy) {
- return this.skewO(x, 0, cx, cy)
+ skewXO ( x, cx, cy ) {
+
+ return this.skewO( x, 0, cx, cy )
+
}
// SkewY
- skewY (y, cx, cy) {
- return this.skew(0, y, cx, cy)
+ skewY ( y, cx, cy ) {
+
+ return this.skew( 0, y, cx, cy )
+
}
- skewYO (y, cx, cy) {
- return this.skewO(0, y, cx, cy)
+ skewYO ( y, cx, cy ) {
+
+ return this.skewO( 0, y, cx, cy )
+
}
// Transform around a center point
- aroundO (cx, cy, matrix) {
+ aroundO ( cx, cy, matrix ) {
+
var dx = cx || 0
var dy = cy || 0
- return this.translateO(-dx, -dy).lmultiplyO(matrix).translateO(dx, dy)
+ return this.translateO( -dx, -dy ).lmultiplyO( matrix ).translateO( dx, dy )
+
}
- around (cx, cy, matrix) {
- return this.clone().aroundO(cx, cy, matrix)
+ around ( cx, cy, matrix ) {
+
+ return this.clone().aroundO( cx, cy, matrix )
+
}
// Check if two matrices are equal
- equals (other) {
- var comp = new Matrix(other)
- return closeEnough(this.a, comp.a) && closeEnough(this.b, comp.b) &&
- closeEnough(this.c, comp.c) && closeEnough(this.d, comp.d) &&
- closeEnough(this.e, comp.e) && closeEnough(this.f, comp.f)
+ equals ( other ) {
+
+ var comp = new Matrix( other )
+ return closeEnough( this.a, comp.a ) && closeEnough( this.b, comp.b )
+ && closeEnough( this.c, comp.c ) && closeEnough( this.d, comp.d )
+ && closeEnough( this.e, comp.e ) && closeEnough( this.f, comp.f )
+
}
// Convert matrix to string
toString () {
+
return 'matrix(' + this.a + ',' + this.b + ',' + this.c + ',' + this.d + ',' + this.e + ',' + this.f + ')'
+
}
toArray () {
- return [this.a, this.b, this.c, this.d, this.e, this.f]
+
+ return [ this.a, this.b, this.c, this.d, this.e, this.f ]
+
}
valueOf () {
+
return {
a: this.a,
b: this.b,
@@ -400,56 +480,62 @@ export default class Matrix {
e: this.e,
f: this.f
}
+
}
- static fromArray (a) {
+ static fromArray ( a ) {
+
return { a: a[0], b: a[1], c: a[2], d: a[3], e: a[4], f: a[5] }
+
}
- static isMatrixLike (o) {
+ static isMatrixLike ( o ) {
+
return (
- o.a != null ||
- o.b != null ||
- o.c != null ||
- o.d != null ||
- o.e != null ||
- o.f != null
+ o.a != null
+ || o.b != null
+ || o.c != null
+ || o.d != null
+ || o.e != null
+ || o.f != null
)
+
}
- static formatTransforms (o) {
+ static formatTransforms ( o ) {
+
// Get all of the parameters required to form the matrix
var flipBoth = o.flip === 'both' || o.flip === true
- var flipX = o.flip && (flipBoth || o.flip === 'x') ? -1 : 1
- var flipY = o.flip && (flipBoth || o.flip === 'y') ? -1 : 1
+ var flipX = o.flip && ( flipBoth || o.flip === 'x' ) ? -1 : 1
+ var flipY = o.flip && ( flipBoth || o.flip === 'y' ) ? -1 : 1
var skewX = o.skew && o.skew.length ? o.skew[0]
- : isFinite(o.skew) ? o.skew
- : isFinite(o.skewX) ? o.skewX
- : 0
+ : isFinite( o.skew ) ? o.skew
+ : isFinite( o.skewX ) ? o.skewX
+ : 0
var skewY = o.skew && o.skew.length ? o.skew[1]
- : isFinite(o.skew) ? o.skew
- : isFinite(o.skewY) ? o.skewY
- : 0
+ : isFinite( o.skew ) ? o.skew
+ : isFinite( o.skewY ) ? o.skewY
+ : 0
var scaleX = o.scale && o.scale.length ? o.scale[0] * flipX
- : isFinite(o.scale) ? o.scale * flipX
- : isFinite(o.scaleX) ? o.scaleX * flipX
- : flipX
+ : isFinite( o.scale ) ? o.scale * flipX
+ : isFinite( o.scaleX ) ? o.scaleX * flipX
+ : flipX
var scaleY = o.scale && o.scale.length ? o.scale[1] * flipY
- : isFinite(o.scale) ? o.scale * flipY
- : isFinite(o.scaleY) ? o.scaleY * flipY
- : flipY
+ : isFinite( o.scale ) ? o.scale * flipY
+ : isFinite( o.scaleY ) ? o.scaleY * flipY
+ : flipY
var shear = o.shear || 0
var theta = o.rotate || o.theta || 0
- var origin = new Point(o.origin || o.around || o.ox || o.originX, o.oy || o.originY)
+ var origin = new Point( o.origin || o.around || o.ox || o.originX, o.oy || o.originY )
var ox = origin.x
var oy = origin.y
- var position = new Point(o.position || o.px || o.positionX, o.py || o.positionY)
+ var position = new Point( o.position || o.px || o.positionX, o.py || o.positionY )
var px = position.x
var py = position.y
- var translate = new Point(o.translate || o.tx || o.translateX, o.ty || o.translateY)
+ var translate = new Point( o.translate || o.tx || o.translateX, o.ty || o.translateY )
var tx = translate.x
var ty = translate.y
- var relative = new Point(o.relative || o.rx || o.relativeX, o.ry || o.relativeY)
+ var relative = new Point( o.relative || o.rx || o.relativeX, o.ry || o.relativeY )
var rx = relative.x
var ry = relative.y
@@ -457,10 +543,12 @@ export default class Matrix {
return {
scaleX, scaleY, skewX, skewY, shear, theta, rx, ry, tx, ty, ox, oy, px, py
}
+
}
// left matrix, right matrix, target matrix which is overwritten
- static matrixMultiply (l, r, o) {
+ static matrixMultiply ( l, r, o ) {
+
// Work out the product directly
var a = l.a * r.a + l.c * r.b
var b = l.b * r.a + l.d * r.b
@@ -478,23 +566,31 @@ export default class Matrix {
o.f = f
return o
+
}
+
}
export function ctm () {
- return new Matrix(this.node.getCTM())
+
+ return new Matrix( this.node.getCTM() )
+
}
export function screenCTM () {
+
/* https://bugzilla.mozilla.org/show_bug.cgi?id=1344537
This is needed because FF does not return the transformation matrix
for the inner coordinate system when getScreenCTM() is called on nested svgs.
However all other Browsers do that */
- if (typeof this.isRoot === 'function' && !this.isRoot()) {
- var rect = this.rect(1, 1)
+ if ( typeof this.isRoot === 'function' && !this.isRoot() ) {
+
+ var rect = this.rect( 1, 1 )
var m = rect.node.getScreenCTM()
rect.remove()
- return new Matrix(m)
+ return new Matrix( m )
+
}
- return new Matrix(this.node.getScreenCTM())
+ return new Matrix( this.node.getScreenCTM() )
+
}
diff --git a/src/types/Morphable.js b/src/types/Morphable.js
index 703cc00..87fa800 100644
--- a/src/types/Morphable.js
+++ b/src/types/Morphable.js
@@ -11,135 +11,200 @@ import SVGArray from './SVGArray.js'
import SVGNumber from './SVGNumber.js'
export default class Morphable {
- constructor (stepper) {
- this._stepper = stepper || new Ease('-')
+
+ 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) {
+ from ( val ) {
+
+ if ( val == null ) {
+
return this._from
+
}
- this._from = this._set(val)
+ this._from = this._set( val )
return this
+
}
- to (val) {
- if (val == null) {
+ to ( val ) {
+
+ if ( val == null ) {
+
return this._to
+
}
- this._to = this._set(val)
+ this._to = this._set( val )
return this
+
}
- type (type) {
+ type ( type ) {
+
// getter
- if (type == null) {
+ if ( type == null ) {
+
return this._type
+
}
// setter
this._type = type
return this
+
}
- _set (value) {
- if (!this._type) {
+ _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)
+ 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 if ( numberAndUnit.test( value ) ) {
+
+ this.type( SVGNumber )
+
} else {
- this.type(NonMorphable)
+
+ 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 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)
+
+ this.type( NonMorphable )
+
}
+
}
- var result = (new this._type(value)).toArray()
+ 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)
+ this._context = this._context
+ || Array.apply( null, Array( result.length ) ).map( Object )
return result
+
}
- stepper (stepper) {
- if (stepper == null) return this._stepper
+ 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) {
+ .map( this._stepper.done )
+ .reduce( function ( last, curr ) {
+
return last && curr
- }, true)
+
+ }, true )
return complete
+
}
- at (pos) {
+ 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)
- })
+ 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)
+
+ constructor ( ...args ) {
+
+ this.init( ...args )
+
}
- init (val) {
- val = Array.isArray(val) ? val[0] : val
+ init ( val ) {
+
+ val = Array.isArray( val ) ? val[0] : val
this.value = val
return this
+
}
valueOf () {
+
return this.value
+
}
toArray () {
- return [this.value]
+
+ return [ this.value ]
+
}
+
}
export class TransformBag {
- constructor (...args) {
- this.init(...args)
+
+ constructor ( ...args ) {
+
+ this.init( ...args )
+
}
- init (obj) {
- if (Array.isArray(obj)) {
+ init ( obj ) {
+
+ if ( Array.isArray( obj ) ) {
+
obj = {
scaleX: obj[0],
scaleY: obj[1],
@@ -150,13 +215,16 @@ export class TransformBag {
originX: obj[6],
originY: obj[7]
}
+
}
- Object.assign(this, TransformBag.defaults, obj)
+ Object.assign( this, TransformBag.defaults, obj )
return this
+
}
toArray () {
+
var v = this
return [
@@ -169,7 +237,9 @@ export class TransformBag {
v.originX,
v.originY
]
+
}
+
}
TransformBag.defaults = {
@@ -184,40 +254,56 @@ TransformBag.defaults = {
}
export class ObjectBag {
- constructor (...args) {
- this.init(...args)
+
+ constructor ( ...args ) {
+
+ this.init( ...args )
+
}
- init (objOrArr) {
+ init ( objOrArr ) {
+
this.values = []
- if (Array.isArray(objOrArr)) {
+ if ( Array.isArray( objOrArr ) ) {
+
this.values = objOrArr
return
+
}
- var entries = Object.entries(objOrArr || {}).sort((a, b) => {
+ var entries = Object.entries( objOrArr || {} ).sort( ( a, b ) => {
+
return a[0] - b[0]
- })
- this.values = entries.reduce((last, curr) => last.concat(curr), [])
+ } )
+
+ 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) {
+ 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 = [
@@ -226,21 +312,29 @@ const morphableTypes = [
ObjectBag
]
-export function registerMorphableType (type = []) {
- morphableTypes.push(...[].concat(type))
+export function registerMorphableType ( type = [] ) {
+
+ morphableTypes.push( ...[].concat( type ) )
+
}
export function makeMorphable () {
- extend(morphableTypes, {
- to (val) {
+
+ extend( morphableTypes, {
+ to ( val ) {
+
return new Morphable()
- .type(this.constructor)
- .from(this.valueOf())
- .to(val)
+ .type( this.constructor )
+ .from( this.valueOf() )
+ .to( val )
+
},
- fromArray (arr) {
- this.init(arr)
+ fromArray ( arr ) {
+
+ this.init( arr )
return this
+
}
- })
+ } )
+
}
diff --git a/src/types/PathArray.js b/src/types/PathArray.js
index 989cd8f..739218d 100644
--- a/src/types/PathArray.js
+++ b/src/types/PathArray.js
@@ -12,131 +12,182 @@ import Point from './Point.js'
import SVGArray from './SVGArray.js'
import parser from '../modules/core/parser.js'
-const PathArray = subClassArray('PathArray', SVGArray)
+const PathArray = subClassArray( 'PathArray', SVGArray )
export default PathArray
-export function pathRegReplace (a, b, c, d) {
- return c + d.replace(dots, ' .')
+export function pathRegReplace ( a, b, c, d ) {
+
+ return c + d.replace( dots, ' .' )
+
}
-function arrayToString (a) {
- for (var i = 0, il = a.length, s = ''; i < il; i++) {
+function arrayToString ( a ) {
+
+ for ( var i = 0, il = a.length, s = ''; i < il; i++ ) {
+
s += a[i][0]
- if (a[i][1] != null) {
+ if ( a[i][1] != null ) {
+
s += a[i][1]
- if (a[i][2] != null) {
+ if ( a[i][2] != null ) {
+
s += ' '
s += a[i][2]
- if (a[i][3] != null) {
+ if ( a[i][3] != null ) {
+
s += ' '
s += a[i][3]
s += ' '
s += a[i][4]
- if (a[i][5] != null) {
+ if ( a[i][5] != null ) {
+
s += ' '
s += a[i][5]
s += ' '
s += a[i][6]
- if (a[i][7] != null) {
+ if ( a[i][7] != null ) {
+
s += ' '
s += a[i][7]
+
}
+
}
+
}
+
}
+
}
+
}
return s + ' '
+
}
const pathHandlers = {
- M: function (c, p, p0) {
+ M: function ( c, p, p0 ) {
+
p.x = p0.x = c[0]
p.y = p0.y = c[1]
- return ['M', p.x, p.y]
+ return [ 'M', p.x, p.y ]
+
},
- L: function (c, p) {
+ L: function ( c, p ) {
+
p.x = c[0]
p.y = c[1]
- return ['L', c[0], c[1]]
+ return [ 'L', c[0], c[1] ]
+
},
- H: function (c, p) {
+ H: function ( c, p ) {
+
p.x = c[0]
- return ['H', c[0]]
+ return [ 'H', c[0] ]
+
},
- V: function (c, p) {
+ V: function ( c, p ) {
+
p.y = c[0]
- return ['V', c[0]]
+ return [ 'V', c[0] ]
+
},
- C: function (c, p) {
+ C: function ( c, p ) {
+
p.x = c[4]
p.y = c[5]
- return ['C', c[0], c[1], c[2], c[3], c[4], c[5]]
+ return [ 'C', c[0], c[1], c[2], c[3], c[4], c[5] ]
+
},
- S: function (c, p) {
+ S: function ( c, p ) {
+
p.x = c[2]
p.y = c[3]
- return ['S', c[0], c[1], c[2], c[3]]
+ return [ 'S', c[0], c[1], c[2], c[3] ]
+
},
- Q: function (c, p) {
+ Q: function ( c, p ) {
+
p.x = c[2]
p.y = c[3]
- return ['Q', c[0], c[1], c[2], c[3]]
+ return [ 'Q', c[0], c[1], c[2], c[3] ]
+
},
- T: function (c, p) {
+ T: function ( c, p ) {
+
p.x = c[0]
p.y = c[1]
- return ['T', c[0], c[1]]
+ return [ 'T', c[0], c[1] ]
+
},
- Z: function (c, p, p0) {
+ Z: function ( c, p, p0 ) {
+
p.x = p0.x
p.y = p0.y
- return ['Z']
+ return [ 'Z' ]
+
},
- A: function (c, p) {
+ A: function ( c, p ) {
+
p.x = c[5]
p.y = c[6]
- return ['A', c[0], c[1], c[2], c[3], c[4], c[5], c[6]]
+ return [ 'A', c[0], c[1], c[2], c[3], c[4], c[5], c[6] ]
+
}
}
-let mlhvqtcsaz = 'mlhvqtcsaz'.split('')
+let mlhvqtcsaz = 'mlhvqtcsaz'.split( '' )
+
+for ( var i = 0, il = mlhvqtcsaz.length; i < il; ++i ) {
+
+ pathHandlers[mlhvqtcsaz[i]] = ( function ( i ) {
+
+ return function ( c, p, p0 ) {
+
+ if ( i === 'H' ) c[0] = c[0] + p.x
+ else if ( i === 'V' ) c[0] = c[0] + p.y
+ else if ( i === 'A' ) {
-for (var i = 0, il = mlhvqtcsaz.length; i < il; ++i) {
- pathHandlers[mlhvqtcsaz[i]] = (function (i) {
- return function (c, p, p0) {
- if (i === 'H') c[0] = c[0] + p.x
- else if (i === 'V') c[0] = c[0] + p.y
- else if (i === 'A') {
c[5] = c[5] + p.x
c[6] = c[6] + p.y
+
} else {
- for (var j = 0, jl = c.length; j < jl; ++j) {
- c[j] = c[j] + (j % 2 ? p.y : p.x)
+
+ for ( var j = 0, jl = c.length; j < jl; ++j ) {
+
+ c[j] = c[j] + ( j % 2 ? p.y : p.x )
+
}
+
}
- return pathHandlers[i](c, p, p0)
+ return pathHandlers[i]( c, p, p0 )
+
}
- })(mlhvqtcsaz[i].toUpperCase())
+
+ } )( mlhvqtcsaz[i].toUpperCase() )
+
}
-extend(PathArray, {
+extend( PathArray, {
// Convert array to string
toString () {
- return arrayToString(this)
+
+ return arrayToString( this )
+
},
// Move path string
- move (x, y) {
+ move ( x, y ) {
+
// get bounding box of current situation
var box = this.bbox()
@@ -144,110 +195,154 @@ extend(PathArray, {
x -= box.x
y -= box.y
- if (!isNaN(x) && !isNaN(y)) {
+ if ( !isNaN( x ) && !isNaN( y ) ) {
+
// move every point
- for (var l, i = this.length - 1; i >= 0; i--) {
+ for ( var l, i = this.length - 1; i >= 0; i-- ) {
+
l = this[i][0]
- if (l === 'M' || l === 'L' || l === 'T') {
+ if ( l === 'M' || l === 'L' || l === 'T' ) {
+
this[i][1] += x
this[i][2] += y
- } else if (l === 'H') {
+
+ } else if ( l === 'H' ) {
+
this[i][1] += x
- } else if (l === 'V') {
+
+ } else if ( l === 'V' ) {
+
this[i][1] += y
- } else if (l === 'C' || l === 'S' || l === 'Q') {
+
+ } else if ( l === 'C' || l === 'S' || l === 'Q' ) {
+
this[i][1] += x
this[i][2] += y
this[i][3] += x
this[i][4] += y
- if (l === 'C') {
+ if ( l === 'C' ) {
+
this[i][5] += x
this[i][6] += y
+
}
- } else if (l === 'A') {
+
+ } else if ( l === 'A' ) {
+
this[i][6] += x
this[i][7] += y
+
}
+
}
+
}
return this
+
},
// Resize path string
- size (width, height) {
+ size ( width, height ) {
+
// get bounding box of current situation
var box = this.bbox()
var i, l
// recalculate position of all points according to new size
- for (i = this.length - 1; i >= 0; i--) {
+ for ( i = this.length - 1; i >= 0; i-- ) {
+
l = this[i][0]
- if (l === 'M' || l === 'L' || l === 'T') {
- this[i][1] = ((this[i][1] - box.x) * width) / box.width + box.x
- this[i][2] = ((this[i][2] - box.y) * height) / box.height + box.y
- } else if (l === 'H') {
- this[i][1] = ((this[i][1] - box.x) * width) / box.width + box.x
- } else if (l === 'V') {
- this[i][1] = ((this[i][1] - box.y) * height) / box.height + box.y
- } else if (l === 'C' || l === 'S' || l === 'Q') {
- this[i][1] = ((this[i][1] - box.x) * width) / box.width + box.x
- this[i][2] = ((this[i][2] - box.y) * height) / box.height + box.y
- this[i][3] = ((this[i][3] - box.x) * width) / box.width + box.x
- this[i][4] = ((this[i][4] - box.y) * height) / box.height + box.y
-
- if (l === 'C') {
- this[i][5] = ((this[i][5] - box.x) * width) / box.width + box.x
- this[i][6] = ((this[i][6] - box.y) * height) / box.height + box.y
+ if ( l === 'M' || l === 'L' || l === 'T' ) {
+
+ this[i][1] = ( ( this[i][1] - box.x ) * width ) / box.width + box.x
+ this[i][2] = ( ( this[i][2] - box.y ) * height ) / box.height + box.y
+
+ } else if ( l === 'H' ) {
+
+ this[i][1] = ( ( this[i][1] - box.x ) * width ) / box.width + box.x
+
+ } else if ( l === 'V' ) {
+
+ this[i][1] = ( ( this[i][1] - box.y ) * height ) / box.height + box.y
+
+ } else if ( l === 'C' || l === 'S' || l === 'Q' ) {
+
+ this[i][1] = ( ( this[i][1] - box.x ) * width ) / box.width + box.x
+ this[i][2] = ( ( this[i][2] - box.y ) * height ) / box.height + box.y
+ this[i][3] = ( ( this[i][3] - box.x ) * width ) / box.width + box.x
+ this[i][4] = ( ( this[i][4] - box.y ) * height ) / box.height + box.y
+
+ if ( l === 'C' ) {
+
+ this[i][5] = ( ( this[i][5] - box.x ) * width ) / box.width + box.x
+ this[i][6] = ( ( this[i][6] - box.y ) * height ) / box.height + box.y
+
}
- } else if (l === 'A') {
+
+ } else if ( l === 'A' ) {
+
// resize radii
- this[i][1] = (this[i][1] * width) / box.width
- this[i][2] = (this[i][2] * height) / box.height
+ this[i][1] = ( this[i][1] * width ) / box.width
+ this[i][2] = ( this[i][2] * height ) / box.height
// move position values
- this[i][6] = ((this[i][6] - box.x) * width) / box.width + box.x
- this[i][7] = ((this[i][7] - box.y) * height) / box.height + box.y
+ this[i][6] = ( ( this[i][6] - box.x ) * width ) / box.width + box.x
+ this[i][7] = ( ( this[i][7] - box.y ) * height ) / box.height + box.y
+
}
+
}
return this
+
},
// Test if the passed path array use the same path data commands as this path array
- equalCommands (pathArray) {
+ equalCommands ( pathArray ) {
+
var i, il, equalCommands
- pathArray = new PathArray(pathArray)
+ pathArray = new PathArray( pathArray )
equalCommands = this.length === pathArray.length
- for (i = 0, il = this.length; equalCommands && i < il; i++) {
+ for ( i = 0, il = this.length; equalCommands && i < il; i++ ) {
+
equalCommands = this[i][0] === pathArray[i][0]
+
}
return equalCommands
+
},
// Make path array morphable
- morph (pathArray) {
- pathArray = new PathArray(pathArray)
+ morph ( pathArray ) {
+
+ pathArray = new PathArray( pathArray )
+
+ if ( this.equalCommands( pathArray ) ) {
- if (this.equalCommands(pathArray)) {
this.destination = pathArray
+
} else {
+
this.destination = null
+
}
return this
+
},
// Get morphed path array at given position
- at (pos) {
+ at ( pos ) {
+
// make sure a destination is defined
- if (!this.destination) return this
+ if ( !this.destination ) return this
var sourceArray = this
var destinationArray = this.destination.value
@@ -257,47 +352,61 @@ extend(PathArray, {
// Animate has specified in the SVG spec
// See: https://www.w3.org/TR/SVG11/paths.html#PathElement
- for (i = 0, il = sourceArray.length; i < il; i++) {
- array[i] = [sourceArray[i][0]]
- for (j = 1, jl = sourceArray[i].length; j < jl; j++) {
- array[i][j] = sourceArray[i][j] + (destinationArray[i][j] - sourceArray[i][j]) * pos
+ for ( i = 0, il = sourceArray.length; i < il; i++ ) {
+
+ array[i] = [ sourceArray[i][0] ]
+ for ( j = 1, jl = sourceArray[i].length; j < jl; j++ ) {
+
+ array[i][j] = sourceArray[i][j] + ( destinationArray[i][j] - sourceArray[i][j] ) * pos
+
}
// For the two flags of the elliptical arc command, the SVG spec say:
// Flags and booleans are interpolated as fractions between zero and one, with any non-zero value considered to be a value of one/true
// Elliptical arc command as an array followed by corresponding indexes:
// ['A', rx, ry, x-axis-rotation, large-arc-flag, sweep-flag, x, y]
// 0 1 2 3 4 5 6 7
- if (array[i][0] === 'A') {
- array[i][4] = +(array[i][4] !== 0)
- array[i][5] = +(array[i][5] !== 0)
+ if ( array[i][0] === 'A' ) {
+
+ array[i][4] = +( array[i][4] !== 0 )
+ array[i][5] = +( array[i][5] !== 0 )
+
}
+
}
// Directly modify the value of a path array, this is done this way for performance
pathArray.value = array
return pathArray
+
},
// Absolutize and parse path to array
- parse (array = [['M', 0, 0]]) {
+ parse ( array = [ [ 'M', 0, 0 ] ] ) {
+
// if it's already a patharray, no need to parse it
- if (array instanceof PathArray) return array
+ if ( array instanceof PathArray ) return array
// prepare for parsing
var s
var paramCnt = { 'M': 2, 'L': 2, 'H': 1, 'V': 1, 'C': 6, 'S': 4, 'Q': 4, 'T': 2, 'A': 7, 'Z': 0 }
- if (typeof array === 'string') {
+ if ( typeof array === 'string' ) {
+
array = array
- .replace(numbersWithDots, pathRegReplace) // convert 45.123.123 to 45.123 .123
- .replace(pathLetters, ' $& ') // put some room between letters and numbers
- .replace(hyphen, '$1 -') // add space before hyphen
+ .replace( numbersWithDots, pathRegReplace ) // convert 45.123.123 to 45.123 .123
+ .replace( pathLetters, ' $& ' ) // put some room between letters and numbers
+ .replace( hyphen, '$1 -' ) // add space before hyphen
.trim() // trim
- .split(delimiter) // split into array
+ .split( delimiter ) // split into array
+
} else {
- array = array.reduce(function (prev, curr) {
- return [].concat.call(prev, curr)
- }, [])
+
+ array = array.reduce( function ( prev, curr ) {
+
+ return [].concat.call( prev, curr )
+
+ }, [] )
+
}
// array now is an array containing all parts of a path e.g. ['M', '0', '0', 'L', '30', '30' ...]
@@ -308,30 +417,41 @@ extend(PathArray, {
var len = array.length
do {
+
// Test if we have a path letter
- if (isPathLetter.test(array[index])) {
+ if ( isPathLetter.test( array[index] ) ) {
+
s = array[index]
++index
- // If last letter was a move command and we got no new, it defaults to [L]ine
- } else if (s === 'M') {
+ // If last letter was a move command and we got no new, it defaults to [L]ine
+
+ } else if ( s === 'M' ) {
+
s = 'L'
- } else if (s === 'm') {
+
+ } else if ( s === 'm' ) {
+
s = 'l'
+
}
- result.push(pathHandlers[s].call(null,
- array.slice(index, (index = index + paramCnt[s.toUpperCase()])).map(parseFloat),
+ result.push( pathHandlers[s].call( null,
+ array.slice( index, ( index = index + paramCnt[s.toUpperCase()] ) ).map( parseFloat ),
p, p0
)
)
- } while (len > index)
+
+ } while ( len > index )
return result
+
},
// Get bounding box of path
bbox () {
- parser().path.setAttribute('d', this.toString())
+
+ parser().path.setAttribute( 'd', this.toString() )
return parser.nodes.path.getBBox()
+
}
-})
+} )
diff --git a/src/types/Point.js b/src/types/Point.js
index 27d81ea..16ae44d 100644
--- a/src/types/Point.js
+++ b/src/types/Point.js
@@ -1,45 +1,59 @@
export default class Point {
+
// Initialize
- constructor (...args) {
- this.init(...args)
+ constructor ( ...args ) {
+
+ this.init( ...args )
+
}
- init (x, y) {
+ init ( x, y ) {
+
let source
let base = { x: 0, y: 0 }
// ensure source as object
- source = Array.isArray(x) ? { x: x[0], y: x[1] }
+ source = Array.isArray( x ) ? { x: x[0], y: x[1] }
: typeof x === 'object' ? { x: x.x, y: x.y }
- : { x: x, y: y }
+ : { x: x, y: y }
// merge source
this.x = source.x == null ? base.x : source.x
this.y = source.y == null ? base.y : source.y
return this
+
}
// Clone point
clone () {
- return new Point(this)
+
+ return new Point( this )
+
}
// transform point with matrix
- transform (m) {
+ transform ( m ) {
+
// Perform the matrix multiplication
var x = m.a * this.x + m.c * this.y + m.e
var y = m.b * this.x + m.d * this.y + m.f
// Return the required point
- return new Point(x, y)
+ return new Point( x, y )
+
}
toArray () {
- return [this.x, this.y]
+
+ return [ this.x, this.y ]
+
}
+
}
-export function point (x, y) {
- return new Point(x, y).transform(this.screenCTM().inverse())
+export function point ( x, y ) {
+
+ return new Point( x, y ).transform( this.screenCTM().inverse() )
+
}
diff --git a/src/types/PointArray.js b/src/types/PointArray.js
index b246b2f..581b7dc 100644
--- a/src/types/PointArray.js
+++ b/src/types/PointArray.js
@@ -3,76 +3,97 @@ import { extend } from '../utils/adopter.js'
import { subClassArray } from './ArrayPolyfill.js'
import SVGArray from './SVGArray.js'
-const PointArray = subClassArray('PointArray', SVGArray)
+const PointArray = subClassArray( 'PointArray', SVGArray )
export default PointArray
-extend(PointArray, {
+extend( PointArray, {
// Convert array to string
toString () {
+
// convert to a poly point string
- for (var i = 0, il = this.length, array = []; i < il; i++) {
- array.push(this[i].join(','))
+ for ( var i = 0, il = this.length, array = []; i < il; i++ ) {
+
+ array.push( this[i].join( ',' ) )
+
}
- return array.join(' ')
+ return array.join( ' ' )
+
},
// Convert array to line object
toLine () {
+
return {
x1: this[0][0],
y1: this[0][1],
x2: this[1][0],
y2: this[1][1]
}
+
},
// Get morphed array at given position
- at (pos) {
+ at ( pos ) {
+
// make sure a destination is defined
- if (!this.destination) return this
+ if ( !this.destination ) return this
// generate morphed point string
- for (var i = 0, il = this.length, array = []; i < il; i++) {
- array.push([
- this[i][0] + (this.destination[i][0] - this[i][0]) * pos,
- this[i][1] + (this.destination[i][1] - this[i][1]) * pos
- ])
+ for ( var i = 0, il = this.length, array = []; i < il; i++ ) {
+
+ array.push( [
+ this[i][0] + ( this.destination[i][0] - this[i][0] ) * pos,
+ this[i][1] + ( this.destination[i][1] - this[i][1] ) * pos
+ ] )
+
}
- return new PointArray(array)
+ return new PointArray( array )
+
},
// Parse point string and flat array
- parse (array = [[0, 0]]) {
+ parse ( array = [ [ 0, 0 ] ] ) {
+
var points = []
// if it is an array
- if (array instanceof Array) {
+ if ( array instanceof Array ) {
+
// and it is not flat, there is no need to parse it
- if (array[0] instanceof Array) {
+ if ( array[0] instanceof Array ) {
+
return array
+
}
+
} else { // Else, it is considered as a string
+
// parse points
- array = array.trim().split(delimiter).map(parseFloat)
+ array = array.trim().split( delimiter ).map( parseFloat )
+
}
// validate points - https://svgwg.org/svg2-draft/shapes.html#DataTypePoints
// Odd number of coordinates is an error. In such cases, drop the last odd coordinate.
- if (array.length % 2 !== 0) array.pop()
+ if ( array.length % 2 !== 0 ) array.pop()
// wrap points in two-tuples and parse points as floats
- for (var i = 0, len = array.length; i < len; i = i + 2) {
- points.push([ array[i], array[i + 1] ])
+ for ( var i = 0, len = array.length; i < len; i = i + 2 ) {
+
+ points.push( [ array[i], array[i + 1] ] )
+
}
return points
+
},
// Move point string
- move (x, y) {
+ move ( x, y ) {
+
var box = this.bbox()
// get relative offset
@@ -80,41 +101,54 @@ extend(PointArray, {
y -= box.y
// move every point
- if (!isNaN(x) && !isNaN(y)) {
- for (var i = this.length - 1; i >= 0; i--) {
- this[i] = [this[i][0] + x, this[i][1] + y]
+ if ( !isNaN( x ) && !isNaN( y ) ) {
+
+ for ( var i = this.length - 1; i >= 0; i-- ) {
+
+ this[i] = [ this[i][0] + x, this[i][1] + y ]
+
}
+
}
return this
+
},
// Resize poly string
- size (width, height) {
+ size ( width, height ) {
+
var i
var box = this.bbox()
// recalculate position of all points according to new size
- for (i = this.length - 1; i >= 0; i--) {
- if (box.width) this[i][0] = ((this[i][0] - box.x) * width) / box.width + box.x
- if (box.height) this[i][1] = ((this[i][1] - box.y) * height) / box.height + box.y
+ for ( i = this.length - 1; i >= 0; i-- ) {
+
+ if ( box.width ) this[i][0] = ( ( this[i][0] - box.x ) * width ) / box.width + box.x
+ if ( box.height ) this[i][1] = ( ( this[i][1] - box.y ) * height ) / box.height + box.y
+
}
return this
+
},
// Get bounding box of points
bbox () {
+
var maxX = -Infinity
var maxY = -Infinity
var minX = Infinity
var minY = Infinity
- this.forEach(function (el) {
- maxX = Math.max(el[0], maxX)
- maxY = Math.max(el[1], maxY)
- minX = Math.min(el[0], minX)
- minY = Math.min(el[1], minY)
- })
+ this.forEach( function ( el ) {
+
+ maxX = Math.max( el[0], maxX )
+ maxY = Math.max( el[1], maxY )
+ minX = Math.min( el[0], minX )
+ minY = Math.min( el[1], minY )
+
+ } )
return { x: minX, y: minY, width: maxX - minX, height: maxY - minY }
+
}
-})
+} )
diff --git a/src/types/SVGArray.js b/src/types/SVGArray.js
index 7f27ec4..7d59af1 100644
--- a/src/types/SVGArray.js
+++ b/src/types/SVGArray.js
@@ -2,49 +2,65 @@ import { delimiter } from '../modules/core/regex.js'
import { extend } from '../utils/adopter.js'
import { subClassArray } from './ArrayPolyfill.js'
-const SVGArray = subClassArray('SVGArray', Array, function (arr) {
- this.init(arr)
-})
+const SVGArray = subClassArray( 'SVGArray', Array, function ( arr ) {
+
+ this.init( arr )
+
+} )
export default SVGArray
-extend(SVGArray, {
- init (arr) {
+extend( SVGArray, {
+ init ( arr ) {
+
// This catches the case, that native map tries to create an array with new Array(1)
- if (typeof arr === 'number') return this
+ if ( typeof arr === 'number' ) return this
this.length = 0
- this.push(...this.parse(arr))
+ this.push( ...this.parse( arr ) )
return this
+
},
toArray () {
- return Array.prototype.concat.apply([], this)
+
+ return Array.prototype.concat.apply( [], this )
+
},
toString () {
- return this.join(' ')
+
+ return this.join( ' ' )
+
},
// Flattens the array if needed
valueOf () {
+
const ret = []
- ret.push(...this)
+ ret.push( ...this )
return ret
+
},
// Parse whitespace separated string
- parse (array = []) {
+ parse ( array = [] ) {
+
// If already is an array, no need to parse it
- if (array instanceof Array) return array
+ if ( array instanceof Array ) return array
+
+ return array.trim().split( delimiter ).map( parseFloat )
- return array.trim().split(delimiter).map(parseFloat)
},
clone () {
- return new this.constructor(this)
+
+ return new this.constructor( this )
+
},
toSet () {
- return new Set(this)
+
+ return new Set( this )
+
}
-})
+} )
diff --git a/src/types/SVGNumber.js b/src/types/SVGNumber.js
index ea21cbd..a35ed66 100644
--- a/src/types/SVGNumber.js
+++ b/src/types/SVGNumber.js
@@ -2,88 +2,126 @@ import { numberAndUnit } from '../modules/core/regex.js'
// Module for unit convertions
export default class SVGNumber {
+
// Initialize
- constructor (...args) {
- this.init(...args)
+ constructor ( ...args ) {
+
+ this.init( ...args )
+
}
- init (value, unit) {
- unit = Array.isArray(value) ? value[1] : unit
- value = Array.isArray(value) ? value[0] : value
+ init ( value, unit ) {
+
+ unit = Array.isArray( value ) ? value[1] : unit
+ value = Array.isArray( value ) ? value[0] : value
// initialize defaults
this.value = 0
this.unit = unit || ''
// parse value
- if (typeof value === 'number') {
+ if ( typeof value === 'number' ) {
+
// ensure a valid numeric value
- this.value = isNaN(value) ? 0 : !isFinite(value) ? (value < 0 ? -3.4e+38 : +3.4e+38) : value
- } else if (typeof value === 'string') {
- unit = value.match(numberAndUnit)
+ this.value = isNaN( value ) ? 0 : !isFinite( value ) ? ( value < 0 ? -3.4e+38 : +3.4e+38 ) : value
+
+ } else if ( typeof value === 'string' ) {
+
+ unit = value.match( numberAndUnit )
+
+ if ( unit ) {
- if (unit) {
// make value numeric
- this.value = parseFloat(unit[1])
+ this.value = parseFloat( unit[1] )
// normalize
- if (unit[5] === '%') { this.value /= 100 } else if (unit[5] === 's') {
+ if ( unit[5] === '%' ) {
+
+ this.value /= 100
+
+ } else if ( unit[5] === 's' ) {
+
this.value *= 1000
+
}
// store unit
this.unit = unit[5]
+
}
+
} else {
- if (value instanceof SVGNumber) {
+
+ if ( value instanceof SVGNumber ) {
+
this.value = value.valueOf()
this.unit = value.unit
+
}
+
}
return this
+
}
toString () {
- return (this.unit === '%' ? ~~(this.value * 1e8) / 1e6
+
+ return ( this.unit === '%' ? ~~( this.value * 1e8 ) / 1e6
: this.unit === 's' ? this.value / 1e3
- : this.value
+ : this.value
) + this.unit
+
}
toJSON () {
+
return this.toString()
+
}
toArray () {
- return [this.value, this.unit]
+
+ return [ this.value, this.unit ]
+
}
valueOf () {
+
return this.value
+
}
// Add number
- plus (number) {
- number = new SVGNumber(number)
- return new SVGNumber(this + number, this.unit || number.unit)
+ plus ( number ) {
+
+ number = new SVGNumber( number )
+ return new SVGNumber( this + number, this.unit || number.unit )
+
}
// Subtract number
- minus (number) {
- number = new SVGNumber(number)
- return new SVGNumber(this - number, this.unit || number.unit)
+ minus ( number ) {
+
+ number = new SVGNumber( number )
+ return new SVGNumber( this - number, this.unit || number.unit )
+
}
// Multiply number
- times (number) {
- number = new SVGNumber(number)
- return new SVGNumber(this * number, this.unit || number.unit)
+ times ( number ) {
+
+ number = new SVGNumber( number )
+ return new SVGNumber( this * number, this.unit || number.unit )
+
}
// Divide number
- divide (number) {
- number = new SVGNumber(number)
- return new SVGNumber(this / number, this.unit || number.unit)
+ divide ( number ) {
+
+ number = new SVGNumber( number )
+ return new SVGNumber( this / number, this.unit || number.unit )
+
}
+
}