@turbox3d/renderer-core
Version:
Large-scale declarative graphic ui core renderer
582 lines • 21.8 kB
JavaScript
import _defineProperty from "@babel/runtime/helpers/esm/defineProperty";
import _classCallCheck from "@babel/runtime/helpers/esm/classCallCheck";
import _createClass from "@babel/runtime/helpers/esm/createClass";
import _possibleConstructorReturn from "@babel/runtime/helpers/esm/possibleConstructorReturn";
import _getPrototypeOf from "@babel/runtime/helpers/esm/getPrototypeOf";
import _inherits from "@babel/runtime/helpers/esm/inherits";
function _callSuper(t, o, e) { return o = _getPrototypeOf(o), _possibleConstructorReturn(t, _isNativeReflectConstruct() ? Reflect.construct(o, e || [], _getPrototypeOf(t).constructor) : o.apply(t, e)); }
function _isNativeReflectConstruct() { try { var t = !Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); } catch (t) {} return (_isNativeReflectConstruct = function _isNativeReflectConstruct() { return !!t; })(); }
/* eslint-disable react/no-unused-class-component-methods */
/* eslint-disable react/no-unused-prop-types */
/* eslint-disable react/require-default-props */
import { InteractiveController, EventType } from '@turbox3d/event-manager';
import { remove, getContextParam, getContextEnv } from '@turbox3d/shared';
import { Component } from './component';
export var SceneType;
(function (SceneType) {
SceneType["Scene2D"] = "2d";
SceneType["Scene3D"] = "3d";
})(SceneType || (SceneType = {}));
export var BaseScene = /*#__PURE__*/function (_Component) {
function BaseScene(props) {
var _this;
_classCallCheck(this, BaseScene);
_this = _callSuper(this, BaseScene, [props]);
_this.tickers = [];
_this.width = BaseScene.DEFAULT_WIDTH;
_this.height = BaseScene.DEFAULT_HEIGHT;
_this.renderFlag = true;
_this.getCoordinateCtrl = function () {
return _this.coordinate;
};
_this.getCurrentInteractiveController = function () {
var app = _this.getCurrentApp();
if (!app) {
return;
}
var obj = BaseScene.interactiveMap.get(app);
if (!obj) {
return;
}
return obj[_this.props.id];
};
_this.getCurrentApp = function () {
return BaseScene.appMap.get(_this.props.container);
};
_this.updateCursorHandler = function () {
var cursor = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'inherit';
var app = _this.getCurrentApp();
if (!app) {
return;
}
_this.updateCursor(app, cursor);
};
_this.getSceneTools = function () {
var ctrl = _this.getCurrentInteractiveController();
return {
// eslint-disable-next-line @typescript-eslint/no-empty-function
updateInteractiveObject: ctrl ? ctrl.updateInteractiveObject : function () {},
updateCursor: _this.updateCursorHandler,
hitTarget: ctrl ? ctrl.hitTarget : function () {},
coordinateTransform: _this.coordinateTransform,
getCamera: function getCamera() {
return _this.camera;
},
getRaycaster: function getRaycaster() {
return _this.raycaster;
},
getScene: function getScene() {
return _this.scene;
},
getRootView: function getRootView() {
return _this.view;
},
getScreenShot: function getScreenShot(sx, sy, w, h, fileType, quality, isBase64) {
return _this.getScreenShot(sx, sy, w, h, fileType, quality, isBase64);
},
getApp: function getApp() {
return _this.getCurrentApp();
},
addTicker: function addTicker(ticker) {
_this.tickers.push(ticker);
},
removeTicker: function removeTicker(ticker) {
remove(_this.tickers, ticker);
}
};
};
/**
* 坐标转化
*/
_this.coordinateTransform = function (point, type, z) {
return _this.coordinate ? _this.coordinate.transform(point, type, z) : {
x: 0,
y: 0
};
};
_this.resizeHandler = function () {
var _this$props$disableRe = _this.props.disableResize,
disableResize = _this$props$disableRe === void 0 ? false : _this$props$disableRe;
var app = _this.getCurrentApp();
if (!app) {
return;
}
!disableResize && _this.resizeStageByCanvas(app);
};
/**
* 计算2d原始视图的缩放和位置
*/
_this.compute2dOriginView = function () {
var _this$props = _this.props,
camera2dSize = _this$props.camera2dSize,
cameraPosition = _this$props.cameraPosition,
coordinateType = _this$props.coordinateType,
viewport = _this$props.viewport;
var width = viewport ? viewport.width : _this.width;
var height = viewport ? viewport.height : _this.height;
var rangeW = camera2dSize && camera2dSize.x || width;
var rangeH = camera2dSize && camera2dSize.y || height;
// 根据相机范围计算模型容器的缩放比例
// 取二者中较小值,保证可以完整的展示场景
var scale = Math.min(width / rangeW, height / rangeH);
var centerX = width / 2;
var centerY = height / 2;
var pX = (cameraPosition === null || cameraPosition === void 0 ? void 0 : cameraPosition.x) === void 0 ? centerX : cameraPosition.x;
var pY;
if ((cameraPosition === null || cameraPosition === void 0 ? void 0 : cameraPosition.y) === void 0) {
pY = centerY;
} else if (coordinateType === 'front' || coordinateType === 'left') {
pY = -cameraPosition.y;
} else {
pY = cameraPosition.y;
}
// 模型世界坐标以画布中心为原点
var x = centerX - pX * scale;
var y = centerY - pY * scale;
if (viewport) {
_this.setViewVisible(viewport.visible);
}
_this.setViewPosition({
x: x,
y: y
});
if (coordinateType === 'front' || coordinateType === 'left') {
_this.setViewScale({
x: scale,
y: -scale
});
} else {
_this.setViewScale({
x: scale,
y: scale
});
}
};
_this.onClick = function (event) {
var _this$props2 = _this.props,
onClickNothing = _this$props2.onClickNothing,
commandMgr = _this$props2.commandMgr;
if (onClickNothing) {
onClickNothing(event);
}
if (commandMgr) {
commandMgr.distributeEvent(EventType.onClick, _this.getViewEntity(), event, _this.getSceneTools());
}
};
_this.onDBClick = function (event) {
var _this$props3 = _this.props,
onClickNothing = _this$props3.onClickNothing,
commandMgr = _this$props3.commandMgr;
if (onClickNothing) {
onClickNothing(event);
}
if (commandMgr) {
commandMgr.distributeEvent(EventType.onDBClick, _this.getViewEntity(), event, _this.getSceneTools());
}
};
_this.onRightClick = function (event) {
var _this$props4 = _this.props,
onClickNothing = _this$props4.onClickNothing,
commandMgr = _this$props4.commandMgr;
if (onClickNothing) {
onClickNothing(event);
}
if (commandMgr) {
commandMgr.distributeEvent(EventType.onRightClick, _this.getViewEntity(), event, _this.getSceneTools());
}
};
_this.onDragStart = function (event) {
var _this$props5 = _this.props,
_this$props5$draggabl = _this$props5.draggable,
draggable = _this$props5$draggabl === void 0 ? true : _this$props5$draggabl,
commandMgr = _this$props5.commandMgr;
if (draggable) {
_this.canvasDragImpl(event, 'start');
}
if (commandMgr) {
commandMgr.distributeEvent(EventType.onDragStart, _this.getViewEntity(), event, _this.getSceneTools());
}
};
_this.onDragMove = function (event) {
var _this$props6 = _this.props,
_this$props6$draggabl = _this$props6.draggable,
draggable = _this$props6$draggabl === void 0 ? true : _this$props6$draggabl,
commandMgr = _this$props6.commandMgr;
if (draggable) {
_this.canvasDragImpl(event, 'move');
}
if (commandMgr) {
commandMgr.distributeEvent(EventType.onDragMove, _this.getViewEntity(), event, _this.getSceneTools());
}
};
_this.onDragEnd = function (event) {
var _this$props7 = _this.props,
_this$props7$draggabl = _this$props7.draggable,
draggable = _this$props7$draggabl === void 0 ? true : _this$props7$draggabl,
commandMgr = _this$props7.commandMgr;
if (draggable) {
_this.canvasDragImpl(event, 'end');
}
if (commandMgr) {
commandMgr.distributeEvent(EventType.onDragEnd, _this.getViewEntity(), event, _this.getSceneTools());
}
};
_this.onPinchStart = function (event) {
var commandMgr = _this.props.commandMgr;
if (commandMgr) {
commandMgr.distributeEvent(EventType.onPinchStart, _this.getViewEntity(), event, _this.getSceneTools());
}
};
_this.onPinch = function (event) {
var _this$props8 = _this.props,
_this$props8$scalable = _this$props8.scalable,
scalable = _this$props8$scalable === void 0 ? true : _this$props8$scalable,
commandMgr = _this$props8.commandMgr;
if (scalable) {
_this.canvasScaleImpl(event);
}
if (commandMgr) {
commandMgr.distributeEvent(EventType.onPinch, _this.getViewEntity(), event, _this.getSceneTools());
}
};
_this.onPinchEnd = function (event) {
var commandMgr = _this.props.commandMgr;
if (commandMgr) {
commandMgr.distributeEvent(EventType.onPinchEnd, _this.getViewEntity(), event, _this.getSceneTools());
}
};
_this.onRotateStart = function (event) {
var commandMgr = _this.props.commandMgr;
if (commandMgr) {
commandMgr.distributeEvent(EventType.onRotateStart, _this.getViewEntity(), event, _this.getSceneTools());
}
};
_this.onRotate = function (event) {
var commandMgr = _this.props.commandMgr;
if (commandMgr) {
commandMgr.distributeEvent(EventType.onRotate, _this.getViewEntity(), event, _this.getSceneTools());
}
};
_this.onRotateEnd = function (event) {
var commandMgr = _this.props.commandMgr;
if (commandMgr) {
commandMgr.distributeEvent(EventType.onRotateEnd, _this.getViewEntity(), event, _this.getSceneTools());
}
};
_this.onPress = function (event) {
var commandMgr = _this.props.commandMgr;
if (commandMgr) {
commandMgr.distributeEvent(EventType.onPress, _this.getViewEntity(), event, _this.getSceneTools());
}
};
_this.onPressUp = function (event) {
var commandMgr = _this.props.commandMgr;
if (commandMgr) {
commandMgr.distributeEvent(EventType.onPressUp, _this.getViewEntity(), event, _this.getSceneTools());
}
};
_this.onPointerMove = function (event) {
var commandMgr = _this.props.commandMgr;
if (commandMgr) {
commandMgr.distributeEvent(EventType.onCarriageMove, _this.getViewEntity(), event, _this.getSceneTools());
}
};
_this.onPointerUp = function (event) {
var commandMgr = _this.props.commandMgr;
if (commandMgr) {
commandMgr.distributeEvent(EventType.onCarriageEnd, _this.getViewEntity(), event, _this.getSceneTools());
}
};
_this.onWheel = function (event) {
var _this$props9 = _this.props,
_this$props9$scalable = _this$props9.scalable,
scalable = _this$props9$scalable === void 0 ? true : _this$props9$scalable,
commandMgr = _this$props9.commandMgr;
if (scalable) {
_this.canvasScaleImpl(event);
}
var ctrl = _this.getCurrentInteractiveController();
if (commandMgr && ctrl) {
commandMgr.distributeEvent(EventType.onWheel, _this.getViewEntity(), event, _this.getSceneTools());
}
};
_this.maxFPS = _this.props.maxFPS || 60;
if (_this.props.viewport) {
_this.resolution = _this.props.viewport.resolution || getContextParam('devicePixelRatio');
} else {
_this.resolution = _this.props.resolution || getContextParam('devicePixelRatio');
}
_this.updateRenderFlag(_this.props.renderFlag);
if (!BaseScene.appMap.has(_this.props.container)) {
var app = _this.createApp();
// 关闭默认交互
_this.destroyRendererInteraction(app);
// 缓存,挂载到同一元素的使用一个 gl 上下文
BaseScene.appMap.set(_this.props.container, app);
}
_this.view = _this.createView();
// 初始化坐标系系统
var currentApp = _this.getCurrentApp();
if (currentApp) {
_this.coordinate = _this.createCoordinateController(currentApp);
}
// 初始化交互控制器
_this.initInteractiveController();
_this.sceneContext = {
getCommandManager: function getCommandManager() {
return _this.props.commandMgr;
},
getSceneTools: _this.getSceneTools
};
return _this;
}
_inherits(BaseScene, _Component);
return _createClass(BaseScene, [{
key: "componentDidMount",
value: function componentDidMount() {
this.loadCanvas();
}
}, {
key: "componentDidUpdate",
value: function componentDidUpdate() {
var _this$props0 = this.props,
viewport = _this$props0.viewport,
_this$props0$disableR = _this$props0.disableResize,
disableResize = _this$props0$disableR === void 0 ? false : _this$props0$disableR,
_this$props0$renderFl = _this$props0.renderFlag,
renderFlag = _this$props0$renderFl === void 0 ? true : _this$props0$renderFl;
var app = this.getCurrentApp();
if (!app) {
return;
}
this.updateRenderFlag(renderFlag);
this.setBackGroundImage(app);
if (this.sceneType === SceneType.Scene3D) {
this.updateCameraInfo();
}
if (!viewport) {
this.resolution = this.props.resolution || getContextParam('devicePixelRatio');
this.updateResolution(app);
!disableResize && this.resizeStageByCanvas(app);
return;
}
var ctrl = this.getCurrentInteractiveController();
if (ctrl) {
ctrl.updateViewportInfo(viewport);
}
this.resolution = viewport.resolution || getContextParam('devicePixelRatio');
this.updateResolution(app);
!disableResize && this.resizeStageByCanvas(app);
// 重新计算 viewport
this.computeViewport();
}
}, {
key: "componentWillUnmount",
value: function componentWillUnmount() {
if (getContextParam('$$turbox_hot')) {
var app = this.getCurrentApp();
if (app) {
this.removeAppChildrenView(app);
}
return;
}
// 取消事件监听
var ctrl = this.getCurrentInteractiveController();
if (ctrl) {
ctrl.removeAllListener();
}
if (BaseScene.appMap.has(this.props.container)) {
var _app = this.getCurrentApp();
if (_app) {
this.destroyApp(_app);
}
BaseScene.appMap["delete"](this.props.container);
BaseScene.appMountedStatus["delete"](this.props.container);
}
if (getContextEnv() === 'browser') {
this.mountTimer && cancelAnimationFrame(this.mountTimer);
window.removeEventListener('resize', this.resizeHandler, false);
} else {
// vm 环境
this.unmountCanvas();
}
}
}, {
key: "initInteractiveController",
value: function initInteractiveController() {
var app = this.getCurrentApp();
if (!app) {
return;
}
var interactiveController = InteractiveController.create({
renderer: this.getCanvasView(app).renderer,
container: this.view,
viewport: this.props.viewport,
coordinateType: this.props.coordinateType,
canvasHandler: {
onClick: this.onClick,
onDBClick: this.onDBClick,
onRightClick: this.onRightClick,
onDragStart: this.onDragStart,
onDragMove: this.onDragMove,
onDragEnd: this.onDragEnd,
onPinchStart: this.onPinchStart,
onPinch: this.onPinch,
onPinchEnd: this.onPinchEnd,
onRotateStart: this.onRotateStart,
onRotate: this.onRotate,
onRotateEnd: this.onRotateEnd,
onPress: this.onPress,
onPressUp: this.onPressUp,
onPointerMove: this.onPointerMove,
onPointerUp: this.onPointerUp,
onWheel: this.onWheel
},
getCoordinateCtrl: this.getCoordinateCtrl,
getHitTargetOriginal: this.getHitTargetOriginal(),
maxFPS: this.maxFPS
});
var obj = BaseScene.interactiveMap.get(app);
if (!obj) {
BaseScene.interactiveMap.set(app, _defineProperty({}, this.props.id, interactiveController));
} else {
var ic = obj[this.props.id];
ic && ic.removeAllListener();
obj[this.props.id] = interactiveController;
}
}
/** 更新渲染状态 */
}, {
key: "updateRenderFlag",
value: function updateRenderFlag() {
var flag = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
this.renderFlag = flag;
}
}, {
key: "getViewEntity",
value: function getViewEntity() {
return {
id: this.props.id,
type: this.props.type || this.defaultSceneViewType
};
}
}, {
key: "loadCanvas",
value: function loadCanvas() {
var app = this.getCurrentApp();
if (!app) {
return;
}
var renderer = this.getCanvasView(app).renderer;
if (getContextEnv() === 'browser') {
var container = this.props.container;
var el = document.getElementById(container);
// 如果容器 DOM 没有准备好,留到下一帧再检测
if (!el) {
this.mountTimer = requestAnimationFrame(this.loadCanvas);
return;
}
// 挂载
if (!BaseScene.appMountedStatus.has(container)) {
BaseScene.appMountedStatus.set(container, true);
if (getContextParam('$$turbox_hot')) {
el.innerHTML = '';
}
el.appendChild(renderer);
}
window.addEventListener('resize', this.resizeHandler, false);
} else {
// vm 环境
var _container = this.props.container;
if (!BaseScene.appMountedStatus.has(_container)) {
BaseScene.appMountedStatus.set(_container, true);
this.mountCanvas(renderer);
}
}
// 根据容器大小确定画布大小
this.resizeStageByCanvas(app);
// 初始化背景图
this.setBackGroundImage(app);
if (this.sceneType === SceneType.Scene3D) {
// 更新相机信息
this.updateCameraInfo();
// 初始化天空盒
this.initSkyBox(app);
}
// 初始化模型容器
this.addRootViewContainer(app);
// 开始监听画布上的交互
var ctrl = this.getCurrentInteractiveController();
ctrl && ctrl.startListener();
this.props.initialized && this.props.initialized(this.getSceneTools());
}
}, {
key: "updateCameraInfo",
value: function updateCameraInfo() {
var cameraPosition = this.props.cameraPosition;
this.updateCameraPosition({
x: (cameraPosition === null || cameraPosition === void 0 ? void 0 : cameraPosition.x) || 0,
y: (cameraPosition === null || cameraPosition === void 0 ? void 0 : cameraPosition.y) || 0,
z: (cameraPosition === null || cameraPosition === void 0 ? void 0 : cameraPosition.z) || 0
});
}
}, {
key: "resizeStageByCanvas",
value: function resizeStageByCanvas(app) {
var _this$props1 = this.props,
viewport = _this$props1.viewport,
coordinateType = _this$props1.coordinateType;
if (viewport) {
this.resizeViewport(app);
}
this.resizeStage(app);
this.width = this.getCanvasView(app).width / this.resolution;
this.height = this.getCanvasView(app).height / this.resolution;
if (this.sceneType === SceneType.Scene2D && coordinateType) {
this.compute2dOriginView();
}
}
/** 计算视口的缩放和位置、可见性 */
}, {
key: "computeViewport",
value: function computeViewport() {
var viewport = this.props.viewport;
if (!viewport) {
return;
}
// resize 提高性能做法:放大对应视口的精灵,先让显示逻辑正确
var viewportInfo = this.getViewportInfo();
if (viewportInfo && viewportInfo.width && viewportInfo.width > 0 && viewportInfo.height && viewportInfo.height > 0) {
var ratio = Math.min(viewport.width / viewportInfo.width, viewport.height / viewportInfo.height);
var scale = viewportInfo.scale;
this.setViewportScale({
x: scale.x * ratio,
y: scale.y * ratio
});
}
// 重新计算对应视口的精灵
this.setViewportPosition({
x: viewport.x,
y: viewport.y
});
this.setViewportVisible(viewport.visible);
}
}]);
}(Component);
/** 默认背景色 */
BaseScene.BACKGROUND_COLOR = 0xffffff;
/** 默认背景透明度 */
BaseScene.BACKGROUND_ALPHA = 1;
/** 默认画布宽度 */
BaseScene.DEFAULT_WIDTH = 600;
/** 默认画布高度 */
BaseScene.DEFAULT_HEIGHT = 400;
// static DEFAULT_SCALE_NUM = 0.01;
BaseScene.SCALE_BIGGER = 1.1;
BaseScene.SCALE_SMALLER = 1 / 1.1;
/** 挂载点与应用上下文的映射关系 */
BaseScene.appMap = new Map();
/** 应用上下文与不同视角交互控制器的映射关系 */
BaseScene.interactiveMap = new Map();
/** 应用上下文是否已经挂载的状态 */
BaseScene.appMountedStatus = new Map();