src_js/iconolab-bundle/src/components/editor/ZoomThumbnail.vue
author ymh <ymh.work@gmail.com>
Thu, 02 Aug 2018 16:15:39 +0200
changeset 593 f8310b7ddef0
parent 502 89dc19ad8073
permissions -rw-r--r--
Added tag 0.1.10 for changeset a87ffe8e08e5

<template>
    <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="svgWidth" v-bind:height="svgHeight"
                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, params.onEnd);

            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('x', this.data('maxx'))
            };
            if (this.data('y') > this.data('maxy')) {
                this.data('y', this.data('maxy'))
            };
            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',
            'parentViewBox',
            'imageWidth',
            'imageHeight',
        ],
        data() {
            return {
                svgWidth: 0,
                svgHeight: 0,
                loaded: false,
                viewBox: [0, 0, 0, 0],
                ratioX: 1,
                ratioY: 1,
            }
        },
        computed: {
            x: function() {
                return this.parentViewBox[0] * this.ratioX
            },
            y: function() {
                return this.parentViewBox[1] * this.ratioY
            },
            width: function() {
                return this.parentViewBox[2] * this.ratioX
            },
            height: function() {
                return this.parentViewBox[3] * this.ratioY
            }
        },
        methods: {
            reset: function() {
                var handler = new Snap(this.$refs.handler);
                handler.node.removeAttribute('transform');
            },
            getCenter: function() {
                const bbox = new Snap(this.$refs.handler).getBBox();

                return {
                    x: bbox.cx / this.ratioX,
                    y: bbox.cy / this.ratioY
                }
            }
        },
        mounted() {

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

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

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

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

            }

            img.src = this.image;
        }
    }

</script>

<style scoped>
.zoom-wrapper {
    background-color: #fff;
}
.move-handler {
    cursor: -moz-grab;
    cursor: -webkit-grab;
    cursor: grab;
}
</style>