Merge pull request #14229 from thoys/feat/create/tooltips

MS19052 [CreateApp]: Tooltips
This commit is contained in:
John Conklin II 2018-10-25 14:52:16 -07:00 committed by GitHub
commit 2dfd63f4e7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 655 additions and 1 deletions

View file

@ -0,0 +1,500 @@
{
"shape": {
"tooltip": "The shape of this entity's geometry."
},
"color": {
"tooltip": "The RGB value of this entity."
},
"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."
},
"keyLight.color": {
"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": "A JSON string containing a texture. Use a name from the Original Texture property to override it."
},
"originalTextures": {
"tooltip": "A JSON string containing the original texture used on the model."
},
"image": {
"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."
},
"particleTextures": {
"tooltip": "The URL of a JPG or PNG image file to display for each particle.",
"jsPropertyName": "textures"
},
"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."
},
"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": ""
},
"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": ""
},
"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."
},
"materialURL": {
"tooltip": "The URL to an external JSON file or \"materialData\", \"materialData?<material name> to use Material Data."
},
"materialData": {
"tooltip": "Can be used instead of a JSON file when material set to materialData."
},
"materialNameToReplace": {
"tooltip": "Material name of parent entity to map this material entity on.",
"jsPropertyName": "parentMaterialName"
},
"submeshToReplace": {
"tooltip": "Submesh index of the parent entity to map this material on.",
"jsPropertyName": "parentMaterialName"
},
"selectSubmesh": {
"tooltip": "If enabled, \"Select Submesh\" property will show up, otherwise \"Material Name to Replace\" will be shown.",
"skipJSProperty": true
},
"priority": {
"tooltip": "The priority of the material, where a larger number means higher priority. Original materials = 0."
},
"materialMappingPos": {
"tooltip": "The offset position of the bottom left of the material within the parent's UV space."
},
"materialMappingScale": {
"tooltip": "How many times the material will repeat in each direction within the parent's UV space."
},
"materialMappingRot": {
"tooltip": "How much to rotate the material within the parent's UV-space, in degrees."
},
"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."
},
"visible": {
"tooltip": "If enabled, this entity will be visible."
},
"locked": {
"tooltip": "If enabled, this entity will be locked."
},
"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"
},
"collidesWithOtherAvatar": {
"tooltip": "If enabled, this entity will collide with other user's avatars.",
"jsPropertyName": "collidesWith"
},
"collidesWithMyAvatar": {
"tooltip": "If enabled, this entity will collide with your own avatar.",
"jsPropertyName": "collidesWith"
},
"collisionSoundURL": {
"tooltip": "The URL of a sound to play when the entity collides with something else."
},
"grab.grabbable": {
"tooltip": "If enabled, this entity will allow grabbing input and will be moveable."
},
"grab.triggerable": {
"tooltip": "If enabled, the collider on this entity is used for triggering events."
},
"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."
},
"grab.grabFollowsController": {
"tooltip": "If enabled, grabbed entities will follow the movements of your hand controller instead of your avatar's hand."
},
"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."
},
"alignToGrid": {
"tooltip": "Used to align entities to the grid, or floor of the environment.",
"skipJSProperty": true
},
"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
}
}

View file

@ -2481,6 +2481,12 @@ 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'),
hmdActive: HMD.active,
});
}
};

View file

@ -1598,3 +1598,26 @@ 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-family: Raleway-SemiBold;
font-size: 11px;
color: #000000;
bottom: 0;
margin-top: 5px;
}

View file

@ -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>

View file

@ -0,0 +1,116 @@
// 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;
const TOOLTIP_DELAY = 500; // ms
const TOOLTIP_DEBUG = false;
function CreateAppTooltip() {
this._tooltipData = null;
this._tooltipDiv = null;
this._delayTimeout = null;
this._isEnabled = false;
}
CreateAppTooltip.prototype = {
_tooltipData: null,
_tooltipDiv: null,
_delayTimeout: null,
_isEnabled: null,
_removeTooltipIfExists: function() {
if (this._delayTimeout !== null) {
window.clearTimeout(this._delayTimeout);
this._delayTimeout = null;
}
if (this._tooltipDiv !== null) {
this._tooltipDiv.remove();
this._tooltipDiv = null;
}
},
setIsEnabled: function(isEnabled) {
this._isEnabled = isEnabled;
},
setTooltipData: function(tooltipData) {
this._tooltipData = tooltipData;
},
registerTooltipElement: function(element, tooltipID) {
element.addEventListener("mouseover", function() {
if (!this._isEnabled) {
return;
}
this._removeTooltipIfExists();
this._delayTimeout = window.setTimeout(function() {
let tooltipData = this._tooltipData[tooltipID];
if (!tooltipData || tooltipData.tooltip === "") {
if (!TOOLTIP_DEBUG) {
return;
}
tooltipData = {tooltip: 'PLEASE SET THIS TOOLTIP'};
}
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;
let desiredTooltipLeft = window.pageXOffset + elementRect.left;
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;
}
if ((window.innerWidth + window.pageXOffset) < (desiredTooltipLeft + elTip.clientWidth)) {
elTip.style.left = document.body.clientWidth + window.pageXOffset - elTip.offsetWidth;
} else {
elTip.style.left = desiredTooltipLeft;
}
this._tooltipDiv = elTip;
}.bind(this), TOOLTIP_DELAY);
}.bind(this), false);
element.addEventListener("mouseout", function() {
if (!this._isEnabled) {
return;
}
this._removeTooltipIfExists();
}.bind(this), false);
}
};

View file

@ -1316,6 +1316,7 @@ var colorPickers = {};
var particlePropertyUpdates = {};
var selectedEntityProperties;
var lastEntityID = null;
var createAppTooltip = new CreateAppTooltip();
function debugPrint(message) {
EventBridge.emitWebEvent(
@ -2668,7 +2669,7 @@ function showParentMaterialNameBox(number, elNumber, elString) {
function loaded() {
openEventBridge(function() {
openEventBridge(function() {
let elPropertiesList = document.getElementById("properties-list");
GROUPS.forEach(function(group) {
@ -2737,6 +2738,8 @@ function loaded() {
let elLabel = document.createElement('label');
elLabel.innerText = propertyData.label;
elLabel.setAttribute("for", propertyElementID);
createAppTooltip.registerTooltipElement(elLabel, propertyID);
let property = {
data: propertyData,
@ -3159,6 +3162,9 @@ function loaded() {
activeElement.select();
}
}
} else if (data.type === 'tooltipsReply') {
createAppTooltip.setIsEnabled(!data.hmdActive);
createAppTooltip.setTooltipData(data.tooltips);
}
});
}
@ -3174,6 +3180,7 @@ function loaded() {
let elLabel = document.createElement('label');
elLabel.setAttribute("for", serverScriptStatusElementID);
elLabel.innerText = "Server Script Status";
createAppTooltip.registerTooltipElement(elLabel, "serverScriptsStatus");
let elServerScriptStatus = document.createElement('span');
elServerScriptStatus.setAttribute("id", serverScriptStatusElementID);
elDiv.appendChild(elLabel);
@ -3390,5 +3397,6 @@ function loaded() {
setTimeout(function() {
EventBridge.emitWebEvent(JSON.stringify({ type: 'propertiesPageReady' }));
EventBridge.emitWebEvent(JSON.stringify({ type: 'tooltipsRequest' }));
}, 1000);
}