import { StringEncoder } from '@uino/base-thing';
import { Utils } from '../common/Utils';
import { Object3D } from './Object3D';
import { RenderType } from '../const';
const __ = {
private: Symbol('private'),
}
let _scale = [1, 1, 1];
const _spriteTypeName = StringEncoder.toText("<@secret Sprite>");
const registerComponentParam = { isResident: true };
/**
* @class WebView
* The webView object.
* @memberof THING
* @extends THING.Object3D
* @public
*/
class WebView extends Object3D {
/**
* The web view object that can show it as renderable plane in scene.
* @param {Object} param The initial parameters.
*/
constructor(param = {}) {
super(param);
this[__.private] = {};
let _private = this[__.private];
_private.iframeComponent = null;
_private.domScale = [1, 1];
_private.style = null;
_private.regionNode = null;
_private.renderableNode = null;
_private.renderableNodeOpacity = 0;
// Add web view component
_private.iframeComponent = Utils.createObject('WebViewComponent');
this.addComponent(_private.iframeComponent, 'iframe', registerComponentParam);
// Setup web view component
_private.iframeComponent.url = Utils.parseValue(param['url'], '');
_private.iframeComponent.domWidth = Utils.parseValue(param['domWidth'], 1920);
_private.iframeComponent.domHeight = Utils.parseValue(param['domHeight'], 1080);
_private.iframeComponent.interactive = Utils.parseValue(param['interactive'], false);
_private.iframeComponent.enableEventProxy = true;
// Register web view events
this._registerEvents();
// Create style for digging region
let style = Utils.createObject('Style');
style.setTransparent(false);
style.setSideType('Double');
style.setBlendingType('NoBlending');
style.setOpacityOp(() => { return _private.renderableNodeOpacity; });
style.setColorOp(() => { return [0, 0, 0]; });
_private.style = style;
// Create region node to body
_private.regionNode = Utils.createObject('Node');
this.bodyNode.add(_private.regionNode);
// Dig a renderable region to show web view by plane
this._createRenderableNode();
// Update attributes
this.renderType = Utils.parseValue(param['renderType'], RenderType.Plane);
if (param['domScale']) {
this.domScale = param['domScale'];
}
}
hasResource() {
return false;
}
// #region Private Functions
_updateRgionNodeScale() {
let _private = this[__.private];
if (Utils.isArray(_private.domScale)) {
_scale[0] = _private.domScale[0];
_scale[1] = _private.domScale[1];
}
else {
_scale[0] = this.domWidth * _private.domScale;
_scale[1] = this.domHeight * _private.domScale;
}
_private.regionNode.setScale(_scale);
}
_createRenderableNode() {
let _private = this[__.private];
// We must wait for global cache finished
this.app.global.waitForComplete().then(() => {
if (_private.renderableNode) {
_private.renderableNode.dispose();
_private.renderableNode = null;
}
if (this.renderType == RenderType.Plane) {
_private.renderableNode = this.app.global.cache.models['plane'].clone();
}
else {
_private.renderableNode = Utils.createObject(_spriteTypeName);
}
// Setup style
_private.renderableNode.setAttribute('SkipParentStyleChange', true); // Ignore parent style change
_private.renderableNode.setStyle(_private.style);
// Make renderable region a little smaller to prevent 'white' edge
const scaleFactor = 0.995;
_private.renderableNode.setScale([scaleFactor, scaleFactor, scaleFactor]);
// Render plane to dig region(hole)
_private.renderableNode.setVisible(true);
_private.regionNode.add(_private.renderableNode);
// Update scale
this._updateRgionNodeScale();
// Update region node for web view component
_private.iframeComponent.regionNode = _private.regionNode;
});
}
_registerEvents() {
// Due to interactive web view would catch all events, so we must stop camera control when move into it
this.on('mousemove', (ev) => {
this.app.camera.control.stop();
});
}
// #endregion
/**
* Get renderable node opacity.
* @returns {Number}
* @private
*/
getRenderableNodeOpacity() {
let _private = this[__.private];
return _private.renderableNodeOpacity;
}
/**
* Set renderable node opacity.
* @param {Number} value The opacity value.
* @private
*/
setRenderableNodeOpacity(value) {
let _private = this[__.private];
_private.renderableNodeOpacity = value;
if (_private.renderableNode) {
_private.renderableNode.getStyle().setOpacityOp(() => {
return _private.renderableNodeOpacity;
});
}
}
// #region Accessor
/**
* Get the region node.
* @type {Object}
* @private
*/
get regionNode() {
let _private = this[__.private];
return _private.regionNode;
}
/**
* Get the renderable node.
* @type {Object}
* @private
*/
get renderableNode() {
let _private = this[__.private];
return _private.renderableNode;
}
/**
* Get the iframe component.
* @type {Object}
* @private
*/
get iframeComponent() {
let _private = this[__.private];
return _private.iframeComponent;
}
/**
* Get/Set the render type.
* @type {RenderType}
* @public
*/
get renderType() {
let _private = this[__.private];
return _private.iframeComponent.renderType;
}
set renderType(value) {
let _private = this[__.private];
if (_private.iframeComponent.renderType == value) {
return;
}
_private.iframeComponent.renderType = value;
this._createRenderableNode();
}
/**
* Get/Set url.
* @type {String}
* @public
*/
get url() {
let _private = this[__.private];
return _private.iframeComponent.url;
}
set url(value) {
let _private = this[__.private];
_private.iframeComponent.url = value;
}
/**
* Get/Set DOM width in pixel.
* @type {Number}
* @public
*/
get domWidth() {
let _private = this[__.private];
return _private.iframeComponent.domWidth;
}
set domWidth(value) {
let _private = this[__.private];
_private.iframeComponent.domWidth = value;
}
/**
* Get/Set DOM height in pixel.
* @type {Number}
* @public
*/
get domHeight() {
let _private = this[__.private];
return _private.iframeComponent.domHeight;
}
set domHeight(value) {
let _private = this[__.private];
_private.iframeComponent.domHeight = value;
}
/**
* Get/Set DOM scale(factor).
* @type {Number|Array<Number>}
* @example
* // Keep ratio of size
* webView.domScale = 0.01;
* // Just set width and height without keeping ratio of size
* webView.domScale = [2, 3];
* @public
*/
get domScale() {
let _private = this[__.private];
return _private.domScale;
}
set domScale(value) {
let _private = this[__.private];
if (Utils.isArray(value)) {
_private.domScale = value.slice(0);
}
else {
_private.domScale = value;
}
if (_private.regionNode) {
this._updateRgionNodeScale();
}
}
/**
* Enable/Disable interactive.
* @type {Boolean}
* @public
*/
get interactive() {
let _private = this[__.private];
return _private.iframeComponent.interactive;
}
set interactive(value) {
let _private = this[__.private];
_private.iframeComponent.interactive = value;
}
// #endregion
get isWebView() {
return true;
}
}
export { WebView }