betajs/betajs-media-components

View on GitHub
src/dynamics/_common/helperframe.js

Summary

Maintainability
D
2 days
Test Coverage
Scoped.define("module:Common.Dynamics.Helperframe", [
    "dynamics:Dynamic",
    "base:Async",
    "base:Timers.Timer",
    "base:Objs",
    "browser:Events",
    "browser:Geometry",
    "browser:Info"
], function(Class, Async, Timer, Objs, DomEvents, Geometry, Info, scoped) {
    return Class.extend({
        scoped: scoped
    }, function(inherited) {
        return {

            attrs: {
                "css": "ba-videorecorder",
                "framereversable": true,
                "framedragable": true,
                "frameresizeable": false,
                "framepositionx": 5,
                "framepositiony": 5,
                "frameminwidth": 120,
                "frameminheight": 95,
                "initialpositionx": null,
                "initialpositiony": null,
                "initialwidth": null,
                "initialheight": null,
                "flipframe": false,
                "frameproportional": true,
                "framemainstyle": {
                    opacity: 0.5,
                    position: 'absolute',
                    cursor: 'pointer',
                    zIndex: 100
                }
            },

            types: {
                "framereversable": "boolean",
                "framedragable": "boolean",
                "frameresizeable": "boolean",
                "frameproportional": "boolean",
                "framepositionx": "int",
                "framepositiony": "int",
                "frameminwidth": "int",
                "frameminheight": "int"
            },

            computed: {},

            events: {
                "change:framepositionx change:framepositiony change:framewidth change:frameheight": function(value) {
                    if (typeof this.recorder !== 'undefined') {
                        if (typeof this.recorder._recorder === 'object' && this.__visibleDimensions.accessible) {
                            this.recorder._recorder.updateMultiStreamPosition(
                                this.get("framepositionx"),
                                this.get("framepositiony"),
                                this.get("framewidth"),
                                this.get("frameheight")
                            );
                        } else {
                            // If previous recorder instance will be destroyed (like after rerecord)
                            this.recorder = this.__parent.recorder;
                        }
                    }
                }
            },

            create: function() {
                var _interactionEvent;
                var _frameClicksCount = 0;
                this.__parent = this.parent();
                this.__initialSettings = {
                    reversable: this.get("framereversable"),
                    dragable: this.get("framedragable"),
                    resizeable: this.get("frameresizeable")
                };

                Objs.iter(this.get("framemainstyle"), function(value, index) {
                    this.activeElement().style[index] = value;
                }, this);

                if (!this.get("initialpositionx") || !this.get("initialpositiony")) {
                    this.set("initialpositionx", this.get("framepositionx"));
                    this.set("initialpositiony", this.get("framepositiony"));
                }

                // Create additional related elements after reverse element created
                _interactionEvent = (Info.isTouchable() && !Info.isDesktop()) ? 'touch' : 'click';

                this._frameInteractionEventHandler = this.auto_destroy(new DomEvents());

                this.recorder = this.__parent.recorder;
                this.player = this.__parent.player;
                this.__visibleDimensions = {};
                this.__setHelperFrameDimensions();

                // fit frame dimensions based on source resolution
                // Only after we have _recorder informer
                if (!this.__visibleDimensions.accessible) {
                    var timer = new Timer({
                        context: this,
                        fire: function() {
                            if (this.recorder._recorder._videoTrackSettings && typeof this.recorder._recorder._videoTrackSettings.videoElement === 'object' && timer) {
                                this.set("framewidth", this.__parent.get("addstreampositionwidth"));
                                this.set("frameheight", this.__parent.get("addstreampositionheight"));
                                if (!this.get("initialwidth") || !this.get("initialheight")) {
                                    this.set("initialwidth", this.get("framewidth"));
                                    this.set("initialheight", this.get("frameheight"));
                                }
                                this.fitFrameViewOnScreenVideo();
                                timer.stop();
                            }
                        },
                        delay: 10,
                        destroy_on_stop: true,
                        immediate: true
                    });
                }

                if (this.recorder) {
                    // DO RECORDER STUFF
                    this.recorder._recorder.on("multistream-camera-switched", function(dimensions, isReversed) {
                        if (this.__initialSettings.resizeable && this.__resizerElement) {
                            this.set("frameresizeable", isReversed);
                            this.__resizerElement.style.display = isReversed ? 'none' : 'block';
                        }
                        this.set("framewidth", dimensions.width);
                        this.set("frameheight", dimensions.height);
                    }, this);

                    // If Reverse Cameras Settings is true
                    if (this.get("framereversable")) {
                        this._frameInteractionEventHandler.on(this.activeElement(), _interactionEvent, function(ev) {
                            _frameClicksCount++;
                            // because not enough info regarding supported versions also not be able to support mobile, avoided to use dblclick event
                            if (_frameClicksCount === 1)
                                Async.eventually(function() {
                                    _frameClicksCount = 0;
                                }, this, 400);

                            if (_frameClicksCount >= 2) {
                                this.recorder.reverseCameraScreens();
                            }
                        }, this);
                    }

                    // If Drag Settings is true
                    if (this.get("framedragable"))
                        this.addDragOption(this.__parent.activeElement());

                    if (this.get("frameresizeable")) {
                        this.addResize((Info.isTouchable() && !Info.isDesktop()), null, {
                            width: '7px',
                            height: '7px',
                            borderRight: '1px solid white',
                            borderBottom: '1px solid white',
                            bottom: 0,
                            right: 0,
                            position: 'absolute',
                            cursor: 'nwse-resize',
                            zIndex: 200
                        });
                    }
                } else if (this.player) {
                    // DO PLAYER STUFF
                }
            },

            functions: {},

            /**
             * Will calculate real
             * @private
             */
            fitFrameViewOnScreenVideo: function() {

                // It will be accessible when at least one of the
                // EventListeners will be fired
                var vts = this.recorder._recorder._videoTrackSettings;
                if (!vts)
                    return;
                var _height = this.__parent.get('height') ? vts.videoElement.height : vts.videoInnerFrame.height;

                if (!this.__vts) this.__vts = vts;

                this.__translate = Geometry.padFitBoxInBox(vts.width, vts.height, vts.videoElement.width, _height);

                if (!this.__resizing) {
                    this.__visibleDimensions.x = this.__translate.offsetX + this.get("framepositionx") * this.__translate.scale;
                    this.__visibleDimensions.y = this.__translate.offsetY + this.get("framepositiony") * this.__translate.scale;
                }

                this.__visibleDimensions.width = this.get("framewidth") * this.__translate.scale;
                this.__visibleDimensions.height = this.get("frameheight") * this.__translate.scale;

                this.__visibleDimensions.accessible = true;

                if (!this.__dragging && !this.__resizing) {
                    this.__positions = {
                        initialX: this.__visibleDimensions.x,
                        initialY: this.__visibleDimensions.y,
                        currentX: this.__visibleDimensions.x,
                        currentY: this.__visibleDimensions.y,
                        bottomX: this.__visibleDimensions.x + this.__visibleDimensions.width,
                        bottomY: this.__visibleDimensions.y + this.__visibleDimensions.height,
                        xOffset: 0,
                        yOffset: 0
                    };
                }

                this.__setHelperFrameDimensions();
            },

            /**
             * Will add Drag
             *
             * @param {HTMLElement} container
             * @private
             */
            addDragOption: function(container) {
                this._draggingEvent = this.auto_destroy(new DomEvents());

                var isTouchable = Info.isTouchable() && !Info.isDesktop();
                // switch to touch events if using a touch screen
                var _endEvent = isTouchable ? 'touchend' : 'mouseup';
                var _moveEvent = isTouchable ? 'touchmove' : 'mousemove';
                var _startEvent = isTouchable ? 'touchstart' : 'mousedown';

                this._draggingEvent.on(container, _endEvent, this.__handleMouseEndEvent, this);
                this._draggingEvent.on(container, _moveEvent, this.__handleMouseMoveEvent, this);
                this._draggingEvent.on(container, _startEvent, this.__handleMouseStartEvent, this);
            },

            /**
             * @param {Boolean} isTouchDevice
             * @param {HTMLElement} container
             * @param {Object} options
             * @private
             */
            addResize: function(isTouchDevice, container, options) {
                container = container || this.activeElement();

                this.__resizerElement = document.createElement('div');

                Objs.iter(options, function(value, index) {
                    this.__resizerElement.style[index] = value;
                }, this);

                container.append(this.__resizerElement);
                this.__resizeEvent = this.auto_destroy(new DomEvents());
            },

            /**
             * Handle Draggable Element Mouse Event
             *
             * @param {MouseEvent|TouchEvent} ev
             * @private
             */
            __handleMouseStartEvent: function(ev) {
                ev.preventDefault();
                if (typeof this.__visibleDimensions.accessible === 'undefined') {
                    this.fitFrameViewOnScreenVideo();
                    return;
                }
                this.__dragging = ev.target === this.activeElement();
                this.__resizing = ev.target === this.__resizerElement;

                if (typeof this.__positions === 'object') {
                    if (ev.type === "touchstart") {
                        this.__positions.initialX = ev.touches[0].clientX - this.__positions.xOffset;
                        this.__positions.initialY = ev.touches[0].clientY - this.__positions.yOffset;
                    } else {
                        if (this.__dragging) {
                            this.__positions.initialX = ev.clientX - this.__positions.xOffset;
                            this.__positions.initialY = ev.clientY - this.__positions.yOffset;
                        }
                        this.__positions.bottomX = this.__positions.initialX + this.__visibleDimensions.width;
                        this.__positions.bottomY = this.__positions.initialY + this.__visibleDimensions.height;
                    }
                }
            },


            /**
             * Listener of mouse movement
             *
             * @param {MouseEvent|TouchEvent} ev
             * @private
             */
            __handleMouseMoveEvent: function(ev) {
                var setTranslate = function(el, posX, posY) {
                    el.style.transform = "translate3d(" + posX + "px, " + posY + "px, 0)";
                };

                var setDimension = function(el, width, height) {
                    el.style.width = width;
                    el.style.height = height;
                };

                ev.preventDefault();
                if (!this.__dragging && !this.__resizing) return;
                this.activeElement().style.cursor = 'move';
                this.activeElement().style.opacity = '0';

                var _diffX, _diffY;

                if (ev.type === "touchmove") {
                    this.__positions.currentX = ev.touches[0].clientX - this.__positions.initialX;
                    this.__positions.currentY = ev.touches[0].clientY - this.__positions.initialY;
                } else {
                    if (this.__dragging) {
                        this.__positions.currentX = ev.clientX - this.__positions.initialX;
                        this.__positions.currentY = ev.clientY - this.__positions.initialY;
                    }

                    if (this.__resizing) {
                        // var _d = this.activeElement().getBoundingClientRect();
                        // this.__visibleDimensions.width = this.get("framewidth") * this.__translate.scale;
                        // this.__visibleDimensions.height = this.get("frameheight") * this.__translate.scale;
                        _diffX = ev.clientX - this.__positions.bottomX; //(this.__positions.currentX + this.__visibleDimensions.width);
                        _diffY = ev.clientY - this.__positions.bottomY; //(this.__positions.currentY + this.__visibleDimensions.height);
                    }
                }


                if (this.__dragging) {
                    this.__positions.xOffset = this.__positions.currentX;
                    this.__positions.yOffset = this.__positions.currentY;

                    setTranslate(this.activeElement(), this.__positions.currentX, this.__positions.currentY);
                    this.set("framepositionx", this.__positions.currentX / this.__translate.scale + this.get("initialpositionx"));
                    this.set("framepositiony", this.__positions.currentY / this.__translate.scale + this.get("initialpositiony"));
                }

                if (this.__resizing) {
                    var _height;
                    var _width = this.__visibleDimensions.width + _diffX;
                    if (this.get("frameproportional"))
                        _height = _width / this.__vts.aspectRatio;
                    else
                        _height = this.__visibleDimensions.height + _diffY;

                    this.__positions.bottomX = this.__positions.currentX + _width;
                    this.__positions.bottomY = this.__positions.currentY + _height;

                    this.set("framewidth", _width / this.__translate.scale);
                    this.set("frameheight", _height / this.__translate.scale);

                    this.fitFrameViewOnScreenVideo();
                    setDimension(this.activeElement(), _width, _height);
                }

            },

            /**
             * Listener of movement end
             *
             * @param {MouseEvent|TouchEvent} ev
             * @private
             */
            __handleMouseEndEvent: function(ev) {
                ev.preventDefault();
                if (!this.__dragging && !this.__resizing) return;

                if (!this.__resizing) {
                    this.__positions.initialX = this.__positions.currentX;
                    this.__positions.initialY = this.__positions.currentY;
                } else {
                    this.__positions.bottomX = this.__positions.currentX + this.__visibleDimensions.width;
                    this.__positions.bottomY = this.__positions.currentY + this.__visibleDimensions.height;
                }

                this.activeElement().style.cursor = 'pointer';
                this.activeElement().style.opacity = this.get("framemainstyle").opacity;

                this.__dragging = false;
                this.__resizing = false;
            },

            /**
             * Helper method will set dimensions for multi-screen recorder related elements
             *
             * @param {HTMLElement=} element - HTML element or Null to set dimentions and position
             * @private
             */
            __setHelperFrameDimensions: function(element) {
                element = element || this.activeElement();
                if (element) {
                    element.style.top = this.__visibleDimensions.y + 'px';
                    element.style.left = this.__visibleDimensions.x + 'px';
                    element.style.width = this.__visibleDimensions.width + 'px';
                    element.style.height = this.__visibleDimensions.height + 'px';
                }
            }
        };
    }).register("ba-helperframe");
});