PMA.UI Documentation by Pathomation

components/js/syncview.js

import { Events } from './components';
import { Events as ViewEvents } from '../../view/definitions';
import { rotate } from 'ol/coordinate';

/**
 * Automatically handles syncronization of views between slides
 * @param  {SlideLoader[]} slideLoaders - Array of PMA.UI.Components.SlideLoaders.
 */
export class SyncView {
    constructor(slideLoaders) {
        if (!slideLoaders.length) {
            console.error("Expected array of PMA.UI.Components.SlideLoader");
            return;
        }

        this.slideLoaders = slideLoaders;

        // for syncing viewers
        this.eventsKeys = [];
        this.posSync = [];
        this.overridePosition = false;

        this.listeners = {};
        this.listeners[Events.SyncChanged] = [];

        for (var i = 0; i < this.slideLoaders.length; i++) {
            this.slideLoaders[i].listen(Events.BeforeSlideLoad, this.disableSync.bind(this));
        }
    }
    /**
     * Enables synchronization on the slides
     * @fires PMA.UI.Components.Events#SyncChanged
     */
    enableSync() {
        this.posSync = [];

        for (var i = 0; i < this.slideLoaders.length; i++) {
            var slideLoader = this.slideLoaders[i];

            if (slideLoader.mainViewport && slideLoader.mainViewport.map) {
                this.posSync.push(slideLoader.mainViewport.getPosition());

                var parameter = { index: i, self: this, slideLoaders: this.slideLoaders };
                this.eventsKeys.push({ viewport: slideLoader.mainViewport, callback: viewChanged.bind(this, parameter) });
                slideLoader.mainViewport.listen(ViewEvents.ViewChanged, this.eventsKeys[this.eventsKeys.length - 1].callback);
            }
        }

        this.fireEvent(Events.SyncChanged, true);
    }
    /**
     * Disables synchronization on the slides
     * @fires PMA.UI.Components.Events#SyncChanged
     */
    disableSync() {
        if (this.eventsKeys) {
            while (this.eventsKeys.length > 0) {
                var ek = this.eventsKeys.pop();
                var result = ek.viewport.unlisten(ViewEvents.ViewChanged, ek.callback);
            }
        }

        this.posSync = [];

        this.fireEvent(Events.SyncChanged, false);
    }
    /**
     * Returns a value indicating whether slides are synchronized
     * @fires PMA.UI.Components.Events#SyncChanged
     */
    getStatus() {
        return this.eventsKeys && this.eventsKeys.length > 0;
    }
    /**
     * Attaches an event listener
     * @param {PMA.UI.Components.Events} eventName - The name of the event to listen to
     * @param {function} callback - The function to call when the event occurs
     */
    listen(eventName, callback) {
        if (!this.listeners.hasOwnProperty(eventName)) {
            console.error(eventName + " is not a valid event");
        }

        this.listeners[eventName].push(callback);
    }
    // fires an event
    fireEvent(eventName, eventArgs) {
        if (!this.listeners.hasOwnProperty(eventName)) {
            console.error(eventName + " does not exist");
            return;
        }

        for (var i = 0, max = this.listeners[eventName].length; i < max; i++) {
            this.listeners[eventName][i].call(this, eventArgs);
        }
    }
}



var overridePosition = false;
function viewChanged(parameters) {
    if (parameters && !overridePosition) {
        var self = parameters.self;
        var slideLoader = parameters.slideLoaders[parameters.index];
        let flipState = slideLoader.mainViewport.getFlip();
        for (let i = 0; i < parameters.slideLoaders.length; i++) {
            if (parameters.index == i) {
                continue;
            }

            let sl = parameters.slideLoaders[i];

            let flipStateI = sl.mainViewport.getFlip();
            if (flipStateI.horizontally != flipState.horizontally || flipStateI.vertically != flipState.vertically) {
                sl.mainViewport.setFlip(flipState.horizontally, flipState.vertically);
            }

        }

        var pos = slideLoader.mainViewport.getPosition();
        var oldPos = self.posSync[parameters.index];

        if (isNaN(pos.zoom)) {
            return;
        }

        if (oldPos) {
            var diff = {
                zoom: pos.zoom - oldPos.zoom,
                rotation: pos.rotation - oldPos.rotation,
                center: [pos.center[0] - oldPos.center[0], pos.center[1] - oldPos.center[1]]
            };

            self.posSync[parameters.index] = pos;
            oldPos = self.posSync[parameters.index];

            overridePosition = true;
            for (var i = 0; i < parameters.slideLoaders.length; i++) {
                if (i == parameters.index) {
                    continue;
                }

                var p = self.posSync[i];
                if (p) {
                    p.zoom += diff.zoom;
                    p.rotation += diff.rotation;
                    if (p.rotation != oldPos.rotation) {
                        // different rotation 
                        var d = rotate([diff.center[0], diff.center[1]], p.rotation - oldPos.rotation);
                        p.center[0] += d[0];
                        p.center[1] += d[1];
                    }
                    else {
                        p.center[0] += diff.center[0];
                        p.center[1] += diff.center[1];
                    }

                    parameters.slideLoaders[i].mainViewport.setPosition(p, true);
                    parameters.slideLoaders[i].mainViewport.map.getView().dispatchEvent("change:center");
                }

                self.posSync[i] = p;
            }

            overridePosition = false;
        }
    }
}