--- 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;