From a3b874f9aa77c3c63b106054be3fee8bb6bfe391 Mon Sep 17 00:00:00 2001
From: Thijs Wenker <me@thoys.nl>
Date: Thu, 18 Oct 2018 01:14:13 +0200
Subject: [PATCH] property tooltips

---
 .../system/assets/data/createAppTooltips.json | 458 ++++++++++++++++++
 scripts/system/edit.js                        |   5 +
 scripts/system/html/css/edit-style.css        |  22 +
 scripts/system/html/entityProperties.html     |   1 +
 scripts/system/html/js/createAppTooltip.js    |  84 ++++
 scripts/system/html/js/entityProperties.js    |   8 +-
 6 files changed, 577 insertions(+), 1 deletion(-)
 create mode 100644 scripts/system/assets/data/createAppTooltips.json
 create mode 100644 scripts/system/html/js/createAppTooltip.js

diff --git a/scripts/system/assets/data/createAppTooltips.json b/scripts/system/assets/data/createAppTooltips.json
new file mode 100644
index 0000000000..f8c037297f
--- /dev/null
+++ b/scripts/system/assets/data/createAppTooltips.json
@@ -0,0 +1,458 @@
+{
+    "shape": {
+        "tooltip": "The shape of this entity's geometry."
+    },
+    "color": {
+        "tooltip": "The RGB value of this entity."
+    },
+    "materialURL": {
+        "tooltip": "The URL of a JSON file containing the material. Use this to change the entity's look. "
+    },
+    "text": {
+        "tooltip": "The text to display on the entity."
+    },
+    "textColor": {
+        "tooltip": "The color of the text."
+    },
+    "backgroundColor": {
+        "tooltip": "The color of the background."
+    },
+    "lineHeight": {
+        "tooltip": "The height of each line of text. This determines the size of the text."
+    },
+    "faceCamera": {
+        "tooltip": "If enabled, the entity follows the camera of each user, creating a billboard effect."
+    },
+    "flyingAllowed": {
+        "tooltip": "If enabled, users can fly in the zone."
+    },
+    "ghostingAllowed": {
+        "tooltip": "If enabled, users with avatar collisions turned off will not collide with content in the zone."
+    },
+    "filterURL": {
+        "tooltip": "The URL of a JS file that checks for changes to entity properties within the zone. Runs periodically."
+    },
+    "keyLightMode": {
+        "tooltip": "Configures the key light in the zone. This light is directional."
+    },
+    "keyLightColor": {
+        "tooltip": "The color of the key light."
+    },
+    "keyLight.intensity": {
+        "tooltip": "The intensity of the key light."
+    },
+    "keyLight.direction.y": {
+        "tooltip": "The angle in deg at which light emits. Starts in the entity's -z direction, and rotates around its y axis."
+    },
+    "keyLight.direction.x": {
+        "tooltip": "The angle in deg at which light emits. Starts in the entity's -z direction, and rotates around its x axis."
+    },
+    "keyLight.castShadows": {
+        "tooltip": "If enabled, shadows are cast. The entity or avatar casting the shadow must also have Cast Shadows enabled."
+    },
+    "skyboxMode": {
+        "tooltip": "Configures the skybox in the zone. The skybox is a cube map image."
+    },
+    "skybox.color": {
+        "tooltip": "If the URL is blank, this changes the color of the sky, otherwise it modifies the color of the skybox."
+    },
+    "skybox.url": {
+        "tooltip": "A cube map image that is used to render the sky."
+    },
+    "ambientLightMode": {
+        "tooltip": "Configures the ambient light in the zone. Use this if you want your skybox to reflect light on the content."
+    },
+    "ambientLight.ambientIntensity": {
+        "tooltip": "The intensity of the ambient light."
+    },
+    "ambientLight.ambientURL": {
+        "tooltip": "A cube map image that defines the color of the light coming from each direction."
+    },
+    "hazeMode": {
+        "tooltip": "Configures the haze in the scene."
+    },
+    "haze.hazeRange": {
+        "tooltip": "How far the haze extends out. This is measured in meters."
+    },
+    "haze.hazeAltitudeEffect": {
+        "tooltip": "If enabled, this adjusts the haze intensity as it gets higher."
+    },
+    "haze.hazeBaseRef": {
+        "tooltip": "The base of the altitude range. Measured in entity space."
+    },
+    "haze.hazeCeiling": {
+        "tooltip": "The ceiling of the altitude range. Measured in entity space."
+    },
+    "haze.hazeColor": {
+        "tooltip": "The color of the haze."
+    },
+    "haze.hazeBackgroundBlend": {
+        "tooltip": "How much the skybox shows through the haze. The higher the value, the more it shows through."
+    },
+    "haze.hazeEnableGlare": {
+        "tooltip": "If enabled, a glare is enabled on the skybox, based on the key light."
+    },
+    "haze.hazeGlareColor": {
+        "tooltip": "The color of the glare based on the key light."
+    },
+    "haze.hazeGlareAngle": {
+        "tooltip": "The angular size of the glare and how much it encompasses the skybox, based on the key light."
+    },
+    "bloomMode": {
+        "tooltip": "Configures how much bright areas of the scene glow."
+    },
+    "bloom.bloomIntensity": {
+        "tooltip": "The intensity, or brightness, of the bloom effect."
+    },
+    "bloom.bloomThreshold": {
+        "tooltip": "The cutoff of the bloom. The higher the value, the more only bright areas of the scene will glow."
+    },
+    "bloom.bloomSize": {
+        "tooltip": "The radius of bloom. The higher the value, the larger the bloom."
+    },
+    "modelURL": {
+        "tooltip": "A mesh model from an FBX or OBJ file."
+    },
+    "shapeType": {
+        "tooltip": "The shape of the collision hull used if collisions are enabled. This affects how an entity collides."
+    },
+    "compoundShapeURL": {
+        "tooltip": "The OBJ file to use for the compound shape if Collision Shape is \"compound\"."
+    },
+    "animation.url": {
+        "tooltip": "An animation to play on the model."
+    },
+    "animation.running": {
+        "tooltip": "If enabled, the animation on the model will play automatically."
+    },
+    "animation.allowTranslation": {
+        "tooltip": "If enabled, this allows an entity to move in space during an animation."
+    },
+    "animation.loop": {
+        "tooltip": "If enabled, then the animation will continuously repeat."
+    },
+    "animation.hold": {
+        "tooltip": "If enabled, then rotations and translations of the last frame played are maintained when the animation stops."
+    },
+    "animation.currentFrame": {
+        "tooltip": "The current frame being played in the animation."
+    },
+    "animation.firstFrame": {
+        "tooltip": "The first frame to play in the animation."
+    },
+    "animation.lastFrame": {
+        "tooltip": "The last frame to play in the animation."
+    },
+    "animation.fps": {
+        "tooltip": "The speed of the animation."
+    },
+    "textures": {
+        "tooltip": "The URL of a JPG or PNG image file to display for each particle."
+    },
+    "originalTextures": {
+        "tooltip": "A JSON string containing the original texture used on the model."
+    },
+    "imageUrl": {
+        "tooltip": "The URL for the image source.",
+        "jsPropertyName": "textures"
+    },
+    "sourceUrl": {
+        "tooltip": "The URL for the web page source."
+    },
+    "dpi": {
+        "tooltip": "The resolution to display the page at, in pixels per inch. Use this to resize your web source in the frame."
+    },
+    "isEmitting": {
+        "tooltip": "If enabled, then particles are emitted."
+    },
+    "lifespan": {
+        "tooltip": "How long each particle lives, measured in seconds."
+    },
+    "maxParticles": {
+        "tooltip": "The maximum number of particles to render at one time. Older particles are swapped out for new ones."
+    },
+    "emitRate": {
+        "tooltip": "The number of particles per second to emit."
+    },
+    "emitSpeed": {
+        "tooltip": "The speed that each particle is emitted at, measured in m/s."
+    },
+    "speedSpread": {
+        "tooltip": "The spread in speeds at which particles are emitted at, resulting in a variety of speeds."
+    },
+    "emitDimensions": {
+        "tooltip": "The outer limit radius in dimensions that the particles can be emitted from."
+    },
+    "emitOrientation": {
+        "tooltip": "The orientation of particle emission relative to the entity's axes."
+    },
+    "emitRadiusStart": {
+        "tooltip": "The inner limit radius in dimensions that the particles start emitting from."
+    },
+    "emitterShouldTrail": {
+        "tooltip": "If enabled, then particles are \"left behind\" as the emitter moves, otherwise they are not."
+    },
+    "particleRadius": {
+        "tooltip": "The size of each particle."
+    },
+    "radiusStart": {
+        "tooltip": ""
+    },
+    "radiusFinish": {
+        "tooltip": ""
+    },
+    "radiusSpread": {
+        "tooltip": "The spread in size that each particle is given, resulting in a variety of sizes."
+    },
+    "particleColor": {
+        "tooltip": "The color of each particle.",
+        "jsPropertyName": "color"
+    },
+    "colorSpread": {
+        "tooltip": "The spread in color that each particle is given, resulting in a variety of colors."
+    },
+    "alpha": {
+        "tooltip": "The alpha of each particle."
+    },
+    "alphaStart": {
+        "tooltip": ""
+    },
+    "alphaFinish": {
+        "tooltip": ""
+    },
+    "alphaSpread": {
+        "tooltip": "The spread in alpha that each particle is given, resulting in a variety of alphas."
+    },
+    "emitAcceleration": {
+        "tooltip": "The acceleration that is applied to each particle during its lifetime."
+    },
+    "accelerationSpread": {
+        "tooltip": "The spread in accelerations that each particle is given, resulting in a variety of accelerations."
+    },
+    "particleSpin": {
+        "tooltip": "The spin of each particle in the system."
+    },
+    "spinStart": {
+        "tooltip": ""
+    },
+    "spinFinish": {
+        "tooltip": ""
+    },
+    "spinSpread": {
+        "tooltip": "The spread in spin that each particle is given, resulting in a variety of spins."
+    },
+    "rotateWithEntity": {
+        "tooltip": "If enabled, each particle will spin relative to the roation of the entity as a whole."
+    },
+    "azimuthStart": {
+        "tooltip": "The angle in deg at which particles are emitted. Starts in the entity's -z direction, and rotates around its y axis."
+    },
+    "azimuthFinish": {
+        "tooltip": ""
+    },
+    "polarStart": {
+        "tooltip": "The angle in deg at which particles are emitted.  Starts in the entity's -z direction, and rotates around its y axis."
+    },
+    "polarFinish": {
+        "tooltip": ""
+    },
+    "lightColor": {
+        "tooltip": "The color of the light emitted.",
+        "jsPropertyName": "color"
+    },
+    "intensity": {
+        "tooltip": "The brightness of the light."
+    },
+    "falloffRadius": {
+        "tooltip": "The distance from the light's center where the intensity is reduced."
+    },
+    "isSpotlight": {
+        "tooltip": "If enabled, then the light is directional, otherwise the light is a point light which emits light in all directions."
+    },
+    "exponent": {
+        "tooltip": "Affects the softness of the spotlight beam; the higher the value, the softer the beam."
+    },
+    "cutoff": {
+        "tooltip": "Affects the size of the spotlight beam; the higher the value, the larger the beam."
+    },
+    "id": {
+        "tooltip": "The unique identifier of this entity."
+    },
+    "name": {
+        "tooltip": "The name of this entity."
+    },
+    "description": {
+        "tooltip": "Use this field to describe the entity."
+    },
+    "position": {
+        "tooltip": "The global position of this entity."
+    },
+    "rotation": {
+        "tooltip": "The rotation of the entity with respect to world coordinates."
+    },
+    "dimensions": {
+        "tooltip": "The global dimensions of this entity."
+    },
+    "scale": {
+        "tooltip": "The global scaling of this entity,",
+        "skipJSProperty": true
+    },
+    "registrationPoint": {
+        "tooltip": "The point in the entity at which the entity is rotated about."
+    },
+    "collisionless": {
+        "tooltip": "If enabled, this entity will collide with other entities or avatars."
+    },
+    "dynamic": {
+        "tooltip": "If enabled, this entity has collisions associated with it that can affect its movement."
+    },
+    "collidesWithStatic": {
+        "tooltip": "If enabled, this entity will collide with other non-moving, static entities.",
+        "jsPropertyName": "collidesWith"
+    },
+    "collidesWithDynamic": {
+        "tooltip": "If enabled, this entity will collide with other dynamic entities.",
+        "jsPropertyName": "collidesWith"
+    },
+    "collidesWithKinematic": {
+        "tooltip": "If enabled, this entity will collide with other kinematic entities (they have velocity but are not dynamic).",
+        "jsPropertyName": "collidesWith"
+    },
+    "collidesWithOtherAvatars": {
+        "tooltip": "If enabled, this entity will collide with other user's avatars.",
+        "jsPropertyName": "collidesWith"
+    },
+    "collisionSoundURL": {
+        "tooltip": "The URL of a sound to play when the entity collides with something else."
+    },
+    "grabbable": {
+        "tooltip": "If enabled, this entity will allow grabbing input and will be moveable.",
+        "jsPropertyName": "userData[\"grabbableKey\"][\"grabbable\"]"
+    },
+    "triggerable": {
+        "tooltip": "If enabled, the collider on this entity is used for triggering events.",
+        "jsPropertyName": "userData[\"grabbableKey\"][\"triggerable\"]"
+    },
+    "cloneable": {
+        "tooltip": "If enabled, this entity can be duplicated."
+    },
+    "cloneLifetime": {
+        "tooltip": "The lifetime for clones of this entity."
+    },
+    "cloneLimit": {
+        "tooltip": "The total number of clones of this entity that can exist in the domain at any given time."
+    },
+    "cloneDynamic": {
+        "tooltip": "If enabled, then clones created from this entity will be dynamic, allowing the clone to collide."
+    },
+    "cloneAvatarEntity": {
+        "tooltip": "If enabled, then clones created from this entity will be created as avatar entities."
+    },
+    "ignoreIK": {
+        "tooltip": "If enabled, grabbed entities will follow the movements of your hand controller instead of your avatar's hand.",
+        "jsPropertyName": "userData[\"grabbableKey\"][\"ignoreIK\"]"
+    },
+    "canCastShadow": {
+        "tooltip": "If enabled, this geometry of this entity casts shadows when a shadow-casting light source shines on it."
+    },
+    "parentID": {
+        "tooltip": "The ID of the entity or avatar that this entity is parented to."
+    },
+    "parentJointIndex": {
+        "tooltip": "If the entity is parented to an avatar, this joint defines where on the avatar the entity is parented."
+    },
+    "href": {
+        "tooltip": "The URL that will be opened when a user clicks on this entity. Useful for web pages and portals."
+    },
+    "script": {
+        "tooltip": "The URL to an external JS file to add behaviors to the client."
+    },
+    "serverScripts": {
+        "tooltip": "The URL to an external JS file to add behaviors to the server."
+    },
+    "serverScriptsStatus": {
+        "tooltip": "The status of the server script, if provided. This shows if it's running or has an error.",
+        "skipJSProperty": true
+    },
+    "hasLifetime": {
+        "tooltip": "If enabled, the entity will disappear after a certain amount of time specified by Lifetime.",
+        "jsPropertyName": "lifetime"
+    },
+    "lifetime": {
+        "tooltip": "The time this entity will exist in the environment for."
+    },
+    "userData": {
+        "tooltip": "Used to store extra data about the entity in JSON format."
+    },
+    "velocity": {
+        "tooltip": "The linear velocity vector of the entity. The velocity at which this entity moves forward in space."
+    },
+    "damping": {
+        "tooltip": "The linear damping to slow down the linear velocity of an entity over time."
+    },
+    "angularVelocity": {
+        "tooltip": "The angular velocity of the entity in rad/s with respect to its axes, about its pivot point."
+    },
+    "angularDamping": {
+        "tooltip": "The angular damping to slow down the angular velocity of an entity over time."
+    },
+    "restitution": {
+        "tooltip": "If enabled, the entity can bounce against other objects that also have Bounciness."
+    },
+    "friction": {
+        "tooltip": "The friction applied to slow down an entity when it's moving against another entity."
+    },
+    "density": {
+        "tooltip": "The density of the entity. The higher the density, the harder the entity is to move."
+    },
+    "gravity": {
+        "tooltip": "The acceleration due to gravity that the entity should move with, in world space."
+    },
+    "acceleration": {
+        "tooltip": "A acceleration that the entity should move with, in world space."
+    },
+    "createModel": {
+        "tooltip": "An entity that is based on a custom mesh created from an .OBJ or .FBX.",
+        "skipJSProperty": true
+    },
+    "createShape": {
+        "tooltip": "An entity that has many different primitive shapes.",
+        "skipJSProperty": true
+    },
+    "createLight": {
+        "tooltip": "An entity that emits light.",
+        "skipJSProperty": true
+    },
+    "createText": {
+        "tooltip": "An entity that displays text on a panel.",
+        "skipJSProperty": true
+    },
+    "createImage": {
+        "tooltip": "An entity that displays an image on a panel.",
+        "skipJSProperty": true
+    },
+    "createWeb": {
+        "tooltip": "An entity that displays a web page on a panel.",
+        "skipJSProperty": true
+    },
+    "createZone": {
+        "tooltip": "An entity that can be used for skyboxes, lighting, and can constrain or change avatar behaviors.",
+        "skipJSProperty": true
+    },
+    "createParticle": {
+        "tooltip": "An entity that emits particles.",
+        "skipJSProperty": true
+    },
+    "createMaterial": {
+        "tooltip": "An entity that creates a material that can be attached to a Shape or Model.",
+        "skipJSProperty": true
+    },
+    "useAssetServer": {
+        "tooltip": "A server that hosts content and assets. You can't take items that are hosted here into other domains.",
+        "skipJSProperty": true
+    },
+    "importNewEntity": {
+        "tooltip": "Import a local or hosted file that can be used across domains.",
+        "skipJSProperty": true
+    }
+}
diff --git a/scripts/system/edit.js b/scripts/system/edit.js
index 9f4ec3c62b..c6432ac2f9 100644
--- a/scripts/system/edit.js
+++ b/scripts/system/edit.js
@@ -2481,6 +2481,11 @@ var PropertiesTool = function (opts) {
             }
         } else if (data.type === "propertiesPageReady") {
             updateSelections(true);
+        } else if (data.type === "tooltipsRequest") {
+            emitScriptEvent({
+                type: 'tooltipsReply',
+                tooltips: Script.require('./assets/data/createAppTooltips.json')
+            });
         }
     };
 
diff --git a/scripts/system/html/css/edit-style.css b/scripts/system/html/css/edit-style.css
index 2db7fce065..4ad886f1b7 100644
--- a/scripts/system/html/css/edit-style.css
+++ b/scripts/system/html/css/edit-style.css
@@ -1598,3 +1598,25 @@ input.rename-entity {
     padding-left: 2px;
 }
 
+.createAppTooltip {
+    position: absolute;
+    background: #6a6a6a;
+    border: 1px solid black;
+    width: 258px;
+    min-height: 20px;
+    padding: 5px;
+}
+
+.createAppTooltip .createAppTooltipDescription {
+    font-size: 12px;
+    font-style: italic;
+    color: #ffffff;
+}
+
+.createAppTooltip .createAppTooltipJSAttribute {
+    font-size: 10px;
+    color: #000000;
+    bottom: 0;
+    margin-top: 5px;
+}
+
diff --git a/scripts/system/html/entityProperties.html b/scripts/system/html/entityProperties.html
index 03b034fc83..b56ad346e2 100644
--- a/scripts/system/html/entityProperties.html
+++ b/scripts/system/html/entityProperties.html
@@ -21,6 +21,7 @@
     <script type="text/javascript" src="js/eventBridgeLoader.js"></script>
     <script type="text/javascript" src="js/spinButtons.js"></script>
     <script type="text/javascript" src="js/underscore-min.js"></script>
+    <script type="text/javascript" src="js/createAppTooltip.js"></script>
     <script type="text/javascript" src="js/entityProperties.js"></script>
     <script src="js/jsoneditor.min.js"></script>
 </head>
diff --git a/scripts/system/html/js/createAppTooltip.js b/scripts/system/html/js/createAppTooltip.js
new file mode 100644
index 0000000000..10ad73e1ee
--- /dev/null
+++ b/scripts/system/html/js/createAppTooltip.js
@@ -0,0 +1,84 @@
+//  createAppTooltip.js
+//
+//  Created by Thijs Wenker on 17 Oct 2018
+//  Copyright 2018 High Fidelity, Inc.
+//
+//  Distributed under the Apache License, Version 2.0.
+//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+
+const CREATE_APP_TOOLTIP_OFFSET = 20;
+
+function CreateAppTooltip() {
+    this._tooltipData = null;
+    this._tooltipDiv = null;
+}
+
+CreateAppTooltip.prototype = {
+    _tooltipData: null,
+    _tooltipDiv: null,
+
+    _removeTooltipIfExists: function() {
+        if (this._tooltipDiv !== null) {
+            this._tooltipDiv.remove();
+            this._tooltipDiv = null;
+        }
+    },
+
+    setTooltipData: function(tooltipData) {
+        this._tooltipData = tooltipData;
+    },
+
+    registerTooltipElement: function(element, tooltipID) {
+        element.addEventListener("mouseover", function() {
+
+            this._removeTooltipIfExists();
+
+            let tooltipData = this._tooltipData[tooltipID];
+
+            if (!tooltipData || tooltipData.tooltip === "") {
+                return;
+            }
+
+            let elementRect = element.getBoundingClientRect();
+            let elTip = document.createElement("div");
+            elTip.className = "createAppTooltip";
+
+            let elTipDescription = document.createElement("div");
+            elTipDescription.className = "createAppTooltipDescription";
+            elTipDescription.innerText = tooltipData.tooltip;
+            elTip.appendChild(elTipDescription);
+
+            let jsAttribute = tooltipID;
+            if (tooltipData.jsPropertyName) {
+                jsAttribute = tooltipData.jsPropertyName;
+            }
+
+            if (!tooltipData.skipJSProperty) {
+                let elTipJSAttribute = document.createElement("div");
+                elTipJSAttribute.className = "createAppTooltipJSAttribute";
+                elTipJSAttribute.innerText = `JS Attribute: ${jsAttribute}`;
+                elTip.appendChild(elTipJSAttribute);
+            }
+
+            document.body.appendChild(elTip);
+
+            let elementTop = window.pageYOffset + elementRect.top;
+
+            let desiredTooltipTop = elementTop + element.clientHeight + CREATE_APP_TOOLTIP_OFFSET;
+
+            if ((window.innerHeight + window.pageYOffset) < (desiredTooltipTop + elTip.clientHeight)) {
+                // show above when otherwise out of bounds
+                elTip.style.top = elementTop - CREATE_APP_TOOLTIP_OFFSET - elTip.clientHeight;
+            } else {
+                // show tooltip on below by default
+                elTip.style.top = desiredTooltipTop;
+            }
+            elTip.style.left = window.pageXOffset + elementRect.left;
+
+            this._tooltipDiv = elTip;
+        }.bind(this), false);
+        element.addEventListener("mouseout", function() {
+            this._removeTooltipIfExists();
+        }.bind(this), false);
+    }
+};
diff --git a/scripts/system/html/js/entityProperties.js b/scripts/system/html/js/entityProperties.js
index 676ecaf289..59c2ba702b 100644
--- a/scripts/system/html/js/entityProperties.js
+++ b/scripts/system/html/js/entityProperties.js
@@ -1307,6 +1307,7 @@ var colorPickers = {};
 var particlePropertyUpdates = {};
 var selectedEntityProperties;
 var lastEntityID = null;
+var createAppTooltip = new CreateAppTooltip();
 
 function debugPrint(message) {
     EventBridge.emitWebEvent(
@@ -2659,7 +2660,7 @@ function showParentMaterialNameBox(number, elNumber, elString) {
 
 
 function loaded() {
-    openEventBridge(function() {    
+    openEventBridge(function() {
         let elPropertiesList = document.getElementById("properties-list");
         
         GROUPS.forEach(function(group) {            
@@ -2728,6 +2729,8 @@ function loaded() {
                 let elLabel = document.createElement('label');
                 elLabel.innerText = propertyData.label;
                 elLabel.setAttribute("for", propertyElementID);
+
+                createAppTooltip.registerTooltipElement(elLabel, propertyID);
                 
                 let property = { 
                     data: propertyData, 
@@ -3150,6 +3153,8 @@ function loaded() {
                             activeElement.select();
                         }
                     }
+                } else if (data.type === 'tooltipsReply') {
+                    createAppTooltip.setTooltipData(data.tooltips);
                 }
             });
         }
@@ -3381,5 +3386,6 @@ function loaded() {
 
     setTimeout(function() {
         EventBridge.emitWebEvent(JSON.stringify({ type: 'propertiesPageReady' }));
+        EventBridge.emitWebEvent(JSON.stringify({ type: 'tooltipsRequest' }));
     }, 1000);
 }