]> source.dussan.org Git - svg.js.git/commitdiff
Fixed the relative non-affine transform animations
authorSaivan <savian@me.com>
Mon, 17 Sep 2018 04:10:12 +0000 (14:10 +1000)
committerSaivan <savian@me.com>
Mon, 17 Sep 2018 04:10:12 +0000 (14:10 +1000)
This commit uncovered an issue with the relative non-affine transformations. It is
now correctly fixed and working. Next we should fix the affine transforms as well.

Changes
=======
- Fixed the relative non-affine transformation animations

dirty.html
src/helpers.js
src/runner.js
src/transform.js

index ab9e3c869986542734be7b5c077bb74924373b12..f7542e6474755c14a5a92e25b127098db9b2cf0e 100644 (file)
@@ -25,7 +25,7 @@
 <div id="position"><label>Position: <input type="range" min="0" max="5" step="0.01"></slider></label><span></span></div>
 
 <!-- Making the svg -->
-<svg width=1000px height=1000px id="canvas" viewbox="-1000 -1000 3000 3000">
+<svg width=1000px height=1000px id="canvas" viewbox="-1000 -2000 5000 5000">
   <rect x=50 y=100 width=200 height=100 stroke=none stroke-width=2 />
 </svg>
 
@@ -295,6 +295,7 @@ let canvas = SVG('#canvas')
 // })
 //
 
+canvas.ellipse(20, 20).center(100, 100)
 let r = canvas.rect(200, 400).move(100, 100)
   .attr('opacity', 0.3)
   .transform({ tx: 300, ty: 500, origin: 'top-left' })
@@ -304,26 +305,38 @@ let wait = 1000
 let rAnim = r.clone().attr('fill', '#f00').animate(wait).attr('fill', '#0f0')
 let rDecl = r.clone().attr('fill', 'blue').animate(new SVG.Spring(wait, 15))
 
-// Move once
-setTimeout(() => {
-  let trans = {tx: 500, ty: 300}
-  r.transform(trans, true)
-  rAnim.animate(wait, 0, 'start').transform(trans, true)
-  //rDecl.transform(trans, true)
-}, wait)
-
-// Move again
+// // Move once
 // setTimeout(() => {
-//   let trans = {rotate: 300}
+//   let trans = {tx: 500, ty: 300}
 //   r.transform(trans, true)
-//   rAnim.animate(wait).transform(trans, true)
-//   //rDecl.transform(trans, true)
-// }, 1.5 * wait )
-
-
-
-
+//   // rAnim.animate(wait, 0, 'start').transform(trans, true)
+//   rDecl.transform(trans, true)
+// }, wait)
 
+// Move again
+setTimeout(() => {
+  let transform = {
+    origin: 'top-left',
+    translate: [530, 250],
+    rotate: 300,
+    scale: 2,
+    shear: 1,
+  }
+  let relative = true
+  let affine = false
+  r.transform(transform, relative)
+  rAnim.animate(wait).transform(transform, relative, affine)
+  rDecl.transform(transform, relative, affine)
+}, 0.1 * wait )
+
+
+// declaritive relative (affine/nonaffine)
+// declaritive absolute non affine
+// normal non affine relative
+
+//    D N
+// R
+// A
 
 
 
index d4abc08bd2a2c729a4907bdc86e54ffdc8bb9b73..44bce729915581893f8af87f0e3667f9d4df3f55 100644 (file)
@@ -249,9 +249,10 @@ function formatTransforms (o) {
 }
 
 
-function getOrigin (o, element) {
+function getOrigin (o, element, relative) {
   // Allow origin or around as the names
   let origin = o.around == null ? o.origin : o.around
+  let ox, oy
 
   // Allow the user to pass a string to rotate around a given point
   if (typeof origin === 'string' || origin == null) {
@@ -269,13 +270,22 @@ function getOrigin (o, element) {
       : y + height / 2
 
     // Set the bounds eg : "bottom-left", "Top right", "middle" etc...
-    const ox = o.ox != null ? o.ox : bx
-    const oy = o.oy != null ? o.oy : by
+    ox = o.ox != null ? o.ox : bx
+    oy = o.oy != null ? o.oy : by
 
-    // Set the origin based on the current matrix location
-    return [ox, oy]
+  } else {
+    ox = origin[0]
+    oy = origin[1]
+  }
+
+  // Transform the origin into the current reference frame
+  if ( relative ) {
+    let matrix = new SVG.Matrix(element)
+    let originRelative = new SVG.Point( ox, oy ).transform(matrix)
+    ox = originRelative.x
+    oy = originRelative.y
   }
 
   // Return the origin as it is if it wasn't a string
-  return origin
+  return [ ox, oy ]
 }
index e82d641b5504e6cf23ec817ef166d92d7f519861..881efd412e46ad2231d6141f6c247e6d66804282 100644 (file)
@@ -615,8 +615,10 @@ SVG.extend(SVG.Runner, {
   //
   // M v -----|-----(D M v = F v)------|----->  T v
   //
-  // 1. define the final state (T) and decompose it (once) t = [tx, ty, the, lam, sy, sx]
-  // 2. on every frame: pull the current state of all previous transforms (M - m can change)
+  // 1. define the final state (T) and decompose it (once)
+  //    t = [tx, ty, the, lam, sy, sx]
+  // 2. on every frame: pull the current state of all previous transforms
+  //    (M - m can change)
   //   and then write this as m = [tx0, ty0, the0, lam0, sy0, sx0]
   // 3. Find the interpolated matrix F(pos) = m + pos * (t - m)
   //   - Note F(0) = M
@@ -624,38 +626,43 @@ SVG.extend(SVG.Runner, {
   // 4. Now you get the delta matrix as a result: D = F * inv(M)
 
   transform: function (transforms, relative, affine) {
-    if (this._isDeclarative && this._tryRetarget('transform', transforms)) {
+    // If we have a declarative function, we should retarget it if possible
+    relative = transforms.relative || relative
+    if (this._isDeclarative && !relative && this._tryRetarget('transform', transforms)) {
       return this
     }
 
     // Parse the parameters
     var isMatrix = transforms.a != null
-    relative = transforms.relative || relative
     affine = transforms.affine != null
       ? transforms.affine
       : (affine != null ? affine : !isMatrix)
 
-
-    const morpher = new SVG.Morphable().type(
-      affine ? SVG.Morphable.TransformBag2 : SVG.Matrix
-    ).stepper(this._stepper)
+    // Create a morepher and set its type
+    const morpher = new SVG.Morphable()
+      .type( affine ? SVG.Morphable.TransformBag2 : SVG.Matrix )
+      .stepper(this._stepper)
 
     let origin
     let element
     let current
     let currentAngle
     var u = 0
-    this.queue(function () {
+
+    function setup () {
 
       // make sure element and origin is defined
       element = element || this.element()
-      origin = origin || getOrigin(transforms, element)
+      origin = origin || getOrigin(transforms, element, relative)
+
+this.element().parent().ellipse(50, 50).center(...origin)
 
       // add the runner to the element so it can merge transformations
       element.addRunner(this)
 
       // Deactivate all transforms that have run so far if we are absolute
-      if (!relative) {
+      let absolute = !relative
+      if ( absolute ) {
         element._clearTransformRunnersBefore(this)
       }
 
@@ -686,7 +693,9 @@ SVG.extend(SVG.Runner, {
       morpher.from(start)
       morpher.to(target)
 
-    }, function (pos) {
+    }
+
+    function run (pos) {
 
       // clear all other transforms before this in case something is saved
       // on this runner. We are absolute. We dont need these!
@@ -705,23 +714,25 @@ SVG.extend(SVG.Runner, {
       current = new SVG.Matrix(affineParameters)
 
       this.addTransform(current)
-
       return morpher.done()
+    }
 
-    }, function (newTransforms) {
+    function retarget (newTransforms) {
 
       // only get a new origin if it changed since the last call
-      if ((newTransforms.origin || 'center').toString() != (transforms.origin || 'center').toString()) {
+      if (
+        (newTransforms.origin || 'center').toString()
+        != (transforms.origin || 'center').toString()
+      ) {
         origin = getOrigin (transforms, element)
       }
 
       // overwrite the old transformations with the new ones
       transforms = {...newTransforms, origin}
-    })
-
+    }
 
+    this.queue(setup, run, retarget)
     this._isDeclarative && this._rememberMorpher('transform', morpher)
-
     return this
   },
 
index 0549d7a70246750597f39ba2a31ed9f4dda2593b..35eb53e115f4b69da6531938f35c9f76fbe4da0b 100644 (file)
@@ -58,7 +58,7 @@ SVG.extend(SVG.Element, {
     }
 
     // Set the origin according to the defined transform
-    o = {...o, origin: getOrigin(o, this, relative)}
+    o = {...o, origin: getOrigin(o, this)}
 
     // The user can pass a boolean, an SVG.Element or an SVG.Matrix or nothing
     var cleanRelative = relative === true ? this : (relative || false)