UNPKG

bytev-charts

Version:

基于echarts和JavaScript及ES6封装的一个可以直接调用的图表组件库,内置主题设计,简单快捷,且支持用户自定义配置; npm 安装方式: npm install bytev-charts 若启动提示还需额外install插件,则运行 npm install @babel/runtime-corejs2 即可;

1,574 lines (1,260 loc) 102 kB
import _typeof from "@babel/runtime-corejs2/helpers/typeof"; function _createForOfIteratorHelper(o, allowArrayLike) { var it = typeof _Symbol !== "undefined" && o[_Symbol$iterator] || o["@@iterator"]; if (!it) { if (_Array$isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it["return"] != null) it["return"](); } finally { if (didErr) throw err; } } }; } function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return _Array$from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); } function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; } import _JSON$stringify from "@babel/runtime-corejs2/core-js/json/stringify"; import _Object$assign from "@babel/runtime-corejs2/core-js/object/assign"; import _parseInt from "@babel/runtime-corejs2/core-js/parse-int"; import _Object$create from "@babel/runtime-corejs2/core-js/object/create"; import _Object$keys from "@babel/runtime-corejs2/core-js/object/keys"; import _Array$from from "@babel/runtime-corejs2/core-js/array/from"; import _Symbol from "@babel/runtime-corejs2/core-js/symbol"; import _Symbol$iterator from "@babel/runtime-corejs2/core-js/symbol/iterator"; import _Array$isArray from "@babel/runtime-corejs2/core-js/array/is-array"; import "core-js/modules/es.regexp.exec.js"; import "core-js/modules/es.string.replace.js"; import "core-js/modules/es.function.bind.js"; import "core-js/modules/es.function.name.js"; import "core-js/modules/es.array.for-each.js"; import "core-js/modules/es.object.to-string.js"; import "core-js/modules/web.dom-collections.for-each.js"; import "core-js/modules/es.array.index-of.js"; import "core-js/modules/es.number.to-fixed.js"; import "core-js/modules/web.timers.js"; import "core-js/modules/es.string.repeat.js"; import "core-js/modules/es.array.concat.js"; import "core-js/modules/es.array.map.js"; import "core-js/modules/es.date.to-string.js"; import "core-js/modules/es.array.slice.js"; import * as THREE from './build/three.module.js'; import { FBXLoader } from './examples/jsm/loaders/FBXLoader.js'; import { GLTFLoader } from './examples/jsm/loaders/GLTFLoader.js'; import { RoughnessMipmapper } from './examples/jsm/utils/RoughnessMipmapper.js'; // import { DRACOLoader } from './examples/jsm/loaders/DRACOLoader.js'; import { OrbitControls } from './examples/jsm/controls/OrbitControls.js'; import { TWEEN } from './examples/jsm/libs/tween.module.min.js'; import { VRButton } from './VRButton.js'; // import helvetiker_bold from './font/helvetiker_bold.typeface.js'; //效果 import { Lensflare, LensflareElement } from './examples/jsm/objects/Lensflare.js'; /*模型*/ import EWSN from './examples/models/BTVmodel.js/EWSN.js'; import roundCircle from './examples/models/BTVmodel.js/roundCircle.js'; /*贴图*/ import { rainImg, snowImg } from './examples/textures/weather/weather.js'; import { day, night } from './examples/textures/sky/skyBall.js'; import { honeycomb, floorEffect } from './examples/textures/textures.js'; import { lensflare3_alpha, lensflare0_alpha } from './examples/textures/lensflare/lensflare.js'; // import {CopyShader as SweepingLightShader} from "./examples/jsm/shaders/CopyShader.js"; // import './examples/js/postprocessing/EffectComposer.js' // require('./examples/js/postprocessing/EffectComposer.js') var ByteVThree = { Player: function Player(opt) { var _this = this; opt = opt || {}; var rendObj = { //使用logarithmicDepthBuffer缓冲以降低冲突的概率 logarithmicDepthBuffer: true, //增加下面两个属性,可以抗锯齿 antialias: true, //透明 alpha: true }; if (opt.alpha) { rendObj.alpha = true; } var renderer = new THREE.WebGLRenderer(rendObj); //需要阴影效果 renderer.shadowMap.enabled = true; // renderer.shadowMap.type = THREE.PCFSoftShadowMap; //阴影类型 // renderer.gammaInput = true; // renderer.gammaOutput = true; renderer.setPixelRatio(window.devicePixelRatio); renderer.outputEncoding = THREE.sRGBEncoding; var loader = new THREE.ObjectLoader(); var camera, scene; var controls = null; //add by damon var color = ['#0872EC', '#7DA5E3', '#2EA3CE', '#FDFDFD', '#4A8AEC', '#9A9B9D']; //当前皮肤的第一个颜色的rgba数组 例: [255,255,255,1] var firstColorRgbaArr = []; this.color = color; //各属性 var option = { camera: { position: { x: 0, y: 10, z: 10 } }, //三维文字配置项和样式 '3dText': { /*配置项*/ //字号大小,一般为大写字母的高度 size: 0.5, //文字的厚度 height: 0.2, //'normal', //值为'normal'或'bold',表示是否加粗 weight: 'lighter', //字体,默认是'helvetiker',需对应引用的字体文件 // font: helvetiker_bold,//'helvetiker', //值为'normal'或'italics',表示是否斜体 style: 'normal', //斜角厚度,与文字厚度的作用差不多 bevelThickness: 0.2, //倒角宽度 //值越小字的笔画越细 bevelSize: 0.1, //弧线分段数,使得文字的曲线更加光滑 curveSegments: 12, //布尔值,是否使用倒角,意为在边缘处斜切 是否开启斜角,默认为false。 bevelEnabled: true, //斜角分段数 bevelSegments: 5, /*以下为字体样式*/ //文字颜色 color: 0xFFFFFF, //0x1A3B70,//0xffe502, specular: 0x009900, shininess: 30, shading: THREE.FlatShading } }; this.option = option; //fbx加载器 this.FBXLoader = new FBXLoader(); //gltf加载器 this.GLTFLoader = new GLTFLoader(); // //DRACO加载器 // var dracoLoader = new DRACOLoader(); // var dracoLoader = new DRACOLoader().setDecoderPath( '../three.js/examples/js/libs/draco/' ); //json加载器 this.jsonLoader = loader; //纹理加载器 var textureLoader = new THREE.TextureLoader(); //需要被监听点击事件的数组 存储的都是mesh,对象实例 var clickObjects = []; //动画相关 var clockArr = []; var mixerArr = []; //是否更新动画 var animationIsUpdate = true; //damon 20210804 增加 读取并更新外部定义传入的函数事件 var animateEventObj = {}; this.animateEventObj = animateEventObj; //可以从在setAnimateObj中添加函数, 如果setAnimateObj有值, 则更读取其每个下标里面的方法 this.addAnimateEvent = function (name, fun) { if (name && fun) { animateEventObj[name] = fun; } }; this.removeAnimateEvent = function (name) { if (name) { delete animateEventObj[name]; } }; //相机看向的中心位置 var lookAt = { x: 0, y: 0, z: 0 }; if (opt.lookAt) { lookAt = opt.lookAt; } var vrButton = VRButton.createButton(renderer); var events = {}; this.element = opt.element; opt.element.appendChild(renderer.domElement); this.width = 500; this.height = 500; this.init = function () { _this.load(); }; this.load = function (json) { var project = json.project; if (project.vr !== undefined) renderer.xr.enabled = project.vr; if (project.shadows !== undefined) renderer.shadowMap.enabled = project.shadows; if (project.shadowType !== undefined) renderer.shadowMap.type = project.shadowType; if (project.toneMapping !== undefined) renderer.toneMapping = project.toneMapping; if (project.toneMappingExposure !== undefined) renderer.toneMappingExposure = project.toneMappingExposure; if (project.physicallyCorrectLights !== undefined) renderer.physicallyCorrectLights = project.physicallyCorrectLights; this.setScene(loader.parse(json.scene)); this.setCamera(loader.parse(json.camera)); //add by damon //调用自定义方法 鼠标相机控制器 //this.setControls(); //需要被监听点击事件的数组 存储的都是mesh,对象实例 this.clickObjects = clickObjects; events = { init: [], start: [], stop: [], keydown: [], keyup: [], mousedown: [], mouseup: [], mousemove: [], touchstart: [], touchend: [], touchmove: [], update: [] }; var scriptWrapParams = 'player,renderer,scene,camera'; var scriptWrapResultObj = {}; for (var eventKey in events) { scriptWrapParams += ',' + eventKey; scriptWrapResultObj[eventKey] = eventKey; } var scriptWrapResult = _JSON$stringify(scriptWrapResultObj).replace(/\"/g, ''); for (var uuid in json.scripts) { var object = scene.getObjectByProperty('uuid', uuid, true); if (object === undefined) { console.warn('ByteVThree.Player: Script without object.', uuid); continue; } var scripts = json.scripts[uuid]; for (var i = 0; i < scripts.length; i++) { var script = scripts[i]; var functions = new Function(scriptWrapParams, script.source + '\nreturn ' + scriptWrapResult + ';').bind(object)(this, renderer, scene, camera); for (var name in functions) { if (functions[name] === undefined) continue; if (events[name] === undefined) { console.warn('ByteVThree.Player: Event type not supported (', name, ')'); continue; } events[name].push(functions[name].bind(object)); } } } dispatch(events.init, arguments); }; /* * 获取当前相机位置x、y、z中绝对值的最大 * */ this.getCameraMaxAxis = function () { var x = _this.camera.position.x; var y = _this.camera.position.y; var z = _this.camera.position.z; var max = Math.max.apply(Math, [Math.abs(x), Math.abs(y), Math.abs(z)]); return max; }; /* * 开启坐标轴线辅助 * @param {Number} size 大小(默认相机位置中xyz最大绝对值的1倍) * */ this.setAxesHelper = function (size) { _this.clearAxesHelper(); var max = _this.getCameraMaxAxis(); size = size || max; // 坐标轴助手用于确定中心点 var axesHelper = new THREE.AxesHelper(size); axesHelper.name = 'axesHelper'; //通过position进行平移 axesHelper.position.set(lookAt.x, lookAt.y, lookAt.z); scene.add(axesHelper); // let group = scene.getObjectByName('axesHelperGroup') // if(!group){ // group = new THREE.Object3D() // group.name = "axesHelperGroup" // group.add(axesHelper) // scene.add(group) // } }; /* * 开启网格线辅助 * @param {Object} option 配置项 * { * //网格宽度(默认相机位置中xyz最大绝对值的10倍) * size: 75, * //等分数(默认相机位置中xyz最大绝对值的7倍) * divisions: 30, * //color1 中心线颜色 * color1: "0x2C2C2C" * //color2 网格线颜色 * color2: "0x2C2C2C" * } * */ this.setGridHelper = function () { var option = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; _this.clearGridHelper(); var max = _this.getCameraMaxAxis(); option = _Object$assign({ size: max * 10, divisions: max * 7, color1: "#444444", color2: "#888888" }, option); //网格辅助线 // size -- 网格宽度,默认为 10. // divisions -- 等分数,默认为 10. // colorCenterLine -- 中心线颜色,默认 0x444444 // colorGrid -- 网格线颜色,默认为 0x888888 var gridHelper = new THREE.GridHelper(option.size, option.divisions, option.color1, option.color2); gridHelper.name = 'gridHelper'; //通过position进行平移 gridHelper.position.set(lookAt.x, lookAt.y, lookAt.z); scene.add(gridHelper); }; this.clearAxesHelper = function () { scene.remove(scene.getObjectByName('axesHelper')); }; this.clearGridHelper = function () { scene.remove(scene.getObjectByName('gridHelper')); }; var that = this; this.setCamera = function (value) { camera = value; camera.aspect = this.width / this.height; camera.updateProjectionMatrix(); this.option.camera.position = JSON.parse(_JSON$stringify(camera.position)); }; this.getCamera = function () { return camera; }; this.setScene = function (value) { scene = value; }; this.getScene = function () { return scene; }; this.getRenderer = function () { return renderer; }; this.getChildByUUID = function (uuid) { var _iterator = _createForOfIteratorHelper(scene.children), _step; try { for (_iterator.s(); !(_step = _iterator.n()).done;) { var v = _step.value; if (uuid == v.uuid) { return v; } } } catch (err) { _iterator.e(err); } finally { _iterator.f(); } return null; }; // 根据名字获取子项 this.getObjectByName = function (name) { return null; }; //获取所有模型对象 以模型name作为key的对象 this.getAllChildrenByName = function () { var obj = {}; function fun(children) { if (children) { for (var i = 0; i < children.length; i++) { obj[children[i].name] = children[i]; if (children[i].children.length) { fun(children[i].children); } } } } fun(scene.children); this.allChildrenNameObj = obj; return obj; }; //获取所有模型对象 以模型uuid作为key的对象 this.getAllChildrenByUUID = function () { var obj = {}; function fun(children) { if (children) { for (var i = 0; i < children.length; i++) { obj[children[i].uuid] = children[i]; if (children[i].children.length) { fun(children[i].children); } } } } fun(scene.children); this.allChildrenUUIDObj = obj; return obj; }; /* * 相机场景恢复初始位置 * @param {Object} posObj 包含 x y z 位置的对象() * 可不传参数,不穿恢复默认option中储存的位置,传了即按照传入的位置,并且更新默认位置为新传入的值 * */ this.resetCamera = function () { var posObj = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this.option.camera.position; this.camera.position.set(posObj.x, posObj.y, posObj.z); }; this.resetCameraAndScene = function () {}; //自定义方法 鼠标控制 this.setControls = function () { var option = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; option = _Object$assign({ //是否可以缩放 enableZoom: true, //是否自动旋转 autoRotate: false, //自传速度 autoRotateSpeed: 2.5, //是否开启右键拖拽 相机平移, enablePan: false, //能否使用键盘控制.默认true enableKeys: false, //可以上下翻转的最大角度 1可以180度 0.5可以90度 maxPolarAngle: Math.PI * 1, //设置相机距离原点的最近距离 minDistance: 0, //设置相机距离原点的最远距离 maxDistance: 100 }, option); controls = new OrbitControls(camera, renderer.domElement); //controls.target.set( 0, 0, 0 ); //controls.target.set( 1.486, 0.721, 0.217 ); controls.target.set(lookAt.x, lookAt.y, lookAt.z); controls.update(); // controls.target.set( defaultCamera.position.x, defaultCamera.position.y, defaultCamera.position.z ); // 使动画循环使用时阻尼或自转 意思是否有惯性 //controls.enableDamping = true; //是否可以缩放 controls.enableZoom = option.enableZoom; //true; //是否自动旋转 controls.autoRotate = option.autoRotate; //false; //自传速度 controls.autoRotateSpeed = option.autoRotateSpeed; //是否开启右键拖拽 相机平移, controls.enablePan = option.enablePan; //false; //能否使用键盘控制.默认true controls.enableKeys = option.enableKeys; //false; //Boolean 平移时摄像机位置的转换。true,相机的平移在屏幕空间; //false,摄像机在与摄像机向上方向正交的平面上平移,默认false //controls.screenSpacePaning = true;//false;// // 1可以180度 0.5可以90度 controls.maxPolarAngle = option.maxPolarAngle; //设置相机距离原点的最近距离 controls.minDistance = option.minDistance; //设置相机距离原点的最远距离 controls.maxDistance = option.maxDistance; //10; _this.controls = controls; }; this.getControls = function () { return controls; }; this.setSize = function (width, height) { this.width = width; this.height = height; if (camera) { camera.aspect = this.width / this.height; camera.updateProjectionMatrix(); } if (renderer) { renderer.setSize(width, height); } }; //删除group并释放内存 this.deleteGroup = function (group) { var _group$traverse; if (!group) return; // 递归遍历组对象group释放所有后代网格模型绑定几何体占用内存 group === null || group === void 0 ? void 0 : (_group$traverse = group.traverse) === null || _group$traverse === void 0 ? void 0 : _group$traverse.call(group, function (obj) { if (obj.type === 'Mesh') { var _obj$geometry, _obj$geometry$dispose, _obj$material, _obj$material$dispose; obj === null || obj === void 0 ? void 0 : (_obj$geometry = obj.geometry) === null || _obj$geometry === void 0 ? void 0 : (_obj$geometry$dispose = _obj$geometry.dispose) === null || _obj$geometry$dispose === void 0 ? void 0 : _obj$geometry$dispose.call(_obj$geometry); obj === null || obj === void 0 ? void 0 : (_obj$material = obj.material) === null || _obj$material === void 0 ? void 0 : (_obj$material$dispose = _obj$material.dispose) === null || _obj$material$dispose === void 0 ? void 0 : _obj$material$dispose.call(_obj$material); } }); for (var i = group.children.length - 1; i >= 0; i--) { if (group.children[i] instanceof THREE.Group) { scene.remove(group.children[i]); } } // 删除场景对象scene的子对象group scene.remove(group); }; /* * 创建带光晕的太阳 光源 * */ this.setSunHaloLight = function () { var max = _this.getCameraMaxAxis(); //和天空球的半径同样计算 max*100 //默认0点位置 var position = { x: max * 0, y: max * -100, z: 0 }; var group = scene.getObjectByName('theSunHaloLightGroup'); if (!group) { group = new THREE.Object3D(); group.name = "theSunHaloLightGroup"; group.position.set(0, 0, 0); scene.add(group); } var intensity = max * .1; //0.5 var dirLight = new THREE.DirectionalLight(0xffffff, intensity); dirLight.name = 'theSun'; // dirLight.position.set(position.x, position.y, position.z).normalize(); dirLight.position.set(position.x, position.y, position.z); // dirLight.color.setHSL( 0.1, 0.7, 0.5 ); group.add(dirLight); var textureFlare0 = textureLoader.load(lensflare0_alpha); var textureFlare3 = textureLoader.load(lensflare3_alpha); addLight('#E9CB9B', position); //允许产生阴影 _this.openCastShadow(group); //默认设置9点 _this.moveSunByTime(9); function addLight(color, pos) { var s = 0.2; var size = max * 5; var light = new THREE.PointLight(color, 5, 2000); light.color.set(color); light.name = 'theSunHaloLight'; light.position.set(pos.x, pos.y, pos.z); group.add(light); var lensflare = new Lensflare(); lensflare.position.set(pos.x, pos.y, pos.z); // lensflare.position.set(0, 0, 0) lensflare.addElement(new LensflareElement(textureFlare0, size, 0, light.color)); lensflare.addElement(new LensflareElement(textureFlare3, size * .08, 0.1)); lensflare.addElement(new LensflareElement(textureFlare3, size * .1, 0.2)); lensflare.addElement(new LensflareElement(textureFlare3, size * .18, 0.3)); lensflare.addElement(new LensflareElement(textureFlare3, size * .1, 0.4)); lensflare.addElement(new LensflareElement(textureFlare3, size * .08, 0.5)); lensflare.addElement(new LensflareElement(textureFlare3, size * .1, 0.6)); lensflare.addElement(new LensflareElement(textureFlare3, size * .18, 0.7)); lensflare.addElement(new LensflareElement(textureFlare3, size * .1, 0.8)); light.add(lensflare); } }; //光线强度度逐渐变大 this.lightFadeUp = function (LightObj, msec, callBack) { if (!LightObj) { return false; } //LightObj.intensity = 0; //console.log('moveObj-toPos : ',toPos) var from = { x: 0, y: 0, z: 0 }; var toPos = { x: 10, y: 10, z: 10 }; // 设置动画 var tween = new TWEEN.Tween(from).to(toPos, msec); tween.easing(TWEEN.Easing.Sinusoidal.InOut); tween.onUpdate(function () { if (LightObj.intensity <= 1) { LightObj.intensity += 0.01; } }); // 开启动画 tween.start(); if (callBack) { // 动画执行完毕后回调 tween.onComplete(function () { callBack(); }); } }; /* * 光源强度度逐渐改变 * LightObj 光源对象, * toIntensity 要变成的强度, * msec 时长, * callBack 回调 * */ this.lightGradualChange = function (LightObj, toIntensity, msec, callBack) {}; /* * 材质透明度渐变 * materialObj 材质对象, * toOpacity 要变成的透明度, * msec 时长, * callBack 回调 * */ this.materialGradualChange = function (materialObj, toOpacity) { var msec = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 1000; var callBack = arguments.length > 3 ? arguments[3] : undefined; if (!materialObj || !toOpacity) { return false; } //controls.autoRotate = false; var from = { opacity: materialObj.opacity }; toOpacity = { opacity: toOpacity }; // 设置动画 var tween = new TWEEN.Tween(from).to(toOpacity, msec); tween.easing(TWEEN.Easing.Sinusoidal.InOut); tween.onUpdate(function () { materialObj.opacity = this['_object'].opacity; }); // 开启动画 tween.start(); if (callBack) { // 动画执行完毕后回调 tween.onComplete(function () { callBack(); }); } }; //调整物体角度的方法(目前适用于聚光灯) this.moveAngle = function (obj, toAngle, msec, callBack) { if (!obj || !toAngle) { return false; } //controls.autoRotate = false; var from = { angle: obj.angle }; toAngle = { angle: toAngle }; // 设置动画 var tween = new TWEEN.Tween(from).to(toAngle, msec); tween.easing(TWEEN.Easing.Sinusoidal.InOut); tween.onUpdate(function () { obj.angle = this['_object'].angle; }); // 开启动画 tween.start(); if (callBack) { // 动画执行完毕后回调 tween.onComplete(function () { callBack(); }); } }; this.moveObj = function (obj, toPos, msec, callBack) { if (!obj) { return false; } //console.log('moveObj-toPos : ',toPos) controls.autoRotate = false; var from = obj.position; // 设置动画 var tween = new TWEEN.Tween(from).to(toPos, msec); tween.easing(TWEEN.Easing.Sinusoidal.InOut); tween.onUpdate(function () { obj.position.set(this['_object'].x, this['_object'].y, this['_object'].z); //camera.lookAt(this['_object'].x,this['_object'].y,this['_object'].z) }); // 开启动画 tween.start(); if (callBack) { // 动画执行完毕后回调 tween.onComplete(function () { callBack(); }); } }; this.moveCamera = function (cam, toPos, msec, callBack) { if (!toPos) { return false; } //console.log('moveCamera-toPos : ',toPos) controls.autoRotate = false; var from = cam.position; // 设置动画 var tween = new TWEEN.Tween(from).to(toPos, msec); tween.easing(TWEEN.Easing.Sinusoidal.InOut); tween.onUpdate(function () { cam.position.set(this['_object'].x, this['_object'].y, this['_object'].z); cam.lookAt(lookAt.x, lookAt.y, lookAt.z); }); // 开启动画 tween.start(); if (callBack) { // 动画执行完毕后回调 tween.onComplete(function () { callBack(); }); } }; this.lookAtMove = function (cam, toPos, msec, callBack) { if (!toPos) { return false; } controls.autoRotate = false; var from = cam.position; // 设置动画 var tween = new TWEEN.Tween(from).to(toPos, msec); tween.easing(TWEEN.Easing.Sinusoidal.InOut); tween.onUpdate(function () { cam.lookAt(this['_object'].x, this['_object'].y, this['_object'].z); }); // 开启动画 tween.start(); if (callBack) { // 动画执行完毕后回调 tween.onComplete(function () { callBack(); }); } }; /* * 物体沿坐标轴旋转的方法 * @param {Object} obj - 物体对象, * @param {String} axis - 旋转的坐标轴 x y z * @param {Number} angle - 旋转的角度 * @param {Number} speed - 速度 * @param {function} callBack - 回调 * @param {function} onUpdateFun - 执行中每次的调用方法 * */ this.rotationObj = function (obj, axis, angle) { var _obj$rotation, _this2 = this; var speed = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 0.003; var callBack = arguments.length > 4 ? arguments[4] : undefined; var onUpdateFun = arguments.length > 5 ? arguments[5] : undefined; console.log(angle); if (!obj || !obj.rotation || !axis || !angle) { callBack === null || callBack === void 0 ? void 0 : callBack(); return false; } speed = Math.abs(speed); var current = (obj === null || obj === void 0 ? void 0 : (_obj$rotation = obj.rotation) === null || _obj$rotation === void 0 ? void 0 : _obj$rotation[axis]) || 0; if (current == angle) { callBack === null || callBack === void 0 ? void 0 : callBack(); return; } if (current > angle) { speed = 0 - speed; } this.addAnimateEvent('rotation' + axis + '_' + obj.uuid, function () { if (speed > 0 && obj.rotation[axis] >= angle || speed < 0 && obj.rotation[axis] <= angle) { _this2.removeAnimateEvent('rotation' + axis + '_' + obj.uuid); callBack === null || callBack === void 0 ? void 0 : callBack(); return; } obj.rotation[axis] += speed; onUpdateFun === null || onUpdateFun === void 0 ? void 0 : onUpdateFun(obj.rotation[axis]); }); }; //物体放大缩小的方法 this.scaleObj = function (obj, toScale, msec, callBack) { console.log(789789, obj, toScale, msec, callBack); if (!obj || !toScale) { return false; } //controls.autoRotate = false; var from = { scale: obj.scale }; toScale = { scale: toScale }; // 设置动画 var tween = new TWEEN.Tween(from).to(toScale, msec); tween.easing(TWEEN.Easing.Sinusoidal.InOut); tween.onUpdate(function () { //obj.scale = this['_object'].scale; obj.scale.x = this['_object'].scale.x; obj.scale.y = this['_object'].scale.y; obj.scale.z = this['_object'].scale.z; }); // 开启动画 tween.start(); // 动画执行完毕后回调 tween.onComplete(function () { callBack === null || callBack === void 0 ? void 0 : callBack(); }); }; /* * 暂时未用到 * 对模型参照x、y、z三个轴的角度旋转进行设置 * 需要通过矩阵进行变换 * //调用方式,设置x、y、z轴的旋转 * let xAxis = new THREE.Vector3(1, 0, 0); * let yAxis = new THREE.Vector3(0, 1, 0); * let zAxis = new THREE.Vector3(0, 0, 1); * //模型、旋转轴和旋转角度(弧度) * rotateAroundWorldAxis(model, xAxis, Math.PI / 8); * */ this.rotateAroundWorldAxis = function (object, axis, radians) { var rotWorldMatrix = new THREE.Matrix4(); rotWorldMatrix.makeRotationAxis(axis.normalize(), radians); rotWorldMatrix.multiply(object.matrix); object.matrix = rotWorldMatrix; object.rotation.setFromRotationMatrix(object.matrix); }; // /* // * 为指定gourp组添加贴图纹理 // * @param {Object} group 需要操作的group组对象 // * @param {String} image 需要操作的group组对象 // *可以通过 'image://url' 设置为图片,其中 URL 为图片的链接,或者 dataURI。 // * URL 为图片链接例如: 'image://http://xxx.xxx.xxx/a/b.png' // * URL 为 dataURI 例如: 'image://data:image/gif;base64,R0lGODlhEAAQAMQAAORHHOVSKudfOulrSOp3WOyDZu6QdvCchPGolfO0o/XBs/fNwfjZ0frl3/zy7////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAkAABAALAAAAAAQABAAAAVVICSOZGlCQAosJ6mu7fiyZeKqNKToQGDsM8hBADgUXoGAiqhSvp5QAnQKGIgUhwFUYLCVDFCrKUE1lBavAViFIDlTImbKC5Gm2hB0SlBCBMQiB0UjIQA7' // * */ // this.setGroupImageTexture = function (group, image){ // if(!group || !image) return // // // function x(arr){ // // } // } /* * 创建3d文字 * @param {String} textContent 文字内容 * @param {Object} opt 配置项 * */ // this.font = helvetiker_bold this.set3dText = function (textContent) { var opt = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; debugger; if (!textContent) return false; var textOpt = { name: '', position: { x: 0, y: 0, z: 0 }, rotation: { x: 0, y: 0, z: 0 }, textStyle: JSON.parse(_JSON$stringify(this.option['3dText'])) }; assign(textOpt, opt); function assign(a, b) { for (var k in b) { if (a[k] instanceof Object) { assign(a[k], b[k]); } else { _Object$assign(a, b); } } } var group = scene.getObjectByName("3dTextGroup"); if (!group) { group = new THREE.Object3D(); group.name = "3dTextGroup"; scene.add(group); } // var loader = new THREE.FontLoader(); var geometry; // loader.load( './font/Microsoft YaHei_Regular.json', // //加载好字体后创建三维文字 // function(font) { // option.text.font = font; // option.text.font = helvetiker_bold; geometry = new THREE.TextGeometry(textContent, textOpt.textStyle); //创建法向量材质 // var meshMaterial = new THREE.MeshNormalMaterial({ // flatShading: THREE.FlatShading, // transparent: true, // opacity: 0.9 // }); var meshMaterial = new THREE.MeshPhongMaterial({ color: textOpt.textStyle.color, specular: textOpt.textStyle.specular, shininess: textOpt.textStyle.shininess, shading: textOpt.textStyle.shading }); var mesh = new THREE.Mesh(geometry, meshMaterial); mesh.position.set(textOpt.position.x, textOpt.position.y, textOpt.position.z); mesh.rotation.set(textOpt.rotation.x, textOpt.rotation.y, textOpt.rotation.z); mesh.name = 'text_' + (textOpt.name || textContent); group.add(mesh); // }, // //加载进度 // function(xhr) { // //console.log( (xhr.loaded / xhr.total * 100) + '% loaded' ); // }, // //出现错误 // function(err) { // console.log(err); // } // ); }; /* * 设置东西南北 * @param {Object} option 配置项 * @param {group} reference 参照物group(东西南北基于谁放置,如地图的东南西北,参照物即为该地图),没有的话默认取相机位置中xyz最大绝对值的1倍 * */ this.EWSNMesh = loader.parse(EWSN); this.setEWSN = function (option, reference) { var _option, _option$scale, _option2, _option2$scale, _option3, _option3$scale; // reference = reference || scene.getObjectByName('axesHelperGroup') var arr = ['E', 'W', 'S', 'N']; var group = scene.getObjectByName('EWSN_Group'); _this.deleteGroup(group); group = _this.EWSNMesh; group.name = "EWSN_Group"; scene.add(group); option = _Object$assign({ /* * 中英文 * false/'中'/'ch'/'cn' -中文, * true/'英'/'zh'/'zn' - 英文 * 默认中文 * */ lan: 'cn', // //缩放 // scale: { x: 1, y: 1, z: 1 }, //位置 position: { x: 0, y: 0, z: 0 } }, option || {}); _this.setGroupPositionByCamera(group); group.scale.set(((_option = option) === null || _option === void 0 ? void 0 : (_option$scale = _option.scale) === null || _option$scale === void 0 ? void 0 : _option$scale.x) || group.scale.x * 0.05, ((_option2 = option) === null || _option2 === void 0 ? void 0 : (_option2$scale = _option2.scale) === null || _option2$scale === void 0 ? void 0 : _option2$scale.y) || group.scale.y * 0.05, ((_option3 = option) === null || _option3 === void 0 ? void 0 : (_option3$scale = _option3.scale) === null || _option3$scale === void 0 ? void 0 : _option3$scale.z) || group.scale.z * 0.05); group.position.set(option.position.x, option.position.y, option.position.z); var bbox = null; if (reference && (reference.type == "Group" || reference.type == "Object3D")) { bbox = new THREE.Box3().setFromObject(reference); // //边界的最小坐标值 边界的最大坐标值 // bbox.max.x - bbox.min.x; } else { var max = _this.getCameraMaxAxis() * 0.5; bbox = { max: { x: max, y: max, z: max * .85 }, min: { x: -max, y: -max, z: -max } }; } group.children.forEach(function (itm, idx) { itm.visible = false; }); group.children.forEach(function (itm, idx) { // itm.rotation.x = Math.PI * -.25 switch (itm.name) { case 'E': case '东': itm.position.x = bbox.max.x * 1.5 / group.scale.x; break; case 'W': case '西': itm.position.x = bbox.min.x * 1.5 / group.scale.x; break; case 'S': case '南': itm.position.z = bbox.max.z * 1.25 / group.scale.z; break; case 'N': case '北': itm.position.z = bbox.min.z * 1.25 / group.scale.z; break; } var lan = option.lan; //中文东西南北 if (arr.indexOf(itm.name) == -1 && (lan == '中' || lan == 'ch' || lan == 'cn' || !lan)) { itm.visible = true; } //英文东西南北 if (arr.indexOf(itm.name) != -1 && (lan == '英' || lan == 'zh' || lan == 'zn' || lan == 1 || lan === true)) { itm.visible = true; } }); }; /* * 根据相机动态设置物体group的position和scale * * @param {Object} group 需要设置的group组 * * 因为模型是不规则的,为了更好的计算模型的大小,我们引入了Box3。 * 使用THREE.Box3().setFromObject(group)计算gruop的包围盒的大小,并放group在原点位置。 * 然后根据公式计算得到3d模型对应的画布上group的大小(2D宽度和高度)。 * */ this.setGroupPositionByCamera = function (group) { var bbox = new THREE.Box3().setFromObject(group); var mdlen = bbox.max.x - bbox.min.x; //边界的最小坐标值 边界的最大坐标值 var mdhei = bbox.max.y - bbox.min.y; var mdwid = bbox.max.z - bbox.min.z; // 计算相机到物体正面的距离。 var dist = Math.abs(_this.camera.position.z - group.position.z - mdwid / 2); // 将垂直fov转换为弧度 。 var vFov = _this.camera.fov * Math.PI / 180; // 可见高度。 var vheight = 2 * Math.tan(vFov * 0.5) * dist; // 可见高度的分数。 var fraction = mdhei / vheight; // 立方体的高度(以像素为单位)是画布的高度(以像素为单位)的fraction倍。 var finalHeight = _this.element.offsetHeight * fraction; // 包围盒计算的高/finalHeight = 包围盒计算的宽/finalWidth 。 var finalWidth = finalHeight * mdlen / mdhei; //通过该2D宽度和高度分别与设置的渲染区域的宽和高相比得到两个不同的缩放比例value1和value1。选取两者较小的值,设置为group的缩放比例。 var value1 = _this.element.offsetWidth / finalWidth; // console.log('value1缩放比例值为:' + value1); var value2 = _this.element.offsetHeight / finalHeight; // console.log('value2缩放比例值为:' + value2); if (value1 >= value2) { group.scale.set(value2, value2, value2); } else { group.scale.set(value1, value1, value1); } //再一次使用使用THREE.Box3().setFromObject(group)计算gruop的包围盒的大小(这个是缩放后的group), // 并重新设置position属性。注意:在z轴上设置group位置时不要忘记减去包围盒深度的1/2。 var bbox2 = new THREE.Box3().setFromObject(group); var mdlen2 = bbox2.max.x - bbox2.min.x; var mdhei2 = bbox2.max.y - bbox2.min.y; var mdwid2 = bbox2.max.z - bbox2.min.z; group.position.set(-(bbox2.max.x + bbox2.min.x) / 2, -(bbox2.max.y + bbox2.min.y) / 2, -(bbox2.max.z + bbox2.min.z) / 2 - (bbox2.max.z - bbox2.min.z) / 2); //最后将group添加到scene中。 // 同时引入了AxisHelper来帮助显示坐标轴,以及OrbitControls轨道控制器来控制模型的平移、旋转和缩放效果。 // let axes = new THREE.AxisHelper(100); // this.scene.add(axes); // let controls = new OrbitControls(this.camera, this.renderer.domElement); }; /* * 模型加载完成后,根据option对模型调整 * */ this.onLoadConvertByOption = function (object, option, callBack) { if (!object) { return; } var parent = scene; if (option) { var _option$scale2, _option$scale3, _option$scale4, _option$position, _option$position2, _option$position3, _option$rotation, _option$rotation2, _option$rotation3; parent = (option === null || option === void 0 ? void 0 : option.parent) || scene; //将模型缩放 object.scale.x = (option === null || option === void 0 ? void 0 : (_option$scale2 = option.scale) === null || _option$scale2 === void 0 ? void 0 : _option$scale2.x) || 1; object.scale.y = (option === null || option === void 0 ? void 0 : (_option$scale3 = option.scale) === null || _option$scale3 === void 0 ? void 0 : _option$scale3.y) || 1; object.scale.z = (option === null || option === void 0 ? void 0 : (_option$scale4 = option.scale) === null || _option$scale4 === void 0 ? void 0 : _option$scale4.z) || 1; //移动模型位置 object.position.x = (option === null || option === void 0 ? void 0 : (_option$position = option.position) === null || _option$position === void 0 ? void 0 : _option$position.x) || 0; object.position.y = (option === null || option === void 0 ? void 0 : (_option$position2 = option.position) === null || _option$position2 === void 0 ? void 0 : _option$position2.y) || 0; object.position.z = (option === null || option === void 0 ? void 0 : (_option$position3 = option.position) === null || _option$position3 === void 0 ? void 0 : _option$position3.z) || 0; //移动模型位置 object.rotation.x = (option === null || option === void 0 ? void 0 : (_option$rotation = option.rotation) === null || _option$rotation === void 0 ? void 0 : _option$rotation.x) || 0; object.rotation.y = (option === null || option === void 0 ? void 0 : (_option$rotation2 = option.rotation) === null || _option$rotation2 === void 0 ? void 0 : _option$rotation2.y) || 0; object.rotation.z = (option === null || option === void 0 ? void 0 : (_option$rotation3 = option.rotation) === null || _option$rotation3 === void 0 ? void 0 : _option$rotation3.z) || 0; //name object.name = option === null || option === void 0 ? void 0 : option.name; } parent.add(object); //如果没有传option或是option中没有缩放和位置属性,则把模型调整为自适应大小和位置 if (!option || !option.hasOwnProperty('scale') && !option.hasOwnProperty('position')) { that.setGroupPositionByCamera(object); } //允许阴影投射 _this.openCastShadow(parent); //允许接收阴影 _this.openReceiveShadow(parent); //如果有动画 if (object.animations && object.animations.length) { var mixer = new THREE.AnimationMixer(object); //console.log('mixer',mixer) var action = mixer.clipAction(object.animations[0]); //console.log('action',action) mixerArr.push(mixer); clockArr.push(new THREE.Clock()); action.play(); } //回调,把加载出的模型object传回去 callBack === null || callBack === void 0 ? void 0 : callBack(object); }; /* * 加载进度的提示 * */ this.onprogressTooltip = function (event) { //这是加载进度 var div = document.querySelector('.total' + event.total); if (!div) { div = document.createElement('div'); div.className = 'total' + event.total; _this.element.append(div); } div.style.cssText = "\n\t\t\t\tfont-size: 20px;\n\t\t\t\tcolor: rgb(255 255 255);\n\t\t\t\tz-index: 99;\n\t\t\t\tposition: absolute;\n\t\t\t\tleft: 0;\n\t\t\t\tright: 0;\n\t\t\t\ttop: 0;\n\t\t\t\tbottom: 0;\n\t\t\t\twidth: min-content;\n\t\t\t\theight: min-content;\n\t\t\t\tmargin: auto;\n\t\t\t\tpointer-events:none;\n\t\t\t"; var n = (event.loaded / event.total * 100).toFixed(2); if (n >= 100) { setTimeout(function () { div.remove(); }, 250); } else { div.innerHTML = n + '%'; console.log((event.loaded / event.total * 100).toFixed(2) + '%'); } }; /* * 加载fbx模型的方法 * path: 模型路劲 * { * scale:{x,y,x}, * position:{x,y,x}, * name: '', * parent: '', * } * callBack: '', 回调,传回去加载好的模型 **/ this.loadFBX = function (path, option, callBack) { if (typeof option === 'function') { callBack = option; option = null; } _this.FBXLoader.load(path, function (object) { _this.onLoadConvertByOption(object, option, callBack); }, function (progressEvent) { _this.onprogressTooltip(progressEvent); }, function (errorEvent) { console.error('error:', errorEvent); }); }; /* * 加载json模型的方法 * path: 模型路劲 **/ this.loadJSON = function (path, option, callBack) { _this.jsonLoader.load(path, function (object) { _this.onLoadConvertByOption(object, option, callBack); }, function (progressEvent) { _this.onprogressTooltip(progressEvent); }, function (errorEvent) { console.error('error:', errorEvent); }); }; /* * 加载GLTF模型的方法 * path: 模型路劲 **/ /*this.loadGLTF = (path, option, callBack)=>{ // use of RoughnessMipmapper is optional var roughnessMipmapper = new RoughnessMipmapper( renderer ); this.GLTFLoader.setPath(path); this.GLTFLoader.load( 'DamagedHelmet.gltf', function ( gltf ) { gltf.scene.traverse( function ( child ) { if ( child.isMesh ) { // TOFIX RoughnessMipmapper seems to be broken with WebGL 2.0 // roughnessMipmapper.generateMipmaps( child.material ); } } ); scene.add( gltf.scene ); roughnessMipmapper.dispose(); render(); } ); }*/ /* * 加载GLTF模型的方法 * path: 模型路劲 **/ /*this.loadGLB = (path, option, callBack)=>{ this.loadGLTF(path, option, callBack) }*/ /* * 创建天空球的方法 * @param {Object} option 配置项,属性及默认值: * { name: "", img: "night"-夜晚/"day"-白天/自定义上传base64图片格式, //球体半径 radius: 500, //水平方向上的分段数 widthSegments: 40, //垂直方向上的分段数 heightSegments: 40, //透明度 opacity: 1, * } * */ this.setSkyBall = function () { var option = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; this.clearSkyBall(); var max = this.getCameraMaxAxis(); option = _Object$assign({ name: "", img: day, //"", //球体半径 radius: max * 100, //水平方向上的分段数 widthSegments: max * 10, //垂直方向上的分段数 heightSegments: max * 10, //透明度 opacity: 1 }, option || {}); if (option.img == 'night' || !option.img) { option.img = night; } else if (option.img == 'day') { option.img = day; } var group = scene.getObjectByName("skyBallGroup"); this.deleteGroup(group); if (!group) { group = new THREE.Object3D(); group.name = "skyBallGroup"; scene.add(group); } //创建全景场景 天空球 //3个参数分别代表:球体半径,水平方向和垂直方向上分段数。widthSegments最小值为3,默认值为8。heightSegments最小值为2,默认值为6。 //纬度上的切片数, 经度开始的弧度//,经度划分成30份,纬度划分成30份的球体。 var geometry = new THREE.SphereGeometry(option.radius, option.widthSegments, option.heightSegments); geometry.scale(-1, 1, 1); //变成球体,画面向内 //天空球 var tkq = new THREE.MeshBasicMaterial({ map: textureLoader.load(option.img), side: THREE.DoubleSide, transparent: true, //开启透明 opacity: option.opacity //透明度 }); var tkqMesh = new THREE.Mesh(geometry, tkq); //tkqMesh.rotation.x = -3;//贴图旋转 group.add(tkqMesh); }; /* * 清除天空球 * */ this.clearSkyBall = function () { _this.removeAnimateEvent('skyBallGroup'); _this.deleteGroup(scene.getObjectByName('skyBallGroup')); }; /* * 创建地面的方法 * * @param {Object} option 配置项 * { * name: "", * img: "", * //宽 * width: 100, * //高 * height: 100, * //透明度 * opacity: 1 * } * */ this.setFloor = function () { var option = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; var max = this.getCameraMaxAxis(); option = _Object$assign({ name: "", img: "", //宽 width: max * 10, //高 height: max * 10, //透明度 opacity: 1 }, option || {}); if (!option.img) { option.img = honeycomb; } if (!this.honeycombTexture && option.img != 'none') { this.honeycombTexture = textureLoader.load(option.img); //定义纹理在水平和垂直方向简单的重复到无穷大。 this.honeycombTexture.wrapS = THREE.RepeatWrapping; this.honeycombTexture.wrapT = THREE.RepeatWrapping; } //重复平铺个数 this.honeycombTexture.repeat.set(option.width, option.height); var group = scene.getObjectByName("floorGroup"); this.deleteGroup(group); group = new THREE.Object3D(); group.name = "floorGroup"; scene.add(group); //圆环地面 //THREE.CircleGeometry(半径, 切片数, 纬度开始的弧度, 纬度跨过的弧度); //THREE.CircleGeometry(radius, segments, thetaStart, thetaLength); //正方形 var geometry = new THREE.PlaneGeometry(option.width, option.height); // let material = new THREE.MeshBasicMaterial({ var material = new THREE.MeshStandardMaterial({ color: this.color[0], map: this.honeycombTexture, //光照贴图 lightMap: this.honeycombTexture, //凹凸贴图 bumpMap: this.honeycombTexture, side: THREE.DoubleSide, transparent: true, //开启透明 opacity: option.opacity //透明度 }); var floorHoneycomb = new THREE.Mesh(geometry, material); var color = "rgb(".concat(_parseInt(this.firstColorRgbaArr[0] * .10), ",").concat(_parseInt(this.firstColorRgbaArr[1] * .10), ",").concat(_parseInt(this.firstColorRgbaArr[2] * .10), ")"); var floor = new THREE.Mesh(geometry, new THREE.MeshStandardMaterial({ side: THREE.DoubleSide, color: color })); //设置旋转和位置 floor.rotation.x = floorHoneycomb.rotation.x = -0.5 * Math.PI; floor.position.set(0, -0.01, 0); floorHoneycomb.position.set(0, 0, 0); //允许接收阴影 this.openReceiveShadow(group); group.add(floor, floorHoneycomb); return group; }; // this.setFloor = (option={})=>{ // // } /* * 使用聚光灯能模拟扫描 * */ this.spotLightSweep = function () { var _this$color, _this$color2; var group = scene.getObjectByName('spotLightSweepGroup'); _this.clearSpotLightSweep(); if (!group) { group = new THREE.Object3D(); group.name = "spotLightSweepGroup"; // group.visible = false scene.add(group); } var spotLight1 = new THREE.SpotLight('#FF0000' || ((_this$color = _this.color) === null || _this$color === void 0 ? void 0 : _this$color[0]) || 0x0c0c0c); // 创建聚光灯 var spotLight2 = new THREE.SpotLight('#FFFFFF' || ((_this$color2 = _this.color) === null || _this$color2 === void 0 ? void 0 : _this$color2[1]) || 0x0c0c0c); // 创建聚光灯 spotLight1.position.set(0, 20, 0); spotLight2.position.set(0, 20, 0); //距离 // spotLight1.distance = 30 // spotLight2.distance = 30 // 聚光灯强度 spotLight1.intensity = 10; spotLight2.intensity = 10; // 聚光灯的角度设置为Math.PI/3 var sl1a = Math.PI * 0.002; var sl2a = Math.PI * 0.001; spotLight1.angle = sl1a; spotLight2.angle = sl2a; group.add(spotLight1, spotLight2); _this.addAnimateEvent('spotLightSweeping', function () { spotLight1.angle += 0.001; spotLight2.angle += 0.001; if (spotLight1.angle >= Math.PI * 0.4) { spotLight1.angle = sl1a; } if (spotLight1.angle >= Math.PI * 0.3) { spotLight2.angle = sl2a; } }); }; this.clearSpotLightSweep = function () { _this.removeAnimateEvent('spotLightSweeping'); _this.deleteGroup(scene.getObjectByName('spotLightSweepGroup')); }; /* * 地面扩散 * */ this.setFloorEffcet = function (option) { var max = _this.getCameraMaxAxis(); option = _Object$assign({ name: "", img: "", //宽 width: max * 1.1, //高 height: max * 1.1, //扩散速度 speed: 0.02, //透明度 opacity: 0.75, //颜色 - 默认取皮肤第一个 color: '' }, option || {}); if (!option.img) { option.img = floorEffect; } if (!_this.floorEffectTexture) { _this.floorEffectTexture = textureLoader.load(option.img); } var group = scene.getObjectByName('floorEffectGroup'); _this.clearFloorEffect();