<commit_before>(function ($) {

    var gallery = (function () {
        var images = [];
        var currentImage = 0;

        var imageSize = null;
        var smallImageSize = null;
        var thumbnailSize = null;

        function getImage(index) {
            currentImage = index;
            if (currentImage >= images.length)
                return null;
            return images[currentImage];
        }

        function getCurrent() {
            return currentImage;
        }

        function getNext() {
            ++currentImage;
            if (currentImage >= images.length)
                currentImage = 0;
            return getCurrent();
        }

        function getPrevious() {
            if (currentImage <= 0)
                currentImage = images.length;
            --currentImage;
            return getCurrent();
        }

        function loadData(app_label, content_type, object_id, callback) {
            currentImage = 0;
            url = "/gallery/ajax/gallery_data/" + app_label + "/" + content_type + "/" + object_id;

            $.ajax({
                url: url,
                dataType: "json",
                beforeSend: function(xhr) {
                    if (xhr.overrideMimeType)
                        xhr.overrideMimeType("application/json");
                },
                success: function (response) {
                    images= response.images;
                    imageSize = response.image_size;
                    smallImageSize = response.small_image_size;
                    thumbnailSize = response.thumbnail_size;
                    callback(images);
                }
            });
        }

        function getImageSize() {
            return imageSize;
        }

        function getSmallImageSize() {
            return smallImageSize;
        }

        function getThumbnailSize() {
            return thumbnailSize;
        }

        function getCount() {
            return images.length;
        }

        return {
            getImage: getImage,
            current: getCurrent,
            next: getNext,
            prev: getPrevious,
            load: loadData,
            getImageSize: getImageSize,
            getSmallImageSize: getSmallImageSize,
            getThumbnailSize: getThumbnailSize,
            count: getCount
        };
    })();

    var galleryView = (function (gallery) {
        var $galleryView,
            $imageContainer,
            $image,
            $thumbnails,
            $scrollLeft,
            $scrollRight,
            $choices,
            $thumbnailsView,
            $imageView,
            $thumbnailsContainer;

        var winWidth, winHeight, thumbnailWidth, maxOffset;
        var animationInProgress = false;
        var ready = false;

        function isSmall() {
            winWidth = $(window).width();
            winHeight = $(window).height();

            return winWidth < gallery.getImageSize().width + 220 ||
                winHeight < gallery.getImageSize().height +
                gallery.getThumbnailSize().height + 85;
        }

        function checkScrollButtons(left) {
            if (left < 0)
                $scrollLeft.removeClass("content_gallery_inactive");
            else
                $scrollLeft.addClass("content_gallery_inactive");

            if (left > maxOffset)
                $scrollRight.removeClass("content_gallery_inactive");
            else
                $scrollRight.addClass("content_gallery_inactive");
        }

        function scrollToImage(index) {
            left = parseInt($thumbnails.css("left"));
            begin = thumbnailWidth * index;
            end = thumbnailWidth * (index + 1);

            if (left + begin >= 0 && left + end <= $thumbnailsContainer.width())
                return;

            animationInProgress = true;

            if (left + begin < 0) {
                newLeft = -begin;
                $thumbnails.animate({left: newLeft}, function () {
                    animationInProgress = false;
                });
            }

            if (left + end > $thumbnailsContainer.width()) {
                newLeft = $thumbnailsContainer.width() - end;
                $thumbnails.animate({left: newLeft}, function () {
                    animationInProgress = false;
                 });
            }
            checkScrollButtons(newLeft);
        }

       function setImage(index) {
            img = gallery.getImage(index);
            if (!img) return;
            $choices.addClass("choice");
            $($choices[index]).removeClass("choice");
            src = isSmall() ? img.small_image : img.image;
            $image.animate({width: 0, height: 0}, function () {
                $image.attr("src", src);
                $image.animate({width: img.width, height: img.height});
            });
        }

        function changeImage(index) {
            if (animationInProgress) return;
            setImage(index);
            scrollToImage(index);
        }

        function setImageViewSize(imgSize) {
            $imageContainer.width(imgSize.width);
            $imageContainer.css({"line-height": imgSize.height + "px"});
            $imageView.height(imgSize.height);
        }

        function setThumbnailViewSize(imgSize, thumbnailSize) {
            $thumbnails.width(thumbnailWidth * gallery.count());

            container_width = Math.ceil(imgSize.width / thumbnailWidth) * thumbnailWidth;
            if (container_width > imgSize.width + 140)
                container_width -= thumbnailWidth;

            $thumbnailsView.width(container_width + 60);
            $choices.width(thumbnailSize.width)
                    .height(thumbnailSize.height)
                    .css("line-height", (thumbnailSize.height - 2) + "px");
            $thumbnailsView.height(thumbnailSize.height + 2);
            $thumbnailsContainer.width(container_width);
        }

        function setGalleryViewSize(imgSize, thumbnailSize) {
            $galleryView.width(imgSize.width + 200);
            $galleryView.height(imgSize.height + thumbnailSize.height + 45);
        }

        function setGalleryViewPosition() {
            galLeft = (winWidth - $galleryView.outerWidth()) / 2;
            galTop = (winHeight - $galleryView.outerHeight()) / 2;

            $galleryView.css({"top": galTop, "left": galLeft});
        }

        function nextImage() {
            index = gallery.next();
            changeImage(index);
        }

        function previousImage() {
           index = gallery.prev();
           changeImage(index);
        }

        function scrollLeft() {
            if (animationInProgress) return;
            left = parseInt($thumbnails.css("left"));
            if (left < 0) {
                animationInProgress = true;
                $thumbnails.animate({left: "+=" + thumbnailWidth}, function () {
                    animationInProgress = false;
                });
            checkScrollButtons(left + thumbnailWidth);
            }
        }

        function scrollRight() {
            if (animationInProgress) return;
            left = parseInt($thumbnails.css("left"));
            if (left > maxOffset) {
                animationInProgress = true;
                $thumbnails.animate({left: "-=" + thumbnailWidth}, function () {
                    animationInProgress = false;
                });
            checkScrollButtons(left - thumbnailWidth);
            }
        }

        function resize() {
            if (!ready) return;

            imgSize = isSmall() ? gallery.getSmallImageSize() : gallery.getImageSize();
            thumbnailSize = gallery.getThumbnailSize()

            thumbnailWidth = thumbnailSize.width + 8;

            setImageViewSize(imgSize);
            setThumbnailViewSize(imgSize, thumbnailSize);

            maxOffset = $thumbnailsContainer.width() - $thumbnails.width();

            checkScrollButtons(0);

            setGalleryViewSize(imgSize, thumbnailSize);
            setGalleryViewPosition();

            index = gallery.current();
            setImage(index);
        }

        function init(app_label, content_type, object_id) {
            $galleryView = $("#content_gallery_view");
            $imageView = $("#content_gallery_image_view");
            $imageContainer = $(".content_gallery_image_container");
            $image = $(".content_gallery_image_container > img");
            $thumbnailsView = $("#content_gallery_thumbnails_view");
            $scrollLeft = $(".content_gallery_scroll_left");
            $scrollRight = $(".content_gallery_scroll_right");
            $thumbnailsContainer = $(".content_gallery_thumbnails_container");
            $thumbnails = $(".content_gallery_thumbnails_container > ul");

            $thumbnails.on("click", "li", function () {
                setImage($(this).index());
            });

            $(".content_gallery_prev_image").click(previousImage)
            $(".content_gallery_next_image").click(nextImage);
            $scrollLeft.click(scrollLeft);
            $scrollRight.click(scrollRight);

            $thumbnails.empty();

            gallery.load(app_label, content_type, object_id, function (data) {
                $.each(data, function (index, img) {
                    $thumbnails.append($("

")
                                .addClass("choice")
                                .append($("")
                                    .attr("src", img.thumbnail)
                                    )
                                );
                });

                $choices = $thumbnails.children();

                ready = true;
                resize();

                $("#content_gallery").show();
            });
        }

        return {
            init: init,
            resize: resize
        };
    })(gallery);

    $(window).resize(galleryView.resize);

    $(function () {
        $(".open_gallery").click(function() {
            matches = $(this).attr("id").match(/^gallery-(\w+)-(\w+)-(\d+)$/i);
            if (!matches) return;
            app_label = matches[1];
            content_type = matches[2];
            object_id = matches[3];
            galleryView.init(app_label, content_type, object_id);
        });

        $(".content_gallery_close").click(function() {
            $("#content_gallery").hide();
        });
    });
})(jQuery);
<commit_msg>Added setImageFast function when resize<commit_after>(function ($) {

    var gallery = (function () {
        var images = [];
        var currentImage = 0;

        var imageSize = null;
        var smallImageSize = null;
        var thumbnailSize = null;

        function getImage(index) {
            currentImage = index;
            if (currentImage >= images.length)
                return null;
            return images[currentImage];
        }

        function getCurrent() {
            return currentImage;
        }

        function getNext() {
            ++currentImage;
            if (currentImage >= images.length)
                currentImage = 0;
            return getCurrent();
        }

        function getPrevious() {
            if (currentImage <= 0)
                currentImage = images.length;
            --currentImage;
            return getCurrent();
        }

        function loadData(app_label, content_type, object_id, callback) {
            currentImage = 0;
            url = "/gallery/ajax/gallery_data/" + app_label + "/" + content_type + "/" + object_id;

            $.ajax({
                url: url,
                dataType: "json",
                beforeSend: function(xhr) {
                    if (xhr.overrideMimeType)
                        xhr.overrideMimeType("application/json");
                },
                success: function (response) {
                    images= response.images;
                    imageSize = response.image_size;
                    smallImageSize = response.small_image_size;
                    thumbnailSize = response.thumbnail_size;
                    callback(images);
                }
            });
        }

        function getImageSize() {
            return imageSize;
        }

        function getSmallImageSize() {
            return smallImageSize;
        }

        function getThumbnailSize() {
            return thumbnailSize;
        }

        function getCount() {
            return images.length;
        }

        return {
            getImage: getImage,
            current: getCurrent,
            next: getNext,
            prev: getPrevious,
            load: loadData,
            getImageSize: getImageSize,
            getSmallImageSize: getSmallImageSize,
            getThumbnailSize: getThumbnailSize,
            count: getCount
        };
    })();

    var galleryView = (function (gallery) {
        var $galleryView,
            $imageContainer,
            $image,
            $thumbnails,
            $scrollLeft,
            $scrollRight,
            $choices,
            $thumbnailsView,
            $imageView,
            $thumbnailsContainer;

        var winWidth, winHeight, thumbnailWidth, maxOffset;
        var animationInProgress = false;
        var ready = false;

        function isSmall() {
            winWidth = $(window).width();
            winHeight = $(window).height();

            return winWidth < gallery.getImageSize().width + 220 ||
                winHeight < gallery.getImageSize().height +
                gallery.getThumbnailSize().height + 85;
        }

        function checkScrollButtons(left) {
            if (left < 0)
                $scrollLeft.removeClass("content_gallery_inactive");
            else
                $scrollLeft.addClass("content_gallery_inactive");

            if (left > maxOffset)
                $scrollRight.removeClass("content_gallery_inactive");
            else
                $scrollRight.addClass("content_gallery_inactive");
        }

        function scrollToImage(index) {
            left = parseInt($thumbnails.css("left"));
            begin = thumbnailWidth * index;
            end = thumbnailWidth * (index + 1);

            if (left + begin >= 0 && left + end <= $thumbnailsContainer.width())
                return;

            animationInProgress = true;

            if (left + begin < 0) {
                newLeft = -begin;
                $thumbnails.animate({left: newLeft}, function () {
                    animationInProgress = false;
                });
            }

            if (left + end > $thumbnailsContainer.width()) {
                newLeft = $thumbnailsContainer.width() - end;
                $thumbnails.animate({left: newLeft}, function () {
                    animationInProgress = false;
                 });
            }
            checkScrollButtons(newLeft);
        }

       function setImage(index) {
            img = gallery.getImage(index);
            if (!img) return;
            $choices.addClass("choice");
            $($choices[index]).removeClass("choice");
            src = isSmall() ? img.small_image : img.image;
            $image.animate({width: 0, height: 0}, function () {
                $image.attr("src", src);
                $image.animate({width: img.width, height: img.height});
            });
        }

       function setImageFast(index) {
            img = gallery.getImage(index);
            if (!img) return;
            $choices.addClass("choice");
            $($choices[index]).removeClass("choice");
            src = isSmall() ? img.small_image : img.image;
            $image.attr("src", src);
        }

        function changeImage(index) {
            if (animationInProgress) return;
            setImage(index);
            scrollToImage(index);
        }

        function setImageViewSize(imgSize) {
            $imageContainer.width(imgSize.width);
            $imageContainer.css({"line-height": imgSize.height + "px"});
            $imageView.height(imgSize.height);
        }

        function setThumbnailViewSize(imgSize, thumbnailSize) {
            $thumbnails.width(thumbnailWidth * gallery.count());

            container_width = Math.ceil(imgSize.width / thumbnailWidth) * thumbnailWidth;
            if (container_width > imgSize.width + 140)
                container_width -= thumbnailWidth;

            $thumbnailsView.width(container_width + 60);
            $choices.width(thumbnailSize.width)
                    .height(thumbnailSize.height)
                    .css("line-height", (thumbnailSize.height - 2) + "px");
            $thumbnailsView.height(thumbnailSize.height + 2);
            $thumbnailsContainer.width(container_width);
        }

        function setGalleryViewSize(imgSize, thumbnailSize) {
            $galleryView.width(imgSize.width + 200);
            $galleryView.height(imgSize.height + thumbnailSize.height + 45);
        }

        function setGalleryViewPosition() {
            galLeft = (winWidth - $galleryView.outerWidth()) / 2;
            galTop = (winHeight - $galleryView.outerHeight()) / 2;

            $galleryView.css({"top": galTop, "left": galLeft});
        }

        function nextImage() {
            index = gallery.next();
            changeImage(index);
        }

        function previousImage() {
           index = gallery.prev();
           changeImage(index);
        }

        function scrollLeft() {
            if (animationInProgress) return;
            left = parseInt($thumbnails.css("left"));
            if (left < 0) {
                animationInProgress = true;
                $thumbnails.animate({left: "+=" + thumbnailWidth}, function () {
                    animationInProgress = false;
                });
            checkScrollButtons(left + thumbnailWidth);
            }
        }

        function scrollRight() {
            if (animationInProgress) return;
            left = parseInt($thumbnails.css("left"));
            if (left > maxOffset) {
                animationInProgress = true;
                $thumbnails.animate({left: "-=" + thumbnailWidth}, function () {
                    animationInProgress = false;
                });
            checkScrollButtons(left - thumbnailWidth);
            }
        }

        function resize() {
            if (!ready) return;

            imgSize = isSmall() ? gallery.getSmallImageSize() : gallery.getImageSize();
            thumbnailSize = gallery.getThumbnailSize()

            thumbnailWidth = thumbnailSize.width + 8;

            setImageViewSize(imgSize);
            setThumbnailViewSize(imgSize, thumbnailSize);

            maxOffset = $thumbnailsContainer.width() - $thumbnails.width();

            checkScrollButtons(0);

            setGalleryViewSize(imgSize, thumbnailSize);
            setGalleryViewPosition();

            index = gallery.current();
            setImageFast(index);
        }

        function init(app_label, content_type, object_id) {
            $galleryView = $("#content_gallery_view");
            $imageView = $("#content_gallery_image_view");
            $imageContainer = $(".content_gallery_image_container");
            $image = $(".content_gallery_image_container > img");
            $thumbnailsView = $("#content_gallery_thumbnails_view");
            $scrollLeft = $(".content_gallery_scroll_left");
            $scrollRight = $(".content_gallery_scroll_right");
            $thumbnailsContainer = $(".content_gallery_thumbnails_container");
            $thumbnails = $(".content_gallery_thumbnails_container > ul");

            $thumbnails.on("click", "li", function () {
                setImage($(this).index());
            });

            $(".content_gallery_prev_image").click(previousImage)
            $(".content_gallery_next_image").click(nextImage);
            $scrollLeft.click(scrollLeft);
            $scrollRight.click(scrollRight);

            $thumbnails.empty();

            gallery.load(app_label, content_type, object_id, function (data) {
                $.each(data, function (index, img) {
                    $thumbnails.append($("

")
                                .addClass("choice")
                                .append($("")
                                    .attr("src", img.thumbnail)
                                    )
                                );
                });

                $choices = $thumbnails.children();

                ready = true;
                resize();

                $("#content_gallery").show();
            });
        }

        return {
            init: init,
            resize: resize
        };
    })(gallery);

    $(window).resize(galleryView.resize);

    $(function () {
        $(".open_gallery").click(function() {
            matches = $(this).attr("id").match(/^gallery-(\w+)-(\w+)-(\d+)$/i);
            if (!matches) return;
            app_label = matches[1];
            content_type = matches[2];
            object_id = matches[3];
            galleryView.init(app_label, content_type, object_id);
        });

        $(".content_gallery_close").click(function() {
            $("#content_gallery").hide();
        });
    });
})(jQuery);
<|endoftext|>


<commit_before>import { Asset } from '../../../asset/asset.js';

import { AnimEvaluator } from '../../../anim/anim.js';

import { Component } from '../component.js';

import {
    ANIM_PARAMETER_BOOLEAN, ANIM_PARAMETER_FLOAT, ANIM_PARAMETER_INTEGER, ANIM_PARAMETER_TRIGGER, ANIM_STATE_START, ANIM_STATE_END, ANIM_STATE_ANY
} from './constants.js';
import { AnimComponentBinder } from './binder.js';
import { AnimComponentLayer } from './layer.js';
import { AnimController } from './controller.js';
import { AnimStateGraph } from './state-graph.js';

/**
 * @private
 * @component Anim
 * @class
 * @name pc.AnimComponent
 * @augments pc.Component
 * @classdesc The Anim Component allows an Entity to playback animations on models and entity properties.
 * @description Create a new AnimComponent.
 * @param {pc.AnimComponentSystem} system - The {@link pc.ComponentSystem} that created this Component.
 * @param {pc.Entity} entity - The Entity that this Component is attached to.
 * @property {number} speed Speed multiplier for animation play back speed. 1.0 is playback at normal speed, 0.0 pauses the animation.
 * @property {boolean} activate If true the first animation will begin playing when the scene is loaded.
 */
function AnimComponent(system, entity) {
    Component.call(this, system, entity);
}
AnimComponent.prototype = Object.create(Component.prototype);
AnimComponent.prototype.constructor = AnimComponent;

Object.assign(AnimComponent.prototype, {
    /**
     * @private
     * @function
     * @name pc.AnimComponent#loadStateGraph
     * @description Initialises component animation controllers using the provided state graph.
     * @param {object} stateGraph - The state graph asset to load into the component. Contains the states, transitions and parameters used to define a complete animation controller.
     */
    loadStateGraph: function (stateGraph) {
        var data = this.data;
        data.stateGraph = stateGraph;
        data.parameters = stateGraph.parameters;
        data.layers = [];

        var graph;
        if (this.entity.model) {
            var m = this.entity.model.model;
            if (m) {
                graph = m.getGraph();
            }
        } else {
            // animating hierarchy without model
            graph = this.entity;
        }

        function addLayer(name, states, transitions, order) {
            var animBinder = new AnimComponentBinder(this, graph);
            var animEvaluator = new AnimEvaluator(animBinder);
            var controller = new AnimController(
                animEvaluator,
                states,
                transitions,
                data.parameters,
                data.activate
            );
            data.layers.push(new AnimComponentLayer(name, controller, this));
            data.layerIndices[name] = order;
        }

        for (var i = 0; i < stateGraph.layers.length; i++) {
            var layer = stateGraph.layers[i];
            addLayer.bind(this)(layer.name, layer.states, layer.transitions, i);
        }
        this.setupAnimationAssets();
    },

    setupAnimationAssets: function () {
        for (var i = 0; i < this.data.layers.length; i++) {
            var layer = this.data.layers[i];
            var layerName = layer.name;
            for (var j = 0; j < layer.states.length; j++) {
                var stateName = layer.states[j];
                if (stateName !== ANIM_STATE_START && stateName !== ANIM_STATE_END && stateName !== ANIM_STATE_ANY) {
                    var stateKey = layerName + ':' + stateName;
                    if (!this.data.animationAssets[stateKey]) {
                        this.data.animationAssets[stateKey] = {
                            asset: null
                        };
                    }
                }
            }
        }
        this.loadAnimationAssets();
    },

    loadAnimationAssets: function () {
        for (var i = 0; i < this.data.layers.length; i++) {
            var layer = this.data.layers[i];
            for (var j = 0; j < layer.states.length; j++) {
                var stateName = layer.states[j];
                var animationAsset = this.data.animationAssets[layer.name + ':' + stateName];
                if (!animationAsset || !animationAsset.asset) {
                    this.removeNodeAnimations(stateName, layer.name);
                    continue;
                }
                var assetId = animationAsset.asset;
                var asset = this.system.app.assets.get(assetId);
                if (asset.resource) {
                    this.assignAnimation(stateName, asset.resource, layer.name);
                } else {
                    asset.once('load', function (layerName, stateName) {
                        return function (asset) {
                            this.assignAnimation(stateName, asset.resource, layerName);
                        }.bind(this);
                    }.bind(this)(layer.name, stateName));
                    this.system.app.assets.load(asset);
                }
            }
        }
    },

    /**
     * @private
     * @function
     * @name pc.AnimComponent#removeStateGraph
     * @description Removes all layers from the anim component.
     */
    removeStateGraph: function () {
        this.data.stateGraph = null;
        this.data.stateGraphAsset = null;
        this.data.animationAssets = {};
        this.data.layers = [];
        this.data.layerIndices = {};
        this.data.parameters = {};
        this.data.playing = false;
    },

    resetStateGraph: function () {
        if (this.stateGraphAsset) {
            var stateGraph = this.system.app.assets.get(this.stateGraphAsset).resource;
            this.loadStateGraph(stateGraph);
        } else {
            this.removeStateGraph();
        }
    },

    /**
     * @private
     * @function
     * @name pc.AnimComponent#reset
     * @description Reset all of the components layers and parameters to their initial states. If a layer was playing before it will continue playing
     */
    reset: function () {
        this.data.parameters = Object.assign({}, this.data.stateGraph.parameters);
        for (var i = 0; i < this.data.layers.length; i++) {
            var layerPlaying = this.data.layers[i].playing;
            this.data.layers[i].reset();
            this.data.layers[i].playing = layerPlaying;
        }
    },

    /**
     * @private
     * @function
     * @name pc.AnimComponent#findAnimationLayer
     * @description Finds a pc.AnimComponentLayer in this component.
     * @param {string} layerName - The name of the anim component layer to find
     * @returns {pc.AnimComponentLayer} layer
     */
    findAnimationLayer: function (layerName) {
        var layerIndex = this.data.layerIndices[layerName];
        return this.data.layers[layerIndex] || null;
    },

    /**
     * @private
     * @function
     * @name pc.AnimComponent#assignAnimation
     * @description Associates an animation with a state in the loaded state graph. If all states are linked and the pc.AnimComponent.activate value was set to true then the component will begin playing.
     * @param {string} nodeName - The name of the state node that this animation should be associated with.
     * @param {object} animTrack - The animation track that will be assigned to this state and played whenever this state is active.
     * @param {string?} layerName - The name of the anim component layer to update. If omitted the default layer is used.
     */
    assignAnimation: function (nodeName, animTrack, layerName) {
        if (!this.data.stateGraph) {
            // #ifdef DEBUG
            console.error('assignAnimation: Trying to assign an anim track before the state graph has been loaded. Have you called loadStateGraph?');
            // #endif
            return;
        }
        var layer = layerName ? this.findAnimationLayer(layerName) : this.baseLayer;
        if (!layer) {
            // #ifdef DEBUG
            console.error('assignAnimation: Trying to assign an anim track to a layer that doesn\'t exist');
            // #endif
            return;
        }
        layer.assignAnimation(nodeName, animTrack);
    },

    /**
     * @private
     * @function
     * @name pc.AnimComponent#removeStateAnimations
     * @description Removes animations from a state in the loaded state graph.
     * @param {string} nodeName - The name of the state node that should have its animation tracks removed.
     * @param {string?} layerName - The name of the anim component layer to update. If omitted the default layer is used.
     */
    removeNodeAnimations: function (nodeName, layerName) {
        var layer = layerName ? this.findAnimationLayer(layerName) : this.baseLayer;
        if (!layer) {
            // #ifdef DEBUG
            console.error('removeStateAnimations: Trying to remove animation tracks from a state before the state graph has been loaded. Have you called loadStateGraph?');
            // #endif
            return;
        }
        layer.removeNodeAnimations(nodeName);
    },

    getParameterValue: function (name, type) {
        var param = this.data.parameters[name];
        if (param && param.type === type) {
            return param.value;
        }
        // #ifdef DEBUG
        console.log('Cannot get parameter value. No parameter found in anim controller named "' + name + '" of type "' + type + '"');
        // #endif
    },

    setParameterValue: function (name, type, value) {
        var param = this.data.parameters[name];
        if (param && param.type === type) {
            param.value = value;
            return;
        }
        // #ifdef DEBUG
        console.log('Cannot set parameter value. No parameter found in anim controller named "' + name + '" of type "' + type + '"');
        // #endif
    },

    /**
     * @private
     * @function
     * @name pc.AnimComponent#getFloat
     * @description Returns a float parameter value by name.
     * @param {string} name - The name of the float to return the value of.
     * @returns {number} A float
     */
    getFloat: function (name) {
        return this.getParameterValue(name, ANIM_PARAMETER_FLOAT);
    },

    /**
     * @private
     * @function
     * @name pc.AnimComponent#setFloat
     * @description Sets the value of a float parameter that was defined in the animation components state graph.
     * @param {string} name - The name of the parameter to set.
     * @param {number} value - The new float value to set this parameter to.
     */
    setFloat: function (name, value) {
        this.setParameterValue(name, ANIM_PARAMETER_FLOAT, value);
    },

    /**
     * @private
     * @function
     * @name pc.AnimComponent#getInteger
     * @description Returns an integer parameter value by name.
     * @param {string} name - The name of the integer to return the value of.
     * @returns {number} An integer
     */
    getInteger: function (name) {
        return this.getParameterValue(name, ANIM_PARAMETER_INTEGER);
    },

    /**
     * @private
     * @function
     * @name pc.AnimComponent#setInteger
     * @description Sets the value of an integer parameter that was defined in the animation components state graph.
     * @param {string} name - The name of the parameter to set.
     * @param {number} value - The new integer value to set this parameter to.
     */
    setInteger: function (name, value) {
        if (typeof value === 'number' && value % 1 === 0) {
            this.setParameterValue(name, ANIM_PARAMETER_INTEGER, value);
        } else {
            // #ifdef DEBUG
            console.error('Attempting to assign non integer value to integer parameter');
            // #endif
        }
    },

    /**
     * @private
     * @function
     * @name pc.AnimComponent#getBoolean
     * @description Returns a boolean parameter value by name.
     * @param {string} name - The name of the boolean to return the value of.
     * @returns {boolean} A boolean
     */
    getBoolean: function (name) {
        return this.getParameterValue(name, ANIM_PARAMETER_BOOLEAN);
    },

    /**
     * @private
     * @function
     * @name pc.AnimComponent#setBoolean
     * @description Sets the value of a boolean parameter that was defined in the animation components state graph.
     * @param {string} name - The name of the parameter to set.
     * @param {boolean} value - The new boolean value to set this parameter to.
     */
    setBoolean: function (name, value) {
        this.setParameterValue(name, ANIM_PARAMETER_BOOLEAN, !!value);
    },

    /**
     * @private
     * @function
     * @name pc.AnimComponent#getTrigger
     * @description Returns a trigger parameter value by name.
     * @param {string} name - The name of the trigger to return the value of.
     * @returns {boolean} A boolean
     */
    getTrigger: function (name) {
        return this.getParameterValue(name, ANIM_PARAMETER_TRIGGER);
    },

    /**
     * @private
     * @function
     * @name pc.AnimComponent#setTrigger
     * @description Sets the value of a trigger parameter that was defined in the animation components state graph to true.
     * @param {string} name - The name of the parameter to set.
     */
    setTrigger: function (name) {
        this.setParameterValue(name, ANIM_PARAMETER_TRIGGER, true);
    },

    /**
     * @private
     * @function
     * @name pc.AnimComponent#resetTrigger
     * @description Resets the value of a trigger parameter that was defined in the animation components state graph to false.
     * @param {string} name - The name of the parameter to set.
     */
    resetTrigger: function (name) {
        this.setParameterValue(name, ANIM_PARAMETER_TRIGGER, false);
    }
});

Object.defineProperties(AnimComponent.prototype, {
    /**
     * @private
     * @name pc.AnimComponent#stateGraphAsset
     * @type {number}
     * @description The state graph asset this component should use to generate it's animation state graph
     */
    stateGraphAsset: {
        get: function () {
            return this.data.stateGraphAsset;
        },
        set: function (value) {
            if (value === null) {
                this.removeStateGraph();
                return;
            }

            var _id;
            var _asset;

            if (value instanceof Asset) {
                _id = value.id;
                _asset = this.system.app.assets.get(_id);
                if (!_asset) {
                    this.system.app.assets.add(value);
                    _asset = this.system.app.assets.get(_id);
                }
            } else {
                _id = value;
                _asset = this.system.app.assets.get(_id);
            }
            if (!_asset || this.data.stateGraphAsset === _id) {
                return;
            }

            if (_asset.resource) {
                this.data.stateGraph = _asset.resource;
                this.loadStateGraph(this.data.stateGraph);
                _asset.on('change', function (asset) {
                    this.data.stateGraph = new AnimStateGraph(asset._data);
                    this.loadStateGraph(this.data.stateGraph);
                }.bind(this));
            } else {
                _asset.once('load', function (asset) {
                    this.data.stateGraph = asset.resource;
                    this.loadStateGraph(this.data.stateGraph);
                }.bind(this));
                _asset.on('change', function (asset) {
                    this.data.stateGraph = new AnimStateGraph(asset._data);
                    this.loadStateGraph(this.data.stateGraph);
                }.bind(this));
                this.system.app.assets.load(_asset);
            }
            this.data.stateGraphAsset = _id;
        }
    },
    /**
     * @private
     * @name pc.AnimComponent#animationAssets
     * @type {object}
     * @description The animation assets used to load each states animation tracks
     */
    animationAssets: {
        get: function () {
            return this.data.animationAssets;
        },
        set: function (value) {
            this.data.animationAssets = value;
            this.loadAnimationAssets();
        }
    },
    /**
     * @private
     * @name pc.AnimComponent#playable
     * @type {boolean}
     * @readonly
     * @description Returns whether all component layers are currently playable
     */
    playable: {
        get: function () {
            for (var i = 0; i < this.data.layers.length; i++) {
                if (!this.data.layers[i].playable) {
                    return false;
                }
            }
            return true;
        }
    },
    /**
     * @private
     * @name pc.AnimComponent#baseLayer
     * @type {pc.AnimComponentLayer}
     * @readonly
     * @description Returns the base layer of the state graph
     */
    baseLayer: {
        get: function () {
            if (this.data.layers.length > 0) {
                return this.data.layers[0];
            }
            return null;
        }
    }
});

export { AnimComponent };
<commit_msg>ensure parameters are copied when loading a state graph (#2628)<commit_after>import { Asset } from '../../../asset/asset.js';

import { AnimEvaluator } from '../../../anim/anim.js';

import { Component } from '../component.js';

import {
    ANIM_PARAMETER_BOOLEAN, ANIM_PARAMETER_FLOAT, ANIM_PARAMETER_INTEGER, ANIM_PARAMETER_TRIGGER, ANIM_STATE_START, ANIM_STATE_END, ANIM_STATE_ANY
} from './constants.js';
import { AnimComponentBinder } from './binder.js';
import { AnimComponentLayer } from './layer.js';
import { AnimController } from './controller.js';
import { AnimStateGraph } from './state-graph.js';

/**
 * @private
 * @component Anim
 * @class
 * @name pc.AnimComponent
 * @augments pc.Component
 * @classdesc The Anim Component allows an Entity to playback animations on models and entity properties.
 * @description Create a new AnimComponent.
 * @param {pc.AnimComponentSystem} system - The {@link pc.ComponentSystem} that created this Component.
 * @param {pc.Entity} entity - The Entity that this Component is attached to.
 * @property {number} speed Speed multiplier for animation play back speed. 1.0 is playback at normal speed, 0.0 pauses the animation.
 * @property {boolean} activate If true the first animation will begin playing when the scene is loaded.
 */
function AnimComponent(system, entity) {
    Component.call(this, system, entity);
}
AnimComponent.prototype = Object.create(Component.prototype);
AnimComponent.prototype.constructor = AnimComponent;

Object.assign(AnimComponent.prototype, {
    /**
     * @private
     * @function
     * @name pc.AnimComponent#loadStateGraph
     * @description Initialises component animation controllers using the provided state graph.
     * @param {object} stateGraph - The state graph asset to load into the component. Contains the states, transitions and parameters used to define a complete animation controller.
     */
    loadStateGraph: function (stateGraph) {
        var i;
        var data = this.data;
        data.stateGraph = stateGraph;
        data.parameters = {};
        var paramKeys = Object.keys(stateGraph.parameters);
        for (i = 0; i < paramKeys.length; i++) {
            var paramKey = paramKeys[i];
            data.parameters[paramKey] = {
                type: stateGraph.parameters[paramKey].type,
                value: stateGraph.parameters[paramKey].value
            };
        }
        data.layers = [];

        var graph;
        if (this.entity.model) {
            var m = this.entity.model.model;
            if (m) {
                graph = m.getGraph();
            }
        } else {
            // animating hierarchy without model
            graph = this.entity;
        }

        function addLayer(name, states, transitions, order) {
            var animBinder = new AnimComponentBinder(this, graph);
            var animEvaluator = new AnimEvaluator(animBinder);
            var controller = new AnimController(
                animEvaluator,
                states,
                transitions,
                data.parameters,
                data.activate
            );
            data.layers.push(new AnimComponentLayer(name, controller, this));
            data.layerIndices[name] = order;
        }

        for (i = 0; i < stateGraph.layers.length; i++) {
            var layer = stateGraph.layers[i];
            addLayer.bind(this)(layer.name, layer.states, layer.transitions, i);
        }
        this.setupAnimationAssets();
    },

    setupAnimationAssets: function () {
        for (var i = 0; i < this.data.layers.length; i++) {
            var layer = this.data.layers[i];
            var layerName = layer.name;
            for (var j = 0; j < layer.states.length; j++) {
                var stateName = layer.states[j];
                if (stateName !== ANIM_STATE_START && stateName !== ANIM_STATE_END && stateName !== ANIM_STATE_ANY) {
                    var stateKey = layerName + ':' + stateName;
                    if (!this.data.animationAssets[stateKey]) {
                        this.data.animationAssets[stateKey] = {
                            asset: null
                        };
                    }
                }
            }
        }
        this.loadAnimationAssets();
    },

    loadAnimationAssets: function () {
        for (var i = 0; i < this.data.layers.length; i++) {
            var layer = this.data.layers[i];
            for (var j = 0; j < layer.states.length; j++) {
                var stateName = layer.states[j];
                var animationAsset = this.data.animationAssets[layer.name + ':' + stateName];
                if (!animationAsset || !animationAsset.asset) {
                    this.removeNodeAnimations(stateName, layer.name);
                    continue;
                }
                var assetId = animationAsset.asset;
                var asset = this.system.app.assets.get(assetId);
                if (asset.resource) {
                    this.assignAnimation(stateName, asset.resource, layer.name);
                } else {
                    asset.once('load', function (layerName, stateName) {
                        return function (asset) {
                            this.assignAnimation(stateName, asset.resource, layerName);
                        }.bind(this);
                    }.bind(this)(layer.name, stateName));
                    this.system.app.assets.load(asset);
                }
            }
        }
    },

    /**
     * @private
     * @function
     * @name pc.AnimComponent#removeStateGraph
     * @description Removes all layers from the anim component.
     */
    removeStateGraph: function () {
        this.data.stateGraph = null;
        this.data.stateGraphAsset = null;
        this.data.animationAssets = {};
        this.data.layers = [];
        this.data.layerIndices = {};
        this.data.parameters = {};
        this.data.playing = false;
    },

    resetStateGraph: function () {
        if (this.stateGraphAsset) {
            var stateGraph = this.system.app.assets.get(this.stateGraphAsset).resource;
            this.loadStateGraph(stateGraph);
        } else {
            this.removeStateGraph();
        }
    },

    /**
     * @private
     * @function
     * @name pc.AnimComponent#reset
     * @description Reset all of the components layers and parameters to their initial states. If a layer was playing before it will continue playing
     */
    reset: function () {
        this.data.parameters = Object.assign({}, this.data.stateGraph.parameters);
        for (var i = 0; i < this.data.layers.length; i++) {
            var layerPlaying = this.data.layers[i].playing;
            this.data.layers[i].reset();
            this.data.layers[i].playing = layerPlaying;
        }
    },

    /**
     * @private
     * @function
     * @name pc.AnimComponent#findAnimationLayer
     * @description Finds a pc.AnimComponentLayer in this component.
     * @param {string} layerName - The name of the anim component layer to find
     * @returns {pc.AnimComponentLayer} layer
     */
    findAnimationLayer: function (layerName) {
        var layerIndex = this.data.layerIndices[layerName];
        return this.data.layers[layerIndex] || null;
    },

    /**
     * @private
     * @function
     * @name pc.AnimComponent#assignAnimation
     * @description Associates an animation with a state in the loaded state graph. If all states are linked and the pc.AnimComponent.activate value was set to true then the component will begin playing.
     * @param {string} nodeName - The name of the state node that this animation should be associated with.
     * @param {object} animTrack - The animation track that will be assigned to this state and played whenever this state is active.
     * @param {string?} layerName - The name of the anim component layer to update. If omitted the default layer is used.
     */
    assignAnimation: function (nodeName, animTrack, layerName) {
        if (!this.data.stateGraph) {
            // #ifdef DEBUG
            console.error('assignAnimation: Trying to assign an anim track before the state graph has been loaded. Have you called loadStateGraph?');
            // #endif
            return;
        }
        var layer = layerName ? this.findAnimationLayer(layerName) : this.baseLayer;
        if (!layer) {
            // #ifdef DEBUG
            console.error('assignAnimation: Trying to assign an anim track to a layer that doesn\'t exist');
            // #endif
            return;
        }
        layer.assignAnimation(nodeName, animTrack);
    },

    /**
     * @private
     * @function
     * @name pc.AnimComponent#removeStateAnimations
     * @description Removes animations from a state in the loaded state graph.
     * @param {string} nodeName - The name of the state node that should have its animation tracks removed.
     * @param {string?} layerName - The name of the anim component layer to update. If omitted the default layer is used.
     */
    removeNodeAnimations: function (nodeName, layerName) {
        var layer = layerName ? this.findAnimationLayer(layerName) : this.baseLayer;
        if (!layer) {
            // #ifdef DEBUG
            console.error('removeStateAnimations: Trying to remove animation tracks from a state before the state graph has been loaded. Have you called loadStateGraph?');
            // #endif
            return;
        }
        layer.removeNodeAnimations(nodeName);
    },

    getParameterValue: function (name, type) {
        var param = this.data.parameters[name];
        if (param && param.type === type) {
            return param.value;
        }
        // #ifdef DEBUG
        console.log('Cannot get parameter value. No parameter found in anim controller named "' + name + '" of type "' + type + '"');
        // #endif
    },

    setParameterValue: function (name, type, value) {
        var param = this.data.parameters[name];
        if (param && param.type === type) {
            param.value = value;
            return;
        }
        // #ifdef DEBUG
        console.log('Cannot set parameter value. No parameter found in anim controller named "' + name + '" of type "' + type + '"');
        // #endif
    },

    /**
     * @private
     * @function
     * @name pc.AnimComponent#getFloat
     * @description Returns a float parameter value by name.
     * @param {string} name - The name of the float to return the value of.
     * @returns {number} A float
     */
    getFloat: function (name) {
        return this.getParameterValue(name, ANIM_PARAMETER_FLOAT);
    },

    /**
     * @private
     * @function
     * @name pc.AnimComponent#setFloat
     * @description Sets the value of a float parameter that was defined in the animation components state graph.
     * @param {string} name - The name of the parameter to set.
     * @param {number} value - The new float value to set this parameter to.
     */
    setFloat: function (name, value) {
        this.setParameterValue(name, ANIM_PARAMETER_FLOAT, value);
    },

    /**
     * @private
     * @function
     * @name pc.AnimComponent#getInteger
     * @description Returns an integer parameter value by name.
     * @param {string} name - The name of the integer to return the value of.
     * @returns {number} An integer
     */
    getInteger: function (name) {
        return this.getParameterValue(name, ANIM_PARAMETER_INTEGER);
    },

    /**
     * @private
     * @function
     * @name pc.AnimComponent#setInteger
     * @description Sets the value of an integer parameter that was defined in the animation components state graph.
     * @param {string} name - The name of the parameter to set.
     * @param {number} value - The new integer value to set this parameter to.
     */
    setInteger: function (name, value) {
        if (typeof value === 'number' && value % 1 === 0) {
            this.setParameterValue(name, ANIM_PARAMETER_INTEGER, value);
        } else {
            // #ifdef DEBUG
            console.error('Attempting to assign non integer value to integer parameter');
            // #endif
        }
    },

    /**
     * @private
     * @function
     * @name pc.AnimComponent#getBoolean
     * @description Returns a boolean parameter value by name.
     * @param {string} name - The name of the boolean to return the value of.
     * @returns {boolean} A boolean
     */
    getBoolean: function (name) {
        return this.getParameterValue(name, ANIM_PARAMETER_BOOLEAN);
    },

    /**
     * @private
     * @function
     * @name pc.AnimComponent#setBoolean
     * @description Sets the value of a boolean parameter that was defined in the animation components state graph.
     * @param {string} name - The name of the parameter to set.
     * @param {boolean} value - The new boolean value to set this parameter to.
     */
    setBoolean: function (name, value) {
        this.setParameterValue(name, ANIM_PARAMETER_BOOLEAN, !!value);
    },

    /**
     * @private
     * @function
     * @name pc.AnimComponent#getTrigger
     * @description Returns a trigger parameter value by name.
     * @param {string} name - The name of the trigger to return the value of.
     * @returns {boolean} A boolean
     */
    getTrigger: function (name) {
        return this.getParameterValue(name, ANIM_PARAMETER_TRIGGER);
    },

    /**
     * @private
     * @function
     * @name pc.AnimComponent#setTrigger
     * @description Sets the value of a trigger parameter that was defined in the animation components state graph to true.
     * @param {string} name - The name of the parameter to set.
     */
    setTrigger: function (name) {
        this.setParameterValue(name, ANIM_PARAMETER_TRIGGER, true);
    },

    /**
     * @private
     * @function
     * @name pc.AnimComponent#resetTrigger
     * @description Resets the value of a trigger parameter that was defined in the animation components state graph to false.
     * @param {string} name - The name of the parameter to set.
     */
    resetTrigger: function (name) {
        this.setParameterValue(name, ANIM_PARAMETER_TRIGGER, false);
    }
});

Object.defineProperties(AnimComponent.prototype, {
    /**
     * @private
     * @name pc.AnimComponent#stateGraphAsset
     * @type {number}
     * @description The state graph asset this component should use to generate it's animation state graph
     */
    stateGraphAsset: {
        get: function () {
            return this.data.stateGraphAsset;
        },
        set: function (value) {
            if (value === null) {
                this.removeStateGraph();
                return;
            }

            var _id;
            var _asset;

            if (value instanceof Asset) {
                _id = value.id;
                _asset = this.system.app.assets.get(_id);
                if (!_asset) {
                    this.system.app.assets.add(value);
                    _asset = this.system.app.assets.get(_id);
                }
            } else {
                _id = value;
                _asset = this.system.app.assets.get(_id);
            }
            if (!_asset || this.data.stateGraphAsset === _id) {
                return;
            }

            if (_asset.resource) {
                this.data.stateGraph = _asset.resource;
                this.loadStateGraph(this.data.stateGraph);
                _asset.on('change', function (asset) {
                    this.data.stateGraph = new AnimStateGraph(asset._data);
                    this.loadStateGraph(this.data.stateGraph);
                }.bind(this));
            } else {
                _asset.once('load', function (asset) {
                    this.data.stateGraph = asset.resource;
                    this.loadStateGraph(this.data.stateGraph);
                }.bind(this));
                _asset.on('change', function (asset) {
                    this.data.stateGraph = new AnimStateGraph(asset._data);
                    this.loadStateGraph(this.data.stateGraph);
                }.bind(this));
                this.system.app.assets.load(_asset);
            }
            this.data.stateGraphAsset = _id;
        }
    },
    /**
     * @private
     * @name pc.AnimComponent#animationAssets
     * @type {object}
     * @description The animation assets used to load each states animation tracks
     */
    animationAssets: {
        get: function () {
            return this.data.animationAssets;
        },
        set: function (value) {
            this.data.animationAssets = value;
            this.loadAnimationAssets();
        }
    },
    /**
     * @private
     * @name pc.AnimComponent#playable
     * @type {boolean}
     * @readonly
     * @description Returns whether all component layers are currently playable
     */
    playable: {
        get: function () {
            for (var i = 0; i < this.data.layers.length; i++) {
                if (!this.data.layers[i].playable) {
                    return false;
                }
            }
            return true;
        }
    },
    /**
     * @private
     * @name pc.AnimComponent#baseLayer
     * @type {pc.AnimComponentLayer}
     * @readonly
     * @description Returns the base layer of the state graph
     */
    baseLayer: {
        get: function () {
            if (this.data.layers.length > 0) {
                return this.data.layers[0];
            }
            return null;
        }
    }
});

export { AnimComponent };
<|endoftext|>


<commit_before>import UtilsNew from "../../core/utilsNew.js";
import Region from "../../core/bioinfo/region.js";
import {SVG} from "../../core/svg.js";
import GenomeBrowserConstants from "../genome-browser-constants.js";
import GenomeBrowserUtils from "../genome-browser-utils.js";

export default class KaryotypePanel {

    constructor(target, config) {
        // eslint-disable-next-line no-undef
        Object.assign(this, Backbone.Events);

        this.target = target;
        this.config = {
            ...this.getDefaultConfig(),
            ...config,
        };

        this.#init();
    }

    #init() {
        this.prefix = UtilsNew.randomString(8);
        this.width = this.config.width;
        this.height = this.config.height;

        this.pixelBase = 0;
        this.collapsed = false;
        this.hidden = false;

        // set own region object
        this.region = new Region(this.config.region);

        this.regionChanging = false;
        this.rendered = false;

        this.elements = {};

        this.#initDom();
        this.#initEvents();

        this.setVisible(!this.hidden);
    }

    #initDom() {
        const template = UtilsNew.renderHTML(`

                        ${this.config?.title || ""}

        `);

        this.div = template.querySelector(`div#${this.prefix}`);
        this.title = this.div.querySelector(`div#${this.prefix}Title`);
        this.collapse = this.div.querySelector(`div#${this.prefix}Collapse`);
        this.collapseIcon = this.div.querySelector(`span#${this.prefix}CollapseIcon`);

        // Main content
        this.content = this.div.querySelector(`div#${this.prefix}Content`);

        // Initialize SVG element
        this.svg = SVG.init(this.content, {
            "width": this.width,
            "height": this.height,
        });

        // Mark group element
        this.markGroup = SVG.addChild(this.svg, "g", {
            cursor: "pointer",
        });

        this.positionBox = null;

        this.target.append(this.div);
    }

    #initEvents() {
        this.title.addEventListener("click", () => this.toggleContent());
        this.collapse.addEventListener("click", () => this.toggleContent());
    }

    draw() {
        this.clean();

        // to prevent negative values, we require a width size of at least 500px for drawing the karyotype.
        if (this.width < this.config.minWidth) {
            return;
        }

        let x = 20;
        const xOffset = this.width / this.config.chromosomes.length;
        const yMargin = 2;
        const biggerChr = this.config.chromosomes.reduce((maxSize, chromosome) => {
            return Math.max(maxSize, chromosome.size);
        }, 0);

        this.pixelBase = (this.height - 10) / biggerChr;
        this.chrOffsetY = {};
        this.chrOffsetX = {};

        this.config.chromosomes.forEach((chromosome, index) => {
            const chrSize = chromosome.size * this.pixelBase;
            let y = yMargin + (biggerChr * this.pixelBase) - chrSize;
            this.chrOffsetY[chromosome.name] = y;
            let firstCentromere = true;

            // Create group element to render the chromosome
            const group = SVG.addChild(this.svg, "g", {
                "cursor": "pointer",
                "data-chr-name": chromosome.name,
                "data-chr-index": index,
            });

            // Register click event listener
            group.addEventListener("click", event => {
                const offsetY = (event.pageY - $(this.svg).offset().top);
                const clickPosition = parseInt((offsetY - this.chrOffsetY[chromosome.name]) / this.pixelBase);

                this.#triggerRegionChange({
                    region: new Region({
                        chromosome: chromosome.name,
                        start: clickPosition,
                        end: clickPosition,
                    }),
                    sender: this,
                });
            });

            (chromosome.cytobands || []).forEach(cytoband => {
                const width = this.config.chromosomeWidth;
                const height = this.pixelBase * (cytoband.end - cytoband.start);
                // const color = this.colors[cytoband.stain] || "purple";
                const color = GenomeBrowserConstants.CYTOBANDS_COLORS[cytoband.stain] || "purple";

                if (cytoband.stain == "acen") {
                    let points = "";
                    const middleX = x + width / 2;
                    const middleY = y + height / 2;
                    const endX = x + width;
                    const endY = y + height;

                    if (firstCentromere) {
                        points = `${x},${y} ${endX},${y} ${endX},${middleY} ${middleX},${endY} ${x},${middleY}`;
                        firstCentromere = false;
                    } else {
                        points = `${x},${endY} ${x},${middleY} ${middleX},${y} ${endX},${middleY} ${endX},${endY}`;
                    }

                    SVG.addChild(group, "polyline", {
                        "points": points,
                        "stroke": "black",
                        "opacity": 0.8,
                        "fill": color
                    });
                } else {
                    SVG.addChild(group, "rect", {
                        "x": x,
                        "y": y,
                        "width": width,
                        "height": height,
                        "stroke": "grey",
                        "opacity": 0.8,
                        "fill": color
                    });
                }

                y += height;
            });

            // Display features of interest
            // const featuresGroup = SVG.addChild(group, "g", {});
            this.config.featuresOfInterest.forEach(item => {
                if (item.display?.visible) {
                    item.features.forEach(feature => {
                        if (feature.chromosome === chromosome.name) {
                            const featureHeight = Math.max(1, this.pixelBase * Math.abs(feature.end - feature.start));
                            const featureY = yMargin + (biggerChr * this.pixelBase) - chrSize + Math.min(feature.start, feature.end) * this.pixelBase;

                            // Display region rectangle
                            SVG.addChild(group, "rect", {
                                x: x,
                                y: featureY,
                                width: this.config.chromosomeWidth,
                                height: featureHeight,
                                fill: item.display?.color || "red",
                                opacity: 0.5,
                            });

                            // Display triangle at the right side of the chromosome
                            SVG.addChild(group, "path", {
                                d: `M${x + this.config.chromosomeWidth + 2},${featureY + featureHeight / 2} l3,-3 l0,6 z`,
                                fill: item.display?.color || "red",
                                opacity: 1.0,
                            });
                        }
                    });
                }
            });

            // Generate chromosome name
            const text = SVG.addChild(this.svg, "text", {
                "x": x + 1,
                "y": this.height,
                "font-size": 9,
                "fill": "black"
            });
            text.textContent = chromosome.name;

            this.chrOffsetX[chromosome.name] = x;
            x += xOffset;
        });

        this.positionBox = SVG.addChild(this.svg, "line", {
            "x1": 0,
            "y1": 0,
            "x2": 0,
            "y2": 0,
            "stroke": "orangered",
            "stroke-width": 2,
            "opacity": 0.5
        });
        this.#recalculatePositionBox(this.region);

        this.rendered = true;
        this.trigger("after:render", {
            sender: this,
        });
    }

    #triggerRegionChange(event) {
        if (!this.regionChanging) {
            this.regionChanging = true;
            this.trigger("region:change", event);

            setTimeout(() => {
                this.regionChanging = false;
            }, 700);
        } else {
            this.updateRegionControls();
        }
    }

    #recalculatePositionBox(region) {
        const centerPosition = region.center();
        const pointerPosition = centerPosition * this.pixelBase + this.chrOffsetY[region.chromosome];

        this.positionBox.setAttribute("x1", this.chrOffsetX[region.chromosome] - 10);
        this.positionBox.setAttribute("x2", this.chrOffsetX[region.chromosome] + 23);
        this.positionBox.setAttribute("y1", pointerPosition);
        this.positionBox.setAttribute("y2", pointerPosition);
    }

    show() {
        this.target.style.display = "block";
        this.hidden = false;
    }

    hide() {
        this.target.style.display = "none";
        this.hidden = true;
    }

    setVisible(bool) {
        bool ? this.show() : this.hide();
    }

    showContent() {
        this.content.style.display = "block";
        this.collapse.classList.remove("active");
        this.collapseIcon.classList.remove("fa-plus");
        this.collapseIcon.classList.add("fa-minus");
        this.collapsed = false;
    }

    hideContent() {
        this.content.style.display = "none";
        this.collapse.classList.add("active");
        this.collapseIcon.classList.remove("fa-minus");
        this.collapseIcon.classList.add("fa-plus");
        this.collapsed = true;
    }

    toggleContent() {
        this.collapsed ? this.showContent() : this.hideContent();
    }

    clean() {
        GenomeBrowserUtils.cleanDOMElement(this.svg);
    }

    setTitle(title) {
        this.title.textContent = title;
    }

    setWidth(width) {
        this.width = Math.max(0, width);
        this.svg.setAttribute("width", this.width);

        this.draw();
    }

    setRegion(region) {
        this.region.load(region);
        this.#recalculatePositionBox(this.region);
    }

    updateRegionControls() {
        this.#recalculatePositionBox(this.region);
    }

    addMark() {
        const mark = () => {
            if (this.region.chromosome != null && this.region.start != null) {
                if (this.chrOffsetX[this.region.chromosome] !== null) {
                    const x1 = this.chrOffsetX[this.region.chromosome] - 10;
                    const x2 = this.chrOffsetX[this.region.chromosome];
                    const y1 = (this.region.start * this.pixelBase + this.chrOffsetY[this.region.chromosome]) - 4;
                    const y2 = this.region.start * this.pixelBase + this.chrOffsetY[this.region.chromosome];
                    const y3 = (this.region.start * this.pixelBase + this.chrOffsetY[this.region.chromosome]) + 4;
                    const points = `${x1},${y1} ${x2},${y2} ${x1},${y3} ${x1},${y1}`;

                    SVG.addChild(this.markGroup, "polyline", {
                        "points": points,
                        "stroke": "black",
                        "opacity": 0.8,
                        "fill": "#33FF33"
                    });
                }
            }
        };

        if (this.rendered) {
            mark();
        } else {
            this.on("after:render", () => mark());
        }
    }

    unmark() {
        GenomeBrowserUtils.cleanDOMElement(this.markGroup);
    }

    // Get default configuration for karyotype panel
    getDefaultConfig() {
        return {
            width: 600,
            minWidth: 500,
            height: 75,
            collapsed: false,
            collapsible: true,
            region: null,
            title: "Karyotype",
            chromosomes: [],
            chromosomeWidth: 12,
            featuresOfInterest: [],
        };
    }

}
<commit_msg>gb: fix size of the features of interest mark in karyotype panel #TASK-590<commit_after>import UtilsNew from "../../core/utilsNew.js";
import Region from "../../core/bioinfo/region.js";
import {SVG} from "../../core/svg.js";
import GenomeBrowserConstants from "../genome-browser-constants.js";
import GenomeBrowserUtils from "../genome-browser-utils.js";

export default class KaryotypePanel {

    constructor(target, config) {
        // eslint-disable-next-line no-undef
        Object.assign(this, Backbone.Events);

        this.target = target;
        this.config = {
            ...this.getDefaultConfig(),
            ...config,
        };

        this.#init();
    }

    #init() {
        this.prefix = UtilsNew.randomString(8);
        this.width = this.config.width;
        this.height = this.config.height;

        this.pixelBase = 0;
        this.collapsed = false;
        this.hidden = false;

        // set own region object
        this.region = new Region(this.config.region);

        this.regionChanging = false;
        this.rendered = false;

        this.elements = {};

        this.#initDom();
        this.#initEvents();

        this.setVisible(!this.hidden);
    }

    #initDom() {
        const template = UtilsNew.renderHTML(`

                        ${this.config?.title || ""}

        `);

        this.div = template.querySelector(`div#${this.prefix}`);
        this.title = this.div.querySelector(`div#${this.prefix}Title`);
        this.collapse = this.div.querySelector(`div#${this.prefix}Collapse`);
        this.collapseIcon = this.div.querySelector(`span#${this.prefix}CollapseIcon`);

        // Main content
        this.content = this.div.querySelector(`div#${this.prefix}Content`);

        // Initialize SVG element
        this.svg = SVG.init(this.content, {
            "width": this.width,
            "height": this.height,
        });

        // Mark group element
        this.markGroup = SVG.addChild(this.svg, "g", {
            cursor: "pointer",
        });

        this.positionBox = null;

        this.target.append(this.div);
    }

    #initEvents() {
        this.title.addEventListener("click", () => this.toggleContent());
        this.collapse.addEventListener("click", () => this.toggleContent());
    }

    draw() {
        this.clean();

        // to prevent negative values, we require a width size of at least 500px for drawing the karyotype.
        if (this.width < this.config.minWidth) {
            return;
        }

        let x = 20;
        const xOffset = this.width / this.config.chromosomes.length;
        const yMargin = 2;
        const biggerChr = this.config.chromosomes.reduce((maxSize, chromosome) => {
            return Math.max(maxSize, chromosome.size);
        }, 0);

        this.pixelBase = (this.height - 10) / biggerChr;
        this.chrOffsetY = {};
        this.chrOffsetX = {};

        this.config.chromosomes.forEach((chromosome, index) => {
            const chrSize = chromosome.size * this.pixelBase;
            let y = yMargin + (biggerChr * this.pixelBase) - chrSize;
            this.chrOffsetY[chromosome.name] = y;
            let firstCentromere = true;

            // Create group element to render the chromosome
            const group = SVG.addChild(this.svg, "g", {
                "cursor": "pointer",
                "data-chr-name": chromosome.name,
                "data-chr-index": index,
            });

            // Register click event listener
            group.addEventListener("click", event => {
                const offsetY = (event.pageY - $(this.svg).offset().top);
                const clickPosition = parseInt((offsetY - this.chrOffsetY[chromosome.name]) / this.pixelBase);

                this.#triggerRegionChange({
                    region: new Region({
                        chromosome: chromosome.name,
                        start: clickPosition,
                        end: clickPosition,
                    }),
                    sender: this,
                });
            });

            (chromosome.cytobands || []).forEach(cytoband => {
                const width = this.config.chromosomeWidth;
                const height = this.pixelBase * (cytoband.end - cytoband.start);
                // const color = this.colors[cytoband.stain] || "purple";
                const color = GenomeBrowserConstants.CYTOBANDS_COLORS[cytoband.stain] || "purple";

                if (cytoband.stain == "acen") {
                    let points = "";
                    const middleX = x + width / 2;
                    const middleY = y + height / 2;
                    const endX = x + width;
                    const endY = y + height;

                    if (firstCentromere) {
                        points = `${x},${y} ${endX},${y} ${endX},${middleY} ${middleX},${endY} ${x},${middleY}`;
                        firstCentromere = false;
                    } else {
                        points = `${x},${endY} ${x},${middleY} ${middleX},${y} ${endX},${middleY} ${endX},${endY}`;
                    }

                    SVG.addChild(group, "polyline", {
                        "points": points,
                        "stroke": "black",
                        "opacity": 0.8,
                        "fill": color
                    });
                } else {
                    SVG.addChild(group, "rect", {
                        "x": x,
                        "y": y,
                        "width": width,
                        "height": height,
                        "stroke": "grey",
                        "opacity": 0.8,
                        "fill": color
                    });
                }

                y += height;
            });

            // Display features of interest
            // const featuresGroup = SVG.addChild(group, "g", {});
            this.config.featuresOfInterest.forEach(item => {
                if (item.display?.visible) {
                    item.features.forEach(feature => {
                        if (feature.chromosome === chromosome.name) {
                            const featureHeight = Math.max(1, this.pixelBase * Math.abs(feature.end - feature.start));
                            const featureY = yMargin + (biggerChr * this.pixelBase) - chrSize + Math.min(feature.start, feature.end) * this.pixelBase;

                            // Display region rectangle
                            SVG.addChild(group, "rect", {
                                x: x,
                                y: featureY,
                                width: this.config.chromosomeWidth,
                                height: featureHeight,
                                fill: item.display?.color || "red",
                                opacity: 0.5,
                            });

                            // Display triangle at the right side of the chromosome
                            SVG.addChild(group, "path", {
                                d: `M${x + this.config.chromosomeWidth + 4},${featureY + featureHeight / 2} l5,-5 l0,10 z`,
                                fill: item.display?.color || "red",
                                opacity: 1.0,
                            });
                        }
                    });
                }
            });

            // Generate chromosome name
            const text = SVG.addChild(this.svg, "text", {
                "x": x + 1,
                "y": this.height,
                "font-size": 9,
                "fill": "black"
            });
            text.textContent = chromosome.name;

            this.chrOffsetX[chromosome.name] = x;
            x += xOffset;
        });

        this.positionBox = SVG.addChild(this.svg, "line", {
            "x1": 0,
            "y1": 0,
            "x2": 0,
            "y2": 0,
            "stroke": "orangered",
            "stroke-width": 2,
            "opacity": 0.5
        });
        this.#recalculatePositionBox(this.region);

        this.rendered = true;
        this.trigger("after:render", {
            sender: this,
        });
    }

    #triggerRegionChange(event) {
        if (!this.regionChanging) {
            this.regionChanging = true;
            this.trigger("region:change", event);

            setTimeout(() => {
                this.regionChanging = false;
            }, 700);
        } else {
            this.updateRegionControls();
        }
    }

    #recalculatePositionBox(region) {
        const centerPosition = region.center();
        const pointerPosition = centerPosition * this.pixelBase + this.chrOffsetY[region.chromosome];

        this.positionBox.setAttribute("x1", this.chrOffsetX[region.chromosome] - 10);
        this.positionBox.setAttribute("x2", this.chrOffsetX[region.chromosome] + 23);
        this.positionBox.setAttribute("y1", pointerPosition);
        this.positionBox.setAttribute("y2", pointerPosition);
    }

    show() {
        this.target.style.display = "block";
        this.hidden = false;
    }

    hide() {
        this.target.style.display = "none";
        this.hidden = true;
    }

    setVisible(bool) {
        bool ? this.show() : this.hide();
    }

    showContent() {
        this.content.style.display = "block";
        this.collapse.classList.remove("active");
        this.collapseIcon.classList.remove("fa-plus");
        this.collapseIcon.classList.add("fa-minus");
        this.collapsed = false;
    }

    hideContent() {
        this.content.style.display = "none";
        this.collapse.classList.add("active");
        this.collapseIcon.classList.remove("fa-minus");
        this.collapseIcon.classList.add("fa-plus");
        this.collapsed = true;
    }

    toggleContent() {
        this.collapsed ? this.showContent() : this.hideContent();
    }

    clean() {
        GenomeBrowserUtils.cleanDOMElement(this.svg);
    }

    setTitle(title) {
        this.title.textContent = title;
    }

    setWidth(width) {
        this.width = Math.max(0, width);
        this.svg.setAttribute("width", this.width);

        this.draw();
    }

    setRegion(region) {
        this.region.load(region);
        this.#recalculatePositionBox(this.region);
    }

    updateRegionControls() {
        this.#recalculatePositionBox(this.region);
    }

    addMark() {
        const mark = () => {
            if (this.region.chromosome != null && this.region.start != null) {
                if (this.chrOffsetX[this.region.chromosome] !== null) {
                    const x1 = this.chrOffsetX[this.region.chromosome] - 10;
                    const x2 = this.chrOffsetX[this.region.chromosome];
                    const y1 = (this.region.start * this.pixelBase + this.chrOffsetY[this.region.chromosome]) - 4;
                    const y2 = this.region.start * this.pixelBase + this.chrOffsetY[this.region.chromosome];
                    const y3 = (this.region.start * this.pixelBase + this.chrOffsetY[this.region.chromosome]) + 4;
                    const points = `${x1},${y1} ${x2},${y2} ${x1},${y3} ${x1},${y1}`;

                    SVG.addChild(this.markGroup, "polyline", {
                        "points": points,
                        "stroke": "black",
                        "opacity": 0.8,
                        "fill": "#33FF33"
                    });
                }
            }
        };

        if (this.rendered) {
            mark();
        } else {
            this.on("after:render", () => mark());
        }
    }

    unmark() {
        GenomeBrowserUtils.cleanDOMElement(this.markGroup);
    }

    // Get default configuration for karyotype panel
    getDefaultConfig() {
        return {
            width: 600,
            minWidth: 500,
            height: 75,
            collapsed: false,
            collapsible: true,
            region: null,
            title: "Karyotype",
            chromosomes: [],
            chromosomeWidth: 12,
            featuresOfInterest: [],
        };
    }

}
<|endoftext|>


<commit_before>const txt = 'Hello World!'

module.exports = {
  'Docs Pages': browser => {
    browser
      .url('http://localhost:8080/docs')
      .waitForElementVisible('body', 1000)
      .waitForElementVisible('[data-btn-modal]', 1000)
      .click('[data-btn-modal]')
      .pause(300)
      .assert.containsText('.modal', txt)
      .click('.modal')
      .pause(300)
      .assert.elementNotPresent('.modal')

    browser
      .click('[data-btn-notification]')
      .pause(300)
      .assert.containsText('.notification', txt)
      .click('[data-btn-notification]')
      .pause(300)
      .assert.elementNotPresent('.notification')

    browser
      .click('[data-btn-loading]')
      .pause(100)
      .assert.elementPresent('.loading')
      .click('[data-btn-loading')
      .pause(100)
      .assert.elementNotPresent('.loading')

    browser
      .click('[data-btn-message]')
      .pause(100)
      .assert.count('.message', 1)
      .click('[data-btn-message]')
      .pause(100)
      .assert.count('.message', 2)
      .click('[data-btn-message]')
      .pause(100)
      .assert.count('.message', 3)
      .click('#message-2 .message__close')
      .pause(100)
      .assert.count('.message', 2)
      .click('#message-1 .message__close')
      .pause(100)
      .assert.count('.message', 1)
      .click('#message-0 .message__close')
      .pause(100)
      .assert.count('.message', 0)
      .end()
  },

  afterEach: (browser, done) => {
    browser.updateResults()
    setTimeout(() => done(), 1000)
  }
}
<commit_msg>updated e2e test<commit_after>const txt = 'Hello World!'

module.exports = {
  'Docs Pages': browser => {
    browser
      .url('http://localhost:8080/docs')
      .waitForElementVisible('body', 10000)
      .waitForElementVisible('[data-btn-modal]', 10000)
      .click('[data-btn-modal]')
      .pause(300)
      .assert.containsText('.modal', txt)
      .click('.modal')
      .pause(300)
      .assert.elementNotPresent('.modal')

    browser
      .click('[data-btn-notification]')
      .pause(300)
      .assert.containsText('.notification', txt)
      .click('[data-btn-notification]')
      .pause(300)
      .assert.elementNotPresent('.notification')

    browser
      .click('[data-btn-loading]')
      .pause(100)
      .assert.elementPresent('.loading')
      .click('[data-btn-loading')
      .pause(100)
      .assert.elementNotPresent('.loading')

    browser
      .click('[data-btn-message]')
      .pause(100)
      .assert.count('.message', 1)
      .click('[data-btn-message]')
      .pause(100)
      .assert.count('.message', 2)
      .click('[data-btn-message]')
      .pause(100)
      .assert.count('.message', 3)
      .click('#message-2 .message__close')
      .pause(100)
      .assert.count('.message', 2)
      .click('#message-1 .message__close')
      .pause(100)
      .assert.count('.message', 1)
      .click('#message-0 .message__close')
      .pause(100)
      .assert.count('.message', 0)
      .end()
  },

  afterEach: (browser, done) => {
    browser.updateResults()
    setTimeout(() => done(), 1000)
  }
}
<|endoftext|>


<commit_before>(function () {
  'use strict';
  angular.module('cloudbrain').controller('chartController', [
    '$scope',
    '$http',
    '$interval',
    '$log',
    function ($scope, $http, $interval, $log) {

    $scope.changeColor = function () {
        var color_val = 'rgba(255, 255, 255, 0.8)'
        $scope.chartConfig.options.chart.backgroundColor = color_val;
        $scope.chartPolar.options.chart.backgroundColor = color_val;
        $scope.chartBar.options.chart.backgroundColor = color_val;
      }
      $scope.getDevices = (function () {
        var url = 'http://datastore.cloudbrain.rocks/devices?callback=JSON_CALLBACK';
        $http.jsonp(url).success(function (data, status, headers) {
          $scope.device_names = data.filter(function (name) {
            return name !== '';
          });
        }).error(function (data, status, headers) {
          $log.log('Failed to Get Devices')
        });
      });
      $scope.getDevices();

      $scope.setChannelSeries = (function(data){
        var keys = Object.keys(data[0]);
        var key_length = keys.length;
        var channel_numbers = [];
        for (var obj of keys){
          if (obj != 'timestamp'){
            channel_numbers.push(obj);
            //$log.log(channel_numbers);
          };
        };
        //$log.log(channel_numbers);
        for (var obj in channel_numbers){
          //$log.log('object' +obj);
          $scope.chartConfig.series.push({name: channel_numbers[obj], data: [], id: obj, marker: {
            enabled: false,
            symbol: 'circle'
          }});
          $scope.chartStock.series.push({name: channel_numbers[obj], data: [], id: obj});
          //$log.log($scope.chartConfig.series.length);
        };
      });

$scope.url = 'http://datastore.cloudbrain.rocks/data?device_name=openbci&metric=eeg&device_id=marion&callback=JSON_CALLBACK';
$scope.getData = function (device) {
  $scope.chartConfig.title.text = device.name + ' ' + device.id;
  $scope.chartPolar.title.text = device.name + ' ' + device.id;
  $scope.chartBar.title.text = device.name + ' ' + device.id;
  $scope.chartStock.title.text = device.name + ' ' + device.id;
  var metric = 'eeg';
  var cloudbrain = 'http://datastore.cloudbrain.rocks/data?device_name='+device.name+'&metric='+metric+'&device_id='+device.id+'&callback=JSON_CALLBACK';
        //initialize series data for charts
        $http.jsonp(cloudbrain)
        .then(function(response){
          $scope.data = response.data;
          $scope.setChannelSeries($scope.data);
        },
        function(response){
          $log.log('fail');
        });

        $interval(function () {
          $http.jsonp($scope.url)
          .then(function(response){
            $scope.data = response.data;
        //$log.log($scope.chartConfig.series[0]);
        for (var obj in $scope.data){
              //$log.log(obj);
              var count = 0;
              for (var prop in $scope.data[obj]){
                if (prop != 'timestamp'){
                  //$log.log("data." + prop + "= " + $scope.data[obj][prop]);
                  //$log.log(count);
                  $scope.chartConfig.series[count].data.push($scope.data[obj][prop]);
                  $scope.chartStock.series[count].data.push($scope.data[obj][prop]);
                  //$log.log($scope.chartConfig.series[count].id);
                  //$log.log($scope.chartConfig.series);
                  count++
              //$log.log($scope.chartConfig.series[0].data);
            };
          };
        };
      },
      function(response){
        $log.log('fail');
      });
        }, 100, 50);
      };

      $scope.chartConfig =
      {
        options: {
          chart: {
            type: 'spline',
            /*backgroundColor: 'rgba(255, 255, 255, 0.2)'*/
          }
        },
        title: {
          text: 'EEG',
          x: - 20 //center
        },
        subtitle: {
          text: 'Source: cloudbrain.rocks',
          x: - 20
        },
        xAxis: {
          categories: [
          'time'
          ]
        },
        yAxis: {
          title: {
            text: 'uV'
          },
          plotLines: [
          {
            value: 0,
            width: 1,
            color: '#808080'
          }
          ]
        },
        legend: {
          layout: 'vertical',
          align: 'right',
          verticalAlign: 'middle',
          borderWidth: 0
        },
        series: [

        ],
        useHighStocks: true
      };

      $scope.chartStock = {
        options: {
          chart: {
            zoomType: 'x',
            type: 'spline'
          },
          legend: {
            enabled: true
          },
          rangeSelector: {
            buttons: [{
              count: 50,
              type: 'millisecond',
              text: '5S'
            }, {
              count: 300,
              type: 'millisecond',
              text: '30S'
            }, {
              type: 'all',
              text: 'All'
            }],
            selected: 0,
            inputEnabled: false
          },

          navigator: {
            enabled: true
          }
        },
        series: [],
        title: {
          text: 'EEG'
        },
        useHighStocks: true
      };

      $scope.chartPolar = {
        options: {
          chart: {
            polar: true,
            type: 'spline',
            margin: [
            50,
            50,
            50,
            50
            ]
          },
          pane: {
            size: '80%'
          },
          tooltip: {
            shared: true,
            pointFormat: '{series.name}: ${point.y:,.0f}
'
          },
          legend: {
            align: 'right',
            verticalAlign: 'top',
            layout: 'vertical'
          }
        },
        title: {
          text: 'EEG',
          x: - 80
        },
        xAxis: {
          categories: [
          'Gamma',
          'Delta',
          'Theta',
          'Beta',
          'Alpha'
          ],
          tickmarkPlacement: 'on',
          lineWidth: 0
        },
        yAxis: {
          gridLineInterpolation: 'polygon',
          lineWidth: 0,
          min: 0
        },
        series: [
        {
          name: 'Device 1',
          data: [
          43000,
          19000,
          60000,
          35000,
          17000
          ],
          pointPlacement: 'on',
          marker: {
            enabled: false,
            symbol: 'circle'
          }
        }
        ]
      };
      $scope.chartBar = {
        options: {
          chart: {
            margin: [
            50,
            50,
            50,
            50
            ],
            type: 'column'
          },
          pane: {
            size: '80%'
          },
          tooltip: {
            shared: true,
            pointFormat: '{series.name}: ${point.y:,.0f}
'
          },
          legend: {
            align: 'right',
            verticalAlign: 'top',
            y: 70,
            layout: 'vertical'
          }
        },
        title: {
          text: 'EEG',
          x: - 80
        },
        xAxis: {
          categories: [
          'Gamma',
          'Delta',
          'Theta',
          'Beta',
          'Alpha'
          ],
          tickmarkPlacement: 'on',
          lineWidth: 0
        },
        yAxis: {
          gridLineInterpolation: 'polygon',
          lineWidth: 0,
          min: 0
        },
        series: [
        {
          name: 'Device 1',
          data: [
          43000,
          19000,
          60000,
          35000,
          17000
          ],
          pointPlacement: 'on',
          marker: {
            enabled: false,
            symbol: 'circle'
          }
        }
        ]
      };
    }
    ]);
}) ();
<commit_msg>last push<commit_after>(function () {
  'use strict';
  angular.module('cloudbrain').controller('chartController', [
    '$scope',
    '$http',
    '$interval',
    '$log',
    function ($scope, $http, $interval, $log) {

    $scope.changeColor = function () {
        var color_val = 'rgba(255, 255, 255, 0.8)'
        $scope.chartPolar.options.chart.backgroundColor = color_val;
        $scope.chartBar.options.chart.backgroundColor = color_val;
      }
      $scope.getDevices = (function () {
        var url = 'http://datastore.cloudbrain.rocks/devices?callback=JSON_CALLBACK';
        $http.jsonp(url).success(function (data, status, headers) {
          $scope.device_names = data.filter(function (name) {
            return name !== '';
          });
        }).error(function (data, status, headers) {
          $log.log('Failed to Get Devices')
        });
      });
      $scope.getDevices();

      $scope.setChannelSeries = (function(data){
        var keys = Object.keys(data[0]);
        var key_length = keys.length;
        var channel_numbers = [];
        for (var obj of keys){
          if (obj != 'timestamp'){
            channel_numbers.push(obj);
            //$log.log(channel_numbers);
          };
        };
        //$log.log(channel_numbers);
        for (var obj in channel_numbers){
          //$log.log('object' +obj);
          $scope.chartStock.series.push({name: channel_numbers[obj], data: [], id: obj});
          //$log.log($scope.chartConfig.series.length);
        };
      });

$scope.url = 'http://datastore.cloudbrain.rocks/data?device_name=openbci&metric=eeg&device_id=marion&callback=JSON_CALLBACK';
$scope.getData = function (device) {
  $scope.chartPolar.title.text = device.name + ' ' + device.id;
  $scope.chartBar.title.text = device.name + ' ' + device.id;
  $scope.chartStock.title.text = device.name + ' ' + device.id;
  var metric = 'eeg';
  $scope.cloudbrain = 'http://datastore.cloudbrain.rocks/data?device_name='+device.name+'&metric='+metric+'&device_id='+device.id+'&callback=JSON_CALLBACK';
        //initialize series data for charts
        $http.jsonp($scope.cloudbrain)
        .then(function(response){
          $scope.data = response.data;
          $scope.setChannelSeries($scope.data);
        },
        function(response){
          $log.log('fail');
        });

        $interval(function () {
          $http.jsonp($scope.cloudbrain)
          .then(function(response){
            $scope.data = response.data;
        //$log.log($scope.chartConfig.series[0]);
        for (var obj in $scope.data){
              //$log.log(obj);
              var count = 0;
              for (var prop in $scope.data[obj]){
                if (prop != 'timestamp'){
                  //$log.log("data." + prop + "= " + $scope.data[obj][prop]);
                  //$log.log(count);
                  //$scope.chartStock.series[count].addPoint($scope.data[obj][prop], true, true);
                 $scope.chartStock.series[count].data.push($scope.data[obj][prop]);
                  //$log.log($scope.chartConfig.series[count].id);
                  //$log.log($scope.chartConfig.series);
                  count++
              //$log.log($scope.chartConfig.series[0].data);
            };
          };
        };
      },
      function(response){
        $log.log('fail');
      });
        }, 100);
      };

      $scope.chartStock = {
        options: {
          chart: {
            zoomType: 'x',
            type: 'spline'
          },
          tooltip: {
            enabled: false
          },
          legend: {
            enabled: true
          },
          rangeSelector: {
            buttons: [{
              count: 50,
              type: 'millisecond',
              text: '5S'
            }, {
              count: 300,
              type: 'millisecond',
              text: '30S'
            }, {
              type: 'all',
              text: 'All'
            }],
            selected: 0,
            inputEnabled: false
          },

          navigator: {
            enabled: true
          }
        },
        series: [],
        title: {
          text: 'EEG'
        },
        useHighStocks: true
      };

      $scope.chartPolar = {
        options: {
          chart: {
            polar: true,
            type: 'spline',
            margin: [
            50,
            50,
            50,
            50
            ]
          },
          pane: {
            size: '80%'
          },
          tooltip: {
            shared: true,
            pointFormat: '{series.name}: ${point.y:,.0f}
'
          },
          legend: {
            align: 'right',
            verticalAlign: 'top',
            layout: 'vertical'
          }
        },
        title: {
          text: 'EEG',
          x: - 80
        },
        xAxis: {
          categories: [
          'Gamma',
          'Delta',
          'Theta',
          'Beta',
          'Alpha'
          ],
          tickmarkPlacement: 'on',
          lineWidth: 0
        },
        yAxis: {
          gridLineInterpolation: 'polygon',
          lineWidth: 0,
          min: 0
        },
        series: [
        {
          name: 'Device 1',
          data: [
          43000,
          19000,
          60000,
          35000,
          17000
          ],
          pointPlacement: 'on',
          marker: {
            enabled: false,
            symbol: 'circle'
          }
        }
        ]
      };
      $scope.chartBar = {
        options: {
          chart: {
            margin: [
            50,
            50,
            50,
            50
            ],
            type: 'column'
          },
          pane: {
            size: '80%'
          },
          tooltip: {
            shared: true,
            pointFormat: '{series.name}: ${point.y:,.0f}
'
          },
          legend: {
            align: 'right',
            verticalAlign: 'top',
            y: 70,
            layout: 'vertical'
          }
        },
        title: {
          text: 'EEG',
          x: - 80
        },
        xAxis: {
          categories: [
          'Gamma',
          'Delta',
          'Theta',
          'Beta',
          'Alpha'
          ],
          tickmarkPlacement: 'on',
          lineWidth: 0
        },
        yAxis: {
          gridLineInterpolation: 'polygon',
          lineWidth: 0,
          min: 0
        },
        series: [
        {
          name: 'Device 1',
          data: [
          43000,
          19000,
          60000,
          35000,
          17000
          ],
          pointPlacement: 'on',
          marker: {
            enabled: false,
            symbol: 'circle'
          }
        }
        ]
      };
    }
    ]);
}) ();
<|endoftext|>