Fix zoom positioning / center.
authorAlexandre Segura <mex.zktk@gmail.com>
Mon, 15 May 2017 12:38:40 +0200
changeset 502 89dc19ad8073
parent 501 fc3df41fb607
child 503 a6290b2fae6b
Fix zoom positioning / center.
src_js/iconolab-bundle/src/components/editor/Canvas.vue
src_js/iconolab-bundle/src/components/editor/ZoomThumbnail.vue
--- a/src_js/iconolab-bundle/src/components/editor/Canvas.vue	Thu May 11 15:45:08 2017 +0200
+++ b/src_js/iconolab-bundle/src/components/editor/Canvas.vue	Mon May 15 12:38:40 2017 +0200
@@ -91,19 +91,22 @@
                     <i class="fa fa-sign-in"></i> <small>Connexion</small>
                 </a>
             </div>
-            <zoom-thumbnail
-                data-intro="Déplacez vous dans l'image zoomée"
-                data-position="top"
-                class="controls-center"
-                ref="thumbnail"
-                @change="changeViewBox($event)"
-                @dragstart="hideTooltip"
-                @dragend="showTooltip"
-                v-bind:image="thumbnail"
-                v-bind:viewport="viewport"
-                v-bind:viewBox="viewBox"
-                v-bind:imageWidth="imageWidth"
-                v-bind:imageHeight="imageHeight"></zoom-thumbnail>
+            <div class="controls-center">
+                <zoom-thumbnail
+                    data-intro="Déplacez vous dans l'image zoomée"
+                    data-position="top"
+                    ref="thumbnail"
+                    @move="changeViewBox($event)"
+                    @moveend="syncViewBox()"
+                    @dragstart="hideTooltip"
+                    @dragend="showTooltip"
+                    v-if="loaded"
+                    v-bind:image="thumbnail"
+                    v-bind:viewport="viewport"
+                    v-bind:parentViewBox="viewBox"
+                    v-bind:imageWidth="imageWidth"
+                    v-bind:imageHeight="imageHeight"></zoom-thumbnail>
+            </div>
             <div class="controls-right" data-intro="Zoomez dans l'image" data-position="top">
                 <button @click="zoomOut" type="button" class="btn"
                     v-bind:class="{ disabled: scale === 1 }">
@@ -362,10 +365,15 @@
             },
 
             getCenter: function() {
-                return {
-                    x: this.viewBox[0] + (this.viewBox[2] / 2),
-                    y: this.viewBox[1] + (this.viewBox[3] / 2)
+
+                if (!this.$refs.thumbnail) {
+                    return {
+                        x: this.viewBox[0] + (this.viewBox[2] / 2),
+                        y: this.viewBox[1] + (this.viewBox[3] / 2)
+                    }
                 }
+
+                return this.$refs.thumbnail.getCenter()
             },
 
             changeViewBox: function(e) {
@@ -377,9 +385,19 @@
                 this.paper.attr({ "viewBox": viewBox });
             },
 
+            syncViewBox: function() {
+                const viewBox = this.paper.attr('viewBox');
+                this.viewBox = [
+                    viewBox.x, viewBox.y,
+                    viewBox.width, viewBox.height
+                ]
+            },
+
             resetZoom: function() {
                 this.scale = 1;
-                this.$refs.thumbnail.reset();
+                if (this.$refs.thumbnail) {
+                    this.$refs.thumbnail.reset();
+                }
             },
 
             animateViewBox: function(viewBox, cb) {
@@ -677,7 +695,7 @@
     }
     .controls .controls-center {
         border-radius: 4px;
-        padding: 8px 8px 4px 8px;
+        padding: 8px;
     }
     .controls .controls-right {
         border-top-right-radius: 4px;
--- a/src_js/iconolab-bundle/src/components/editor/ZoomThumbnail.vue	Thu May 11 15:45:08 2017 +0200
+++ b/src_js/iconolab-bundle/src/components/editor/ZoomThumbnail.vue	Mon May 15 12:38:40 2017 +0200
@@ -1,9 +1,9 @@
 <template>
-    <div>
-        <svg ref="svg" v-bind:width="thumbnailWidth" v-bind:height="thumbnailHeight">
+    <div class="zoom-wrapper" v-bind:style="{ width: svgWidth + 'px', height: svgHeight + 'px' }">
+        <svg ref="svg" v-bind:width="svgWidth" v-bind:height="svgHeight">
             <image xmlns:xlink="http://www.w3.org/1999/xlink"
                 x="0" y="0"
-                v-bind:width="thumbnailWidth" v-bind:height="thumbnailHeight"
+                v-bind:width="svgWidth" v-bind:height="svgHeight"
                 v-bind:xlink:href="image"></image>
             <rect ref="handler"
                 class="move-handler"
@@ -30,11 +30,12 @@
 
             this.data('minx', params.minx); this.data('miny', params.miny);
             this.data('maxx', params.maxx); this.data('maxy', params.maxy);
-            this.data('x', params.x); this.data('y', params.y);
+            this.data('x', params.x);
+            this.data('y', params.y);
             this.data('ibb', this.getBBox());
             this.data('ot', this.transform().local);
 
-            this.drag(onMove, limitStartDrag);
+            this.drag(onMove, limitStartDrag, params.onEnd);
 
             return this;
         };
@@ -47,20 +48,26 @@
 
             this.data('x', +this.data('ox') + tdx);
             this.data('y', +this.data('oy') + tdy);
-            if (this.data('x') > this.data('maxx') - this.data('ibb').width) {
-                this.data('x', this.data('maxx') - this.data('ibb').width)
+
+            if (this.data('x') > this.data('maxx')) {
+                this.data('x', this.data('maxx'))
+            };
+            if (this.data('y') > this.data('maxy')) {
+                this.data('y', this.data('maxy'))
             };
-            if (this.data('y') > this.data('maxy') - this.data('ibb').height) {
-                this.data('y', this.data('maxy') - this.data('ibb').height)
+            if (this.data('x') < this.data('minx')) {
+                this.data('x', this.data('minx'))
             };
-            if (this.data('x') < this.data('minx')) { this.data('x', this.data('minx')) };
-            if (this.data('y') < this.data('miny')) { this.data('y', this.data('miny')) };
+            if (this.data('y') < this.data('miny')) {
+                this.data('y', this.data('miny'))
+            };
 
             this.transform( this.data('ot') + "t" + [ this.data('x'), this.data('y') ]);
         };
 
         function limitStartDrag( x, y, ev ) {
-            this.data('ox', this.data('x')); this.data('oy', this.data('y'));
+            this.data('ox', this.data('x'));
+            this.data('oy', this.data('y'));
         };
     });
 
@@ -68,29 +75,32 @@
         props: [
             'image',
             'viewport',
-            'viewBox',
+            'parentViewBox',
             'imageWidth',
             'imageHeight',
         ],
         data() {
             return {
-                thumbnailWidth: 0,
-                thumbnailHeight: 0,
-                loaded: false
+                svgWidth: 0,
+                svgHeight: 0,
+                loaded: false,
+                viewBox: [0, 0, 0, 0],
+                ratioX: 1,
+                ratioY: 1,
             }
         },
         computed: {
             x: function() {
-                return this.viewBox[0] * this.getRatioX();
+                return this.parentViewBox[0] * this.ratioX
             },
             y: function() {
-                return this.viewBox[1] * this.getRatioY();
+                return this.parentViewBox[1] * this.ratioY
             },
             width: function() {
-                return this.viewBox[2] * this.getRatioX();
+                return this.parentViewBox[2] * this.ratioX
             },
             height: function() {
-                return this.viewBox[3] * this.getRatioY();
+                return this.parentViewBox[3] * this.ratioY
             }
         },
         methods: {
@@ -98,48 +108,69 @@
                 var handler = new Snap(this.$refs.handler);
                 handler.node.removeAttribute('transform');
             },
-            getRatioX: function() {
-                if (this.imageWidth === 0) { return 0; }
+            getCenter: function() {
+                const bbox = new Snap(this.$refs.handler).getBBox();
 
-                return this.thumbnailWidth / this.imageWidth;
-            },
-            getRatioY: function() {
-                if (this.imageHeight === 0) { return 0; }
-
-                return this.thumbnailHeight / this.imageHeight;
+                return {
+                    x: bbox.cx / this.ratioX,
+                    y: bbox.cy / this.ratioY
+                }
             }
         },
         mounted() {
 
-            var svg = new Snap(this.$refs.svg);
-            var handler = new Snap(this.$refs.handler);
+            const svg = new Snap(this.$refs.svg);
+            const handler = new Snap(this.$refs.handler);
 
             var img = new Image();
             img.onload = (e) => {
 
-                svg.attr({
-                    viewBox: [0, 0, img.width, img.height]
+                // The zoom needs to have the same dimensions as the viewport,
+                // in order to reflect the position accordingly
+                const imageSize = Math.max(img.width, img.height);
+                const viewportSize = Math.max(this.viewport.width, this.viewport.height);
+                const viewportRatio = imageSize / viewportSize;
+
+                const svgWidth = (this.viewport.width * viewportRatio);
+                const svgHeight = (this.viewport.height * viewportRatio);
+
+                const viewBox = [0, 0, svgWidth, svgHeight];
+
+                const ratioX = (viewBox[2] / this.parentViewBox[2])
+                const ratioY = (viewBox[3] / this.parentViewBox[3])
+
+                Object.assign(this, {
+                    svgWidth: svgWidth,
+                    svgHeight: svgHeight,
+                    viewBox: viewBox,
+                    ratioX: ratioX,
+                    ratioY: ratioY,
+                    loaded: true
                 });
 
-                Object.assign(this, {
-                    thumbnailWidth: img.width,
-                    thumbnailHeight: img.height,
-                    loaded: true
+                svg.attr({
+                    viewBox: viewBox
                 });
 
                 var self = this;
+                setTimeout(() => {
+                    handler.limitDrag({
+                        x: 0, y: 0,
+                        minx: -(svgWidth / 2), miny: -(svgHeight / 2),
+                        maxx: (svgWidth / 2), maxy: (svgHeight / 2),
+                        onMove: function() {
+                            self.$emit('move', {
+                                x: this.getBBox().x / ratioX,
+                                y: this.getBBox().y / ratioY
+                            });
+                        },
+                        onEnd: function() {
+                            this.node.removeAttribute('transform');
+                            self.$emit('moveend')
+                        }
+                    });
+                }, 500);
 
-                handler.limitDrag({
-                    x: 0, y: 0,
-                    minx: -(img.width / 2), miny: -(img.height / 2),
-                    maxx: (img.width / 2), maxy: (img.height / 2),
-                    onMove: function() {
-                        self.$emit('change', {
-                            x: this.getBBox().x * (self.imageWidth / self.thumbnailWidth),
-                            y: this.getBBox().y * (self.imageHeight / self.thumbnailHeight),
-                        });
-                    }
-                });
             }
 
             img.src = this.image;
@@ -149,6 +180,9 @@
 </script>
 
 <style scoped>
+.zoom-wrapper {
+    background-color: #fff;
+}
 .move-handler {
     cursor: -moz-grab;
     cursor: -webkit-grab;