]> source.dussan.org Git - svg.js.git/commitdiff
Fixed the transformation code to use the bbox properly
authorSaivan <savian@me.com>
Thu, 5 Jul 2018 11:40:08 +0000 (21:40 +1000)
committerSaivan <savian@me.com>
Thu, 5 Jul 2018 11:40:08 +0000 (21:40 +1000)
This commit fixes the transformations and allows single animated
transformations to properly work.

dirty.html
src/helpers.js
src/matrix.js
src/runner.js
src/transform.js
todo.md

index df7c871a8da262d50b754242b809da879385bb9e..3c9b241d925c3ea67b708bb796f0a43af32acfc2 100644 (file)
@@ -259,9 +259,7 @@ SVG('#absolute').on('input slide', function (e) {
 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
@@ -271,20 +269,42 @@ a.timeline().source(() => {
   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})
+// })
+
+
 
 
 
index b25d3b6f161e0791635d23e2f8e1adcecc3896d6..d4abc08bd2a2c729a4907bdc86e54ffdc8bb9b73 100644 (file)
@@ -243,20 +243,8 @@ function formatTransforms (o) {
 
   // 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
   }
 }
 
@@ -273,20 +261,16 @@ function getOrigin (o, element) {
     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]
index 07dc82bc1c5a5387241747cc1e9a1b2c7111e45d..2a9f2a90b978f6c7d9351c73fbe0e2a8433a12d7 100644 (file)
@@ -45,30 +45,30 @@ SVG.Matrix = SVG.invent({
 
       // 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
     },
index 1454ad96891dca034b787245b9ae67dd7c406ca2..da494d3edcba7e7f6df3327f9afef5b676c37157 100644 (file)
@@ -616,8 +616,10 @@ SVG.extend(SVG.Runner, {
 
     // 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
@@ -645,24 +647,23 @@ SVG.extend(SVG.Runner, {
         .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
 
@@ -685,6 +686,7 @@ SVG.extend(SVG.Runner, {
         current = morpher.at(pos).valueOf()
         let matrix = new SVG.Matrix(current)
         this.addTransform(matrix)
+
         return morpher.done()
       }, true)
 
@@ -713,15 +715,8 @@ SVG.extend(SVG.Runner, {
       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)
       }
 
@@ -730,6 +725,7 @@ SVG.extend(SVG.Runner, {
         element._clearTransformRunnersBefore(this)
       }
 
+      // FIXME: This should be current = current || ...
       // Define the starting point for the morpher
       let startMatrix = new SVG.Matrix(relative ? undefined : element)
 
@@ -737,17 +733,18 @@ SVG.extend(SVG.Runner, {
       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)
       }
 
@@ -759,11 +756,13 @@ SVG.extend(SVG.Runner, {
 
       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)
index 8b1d56b056e694114dd4e3382c2e5cb97433dd55..0549d7a70246750597f39ba2a31ed9f4dda2593b 100644 (file)
@@ -58,7 +58,7 @@ SVG.extend(SVG.Element, {
     }
 
     // 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)
@@ -66,132 +66,3 @@ SVG.extend(SVG.Element, {
     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()
-  }
-})
diff --git a/todo.md b/todo.md
index 9b0621ac8144ae15d1535d93b142eb7ec8df30d3..3a9d9ba3168f94b8cfbe0e414c54e8fbdc88a9d9 100644 (file)
--- a/todo.md
+++ b/todo.md
@@ -10,10 +10,10 @@ Ulima
 =====
 - 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
 ====