let a = canvas.rect(200, 400).move(500, 400)
.attr('opacity', 0.3)
.addClass('pink')
- .transform({ tx: 100, ty: 500, origin: 'top-left' })
-
-canvas.ellipse(20, 20).center(700, 1100)
+ // .transform({ tx: 100, ty: 500, origin: 'top-left' })
var timer = 0
return timer
})
-let obj = { rotate: 180, origin: 'center', translate: [300, 0] }
-let obj2 = { rotate: 360, origin: 'center' }
+let obj = { rotate: 180, origin: 'top-left', tx: 500}
+let obj2 = { rotate: 280, origin: 'center' }
-a.clone() // startPosition
+var z = a.clone().attr('fill', 'blue') // startPosition
//a.clone().transform(obj, true).transform(obj2, true) // endPosition
// that works
-a.animate(new SVG.Spring(50, 30)).transform(obj) // animation
+// a.animate(new SVG.Spring(50, 30)).transform(obj, false, true) // animation
// that breaks (why??)
-var b = a.clone().animate(new SVG.Spring(500, 30))
+// var b = a.clone().animate(new SVG.Spring(500, 30))
//debugger
-b.transform(obj) // animation
-//a.animate(300).transform(obj, true).transform(obj2, true) // animation
+//b.transform(obj, false, true) // animation
+a.clone().animate(new SVG.Spring(1000, 15)).transform(obj).transform(obj2, true) // animation
+a.clone().animate(1000).transform(obj).transform(obj2, true) // animation
+a.clone().transform(obj).transform(obj2, true) // endPosition
+
+canvas.ellipse(20, 20).center(500, 400 + 0)
+
+//
+//el.center(100, 400)
+// z.transform({px: 100, py: 400})
+// z.transform({tx: 100, px: 100, py: 400})
+// z.transform({px: 100, py: 400})
+// z.transform({px: 100, py: 400})
+// z.transform({px: 100, py: 400})
+
+
+// SVG.on(document, 'mousemove', (e) => {
+// let {x, y} = canvas.point(e.pageX, e.pageY)
+// el.center(x, y)
+// b.transform ({px: x, py: y, rotate: (x + y) / 3})
+// z.transform ({px: x, py: y }) //, rotate: (x + y) / 3})
+// })
+
+
// Populate all of the values
return {
- scaleX: scaleX,
- scaleY: scaleY,
- skewX: skewX,
- skewY: skewY,
- shear: shear,
- theta: theta,
- rx: rx,
- ry: ry,
- tx: tx,
- ty: ty,
- ox: ox,
- oy: oy,
- px: px,
- py: py
+ scaleX, scaleY, skewX, skewY, shear, theta,
+ rx, ry, tx, ty, ox, oy, px, py
}
}
const { height, width, x, y } = element.bbox()
// Calculate the transformed x and y coordinates
- const bx = string.includes('left') ? x
+ let bx = string.includes('left') ? x
: string.includes('right') ? x + width
: x + width / 2
- const by = string.includes('top') ? y
+ let by = string.includes('top') ? y
: string.includes('bottom') ? y + height
: y + height / 2
- // Find the new center in the transformed coordinates
- const matrix = new SVG.Matrix(element)
- const {x: tx , y: ty} = new SVG.Point(bx, by).transform(matrix)
-
// Set the bounds eg : "bottom-left", "Top right", "middle" etc...
- const ox = o.ox != null ? o.ox : tx
- const oy = o.oy != null ? o.oy : ty
+ const ox = o.ox != null ? o.ox : bx
+ const oy = o.oy != null ? o.oy : by
// Set the origin based on the current matrix location
return [ox, oy]
// Get the proposed transformations and the current transformations
var t = formatTransforms(o)
- var currentTransform = new SVG.Matrix(this)
+ var current = new SVG.Matrix(this)
+ let { x: ox, y: oy } = new SVG.Point(t.ox, t.oy).transform(current)
// Construct the resulting matrix
- var transformer = new SVG.Matrix(currentTransform)
- .translate(-t.ox, -t.oy)
+ var transformer = new SVG.Matrix()
+ .translate(t.rx, t.ry)
+ .lmultiply(current)
+ .translate(-ox, -oy)
.scale(t.scaleX, t.scaleY)
.skew(t.skewX, t.skewY)
.shear(t.shear)
.rotate(t.theta)
- .translate(t.ox, t.oy)
- .translate(t.rx, t.ry)
+ .translate(ox, oy)
// If we want the origin at a particular place, we force it there
if (isFinite(t.px) || isFinite(t.py)) {
- // Figure out where the origin went and the delta to get there
- var current = new SVG.Point(t.ox - t.rx, t.oy - t.ry).transform(transformer)
- var dx = t.px ? t.px - current.x : 0
- var dy = t.py ? t.py - current.y : 0
-
- // Apply another translation
+ const origin = new SVG.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 = transformer.translate(dx, dy)
}
- // We can apply translations after everything else
+ // Translate now after positioning
transformer = transformer.translate(t.tx, t.ty)
return transformer
},
// Parse the parameters
var isMatrix = transforms.a != null
- affine = transforms.affine || affine || !isMatrix
relative = transforms.relative || relative
+ affine = transforms.affine != null
+ ? transforms.affine
+ : (affine != null ? affine : !isMatrix)
/**
The default of relative is false
.stepper(this._stepper)
this.queue(function() {
- if (origin == null) {
- element = this.element()
- let transformedOrigin = getOrigin (transforms, element)
- origin = new SVG.Point(transformedOrigin)
- .transform(new SVG.Matrix(element).inverse())
+ element = this.element()
+ element.addRunner(this)
+ if (origin == null) {
+ origin = new SVG.Point(getOrigin (transforms, element))
transforms = {...transforms, origin: [origin.x, origin.y]}
morpher.to(formatTransforms(transforms))
}
let from = current || {origin}
morpher.from(formatTransforms(from))
- this.element().addRunner(this)
}, function (pos) {
let currentMatrix = element._currentTransform(this)
let {x, y} = origin.transform(currentMatrix)
+
/*
1. Transform the origin by figuring out the delta
current = morpher.at(pos).valueOf()
let matrix = new SVG.Matrix(current)
this.addTransform(matrix)
+
return morpher.done()
}, true)
element.addRunner(this)
if (!origin && affine) {
- // origin = getOrigin(transforms, element)
- // transforms = {...transforms, origin}
-
- let transformedOrigin = getOrigin (transforms, element)
- origin = new SVG.Point(transformedOrigin)
- .transform(new SVG.Matrix(element).inverse())
-
+ origin = new SVG.Point(getOrigin (transforms, element))
transforms = {...transforms, origin: [origin.x, origin.y]}
-
morpher.to(transforms)
}
element._clearTransformRunnersBefore(this)
}
+ // FIXME: This should be current = current || ...
// Define the starting point for the morpher
let startMatrix = new SVG.Matrix(relative ? undefined : element)
if (affine) {
startMatrix.origin = origin
- // that a hack to update the rotation in the morpher
- // so it always takes the shortest path
- const rTarget = transforms.rotate || 0
+ // Get the current and target angle as it was set
+ const rTarget = morpher._to[3]
const rCurrent = startMatrix.decompose(origin[0], origin[1]).rotate
+ // Figure out the shortest path to rotate directly
const possibilities = [rTarget - 360, rTarget, rTarget + 360]
const distances = possibilities.map( a => Math.abs(a - rCurrent) )
const shortest = Math.min(...distances)
const index = distances.indexOf(shortest)
const target = possibilities[index]
+ // HACK: We directly replace the rotation so that its faster
morpher._to.splice(3, 1, target)
}
if (!relative) this.clearTransform()
- let currentMatrix = element._currentTransform(this)
- let {x, y} = origin.transform(currentMatrix)
-
- morpher._from.splice(-2, 2, x, y)
- morpher._to.splice(-2, 2, x, y)
+ // Retarget the origin if we are in an
+ if (affine) {
+ let currentMatrix = element._currentTransform(this)
+ let {x, y} = origin.transform(currentMatrix)
+ morpher._from.splice(-2, 2, x, y)
+ morpher._to.splice(-2, 2, x, y)
+ }
current = morpher.at(pos)
this.addTransform(current)
}
// Set the origin according to the defined transform
- o = {...o, origin: getOrigin(o, this)}
+ o = {...o, origin: getOrigin(o, this, relative)}
// The user can pass a boolean, an SVG.Element or an SVG.Matrix or nothing
var cleanRelative = relative === true ? this : (relative || false)
return this.attr('transform', result)
}
})
-
-SVG.extend(SVG.Timeline, {
- transform: function (o, relative, affine) {
-
- // // get target in case of the fx module, otherwise reference this
- // var target = this.target()
- // , matrix, bbox
- //
- // // act as a getter
- // if (typeof o !== 'object') {
- // // get current matrix
- // matrix = new SVG.Matrix(target).extract()
- //
- // return typeof o === 'string' ? matrix[o] : matrix
- // }
- //
- // // ensure relative flag
- // relative = !!relative || !!o.relative
- //
- // // act on matrix
- // if (o.a != null) {
- // matrix = new SVG.Matrix(o)
- //
- // // act on rotation
- // } else if (o.rotation != null) {
- // // ensure centre point
- // ensureCentre(o, target)
- //
- // // apply transformation
- // matrix = new SVG.Rotate(o.rotation, o.cx, o.cy)
- //
- // // act on scale
- // } else if (o.scale != null || o.scaleX != null || o.scaleY != null) {
- // // ensure centre point
- // ensureCentre(o, target)
- //
- // // ensure scale values on both axes
- // o.scaleX = o.scale != null ? o.scale : o.scaleX != null ? o.scaleX : 1
- // o.scaleY = o.scale != null ? o.scale : o.scaleY != null ? o.scaleY : 1
- //
- // matrix = new SVG.Scale(o.scaleX, o.scaleY, o.cx, o.cy)
- //
- // // act on skew
- // } else if (o.skewX != null || o.skewY != null) {
- // // ensure centre point
- // ensureCentre(o, target)
- //
- // // ensure skew values on both axes
- // o.skewX = o.skewX != null ? o.skewX : 0
- // o.skewY = o.skewY != null ? o.skewY : 0
- //
- // matrix = new SVG.Skew(o.skewX, o.skewY, o.cx, o.cy)
- //
- // // act on flip
- // } else if (o.flip) {
- // if(o.flip == 'x' || o.flip == 'y') {
- // o.offset = o.offset == null ? target.bbox()['c' + o.flip] : o.offset
- // } else {
- // if(o.offset == null) {
- // bbox = target.bbox()
- // o.flip = bbox.cx
- // o.offset = bbox.cy
- // } else {
- // o.flip = o.offset
- // }
- // }
- //
- // matrix = new SVG.Matrix().flip(o.flip, o.offset)
- //
- // // act on translate
- // } else if (o.x != null || o.y != null) {
- // matrix = new SVG.Translate(o.x, o.y)
- // }
- //
- // if(!matrix) return this
- //
- // matrix.relative = relative
- //
- // this.last().transforms.push(matrix)
- //
- // return this._callStart()
- // }
- // // ensure scale values on both axes
- // o.scaleX = o.scale != null ? o.scale : o.scaleX != null ? o.scaleX : 1
- // o.scaleY = o.scale != null ? o.scale : o.scaleY != null ? o.scaleY : 1
- //
- // matrix = new SVG.Scale(o.scaleX, o.scaleY, o.cx, o.cy)
- //
- // // act on skew
- // } else if (o.skewX != null || o.skewY != null) {
- // // ensure centre point
- // ensureCentre(o, target)
- //
- // // ensure skew values on both axes
- // o.skewX = o.skewX != null ? o.skewX : 0
- // o.skewY = o.skewY != null ? o.skewY : 0
- //
- // matrix = new SVG.Skew(o.skewX, o.skewY, o.cx, o.cy)
- //
- // // act on flip
- // } else if (o.flip) {
- // if (o.flip === 'x' || o.flip === 'y') {
- // o.offset = o.offset == null ? target.bbox()['c' + o.flip] : o.offset
- // } else {
- // if (o.offset == null) {
- // bbox = target.bbox()
- // o.flip = bbox.cx
- // o.offset = bbox.cy
- // } else {
- // o.flip = o.offset
- // }
- // }
- //
- // matrix = new SVG.Matrix().flip(o.flip, o.offset)
- //
- // // act on translate
- // } else if (o.x != null || o.y != null) {
- // matrix = new SVG.Translate(o.x, o.y)
- // }
- //
- // if (!matrix) return this
- //
- // matrix.relative = relative
- //
- // this.last().transforms.push(matrix)
- //
- // return this._callStart()
- }
-})
=====
- Use runners[runnerid] = {startTime, runner, persist}
timeline.persist('monkey-in', Infinity)
-
-
-- animation result is different from setting directly
-- format transforms didnt take all parameters into account (theta / rotate)
+- folding transformations
+- testing direct non affine morph
+- why cant i use current?
+- handle null values
Both
====