src_js/iconolab-bundle/src/components/editor/ZoomThumbnail.vue
author Alexandre Segura <mex.zktk@gmail.com>
Tue, 14 Mar 2017 14:10:16 +0100
changeset 428 722d8e9e2f6e
parent 355 004fdb42f063
child 502 89dc19ad8073
permissions -rw-r--r--
Limit zoom handler to bounds.

<template>
    <div>
        <svg ref="svg" v-bind:width="thumbnailWidth" v-bind:height="thumbnailHeight">
            <image xmlns:xlink="http://www.w3.org/1999/xlink"
                x="0" y="0"
                v-bind:width="thumbnailWidth" v-bind:height="thumbnailHeight"
                v-bind:xlink:href="image"></image>
            <rect ref="handler"
                class="move-handler"
                v-bind:x="x" v-bind:y="y"
                v-bind:width="width" v-bind:height="height"
                style="fill: black; opacity: 0.4"></rect>
        </svg>
    </div>
</template>

<script>

    import Snap from 'snapsvg'

    // See http://svg.dabbles.info/snaptut-drag-limit
    Snap.plugin( function( Snap, Element, Paper, global ) {

        Element.prototype.limitDrag = function( params ) {

            var onMove = function(dx, dy) {
                limitMoveDrag.apply(this, arguments);
                params.onMove.apply(this, arguments);
            }

            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('ibb', this.getBBox());
            this.data('ot', this.transform().local);

            this.drag(onMove, limitStartDrag);

            return this;
        };

        function limitMoveDrag( dx, dy ) {
            var tdx, tdy;
            var sInvMatrix = this.transform().globalMatrix.invert();
            sInvMatrix.e = sInvMatrix.f = 0;
            tdx = sInvMatrix.x( dx,dy ); tdy = sInvMatrix.y( dx,dy );

            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('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('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'));
        };
    });

    export default {
        props: [
            'image',
            'viewport',
            'viewBox',
            'imageWidth',
            'imageHeight',
        ],
        data() {
            return {
                thumbnailWidth: 0,
                thumbnailHeight: 0,
                loaded: false
            }
        },
        computed: {
            x: function() {
                return this.viewBox[0] * this.getRatioX();
            },
            y: function() {
                return this.viewBox[1] * this.getRatioY();
            },
            width: function() {
                return this.viewBox[2] * this.getRatioX();
            },
            height: function() {
                return this.viewBox[3] * this.getRatioY();
            }
        },
        methods: {
            reset: function() {
                var handler = new Snap(this.$refs.handler);
                handler.node.removeAttribute('transform');
            },
            getRatioX: function() {
                if (this.imageWidth === 0) { return 0; }

                return this.thumbnailWidth / this.imageWidth;
            },
            getRatioY: function() {
                if (this.imageHeight === 0) { return 0; }

                return this.thumbnailHeight / this.imageHeight;
            }
        },
        mounted() {

            var svg = new Snap(this.$refs.svg);
            var handler = new Snap(this.$refs.handler);

            var img = new Image();
            img.onload = (e) => {

                svg.attr({
                    viewBox: [0, 0, img.width, img.height]
                });

                Object.assign(this, {
                    thumbnailWidth: img.width,
                    thumbnailHeight: img.height,
                    loaded: true
                });

                var self = this;

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

</script>

<style scoped>
.move-handler {
    cursor: -moz-grab;
    cursor: -webkit-grab;
    cursor: grab;
}
</style>