    /** @module ViewBox */
    /**
     * ViewBox provides an api for oprerating with the viewBox argument of the <svg> DOM element.
     */
    export default class ViewBox {
        /**
         * Initialize viewBox
         * @param {number} left   distance of the left edge of the viewbox from document's y axis in SVG pixels
         * @param {number} top    distance of the top edge of the viewbox from the document's x axis in SVG pixels
         * @param {number} width  width of the viewbox in SVG pixels
         * @param {number} height height of the viewbox in SVG pixels
         */
        constructor(left, top, width, height) {
            /**
             * ViewBox attributes before applying zoom and shift
             * @type {object}
             */
            this.real = { left, top, width, height };

            /**
             * The maximum amount of zoom on the viewbox
             * @type {number}
             */
            this.maxZoom = 8;
            /**
             * The minimum amount of zoom on the viewbox
             * @type {number}
             */
            this.minZoom = 0.1;

            /**
             * Amount of zoom on the viewbox, always between this.minZoom and this.maxZoom
             * @type {number}
             */
            this.realZoom = 1;

            /**
             * amount of horizontal shift of the document
             * @type {number}
             */
            this.leftShift = 0;
            /**
             * amount of vertical shift of the document
             * @type {number}
             */
            this.topShift = 0;
        }

        /**
         * update the dimensions of the viewbox (used on window resize)
         * @param  {Number} width  new width of the viewbox in SVG pixels
         * @param  {Number} height new height of the viewbox in SVG pixels
         */
        newDimensions(width, height) {
            // keep the viewbox centered
            this.real.left += (this.real.width - width) / 2;
            this.real.top += (this.real.height - height) / 2;

            // update the dimensions
            this.real.width = width;
            this.real.height = height;
        }

        /**
         * apply viewbox movement and take the zoom into account
         * @param  {number} left horizontal movement
         * @param  {number} top  vertical movement
         */
        move(left, top) {
            this.leftShift += left / this.zoom;
            this.topShift += top / this.zoom;
        }

        /**
         * get the amount of zoom on the viewbox
         * @return {number}
         */
        get zoom() {
            return this.realZoom;
        }

        /**
         * set the amount of zoom on the viewbox
         * @param {number} value the new amount of zoom
         */
        set zoom(value) {
            // fit this.realZoom to fit between this.minZoom and this.maxZoom
            this.realZoom = Math.max(Math.min(value, this.maxZoom), this.minZoom);
        }

        /**
         * get the width of the viewbox with the current zoom applied
         * @return {number} the final width of the viewbox
         */
        get width() {
            return this.real.width / this.zoom;
        }

        /**
         * get the height of the viewbox with the current zoom applied
         * @return {number} the final height of the viewbox
         */
        get height() {
            return this.real.height / this.zoom;
        }

        /**
         * get the horizontal distance from the y axis of the document with zoom and shift value applied
         * @return {number}
         */
        get left() {
            return this.real.left - this.leftShift + (this.real.width - this.width) / 2;
        }

        /**
         * get the vertical distance from the x axis of the document with zoom and shift value applied
         * @return {number}
         */
        get top() {
            return this.real.top - this.topShift + (this.real.height - this.height) / 2;
        }

        /**
         * get the computed viewbox values as a string in the correct format that can be used in the viewBox attribute of the SVG element
         * @return {string} string in format "left top width height"
         */
        get str() {
            return `${this.left} ${this.top} ${this.width} ${this.height}`;
        }

        /**
         * transform horizontal units to the scale and shift of the editor
         * @param  {number} x original horizontal value
         * @return {number}   transformed horizontal value
         */
        transformX(x) {
            return this.left + x / this.zoom;
        }

        /**
         * transform vertical units to the scale and shift of the editor
         * @param  {number} y original vertical value
         * @return {number}   transformed vertical value
         */
        transformY(y) {
            return this.top + y / this.zoom;
        }

        /**
         * transform pageX and pageY parameters of the jquery event to match the zoom and shift of the viewbox
         * @param  {jquery.MouseEvent} event original event
         * @return {jquery.MouseEvent}       the same event but with transformed pageX and pageY members
         */
        transformEvent(event) {
            event.pageX = this.transformX(event.pageX);
            event.pageY = this.transformY(event.pageY);

            return event;
        }
    }