//// overlayManager.js// examples/libraries//// Created by Zander Otavka on 7/24/15// Copyright 2015 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//// Manage overlays with object oriented goodness, instead of ugly `Overlays.h` methods.// Instead of://// var billboard = Overlays.addOverlay("image3d", { visible: false });// ...// Overlays.editOverlay(billboard, { visible: true });// ...// Overlays.deleteOverlay(billboard);//// You can now do://// var billboard = new Image3DOverlay({ visible: false });// ...// billboard.visible = true;// ...// billboard.destroy();//// More on usage below. Examples in `examples/example/overlayPanelExample.js`.//// Note that including this file will delete `Overlays` from the global scope. All the// functionality of `Overlays` is represented here, just better. If you try to use `Overlays`// in tandem, there may be performance problems or nasty surprises.// (function() { // Delete `Overlays` from the global scope. var Overlays = this.Overlays; delete this.Overlays; var ABSTRACT = null; var overlays = {}; var panels = {}; var overlayTypes = {}; function generateOverlayClass(superclass, type, properties) { var that; if (type == ABSTRACT) { that = function(type, params) { superclass.call(this, type, params); }; } else { that = function(params) { superclass.call(this, type, params); }; overlayTypes[type] = that; } that.prototype = new superclass(); that.prototype.constructor = that; properties.forEach(function(prop) { Object.defineProperty(that.prototype, prop, { get: function() { //V8TODO: return Overlays.getProperty(this._id, prop); }, set: function(newValue) { var keyValuePair = {}; keyValuePair[prop] = newValue; this.setProperties(keyValuePair); }, configurable: false }); }); return that; } // // Create a new JavaScript object for an overlay of given ID. // function makeOverlayFromId(id) { var type = Overlays.getOverlayType(id); if (!type) { return null; } var overlay = new overlayTypes[type](); overlay._id = id; overlays[id] = overlay; return overlay; } // // Get or create an overlay object from the id. // // @param knownOverlaysOnly (Optional: Boolean) // If true, a new object will not be created. // @param searchList (Optional: Object) // Map of overlay id's and overlay objects. Can be generated with // `OverlayManager.makeSearchList`. // function findOverlay(id, knownOverlaysOnly, searchList) { if (id > 0) { knownOverlaysOnly = Boolean(knownOverlaysOnly); searchList = searchList || overlays; var foundOverlay = searchList[id]; if (foundOverlay) { return foundOverlay; } if (!knownOverlaysOnly) { return makeOverlayFromId(id); } } return null; } // // Create a new JavaScript object for a panel of given ID. // function makePanelFromId(id) { if (!Overlays.isAddedPanel(id)) { return null; } var panel = new OverlayPanel(); panel._id = id; overlays[id] = overlay; return overlay; } // // Get or create a panel object from the id. // // @param knownOverlaysOnly (Optional: Boolean) // If true, a new object will not be created. // @param searchList (Optional: Object) // Map of overlay id's and overlay objects. Can be generated with // `OverlayManager.makeSearchList`. // function findPanel(id, knownPanelsOnly, searchList) { if (id > 0) { knownPanelsOnly = Boolean(knownPanelsOnly); searchList = searchList || panels; var foundPanel = searchList[id]; if (foundPanel) { return foundPanel; } if (!knownPanelsOnly) { return makePanelFromId(id); } } return null; } function findOverlayOrPanel(id, knownObjectsOnly, searchList) { return findOverlay(id, knownObjectsOnly, searchList) || findPanel(id, knownObjectsOnly, searchList); } var Overlay = (function() { var that = function(type, params) { if (type && params) { this._id = Overlays.addOverlay(type, params); overlays[this._id] = this; } else { this._id = 0; } }; that.prototype.constructor = that; Object.defineProperty(that.prototype, "isLoaded", { get: function() { return Overlays.isLoaded(this._id); } }); Object.defineProperty(that.prototype, "parentPanel", { get: function() { return findPanel(Overlays.getParentPanel(this._id)); } }); that.prototype.getTextSize = function(text) { return Overlays.textSize(this._id, text); }; that.prototype.setProperties = function(properties) { Overlays.editOverlay(this._id, properties); }; that.prototype.clone = function() { return makeOverlayFromId(Overlays.cloneOverlay(this._id)); }; that.prototype.destroy = function() { Overlays.deleteOverlay(this._id); }; that.prototype.isPanelAttachable = function() { return false; }; return generateOverlayClass(that, ABSTRACT, [ "alpha", "pulseMax", "pulseMin", "pulsePeriod", "alphaPulse", "colorPulse", "visible", "anchor" ]); })(); // Supports multiple inheritance of properties. Just `concat` them onto the end of the // properties list. var PanelAttachable = ["offsetPosition", "offsetRotation", "offsetScale"]; var Billboardable = ["isFacingAvatar"]; var Overlay2D = generateOverlayClass(Overlay, ABSTRACT, [ "bounds", "x", "y", "width", "height" ]); var Base3DOverlay = generateOverlayClass(Overlay, ABSTRACT, [ "position", "lineWidth", "rotation", "isSolid", "isFilled", "isWire", "isDashedLine", "ignoreRayIntersection", "drawInFront" ]); var Planar3DOverlay = generateOverlayClass(Base3DOverlay, ABSTRACT, [ "dimensions" ]); var Billboard3DOverlay = generateOverlayClass(Planar3DOverlay, ABSTRACT, [ ].concat(PanelAttachable).concat(Billboardable)); Billboard3DOverlay.prototype.isPanelAttachable = function() { return true; }; var Volume3DOverlay = generateOverlayClass(Base3DOverlay, ABSTRACT, [ "dimensions" ]); Image3DOverlay = generateOverlayClass(Billboard3DOverlay, "image3d", [ "url", "subImage" ]); Text3DOverlay = generateOverlayClass(Billboard3DOverlay, "text3d", [ "text", "backgroundColor", "backgroundAlpha", "lineHeight", "leftMargin", "topMargin", "rightMargin", "bottomMargin" ]); Cube3DOverlay = generateOverlayClass(Volume3DOverlay, "cube", [ "borderSize" ]); Sphere3DOverlay = generateOverlayClass(Volume3DOverlay, "sphere", [ ]); Circle3DOverlay = generateOverlayClass(Planar3DOverlay, "circle3d", [ "startAt", "endAt", "outerRadius", "innerRadius", "hasTickMarks", "majorTickMarksAngle", "minorTickMarksAngle", "majorTickMarksLength", "minorTickMarksLength", "majorTickMarksColor", "minorTickMarksColor" ]); Rectangle3DOverlay = generateOverlayClass(Planar3DOverlay, "rectangle3d", [ ]); Line3DOverlay = generateOverlayClass(Base3DOverlay, "line3d", [ "start", "end" ]); Grid3DOverlay = generateOverlayClass(Planar3DOverlay, "grid", [ "minorGridWidth", "majorGridEvery" ]); ModelOverlay = generateOverlayClass(Volume3DOverlay, "model", [ "url", "dimensions", "textures" ]); OverlayPanel = (function() { var that = function(params) { this._id = Overlays.addPanel(params); panels[this._id] = this; }; that.prototype.constructor = that; var props = [ "anchorPosition", "anchorPositionBinding", "anchorRotation", "anchorRotationBinding", "anchorScale", "visible" ].concat(PanelAttachable).concat(Billboardable) props.forEach(function(prop) { Object.defineProperty(that.prototype, prop, { get: function() { return Overlays.getPanelProperty(this._id, prop); }, set: function(newValue) { var keyValuePair = {}; keyValuePair[prop] = newValue; this.setProperties(keyValuePair); }, configurable: false }); }); Object.defineProperty(that.prototype, "parentPanel", { get: function() { return findPanel(Overlays.getParentPanel(this._id)); } }); Object.defineProperty(that.prototype, "children", { get: function() { var idArray = Overlays.getPanelProperty(this._id, "children"); var objArray = []; for (var i = 0; i < idArray.length; i++) { objArray[i] = findOverlayOrPanel(idArray[i]); } return objArray; } }); that.prototype.addChild = function(child) { Overlays.setParentPanel(child._id, this._id); return child; }; that.prototype.removeChild = function(child) { if (child.parentPanel === this) { Overlays.setParentPanel(child._id, 0); } }; that.prototype.setProperties = function(properties) { Overlays.editPanel(this._id, properties); }; that.prototype.setChildrenVisible = function() { this.children.forEach(function(child) { child.visible = true; if (child.setChildrenVisible !== undefined) { child.setChildrenVisible(); } }); }; that.prototype.destroy = function() { Overlays.deletePanel(this._id); }; return that; })(); OverlayManager = { findOnRay: function(pickRay, knownOverlaysOnly, searchList) { var rayPickResult = Overlays.findRayIntersection(pickRay); if (rayPickResult.intersects) { return findOverlay(rayPickResult.overlayID, knownOverlaysOnly, searchList); } return null; }, findAtPoint: function(point, knownOverlaysOnly, searchList) { var foundID = Overlays.getOverlayAtPoint(point); if (foundID) { return findOverlay(foundID, knownOverlaysOnly, searchList); } else { var pickRay = Camera.computePickRay(point.x, point.y); return OverlayManager.findOnRay(pickRay, knownOverlaysOnly, searchList); } }, makeSearchList: function(array) { var searchList = {}; array.forEach(function(object) { searchList[object._id] = object; }); return searchList; }, findRayIntersection: function(pickRay) { return Overlays.findRayIntersection(pickRay); } }; // Threadsafe cleanup of JavaScript objects. function onOverlayDeleted(id) { if (id in overlays) { if (overlays[id].parentPanel) { overlays[id].parentPanel.removeChild(overlays[id]); } delete overlays[id]; } } function onPanelDeleted(id) { if (id in panels) { if (panels[id].parentPanel) { panels[id].parentPanel.removeChild(panels[id]); } delete panels[id]; } } Overlays.overlayDeleted.connect(onOverlayDeleted); Overlays.panelDeleted.connect(onPanelDeleted);})();
//
// overlayManager.js
// examples/libraries
//
// Created by Zander Otavka on 7/24/15
// Copyright 2015 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
//
// Manage overlays with object oriented goodness, instead of ugly `Overlays.h` methods.
// Instead of:
//
// var billboard = Overlays.addOverlay("image3d", { visible: false });
// ...
// Overlays.editOverlay(billboard, { visible: true });
// ...
// Overlays.deleteOverlay(billboard);
//
// You can now do:
//
// var billboard = new Image3DOverlay({ visible: false });
// ...
// billboard.visible = true;
// ...
// billboard.destroy();
//
// More on usage below. Examples in `examples/example/overlayPanelExample.js`.
//
// Note that including this file will delete `Overlays` from the global scope. All the
// functionality of `Overlays` is represented here, just better. If you try to use `Overlays`
// in tandem, there may be performance problems or nasty surprises.
//
(function() {
// Delete `Overlays` from the global scope.
var Overlays = this.Overlays;
delete this.Overlays;
var ABSTRACT = null;
var overlays = {};
var panels = {};
var overlayTypes = {};
function generateOverlayClass(superclass, type, properties) {
var that;
if (type == ABSTRACT) {
that = function(type, params) {
superclass.call(this, type, params);
};
} else {
that = function(params) {
superclass.call(this, type, params);
};
overlayTypes[type] = that;
}
that.prototype = new superclass();
that.prototype.constructor = that;
properties.forEach(function(prop) {
Object.defineProperty(that.prototype, prop, {
get: function() {
//V8TODO:
return Overlays.getProperty(this._id, prop);
},
set: function(newValue) {
var keyValuePair = {};
keyValuePair[prop] = newValue;
this.setProperties(keyValuePair);
},
configurable: false
});
});
return that;
}
//
// Create a new JavaScript object for an overlay of given ID.
//
function makeOverlayFromId(id) {
var type = Overlays.getOverlayType(id);
if (!type) {
return null;
}
var overlay = new overlayTypes[type]();
overlay._id = id;
overlays[id] = overlay;
return overlay;
}
//
// Get or create an overlay object from the id.
//
// @param knownOverlaysOnly (Optional: Boolean)
// If true, a new object will not be created.
// @param searchList (Optional: Object)
// Map of overlay id's and overlay objects. Can be generated with
// `OverlayManager.makeSearchList`.
//
function findOverlay(id, knownOverlaysOnly, searchList) {
if (id > 0) {
knownOverlaysOnly = Boolean(knownOverlaysOnly);
searchList = searchList || overlays;
var foundOverlay = searchList[id];
if (foundOverlay) {
return foundOverlay;
}
if (!knownOverlaysOnly) {
return makeOverlayFromId(id);
}
}
return null;
}
//
// Create a new JavaScript object for a panel of given ID.
//
function makePanelFromId(id) {
if (!Overlays.isAddedPanel(id)) {
return null;
}
var panel = new OverlayPanel();
panel._id = id;
overlays[id] = overlay;
return overlay;
}
//
// Get or create a panel object from the id.
//
// @param knownOverlaysOnly (Optional: Boolean)
// If true, a new object will not be created.
// @param searchList (Optional: Object)
// Map of overlay id's and overlay objects. Can be generated with
// `OverlayManager.makeSearchList`.
//
function findPanel(id, knownPanelsOnly, searchList) {
if (id > 0) {
knownPanelsOnly = Boolean(knownPanelsOnly);
searchList = searchList || panels;
var foundPanel = searchList[id];
if (foundPanel) {
return foundPanel;
}
if (!knownPanelsOnly) {
return makePanelFromId(id);
}
}
return null;
}
function findOverlayOrPanel(id, knownObjectsOnly, searchList) {
return findOverlay(id, knownObjectsOnly, searchList) ||
findPanel(id, knownObjectsOnly, searchList);
}
var Overlay = (function() {
var that = function(type, params) {
if (type && params) {
this._id = Overlays.addOverlay(type, params);
overlays[this._id] = this;
} else {
this._id = 0;
}
};
that.prototype.constructor = that;
Object.defineProperty(that.prototype, "isLoaded", {
get: function() {
return Overlays.isLoaded(this._id);
}
});
Object.defineProperty(that.prototype, "parentPanel", {
get: function() {
return findPanel(Overlays.getParentPanel(this._id));
}
});
that.prototype.getTextSize = function(text) {
return Overlays.textSize(this._id, text);
};
that.prototype.setProperties = function(properties) {
Overlays.editOverlay(this._id, properties);
};
that.prototype.clone = function() {
return makeOverlayFromId(Overlays.cloneOverlay(this._id));
};
that.prototype.destroy = function() {
Overlays.deleteOverlay(this._id);
};
that.prototype.isPanelAttachable = function() {
return false;
};
return generateOverlayClass(that, ABSTRACT, [
"alpha", "pulseMax", "pulseMin", "pulsePeriod",
"alphaPulse", "colorPulse", "visible", "anchor"
]);
})();
// Supports multiple inheritance of properties. Just `concat` them onto the end of the
// properties list.
var PanelAttachable = ["offsetPosition", "offsetRotation", "offsetScale"];
var Billboardable = ["isFacingAvatar"];
var Overlay2D = generateOverlayClass(Overlay, ABSTRACT, [
"bounds", "x", "y", "width", "height"
]);
var Base3DOverlay = generateOverlayClass(Overlay, ABSTRACT, [
"position", "lineWidth", "rotation", "isSolid", "isFilled", "isWire", "isDashedLine",
"ignoreRayIntersection", "drawInFront"
]);
var Planar3DOverlay = generateOverlayClass(Base3DOverlay, ABSTRACT, [
"dimensions"
]);
var Billboard3DOverlay = generateOverlayClass(Planar3DOverlay, ABSTRACT, [
].concat(PanelAttachable).concat(Billboardable));
Billboard3DOverlay.prototype.isPanelAttachable = function() { return true; };
var Volume3DOverlay = generateOverlayClass(Base3DOverlay, ABSTRACT, [
"dimensions"
]);
Image3DOverlay = generateOverlayClass(Billboard3DOverlay, "image3d", [
"url", "subImage"
]);
Text3DOverlay = generateOverlayClass(Billboard3DOverlay, "text3d", [
"text", "backgroundColor", "backgroundAlpha", "lineHeight", "leftMargin", "topMargin",
"rightMargin", "bottomMargin"
]);
Cube3DOverlay = generateOverlayClass(Volume3DOverlay, "cube", [
"borderSize"
]);
Sphere3DOverlay = generateOverlayClass(Volume3DOverlay, "sphere", [
]);
Circle3DOverlay = generateOverlayClass(Planar3DOverlay, "circle3d", [
"startAt", "endAt", "outerRadius", "innerRadius", "hasTickMarks",
"majorTickMarksAngle", "minorTickMarksAngle", "majorTickMarksLength",
"minorTickMarksLength", "majorTickMarksColor", "minorTickMarksColor"
]);
Rectangle3DOverlay = generateOverlayClass(Planar3DOverlay, "rectangle3d", [
]);
Line3DOverlay = generateOverlayClass(Base3DOverlay, "line3d", [
"start", "end"
]);
Grid3DOverlay = generateOverlayClass(Planar3DOverlay, "grid", [
"minorGridWidth", "majorGridEvery"
]);
ModelOverlay = generateOverlayClass(Volume3DOverlay, "model", [
"url", "dimensions", "textures"
]);
OverlayPanel = (function() {
var that = function(params) {
this._id = Overlays.addPanel(params);
panels[this._id] = this;
};
that.prototype.constructor = that;
var props = [
"anchorPosition", "anchorPositionBinding", "anchorRotation", "anchorRotationBinding", "anchorScale", "visible"
].concat(PanelAttachable).concat(Billboardable)
props.forEach(function(prop) {
Object.defineProperty(that.prototype, prop, {
get: function() {
return Overlays.getPanelProperty(this._id, prop);
},
set: function(newValue) {
var keyValuePair = {};
keyValuePair[prop] = newValue;
this.setProperties(keyValuePair);
},
configurable: false
});
});
Object.defineProperty(that.prototype, "parentPanel", {
get: function() {
return findPanel(Overlays.getParentPanel(this._id));
}
});
Object.defineProperty(that.prototype, "children", {
get: function() {
var idArray = Overlays.getPanelProperty(this._id, "children");
var objArray = [];
for (var i = 0; i < idArray.length; i++) {
objArray[i] = findOverlayOrPanel(idArray[i]);
}
return objArray;
}
});
that.prototype.addChild = function(child) {
Overlays.setParentPanel(child._id, this._id);
return child;
};
that.prototype.removeChild = function(child) {
if (child.parentPanel === this) {
Overlays.setParentPanel(child._id, 0);
}
};
that.prototype.setProperties = function(properties) {
Overlays.editPanel(this._id, properties);
};
that.prototype.setChildrenVisible = function() {
this.children.forEach(function(child) {
child.visible = true;
if (child.setChildrenVisible !== undefined) {
child.setChildrenVisible();
}
});
};
that.prototype.destroy = function() {
Overlays.deletePanel(this._id);
};
return that;
})();
OverlayManager = {
findOnRay: function(pickRay, knownOverlaysOnly, searchList) {
var rayPickResult = Overlays.findRayIntersection(pickRay);
if (rayPickResult.intersects) {
return findOverlay(rayPickResult.overlayID, knownOverlaysOnly, searchList);
}
return null;
},
findAtPoint: function(point, knownOverlaysOnly, searchList) {
var foundID = Overlays.getOverlayAtPoint(point);
if (foundID) {
return findOverlay(foundID, knownOverlaysOnly, searchList);
} else {
var pickRay = Camera.computePickRay(point.x, point.y);
return OverlayManager.findOnRay(pickRay, knownOverlaysOnly, searchList);
}
},
makeSearchList: function(array) {
var searchList = {};
array.forEach(function(object) {
searchList[object._id] = object;
});
return searchList;
},
findRayIntersection: function(pickRay) {
return Overlays.findRayIntersection(pickRay);
}
};
// Threadsafe cleanup of JavaScript objects.
function onOverlayDeleted(id) {
if (id in overlays) {
if (overlays[id].parentPanel) {
overlays[id].parentPanel.removeChild(overlays[id]);
}
delete overlays[id];
}
}
function onPanelDeleted(id) {
if (id in panels) {
if (panels[id].parentPanel) {
panels[id].parentPanel.removeChild(panels[id]);
}
delete panels[id];
}
}
Overlays.overlayDeleted.connect(onOverlayDeleted);
Overlays.panelDeleted.connect(onPanelDeleted);
})();