UNPKG

@turbox3d/renderer-core

Version:

Large-scale declarative graphic ui core renderer

586 lines (585 loc) 22.7 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports.SceneType = exports.BaseScene = void 0; var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty")); var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck")); var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass")); var _possibleConstructorReturn2 = _interopRequireDefault(require("@babel/runtime/helpers/possibleConstructorReturn")); var _getPrototypeOf2 = _interopRequireDefault(require("@babel/runtime/helpers/getPrototypeOf")); var _inherits2 = _interopRequireDefault(require("@babel/runtime/helpers/inherits")); var _eventManager = require("@turbox3d/event-manager"); var _shared = require("@turbox3d/shared"); var _component = require("./component"); function _callSuper(t, o, e) { return o = (0, _getPrototypeOf2["default"])(o), (0, _possibleConstructorReturn2["default"])(t, _isNativeReflectConstruct() ? Reflect.construct(o, e || [], (0, _getPrototypeOf2["default"])(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 */ var SceneType; (function (SceneType) { SceneType["Scene2D"] = "2d"; SceneType["Scene3D"] = "3d"; })(SceneType || (exports.SceneType = SceneType = {})); var BaseScene = exports.BaseScene = /*#__PURE__*/function (_Component) { function BaseScene(props) { var _this; (0, _classCallCheck2["default"])(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) { (0, _shared.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(_eventManager.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(_eventManager.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(_eventManager.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(_eventManager.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(_eventManager.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(_eventManager.EventType.onDragEnd, _this.getViewEntity(), event, _this.getSceneTools()); } }; _this.onPinchStart = function (event) { var commandMgr = _this.props.commandMgr; if (commandMgr) { commandMgr.distributeEvent(_eventManager.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(_eventManager.EventType.onPinch, _this.getViewEntity(), event, _this.getSceneTools()); } }; _this.onPinchEnd = function (event) { var commandMgr = _this.props.commandMgr; if (commandMgr) { commandMgr.distributeEvent(_eventManager.EventType.onPinchEnd, _this.getViewEntity(), event, _this.getSceneTools()); } }; _this.onRotateStart = function (event) { var commandMgr = _this.props.commandMgr; if (commandMgr) { commandMgr.distributeEvent(_eventManager.EventType.onRotateStart, _this.getViewEntity(), event, _this.getSceneTools()); } }; _this.onRotate = function (event) { var commandMgr = _this.props.commandMgr; if (commandMgr) { commandMgr.distributeEvent(_eventManager.EventType.onRotate, _this.getViewEntity(), event, _this.getSceneTools()); } }; _this.onRotateEnd = function (event) { var commandMgr = _this.props.commandMgr; if (commandMgr) { commandMgr.distributeEvent(_eventManager.EventType.onRotateEnd, _this.getViewEntity(), event, _this.getSceneTools()); } }; _this.onPress = function (event) { var commandMgr = _this.props.commandMgr; if (commandMgr) { commandMgr.distributeEvent(_eventManager.EventType.onPress, _this.getViewEntity(), event, _this.getSceneTools()); } }; _this.onPressUp = function (event) { var commandMgr = _this.props.commandMgr; if (commandMgr) { commandMgr.distributeEvent(_eventManager.EventType.onPressUp, _this.getViewEntity(), event, _this.getSceneTools()); } }; _this.onPointerMove = function (event) { var commandMgr = _this.props.commandMgr; if (commandMgr) { commandMgr.distributeEvent(_eventManager.EventType.onCarriageMove, _this.getViewEntity(), event, _this.getSceneTools()); } }; _this.onPointerUp = function (event) { var commandMgr = _this.props.commandMgr; if (commandMgr) { commandMgr.distributeEvent(_eventManager.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(_eventManager.EventType.onWheel, _this.getViewEntity(), event, _this.getSceneTools()); } }; _this.maxFPS = _this.props.maxFPS || 60; if (_this.props.viewport) { _this.resolution = _this.props.viewport.resolution || (0, _shared.getContextParam)('devicePixelRatio'); } else { _this.resolution = _this.props.resolution || (0, _shared.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; } (0, _inherits2["default"])(BaseScene, _Component); return (0, _createClass2["default"])(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 || (0, _shared.getContextParam)('devicePixelRatio'); this.updateResolution(app); !disableResize && this.resizeStageByCanvas(app); return; } var ctrl = this.getCurrentInteractiveController(); if (ctrl) { ctrl.updateViewportInfo(viewport); } this.resolution = viewport.resolution || (0, _shared.getContextParam)('devicePixelRatio'); this.updateResolution(app); !disableResize && this.resizeStageByCanvas(app); // 重新计算 viewport this.computeViewport(); } }, { key: "componentWillUnmount", value: function componentWillUnmount() { if ((0, _shared.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 ((0, _shared.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 = _eventManager.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, (0, _defineProperty2["default"])({}, 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 ((0, _shared.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 ((0, _shared.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.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();