Kaynağa Gözat

Added Animation Control

Szeyin Lee 7 yıl önce
ebeveyn
işleme
9cbb5911f8

+ 262 - 78
Viewer/assets/templates/default/navbar.html

@@ -1,121 +1,305 @@
 <style>
     nav-bar {
         position: absolute;
-        height: 160px;
+        height: 48px;
         width: 100%;
-        bottom: 0;
-        background-color: rgba(0, 0, 0, 0.3);
-        color: white;
-        transition: 1s;
-        align-items: flex-start;
-        justify-content: space-around;
+        bottom: 10px;
         display: flex;
-
-        flex-direction: column;
+        justify-content: center;
     }
 
-    /* Big screens have room for the entire navbar */
+    nav-bar .nav-container {
+        display: flex;
+        flex-direction: row;
+        margin: 0 10px;
+        height: 100%;
+        width: 100%;
+        justify-content: center;
+    }
 
-    @media screen and (min-width: 768px) {
-        nav-bar {
-            align-items: center;
-            flex-direction: row;
-            justify-content: space-between;
-            height: 80px;
-        }
+    nav-bar .animation-control {
+        background-color: rgba(91, 93, 107, .75);
+        display: flex;
+        flex-direction: row;
+        height: 100%;
+        width: 100%;
+        max-width: 1280px;
+        justify-content: center;
     }
 
-    div.flex-container {
+    nav-bar .flex-container {
         display: flex;
+        flex-direction: row;
+        justify-content: center;
+        height: 100%;
         width: 100%;
     }
 
-    div.thumbnail {
-        position: relative;
-        overflow: hidden;
-        display: block;
-        width: 40px;
-        height: 40px;
-        background-size: cover;
-        background-position: center;
-        border-radius: 20px;
-        margin: 0 10px;
+    nav-bar button {
+        background: none;
+        border: none;
+        color: white;
+        margin: 0;
+        padding: 0;
+
+        height: 100%;
+        min-width: 48px;
+        cursor: pointer;
+    }
+
+    nav-bar button:hover,
+    nav-bar button:active,
+    nav-bar button:focus {
+        background: none;
+        border: none;
+        outline: none;
+    }
+
+    nav-bar button:hover {
+        background-color: rgba(22, 24, 26, .20);
     }
 
-    div.title-container {
+    nav-bar .control-text {
+        font-family: "Segoe UI";
+        font-size: 12px;
+        font-weight: 400;
+        pointer-events: none;
+    }
+
+    nav-bar .icon {
+        width: 18px;
+    }
+
+    nav-bar img {
+        pointer-events: none;
+    }
+
+    .small-icon {
+        width: 12px;
+    }
+
+    .types {
+        display: flex;
         flex-direction: column;
+        width: 48px;
+    }
+
+    .types .flex-container,
+    .speed .flex-container {
+        align-items: center;
+    }
+
+    .menu-options {
+        position: absolute;
+        bottom: 48px;
+        width: 48px;
+        background-color: rgba(22, 24, 26, .90);
+    }
+
+    .animation-label,
+    .types-icon,
+    .help,
+    .speed {
+        display: none;
+    }
+
+    .progress-control {
         display: flex;
-        justify-content: space-between;
+        flex: 1;
+        position: relative;
+        overflow: hidden;
+        cursor: pointer;
     }
 
-    span.model-title {
-        font-size: 125%;
+    .progress-bar {
+        align-self: center;
+        flex: 1;
+        background-color: rgb(255, 255, 255);
+        height: 4px;
+        position: absolute;
+        width: calc(100% - 48px);
+        right: 0;
+        pointer-events: none;
     }
 
-    span.model-subtitle {
-        font-size: 90%;
+    .animation-number {
+        margin: 0 6px;
     }
 
-    div.button-container,
-    div.animation-container {
-        align-items: center;
-        justify-content: flex-end;
+    .speed-text {
+        margin-right: 6px;
+    }
+
+    .progress-wrapper {
+        height: 0px;
+        background-color: rgba(91, 93, 107, .75);
+        width: 100%;
+        border-top: 4px solid rgba(204, 210, 214, .4);
     }
 
-    div.button {
+    .progress-circle {
+        width: 12px;
+        height: 12px;
+        border: 2px solid rgb(255, 255, 255);
+        border-radius: 50%;
+        background-color: rgb(91, 93, 107);
         cursor: pointer;
-        height: 30px;
-        margin: 0 10px;
+        position: relative;
+        bottom: 10px;
+        pointer-events: none;
     }
 
-    div.button img {
+    .default-control {
+        background-color: rgba(91, 93, 107, .75);
+        display: flex;
+        flex-direction: row;
         height: 100%;
     }
-</style>
 
-{{#if disableOnFullscreen}}
-<style>
-    viewer:fullscreen nav-bar {
-        display: none;
+    .menu-options button {
+        width: 100%;
+        height: 48px;
+        color: rgb(142, 147, 155);
     }
 
-    viewer:-moz-full-screen nav-bar {
-        display: none;
+    .menu-options button {
+        width: 100%;
+        height: 48px;
+        color: rgb(142, 147, 155);
     }
 
-    viewer:-webkit-full-screen nav-bar {
-        display: none;
+    .menu-options button:hover {
+        background-color: transparent;
+        color: rgb(255, 255, 255);
+    }
+
+    .menu-options .animation-number {
+        margin: 0 18px 0 6px;
+    }
+
+    .menu-options .speed-text {
+        margin-right: 18px;
+    }
+
+    .menu-options {
+        visibility: hidden;
+    }
+
+    .open .menu-options {
+        visibility: visible;
+    }
+
+    @media screen and (min-width: 540px) {
+        .types-icon,
+        .speed {
+            display: flex;
+        }
+
+        .help {
+            display: block;
+        }
+        .types {
+            width: 84px;
+            margin-right: 34px;
+        }
+
+        .types .menu-options {
+            width: 84px;
+        }
+        .speed {
+            margin-right: 4px;
+            width: 64px;
+        }
+
+        .speed .menu-options {
+            width: 64px;
+        }
+    }
+
+    @media screen and (min-width: 1024px) {
+        .speed {
+            margin-right: 28px;
+        }
+        .animation-label {
+            display: block;
+            margin-left: 6px;
+        }
+        .types {
+            width: 144px;
+            margin-right: 0px;
+        }
+        .types .menu-options {
+            width: 144px;
+        }
     }
 </style>
-{{/if}}
 
-<div class="flex-container" id="model-metadata">
-    <!-- holding the description -->
-    <div class="thumbnail">
-        <!-- holding the thumbnail 
-        <img src="{{thumbnail}}" alt="{{title}}">-->
-    </div>
-    <div class="title-container">
+{{#if (or (not animations) hideAnimations)}}
+<style>
+    nav-bar .nav-container {
+        justify-content: flex-end;
+    }
+</style>
+{{/if}}
 
-        <span class="model-title">{{#if title}}{{title}}{{/if}}</span>
-        <span class="model-subtitle"> {{#if subtitle}}{{subtitle}} {{/if}}</span>
+<div class="nav-container" id="navbar-control">
+    {{#unless (or (not animations) hideAnimations)}}
+    <div class="animation-control">
+        <div class="types">
+            <button class="flex-container" id="types-button">
+                <img src="{{typeImg}}" class="svg icon types-icon">
+                <span class="control-text animation-label">Animation</span>
+                <span class="control-text animation-number">{{selectedAnimation}}</span>
+                <img src="{{upImg}}" class="small-icon">
+            </button>
+            <div class="menu-options">
+                {{#each animations}} {{#unless (eq ../selectedAnimation (add @index 1))}}
+                <button class="flex-container" id="label-option-button" data-value="{{this}}">
+                    <img src="{{../typeImg}}" class="icon types-icon">
+                    <span class="control-text animation-label">Animation</span>
+                    <span class="control-text animation-number">{{add @index 1}}</span>
+                </button>
+                {{/unless}} {{/each}}
+            </div>
+        </div>
+        <div class="progress-control" id="progress-control">
+            <button class="play-pause" id="play-pause-button">
+                {{#if paused}}
+                <img src="{{playImg}}" class="icon play-button">{{else}}
+                <img src="{{pauseImg}}" class="icon pause-button">{{/if}}
+            </button>
+            <div class="progress-bar-container flex-container" id="progress-bar-container">
+                <div class="progress-bar">
+                    <div class="progress-wrapper" id="progress-wrapper">
+                        <div class="progress-circle" id="progress-circle"></div>
+                    </div>
+                </div>
+            </div>
+        </div>
+        <div class="speed">
+            <button class="flex-container" id="speed-button">
+                <span class="control-text speed-text">{{selectedSpeed}}</span>
+                <img src="{{upImg}}" class="small-icon">
+            </button>
+            <div class="menu-options">
+                {{#eachInMap speedList}} {{#unless (eq ../selectedSpeed id)}}
+                <button class="flex-container" id="speed-option-button" data-value="{{value}}">
+                    <span class="control-text speed-text">{{id}}</span>
+                </button>
+                {{/unless}} {{/eachInMap}}
+            </div>
+        </div>
     </div>
-</div>
-{{#if animations}} {{#if hideAnimations}}{{else}}
-<div class="animation-container flex-container">
-    <select id="animation-selector" name="animations">
-        {{#each animations}}
-        <option value="{{this}}">{{this}}</option>> {{/each}}
-    </select>
-</div>
-{{/if}} {{/if}}
-<div class="button-container flex-container">
-    <!-- holding the buttons -->
-    {{#eachInMap buttons}}
-    <div id="{{id}}" class="button">
-        {{#if text}}
-        <span>{{text}}</span>> {{/if}} {{#if image}}
-        <img src="{{image}}" alt="{{altText}}"> {{/if}}
+    {{/unless}}
+    <div class="default-control">
+        {{#unless hideHelp}}
+        <button class="help" id="help-button" title="Help">
+            <img src="{{helpImg}}" class="icon">
+        </button>
+        {{/unless}} {{#unless hideFullScreen}}
+        <button class="fullscreen" id="fullscreen-button" title="Fullscreen">
+            <img src="{{fullImg}}" class="icon">
+        </button>
+        {{/unless}}
     </div>
-    {{/eachInMap}}
 </div>

+ 18 - 12
Viewer/src/configuration/types/default.ts

@@ -24,22 +24,28 @@ export let defaultConfiguration: ViewerConfiguration = {
         navBar: {
             html: require("../../../assets/templates/default/navbar.html"),
             params: {
-                buttons: {
-                    /*"help-button": {
-                        altText: "Help",
-                        image: require('../../../assets/img/help-circle.png')
-                    },*/
-                    "fullscreen-button": {
-                        altText: "Fullscreen",
-                        image: require('../../../assets/img/fullscreen.png')
-                    }
+                speedList: {
+                    "0.5x": "0.5",
+                    "1.0x": "1.0",
+                    "1.5x": "1.5",
+                    "2.0x" : "2.0",
                 },
-                visibilityTimeout: 2000
+
+                // update these to font
+                typeImg: "https://denalicdn.blob.core.windows.net/webassets/animation/Icon_Animation.svg",
+                playImg: "https://denalicdn.blob.core.windows.net/webassets/animation/Icon_Play.svg",
+                upImg: "https://denalicdn.blob.core.windows.net/webassets/animation/Icon_UpChevron.svg",
+                helpImg: "https://denalicdn.blob.core.windows.net/webassets/animation/Icon_Help.svg",
+                fullImg: "https://denalicdn.blob.core.windows.net/webassets/animation/Icon_FullScreen.svg",
+                pauseImg: "https://denalicdn.blob.core.windows.net/webassets/animation/Icon_Pause.svg", 
+                
             },
             events: {
-                pointerdown: { 'fullscreen-button': true/*, '#help-button': true*/ },
+                pointerdown: {
+                    'navbar-control': true,
+                    'help-button': true
+                },
                 pointerover: true,
-                change: { 'animation-selector': true }
             }
         },
         overlay: {

+ 3 - 2
Viewer/src/eventManager.ts

@@ -30,8 +30,9 @@ export class EventManager {
             this._callbacksContainer[templateName] = [];
         }
         this._callbacksContainer[templateName].push({
-            eventType: eventType,
-            callback: callback
+            eventType,
+            callback,
+            selector
         });
     }
 

+ 14 - 9
Viewer/src/model/modelAnimation.ts

@@ -146,11 +146,12 @@ export class GroupModelAnimation implements IModelAnimation {
      * In correlation to an arry, this would be ".length"
      */
     public get frames(): number {
-        let animationFrames = this._animationGroup.targetedAnimations.map(ta => {
+        /*let animationFrames = this._animationGroup.targetedAnimations.map(ta => {
             let keys = ta.animation.getKeys();
             return keys[keys.length - 1].frame;
         });
-        return Math.max.apply(null, animationFrames);
+        return Math.max.apply(null, animationFrames);*/
+        return this._animationGroup.to - this._animationGroup.from;
     }
 
     /**
@@ -161,7 +162,7 @@ export class GroupModelAnimation implements IModelAnimation {
      */
     public get currentFrame(): number {
         // get the first currentFrame found
-        for (let i = 0; i < this._animationGroup.animatables.length; ++i) {
+        /*for (let i = 0; i < this._animationGroup.animatables.length; ++i) {
             let animatable: Animatable = this._animationGroup.animatables[i];
             let animations = animatable.getAnimations();
             if (!animations || !animations.length) {
@@ -172,8 +173,12 @@ export class GroupModelAnimation implements IModelAnimation {
                     return animations[idx].currentFrame;
                 }
             }
+        }*/
+        if (this._animationGroup.targetedAnimations[0] && this._animationGroup.targetedAnimations[0].animation.runtimeAnimations[0]) {
+            return this._animationGroup.targetedAnimations[0].animation.runtimeAnimations[0].currentFrame - this._animationGroup.from;
+        } else {
+            return 0;
         }
-        return 0;
     }
 
     /**
@@ -234,7 +239,10 @@ export class GroupModelAnimation implements IModelAnimation {
      * Restart the animation group
      */
     restart() {
-        this._animationGroup.restart();
+        if (this.state === AnimationState.PAUSED)
+            this._animationGroup.restart();
+        else
+            this.start();
     }
 
     /**
@@ -242,10 +250,7 @@ export class GroupModelAnimation implements IModelAnimation {
      * @param frameNumber Go to a specific frame in the animation
      */
     goToFrame(frameNumber: number) {
-        // this._animationGroup.goToFrame(frameNumber);
-        this._animationGroup['_animatables'].forEach(a => {
-            a.goToFrame(frameNumber);
-        })
+        this._animationGroup.goToFrame(frameNumber + this._animationGroup.from);
     }
 
     /**

+ 10 - 3
Viewer/src/model/viewerModel.ts

@@ -1,7 +1,7 @@
 import { ISceneLoaderPlugin, ISceneLoaderPluginAsync, AnimationGroup, Animatable, AbstractMesh, Tools, Scene, SceneLoader, Observable, SceneLoaderProgressEvent, Tags, ParticleSystem, Skeleton, IDisposable, Nullable, Animation, Quaternion, Material, Vector3, AnimationPropertiesOverride } from "babylonjs";
 import { GLTFFileLoader, GLTF2 } from "babylonjs-loaders";
 import { IModelConfiguration } from "../configuration/configuration";
-import { IModelAnimation, GroupModelAnimation, AnimationPlayMode } from "./modelAnimation";
+import { IModelAnimation, GroupModelAnimation, AnimationPlayMode, AnimationState } from "./modelAnimation";
 
 import * as deepmerge from '../../assets/deepmerge.min.js';
 import { AbstractViewer } from "..";
@@ -254,13 +254,20 @@ export class ViewerModel implements IDisposable {
      * @returns The model aniamtion to be played.
      */
     public playAnimation(name: string): IModelAnimation {
+        let animation = this.setCurrentAnimationByName(name);
+        if (animation) {
+            animation.start();
+        }
+        return animation;
+    }
+
+    public setCurrentAnimationByName(name: string) {
         let animation = this._getAnimationByName(name);
         if (animation) {
-            if (this.currentAnimation) {
+            if (this.currentAnimation && this.currentAnimation.state !== AnimationState.STOPPED) {
                 this.currentAnimation.stop();
             }
             this.currentAnimation = animation;
-            animation.start();
             return animation;
         } else {
             throw new Error("animation not found - " + name);

+ 21 - 0
Viewer/src/templateManager.ts

@@ -241,6 +241,27 @@ Handlebars.registerHelper('eachInMap', function (map, block) {
     return out;
 });
 
+Handlebars.registerHelper('add', function (a, b) {
+    var out = a + b;
+    return out;
+});
+
+Handlebars.registerHelper('eq', function (a, b) {
+    var out = (a == b);
+    return out;
+});
+
+
+Handlebars.registerHelper('or', function (a, b) {
+    var out = a || b;
+    return out;
+});
+
+Handlebars.registerHelper('not', function (a) {
+    var out = !a;
+    return out;
+});
+
 /**
  * This class represents a single template in the viewer's template tree.
  * An example for a template is a single canvas, an overlay (containing sub-templates) or the navigation bar.

+ 141 - 59
Viewer/src/viewer/defaultViewer.ts

@@ -7,6 +7,7 @@ import { SpotLight, MirrorTexture, Plane, ShadowGenerator, Texture, BackgroundMa
 import { CameraBehavior } from '../interfaces';
 import { ViewerModel } from '../model/viewerModel';
 import { extendClassWithConfig } from '../helper';
+import { IModelAnimation } from 'model/modelAnimation';
 
 /**
  * The Default viewer is the default implementation of the AbstractViewer.
@@ -55,48 +56,140 @@ export class DefaultViewer extends AbstractViewer {
     private _initNavbar() {
         let navbar = this.templateManager.getTemplate('navBar');
         if (navbar) {
-            let navbarHeight = navbar.parent.clientHeight + 'px';
-
-            let navbarShown: boolean = true;
-            let timeoutCancel /*: number*/;
-
-            let triggerNavbar = function (show: boolean = false, evt: PointerEvent) {
-                // only left-click on no-button.
-                if (!navbar || evt.button > 0) return;
-                // clear timeout
-                timeoutCancel && clearTimeout(timeoutCancel);
-                // if state is the same, do nothing
-                if (show === navbarShown) return;
-                //showing? simply show it!
-                if (show) {
-                    navbar.parent.style.bottom = show ? '0px' : '-' + navbarHeight;
-                    navbarShown = show;
+            this.onFrameRenderedObservable.add(this._updateProgressBar);
+            this.templateManager.eventManager.registerCallback('navBar', this._handlePointerDown, 'pointerdown');
+            // an example how to trigger the help button. publiclly available
+            this.templateManager.eventManager.registerCallback("navBar", () => {
+                // do your thing
+            }, "pointerdown", "#help-button");
+        }
+    }
+
+    private _animationList: string[];
+    private _currentAnimation: IModelAnimation;
+    private _isAnimationPaused: boolean;
+
+    private _handlePointerDown = (event: EventCallback) => {
+
+        let pointerDown = <PointerEvent>event.event;
+        if (pointerDown.button !== 0) return;
+        var element = (<HTMLElement>event.event.srcElement);
+
+        if (!element) {
+            return;
+        }
+
+        let parentClasses = element.parentElement!.classList;
+
+        switch (element.id) {
+            case "speed-button":
+            case "types-button":
+                if (parentClasses.contains("open")) {
+                    parentClasses.remove("open");
                 } else {
-                    let visibilityTimeout = 2000;
-                    if (navbar.configuration.params && navbar.configuration.params.visibilityTimeout !== undefined) {
-                        visibilityTimeout = <number>navbar.configuration.params.visibilityTimeout;
-                    }
-                    // not showing? set timeout until it is removed.
-                    timeoutCancel = setTimeout(function () {
-                        if (navbar) {
-                            navbar.parent.style.bottom = '-' + navbarHeight;
-                        }
-                        navbarShown = show;
-                    }, visibilityTimeout);
+                    parentClasses.add("open");
+                }
+                break;
+            case "play-pause-button":
+                this._togglePlayPause();
+                break;
+            case "label-option-button":
+                var label = element.dataset["value"];
+                if (label) {
+                    this._updateAnimationType(label);
                 }
+                break;
+            case "speed-option-button":
+                if (!this._currentAnimation) {
+                    return;
+                }
+                var speed = element.dataset["value"];
+                if (speed)
+                    this._updateAnimationSpeed(speed);
+                break;
+            case "progress-bar-container":
+                if (!this._currentAnimation) return;
+                const gotoFrame = (pointerDown.offsetX / element.clientWidth) * this._currentAnimation.frames;
+                if (isNaN(gotoFrame)) return;
+                this._currentAnimation.goToFrame(gotoFrame);
+                break;
+            case "fullscreen-button":
+                this.toggleFullscreen();
+            default:
+                return;
+        }
+    }
+
+    /**
+     * Plays or Pauses animation
+     */
+    private _togglePlayPause = () => {
+        if (!this._currentAnimation) {
+            return;
+        }
+        if (this._isAnimationPaused) {
+            this._currentAnimation.restart();
+        } else {
+            this._currentAnimation.pause();
+        }
+
+        this._isAnimationPaused = !this._isAnimationPaused;
+
+        let navbar = this.templateManager.getTemplate('navBar');
+        if (!navbar) return;
+
+        navbar.updateParams({
+            paused: this._isAnimationPaused,
+        });
+    }
+
+    /**
+     * Control progress bar position based on animation current frame
+     */
+    private _updateProgressBar = () => {
+        var progressWrapper = document.getElementById("progress-wrapper");
+        if (progressWrapper && this._currentAnimation) {
+            const progress = this._currentAnimation.currentFrame / this._currentAnimation.frames * 100;
+            if (isNaN(progress)) return;
+            progressWrapper.style.transform = "translateX(" + progress + "%)";
+        }
+    }
+
+    /** 
+     * Update Current Animation Speed
+     */
+    private _updateAnimationSpeed = (speed: string) => {
+        let navbar = this.templateManager.getTemplate('navBar');
+        if (!navbar) return;
+
+        if (speed && this._currentAnimation) {
+            this._currentAnimation.speedRatio = parseFloat(speed);
+            if (!this._isAnimationPaused) {
+                this._currentAnimation.restart();
             }
+            navbar.updateParams({
+                selectedSpeed: speed + "x",
+            });
+        }
+    }
 
-            this.templateManager.eventManager.registerCallback('viewer', triggerNavbar.bind(this, false), 'pointerout');
-            this.templateManager.eventManager.registerCallback('viewer', triggerNavbar.bind(this, true), 'pointerdown');
-            this.templateManager.eventManager.registerCallback('viewer', triggerNavbar.bind(this, false), 'pointerup');
-            this.templateManager.eventManager.registerCallback('navBar', triggerNavbar.bind(this, true), 'pointerover');
+    /** 
+     * Update Current Animation Type
+     */
+    private _updateAnimationType = (label: string) => {
+        let navbar = this.templateManager.getTemplate('navBar');
+        if (!navbar) return;
 
-            this.templateManager.eventManager.registerCallback('navBar', this.toggleFullscreen, 'pointerdown', '#fullscreen-button');
-            this.templateManager.eventManager.registerCallback('navBar', (data) => {
-                if (data && data.event && data.event.target)
-                    this.sceneManager.models[0].playAnimation(data.event.target['value']);
-            }, 'change', '#animation-selector');
+        if (label) {
+            this._currentAnimation = this.sceneManager.models[0].setCurrentAnimationByName(label);
         }
+
+        navbar.updateParams({
+            selectedAnimation: (this._animationList.indexOf(label) + 1),
+        });
+
+        // reset speed when a new animation is selected
+        this._updateAnimationSpeed("1.0");
     }
 
     /**
@@ -135,32 +228,21 @@ export class DefaultViewer extends AbstractViewer {
         let navbar = this.templateManager.getTemplate('navBar');
         if (!navbar) return;
 
-        if (model.getAnimationNames().length > 1) {
-            navbar.updateParams({ animations: model.getAnimationNames() });
+        if (model.getAnimationNames().length >= 1) {
+            this._animationList = model.getAnimationNames(),
+                navbar.updateParams({
+                    animations: this._animationList,
+                    //hideAnimations: true,
+                    //hideFullScreen: true,
+                });
+
+            // default animation & speed
+            this._updateAnimationSpeed("1.0");
+            this._isAnimationPaused = !!(model.configuration.animation && model.configuration.animation.autoStart);
+            this._updateAnimationType(this._animationList[0]);
         }
 
         let modelConfiguration = model.configuration;
-
-        let metadataContainer = navbar.parent.querySelector('#model-metadata');
-        if (metadataContainer) {
-            if (modelConfiguration.title !== undefined) {
-                let element = metadataContainer.querySelector('span.model-title');
-                if (element) {
-                    element.innerHTML = modelConfiguration.title;
-                }
-            }
-
-            if (modelConfiguration.subtitle !== undefined) {
-                let element = metadataContainer.querySelector('span.model-subtitle');
-                if (element) {
-                    element.innerHTML = modelConfiguration.subtitle;
-                }
-            }
-
-            if (modelConfiguration.thumbnail !== undefined) {
-                (<HTMLDivElement>metadataContainer.querySelector('.thumbnail')).style.backgroundImage = `url('${modelConfiguration.thumbnail}')`;
-            }
-        }
     }
 
     /**