PageSourceSearch

https://lib.3dnest.cn/release/qspace-plugin/compass3d/1.3.0/umd/Compass3D.js

js 3dnest.cn collected 2026-10-04 19:40:23 UTC 36,733 bytes, 1,234 lines download raw bytes

1(function (global, factory) {
2	typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
3	typeof define === 'function' && define.amd ? define(factory) :
4	(global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.Compass3D = factory());
5}(this, (function () { 'use strict';
6
7	function createCommonjsModule(fn, basedir, module) {
8		return module = {
9		  path: basedir,
10		  exports: {},
11		  require: function (path, base) {
12	      return commonjsRequire(path, (base === undefined || base === null) ? module.path : base);
13	    }
14		}, fn(module, module.exports), module.exports;
15	}
16
17	function commonjsRequire () {
18		throw new Error('Dynamic requires are not currently supported by @rollup/plugin-commonjs');
19	}
20
21	var base = createCommonjsModule(function (module) {
22	/*
23	 * THREE r184 公共 shim — space-sdk-plugin CDN 插件共享
24	 * [r184 compat] ES5 语法,兼容 buble 打包链
25	 */
26	/* eslint-env browser */
27	/* global zqcore */
28
29	var LOG_PREFIX = '[three-shim-r184]';
30
31	var THREE = (typeof window !== 'undefined' && window.THREE) ? window.THREE : null;
32
33	if (!THREE && typeof qspace !== 'undefined' && qspace.THREE) {
34	  THREE = qspace.THREE;
35	}
36
37	if (!THREE) {
38	  console.error(LOG_PREFIX + ' THREE is not available! Load THREE.js before the plugin.');
39	  THREE = {};
40	}
41
42	if (THREE && !THREE.__r184ShimInitialized) {
43	  THREE.__r184ShimInitialized = true;
44
45	  if (!THREE.__compatInit) {
46	    THREE.__compatInit = function (self, BaseCtor, args) {
47	      args = args || [];
48	      if (!BaseCtor) {
49	        console.warn(LOG_PREFIX + ' __compatInit: BaseCtor is undefined');
50	        return;
51	      }
52	      var defaults = _getDefaultArgsFor(BaseCtor);
53	      var tmp = null;
54	      try {
55	        tmp = new (Function.prototype.bind.apply(BaseCtor, [null].concat(args.length ? args : defaults)));
56	      } catch (e1) {
57	        try {
58	          tmp = new BaseCtor();
59	        } catch (e2) {
60	          console.warn(LOG_PREFIX + ' __compatInit failed', BaseCtor.name || BaseCtor);
61	        }
62	      }
63	      if (tmp) _copyOwnProps(self, tmp);
64	    };
65	  }
66
67	  if (!THREE.Math && THREE.MathUtils) {
68	    THREE.Math = THREE.MathUtils;
69	  }
70
71	  var geoAliases = [
72	    'Box', 'Circle', 'Cone', 'Cylinder', 'Dodecahedron', 'Extrude',
73	    'Icosahedron', 'Lathe', 'Octahedron', 'Plane', 'Ring', 'Shape',
74	    'Sphere', 'Tetrahedron', 'Torus', 'TorusKnot', 'Tube'
75	  ];
76	  geoAliases.forEach(function (name) {
77	    var bufferName = name + 'BufferGeometry';
78	    var geoName = name + 'Geometry';
79	    if (!THREE[bufferName] && THREE[geoName]) {
80	      THREE[bufferName] = THREE[geoName];
81	    }
82	  });
83
84	  if (typeof THREE.LinearEncoding === 'undefined') {
85	    THREE.LinearEncoding = 3000;
86	  }
87	  if (typeof THREE.sRGBEncoding === 'undefined') {
88	    THREE.sRGBEncoding = 3001;
89	  }
90
91	  if (THREE.Matrix4 && THREE.Matrix4.prototype && !THREE.Matrix4.prototype.getInverse) {
92	    THREE.Matrix4.prototype.getInverse = function (matrix) {
93	      return this.copy(matrix).invert();
94	    };
95	  }
96
97	  if (THREE.ShaderChunk) {
98	    if (!THREE.ShaderChunk.encodings_fragment && THREE.ShaderChunk.colorspace_fragment) {
99	      THREE.ShaderChunk.encodings_fragment = THREE.ShaderChunk.colorspace_fragment;
100	    }
101	    if (!THREE.ShaderChunk.encodings_pars_fragment && THREE.ShaderChunk.colorspace_pars_fragment) {
102	      THREE.ShaderChunk.encodings_pars_fragment = THREE.ShaderChunk.colorspace_pars_fragment;
103	    }
104	  }
105
106	  _injectExtendedThreeFromQspace(THREE);
107	  _applyLoaderSyncFromQspace(THREE);
108	  _applyMathClassesFromQspace(THREE);
109	  _applyMathUtilsFromQspace(THREE);
110	  _mirrorExtendedThreeToQspace(THREE);
111	}
112
113	function _mirrorExtendedThreeToQspace(THREE) {
114	  if (!THREE || typeof qspace === 'undefined' || !qspace.THREE || qspace.THREE === THREE) return;
115	  var keys = [
116	    'Line2', 'LineGeometry', 'LineMaterial', 'LineSegments2', 'LineSegmentsGeometry',
117	    'CSS2DObject', 'CSS2DRenderer', 'CSS3DObject', 'CSS3DSprite', 'CSS3DRenderer',
118	  ];
119	  keys.forEach(function (key) {
120	    if (THREE[key] && typeof THREE[key] === 'function' && (!qspace.THREE[key] || typeof qspace.THREE[key] !== 'function')) {
121	      qspace.THREE[key] = THREE[key];
122	    }
123	    if (qspace.THREE[key] && typeof qspace.THREE[key] === 'function' && (!THREE[key] || typeof THREE[key] !== 'function')) {
124	      THREE[key] = qspace.THREE[key];
125	    }
126	  });
127	}
128
129	function _applyMathUtilsFromQspace(THREE) {
130	  if (!THREE) return;
131	  var sources = [];
132	  if (typeof qspace !== 'undefined' && qspace.THREE) {
133	    sources.push(qspace.THREE);
134	  }
135	  if (typeof window !== 'undefined' && window.THREE) {
136	    sources.push(window.THREE);
137	  }
138	  var mathUtils = null;
139	  for (var i = 0; i < sources.length; i++) {
140	    var src = sources[i];
141	    if (src && src.MathUtils && typeof src.MathUtils.degToRad === 'function') {
142	      mathUtils = src.MathUtils;
143	      break;
144	    }
145	  }
146	  if (!mathUtils) return;
147	  THREE.MathUtils = mathUtils;
148	  THREE.Math = mathUtils;
149	  if (typeof qspace !== 'undefined' && qspace.THREE && qspace.THREE !== THREE) {
150	    qspace.THREE.MathUtils = mathUtils;
151	    qspace.THREE.Math = mathUtils;
152	  }
153	}
154
155	function _applyMathClassesFromQspace(THREE) {
156	  if (!THREE) return;
157	  var mathKeys = ['Vector2', 'Vector3', 'Matrix4', 'Quaternion', 'Color'];
158	  var sources = [];
159	  if (typeof qspace !== 'undefined' && qspace.THREE) {
160	    sources.push(qspace.THREE);
161	  }
162	  if (typeof window !== 'undefined' && window.THREE) {
163	    sources.push(window.THREE);
164	  }
165	  mathKeys.forEach(function (key) {
166	    for (var i = 0; i < sources.length; i++) {
167	      var src = sources[i];
168	      if (src && typeof src[key] === 'function') {
169	        THREE[key] = src[key];
170	        break;
171	      }
172	    }
173	  });
174	}
175
176	function _applyLoaderSyncFromQspace(THREE) {
177	  if (!THREE) return;
178	  if (typeof THREE.RGBFormat === 'undefined') {
179	    THREE.RGBFormat = 1003;
180	  }
181	  if (typeof THREE.RGBAFormat === 'undefined') {
182	    THREE.RGBAFormat = 1023;
183	  }
184	  if (typeof THREE.TriangleFanDrawMode === 'undefined') {
185	    THREE.TriangleFanDrawMode = 0;
186	  }
187	  if (typeof THREE.TriangleStripDrawMode === 'undefined') {
188	    THREE.TriangleStripDrawMode = 1;
189	  }
190
191	  var qTHREE = (typeof qspace !== 'undefined' && qspace.THREE) ? qspace.THREE : {};
192	  var keysToSync = [
193	    'Interpolant', 'Loader', 'Object3D', 'Material', 'BufferGeometry', 'Mesh', 'Group',
194	    'Sprite', 'Vector3', 'Vector2', 'Color', 'Matrix4', 'Camera',
195	    'QuaternionKeyframeTrack', 'NumberKeyframeTrack', 'VectorKeyframeTrack',
196	    'AnimationClip', 'PropertyBinding', 'LoaderUtils', 'FileLoader', 'TextureLoader',
197	    'ImageBitmapLoader', 'LinearFilter', 'LinearMipmapLinearFilter', 'LinearMipmapNearestFilter',
198	    'NearestFilter', 'NearestMipmapLinearFilter', 'NearestMipmapNearestFilter',
199	    'ClampToEdgeWrapping', 'RepeatWrapping', 'MirroredRepeatWrapping',
200	    'DoubleSide', 'FrontSide', 'TangentSpaceNormalMap', 'Box3', 'Sphere', 'MathUtils',
201	    'BufferAttribute', 'InterleavedBuffer', 'InterleavedBufferAttribute',
202	    'InterpolateDiscrete', 'InterpolateLinear', 'LineBasicMaterial', 'LineLoop', 'LineSegments',
203	    'Points', 'PointsMaterial', 'Skeleton', 'SkinnedMesh', 'Bone', 'CanvasTexture',
204	    'DirectionalLight', 'PointLight', 'SpotLight', 'OrthographicCamera', 'PerspectiveCamera',
205	    'Line', 'MeshStandardMaterial', 'Raycaster', 'UnsignedShortType', 'ColorManagement',
206	    'MeshBasicMaterial', 'MeshPhysicalMaterial', 'RGBAFormat',
207	  ];
208	  keysToSync.forEach(function (key) {
209	    if (qTHREE[key] && !THREE[key]) THREE[key] = qTHREE[key];
210	  });
211	  if (!THREE.TextureLoader && typeof window !== 'undefined' && window.THREE && window.THREE.TextureLoader) {
212	    THREE.TextureLoader = window.THREE.TextureLoader;
213	  }
214	}
215
216	function _injectExtendedThreeFromQspace(target) {
217	  var sources = [];
218	  if (typeof zqcore !== 'undefined' && zqcore.THREE) {
219	    sources.push(zqcore.THREE);
220	  }
221	  if (typeof qspace !== 'undefined' && qspace.THREE) {
222	    sources.push(qspace.THREE);
223	  }
224	  if (typeof window !== 'undefined' && window.THREE) {
225	    sources.push(window.THREE);
226	  }
227	  if (!sources.length) return;
228	  var keys = [
229	    'Line2', 'LineGeometry', 'LineMaterial', 'LineSegments2', 'LineSegmentsGeometry',
230	    'CSS2DObject', 'CSS2DRenderer', 'CSS3DObject', 'CSS3DSprite', 'CSS3DRenderer',
231	    'BoxBufferGeometry', 'PlaneBufferGeometry', 'SphereBufferGeometry',
232	    'CylinderBufferGeometry', 'ConeBufferGeometry', 'CircleBufferGeometry', 'RingBufferGeometry',
233	  ];
234	  keys.forEach(function (key) {
235	    for (var si = 0; si < sources.length; si++) {
236	      var qTHREE = sources[si];
237	      if (qTHREE[key] && typeof qTHREE[key] === 'function') {
238	        if (!target[key] || typeof target[key] !== 'function') {
239	          target[key] = qTHREE[key];
240	        }
241	        break;
242	      }
243	    }
244	  });
245	}
246
247	function _copyOwnProps(target, source) {
248	  var keys = Object.getOwnPropertyNames(source);
249	  for (var i = 0; i < keys.length; i++) {
250	    var key = keys[i];
251	    if (key === 'constructor') continue;
252	    var desc = Object.getOwnPropertyDescriptor(source, key);
253	    try {
254	      Object.defineProperty(target, key, desc);
255	    } catch (_) {}
256	  }
257	}
258
259	function _getDefaultArgsFor(BaseCtor) {
260	  if (!BaseCtor || !THREE) return [];
261	  try {
262	    var name = BaseCtor.name || '';
263	    switch (name) {
264	      case 'OrthographicCamera': return [-1, 1, 1, -1, 0.1, 2000];
265	      case 'PerspectiveCamera': return [];
266	      case 'Mesh': return [new THREE.BufferGeometry(), new THREE.MeshBasicMaterial()];
267	      case 'Line': return [new THREE.BufferGeometry(), new THREE.LineBasicMaterial()];
268	      case 'LineSegments': return [new THREE.BufferGeometry(), new THREE.LineBasicMaterial()];
269	      case 'Line2': return [];
270	      case 'Object3D': return [];
271	      case 'Group': return [];
272	      case 'Sprite': return [];
273	      case 'Loader': return [];
274	      case 'RawShaderMaterial': return [];
275	      case 'ShaderMaterial': return [];
276	      case 'MeshBasicMaterial': return [];
277	      case 'MeshLambertMaterial': return [];
278	      case 'InstancedBufferGeometry': return [];
279	      case 'LineSegmentsGeometry': return [];
280	      case 'LineGeometry': return [];
281	      default: return [];
282	    }
283	  } catch (_) {}
284	  return [];
285	}
286
287	if ( module.exports) {
288	  module.exports = THREE;
289	}
290	});
291
292	var three = createCommonjsModule(function (module) {
293	/** [r184 compat] side-effect init — use window.THREE after load */
294
295
296	var THREE = (typeof window !== 'undefined' && window.THREE) ? window.THREE : {};
297
298	if ( module.exports) {
299	  module.exports = THREE;
300	}
301	});
302
303	/*
304	 * @FileAuthor: ghy
305	 * @Date: 2023-09-20 17:49:17
306	 * @Description: 事件类型
307	 */
308
309	var Event = {
310	  // 指南针相关事件可以在这里添加
311	};
312
313	var event = Event;
314
315	/*
316	 * @FileAuthor: ghy
317	 * @Date: 2023-09-20 19:26:12
318	 * @Description: 状态管理
319	 */
320
321
322
323	function Status(ext) {
324	  this.ext = ext;
325
326	  this.enable = true;
327
328	  this.init();
329	}
330
331	Status.prototype.init = function () {
332	  var this$1 = this;
333
334	  Object.keys(event).forEach(function (EventName) {
335	    var stateItem = Object.create(null);
336
337	    stateItem._state = false;
338	    stateItem._data = null;
339
340	    this$1[event[EventName]] = stateItem;
341
342	    this$1.defineProtpertyOfStatusItem(stateItem, event[EventName]);
343	  });
344	};
345
346	Status.prototype.defineProtpertyOfStatusItem = function (stateItem, eventName) {
347	  var status = this;
348
349	  Object.defineProperties(stateItem, {
350	    state: {
351	      get: function () {
352	        return stateItem._state;
353	      },
354	      set: function (state) {
355	        stateItem._state = state;
356	        var data = stateItem._data;
357	        checkEventState(status, eventName, state, data);
358	      },
359	    },
360	    data: {
361	      get: function () {
362	        return stateItem._data;
363	      },
364	      set: function (data) {
365	        stateItem._data = data;
366	      },
367	    },
368	  });
369	};
370
371	/** 检测事件状态 */
372	function checkEventState(status, eventName, state, data) {
373	  var Ext = status.ext;
374
375	  // 处理指南针相关事件
376	  if (state === true && status.enable && Ext[eventName]) {
377	    Ext[eventName].forEach(function (cb) {
378	      cb(data);
379	    });
380	  }
381	}
382
383	var status = Status;
384
385	/*
386	 * @Author: zxf
387	 * @Date: 2022-04-02 11:26:48
388	 * @Description: 指南针接口
389	 */
390	var initApiMethods = function (ext) {
391	  var Ext = ext;
392
393	  var Methods = Ext.methods;
394
395	  Ext.setDirection = function (quaternion) {
396	    Methods.setDirection(quaternion);
397	  };
398
399	  Ext.show = function () {
400	    Methods.show();
401	  };
402
403	  Ext.hide = function () {
404	    Methods.hide();
405	  };
406	};
407
408	var methods = initApiMethods;
409
410	/*
411	 * @FileAuthor: ghy
412	 * @Date: 2023-08-08 14:48:05
413	 * @Description: 插件方法、事件初始化
414	 */
415
416
417
418	/**
419	 * @description 初始化方法、事件
420	 * @param {Object} Ext 插件实例
421	 */
422	var initApi = function (Ext) {
423	  methods(Ext);
424	};
425
426	var api = initApi;
427
428	/*
429	 * @Author: zxf
430	 * @Date: 2022-04-02 10:38:54
431	 * @Description: 方法集合
432	 */
433
434	function Methods(ext) {
435	  this.ext = ext;
436	}
437
438	/** 模型切换 */
439	Methods.prototype.modelSwitch = function () {
440	  // 清理模型相关状态
441	};
442
443	/** 模式改变 */
444	Methods.prototype.modeChange = function (params) {
445	  // 处理模式改变
446	};
447
448	/** 正在切换全景点 */
449	Methods.prototype.switchPano = function (params) {
450	  // 处理全景点切换
451	};
452
453	Methods.prototype.setDirection = function (radian) {
454	  if (this.ext.compass3d) {
455	    this.ext.compass3d.updatePose(radian);
456	  }
457	};
458
459	Methods.prototype.show = function () {
460	  if (this.ext.compass3d) {
461	    this.ext.compass3d.show();
462	    this.ext.compass3d.updatePose(this.ext.radian);
463	    this.ext.isVisible = true;
464	  }
465	};
466
467	Methods.prototype.hide = function () {
468	  if (this.ext.compass3d) {
469	    this.ext.compass3d.hide();
470	    this.ext.isVisible = false;
471	  }
472	};
473
474	var methods$1 = Methods;
475
476	/*
477	 * @FileAuthor: ghy
478	 * @Date: 2023-09-20 19:22:52
479	 * @Description: hook
480	 */
481
482
483
484	/**
485	 * @description 初始化hook
486	 * @param { Ext } ext 插件实例
487	 */
488	function initHook(ext) {
489	  Object.values(event).forEach(function (value) {
490	    var hookCb = [];
491	    Object.defineProperty(ext, value, {
492	      set: function set(cb) {
493	        hookCb.push(cb);
494	      },
495	      get: function get() {
496	        return hookCb;
497	      },
498	    });
499	  });
500	}
501
502	var hook = initHook;
503
504	/*
505	 * @Author: ncz
506	 * @Date: 2023-02-23 16:57:02
507	 * @Description: 扩展应用支持的平台类型
508	 */
509
510	var platform = {
511	  /** 电脑设备 */
512	  PC: 'pc',
513	  /** VR设备 */
514	  WEBXR: 'webxr',
515	  /** 移动设备 */
516	  MOBILE: 'mobile'
517	};
518
519	var compass3d = createCommonjsModule(function (module) {
520	/**
521	 * 指北针插件
522	 * 基于Three.js实现的四棱锥体指北针,支持相机朝向设置
523	 */
524	var THREE = qspace.THREE;
525
526	var CompassPlugin = function CompassPlugin(container, options) {
527	  if ( options === void 0 ) options = {};
528
529	  this.container = container;
530	  this.options = Object.assign(
531	    {
532	      width: 100,
533	      height: 100,
534	      rotationAngle: 0,
535	      textOffsetX: 0, // 文字水平偏移
536	      textOffsetY: -20, // 文字垂直偏移,减少距离
537	      textContent: 'N', // 指北针文字内容,支持国际化
538	    },
539	    options
540	  );
541
542	  this.scene = null;
543	  this.camera = null;
544	  this.renderer = null;
545	  this.controls = null;
546	  this.group = null;
547	  this.textMesh = null;
548	  this.cssTextElement = null;
549	  this.loadedFont = null;
550	  this.userRotation = new THREE.Quaternion(); // 用户设置的旋转
551	  this.northTip = null; // 北向尖端顶点
552	  this.init();
553	};
554
555	CompassPlugin.prototype.init = function init () {
556	    var this$1 = this;
557
558	  // 确保THREE已经加载
559	  if (typeof THREE === 'undefined') {
560	    console.warn('THREE.js not available, retrying in 100ms...');
561	    setTimeout(function () { return this$1.init(); }, 100);
562	    return;
563	  }
564
565	  this.createScene();
566	  this.createCompass();
567	  this.createLights();
568	  this.loadFont();
569	  this.setupControls();
570	  this.animate();
571	  this.fitToContainer();
572
573	  // 初始化时默认隐藏指北针和文字
574	  this.hide();
575	};
576
577	CompassPlugin.prototype.createScene = function createScene () {
578	  // 创建场景
579	  this.scene = new THREE.Scene();
580
581	  // 创建相机 - 支持完整的3D旋转
582	  this.camera = new THREE.PerspectiveCamera(75, this.options.width / this.options.height, 0.1, 1000);
583	  // 相机初始位置在指北针前方,距离30单位
584	  this.camera.position.set(0, 0, 30);
585	  this.camera.up.set(0, 1, 0); // 设置相机的上方向
586	  this.camera.lookAt(0, 0, 0); // 始终看向指北针中心
587
588	  // 创建WebGL渲染器
589	  this.renderer = new THREE.WebGLRenderer({
590	    antialias: true,
591	    alpha: true, // 启用透明背景
592	  });
593	  this.renderer.setSize(this.options.width, this.options.height);
594	  this.renderer.setClearColor(0x000000, 0); // 设置透明背景
595	  this.container.appendChild(this.renderer.domElement);
596	};
597
598	CompassPlugin.prototype.createCompass = function createCompass () {
599	  // 创建双四棱锥体组
600	  this.group = new THREE.Group();
601
602	  // 上四棱锥
603	  var geometryUp = new THREE.CylinderGeometry(0, 10, 28, 4, 1);
604	  var materialUp = new THREE.MeshPhongMaterial({
605	    color: 0xff4d4d,
606	    shininess: 100,
607	  });
608	  var coneUp = new THREE.Mesh(geometryUp, materialUp);
609	  coneUp.position.y = 14;
610	  this.group.add(coneUp);
611
612	  // 下四棱锥
613	  var geometryDown = new THREE.CylinderGeometry(0, 10, 28, 4, 1);
614	  var materialDown = new THREE.MeshPhongMaterial({
615	    color: 0x00bfff, // 0xffffff
616	    shininess: 100,
617	  });
618	  var coneDown = new THREE.Mesh(geometryDown, materialDown);
619	  coneDown.position.y = -14;
620	  coneDown.rotation.x = Math.PI;
621	  this.group.add(coneDown);
622
623	  this.group.rotation.x = Math.PI / 2;
624	  this.scene.add(this.group);
625
626	  // 创建北向尖端顶点(蓝色四棱锥的顶部,蓝色方向视为北方)
627	  this.northTip = new THREE.Vector3(0, -14, 0);
628
629	  if (this.options.rotationAngle) {
630	    this.scene.rotation.y = (-this.options.rotationAngle * Math.PI) / 180;
631	  }
632	};
633
634	CompassPlugin.prototype.createLights = function createLights () {
635	  // 点光源
636	  var light = new THREE.PointLight(0xffffff, 1, 100);
637	  light.position.set(20, 20, 20);
638	  this.scene.add(light);
639
640	  // 环境光
641	  var ambientLight = new THREE.AmbientLight(0xffffff, 0.8);
642	  this.scene.add(ambientLight);
643	};
644
645	CompassPlugin.prototype.loadFont = function loadFont () {
646	  // 创建文字元素
647	  this.createTextMesh();
648	};
649
650	CompassPlugin.prototype.createTextMesh = function createTextMesh () {
651	  // 移除之前的CSS文字元素
652	  if (this.cssTextElement) {
653	    this.container.removeChild(this.cssTextElement);
654	    this.cssTextElement = null;
655	  }
656
657	  // 创建简单的文字元素
658	  var textElement = document.createElement('div');
659	  textElement.className = 'compass-text';
660	  textElement.textContent = this.options.textContent || 'N';
661	  textElement.style.position = 'absolute';
662	  textElement.style.color = '#ffffff';
663	  textElement.style.fontSize = '12px';
664	  textElement.style.fontFamily = '"PingFangSC-Regular", "Microsoft YaHei", Arial, sans-serif';
665	  textElement.style.fontWeight = 'bold';
666	  textElement.style.textAlign = 'center';
667	  textElement.style.textShadow = '1px 1px 3px rgba(0, 0, 0, 0.8)';
668	  textElement.style.whiteSpace = 'nowrap';
669	  textElement.style.minWidth = '16px';
670	  textElement.style.minHeight = '16px';
671	  textElement.style.lineHeight = '1';
672	  textElement.style.pointerEvents = 'none';
673	  textElement.style.userSelect = 'none';
674	  textElement.style.left = '0px'; // 初始位置设为0
675	  textElement.style.top = '0px'; // 初始位置设为0
676	  textElement.style.zIndex = '1000';
677	  textElement.style.transition = 'none'; // 禁用过渡动画,确保实时跟随
678
679	  // 确保文字始终面向屏幕
680	  textElement.style.transformStyle = 'preserve-3d';
681	  textElement.style.backfaceVisibility = 'hidden';
682	  textElement.style.transform = 'translateZ(0)'; // 强制硬件加速
683
684	  this.container.appendChild(textElement);
685	  this.cssTextElement = textElement;
686	};
687
688	CompassPlugin.prototype.setupControls = function setupControls () {
689	  // 不使用OrbitControls,使用自定义鼠标控制
690	  this.controls = null;
691	};
692
693	CompassPlugin.prototype.animate = function animate () {
694	    var this$1 = this;
695
696	  var animate = function () {
697	    if (typeof requestAnimationFrame !== 'undefined') {
698	      // eslint-disable-next-line no-undef
699	      requestAnimationFrame(animate);
700	    }
701
702	    if (this$1.controls) {
703	      this$1.controls.update();
704	    }
705
706	    // 确保指北针组的世界矩阵是最新的
707	    this$1.group.updateMatrixWorld();
708
709	    // 更新文字位置到北向尖端
710	    this$1.updateTextToNorthTip();
711
712	    this$1.renderer.render(this$1.scene, this$1.camera);
713	  };
714	  animate();
715	};
716
717	// 更新文字内容
718	CompassPlugin.prototype.updateTextContent = function updateTextContent (text) {
719	  if (this.cssTextElement) {
720	    // 如果没有传入文本,使用配置中的默认值
721	    var textToUse = text !== undefined ? text : this.options.textContent || 'N';
722	    this.cssTextElement.textContent = textToUse;
723	    // 同时更新配置,以便后续使用
724	    this.options.textContent = textToUse;
725	  }
726	};
727
728	// 设置文字位置
729	CompassPlugin.prototype.setTextPosition = function setTextPosition (x, y) {
730	  if (this.cssTextElement) {
731	    // 使用translate3d确保硬件加速,同时保持文字面向屏幕
732	    this.cssTextElement.style.transform = "translate3d(" + x + "px, " + y + "px, 0px)";
733	  }
734	};
735
736	CompassPlugin.prototype.fitToContainer = function fitToContainer () {
737	  var size = Math.min(this.options.width, this.options.height);
738	  this.group.scale.set(size / 400, size / 400, size / 400);
739
740	  // 保持相机位置在容器中心,只调整距离
741	  this.camera.position.set(0, 0, 30 * (100 / size));
742	  this.camera.lookAt(0, 0, 0); // 始终看向指北针中心
743	  this.camera.updateProjectionMatrix();
744
745	  this.createTextMesh();
746	};
747
748	// 设置大小
749	CompassPlugin.prototype.setSize = function setSize (width, height) {
750	  this.options.width = width;
751	  this.options.height = height;
752	  this.renderer.setSize(width, height);
753	  this.camera.aspect = width / height;
754	  this.camera.updateProjectionMatrix();
755	  this.fitToContainer();
756	};
757
758	// 销毁
759	CompassPlugin.prototype.destroy = function destroy () {
760	  if (this.renderer) {
761	    this.renderer.dispose();
762	    this.container.removeChild(this.renderer.domElement);
763	  }
764
765	  if (this.cssTextElement) {
766	    this.container.removeChild(this.cssTextElement);
767	  }
768
769	  if (this.scene) {
770	    this.scene.traverse(function (object) {
771	      if (object.geometry) {
772	        object.geometry.dispose();
773	      }
774	      if (object.material) {
775	        if (Array.isArray(object.material)) {
776	          object.material.forEach(function (material) { return material.dispose(); });
777	        } else {
778	          object.material.dispose();
779	        }
780	      }
781	    });
782	  }
783	};
784
785	// 显示指北针
786	CompassPlugin.prototype.show = function show () {
787	  if (this.renderer && this.renderer.domElement) {
788	    this.renderer.domElement.style.display = 'block';
789	  }
790	  if (this.group) {
791	    this.group.visible = true;
792	  }
793	  if (this.cssTextElement) {
794	    this.cssTextElement.style.display = 'block';
795	  }
796	};
797
798	// 隐藏指北针
799	CompassPlugin.prototype.hide = function hide () {
800	  if (this.renderer && this.renderer.domElement) {
801	    this.renderer.domElement.style.display = 'none';
802	  }
803	  if (this.group) {
804	    this.group.visible = false;
805	  }
806	  if (this.cssTextElement) {
807	    this.cssTextElement.style.display = 'none';
808	  }
809	};
810
811	// 更新指北针姿态 - 只修改相机朝向,不动模型朝向
812	CompassPlugin.prototype.updatePose = function updatePose (quaternion) {
813	  if (quaternion) {
814	    // 解析四元数
815	    var rotationQuaternion;
816	    if (quaternion instanceof THREE.Quaternion) {
817	      rotationQuaternion = quaternion.clone();
818	    } else if (Array.isArray(quaternion) && quaternion.length === 4) {
819	      rotationQuaternion = new THREE.Quaternion(quaternion[0], quaternion[1], quaternion[2], quaternion[3]);
820	    } else if (typeof quaternion === 'object' && quaternion.x !== undefined) {
821	      rotationQuaternion = new THREE.Quaternion(quaternion.x, quaternion.y, quaternion.z, quaternion.w);
822	    } else {
823	      return;
824	    }
825
826	    // 计算相机的新位置(围绕指北针旋转)
827	    var distance = 30; // 相机距离指北针的距离
828	    var direction = new THREE.Vector3(0, 0, 1); // 初始方向(Z轴正方向)
829	    direction.applyQuaternion(rotationQuaternion);
830
831	    // 设置相机位置
832	    this.camera.position.copy(direction.multiplyScalar(distance));
833
834	    // 相机始终看向指北针中心
835	    this.camera.lookAt(0, 0, 0);
836
837	    // 更新相机矩阵
838	    this.camera.updateMatrixWorld();
839
840	    // 更新文字位置
841	    this.updateTextToNorthTip();
842	  }
843	};
844
845	// 获取北向尖端的屏幕坐标
846	CompassPlugin.prototype.getNorthTipScreenPosition = function getNorthTipScreenPosition () {
847	  if (!this.northTip || !this.camera || !this.renderer || !this.group) {
848	    return { x: 0, y: 0 };
849	  }
850
851	  // 获取指北针北向尖端的世界坐标
852	  var worldPosition = this.northTip.clone();
853	  worldPosition.applyMatrix4(this.group.matrixWorld);
854
855	  // 将3D世界坐标转换为屏幕坐标
856	  var screenPosition = worldPosition.clone();
857	  screenPosition.project(this.camera);
858
859	  // 转换为屏幕像素坐标
860	  var x = (screenPosition.x * 0.5 + 0.5) * this.options.width;
861	  var y = (screenPosition.y * -0.5 + 0.5) * this.options.height;
862
863	  // 计算指北针北向方向向量(从指北针中心指向北向尖端)
864	  var northDirection = new THREE.Vector3(0, -1, 0); // 指北针北向方向(蓝色端,Y轴负方向)
865	  northDirection.applyMatrix4(this.group.matrixWorld);
866
867	  // 将北向方向向量投影到屏幕空间
868	  var screenNorthDirection = northDirection.clone();
869	  screenNorthDirection.project(this.camera);
870
871	  // 计算北向方向在屏幕上的单位向量
872	  var screenNorthX = screenNorthDirection.x;
873	  var screenNorthY = -screenNorthDirection.y;
874
875	  // 归一化屏幕方向向量
876	  var length = Math.sqrt(screenNorthX * screenNorthX + screenNorthY * screenNorthY);
877	  if (length > 0) {
878	    var normalizedX = screenNorthX / length;
879	    var normalizedY = screenNorthY / length;
880
881	    // 计算偏移距离
882	    var offsetDistance = Math.sqrt(
883	      this.options.textOffsetX * this.options.textOffsetX + this.options.textOffsetY * this.options.textOffsetY
884	    );
885
886	    // 使用固定的偏移距离,确保文字始终在指北针北向尖端的相对位置
887	    var offsetX = normalizedX * offsetDistance;
888	    var offsetY = normalizedY * offsetDistance;
889
890	    // 由于使用transform,需要减去文字元素本身的中心偏移
891	    var elementWidth = this.cssTextElement ? this.cssTextElement.offsetWidth : 16;
892	    var elementHeight = this.cssTextElement ? this.cssTextElement.offsetHeight : 16;
893	    var centerOffsetX = elementWidth / 2;
894	    var centerOffsetY = elementHeight / 2;
895
896	    return {
897	      x: x + offsetX - centerOffsetX,
898	      y: y + offsetY - centerOffsetY,
899	    };
900	  } else {
901	    // 如果无法计算方向,直接使用北向尖端位置
902	    var elementWidth$1 = this.cssTextElement ? this.cssTextElement.offsetWidth : 16;
903	    var elementHeight$1 = this.cssTextElement ? this.cssTextElement.offsetHeight : 16;
904	    var centerOffsetX$1 = elementWidth$1 / 2;
905	    var centerOffsetY$1 = elementHeight$1 / 2;
906
907	    return {
908	      x: x - centerOffsetX$1,
909	      y: y - centerOffsetY$1,
910	    };
911	  }
912	};
913
914	// 更新文字位置到北向尖端
915	CompassPlugin.prototype.updateTextToNorthTip = function updateTextToNorthTip () {
916	  if (this.cssTextElement) {
917	    var screenPos = this.getNorthTipScreenPosition();
918
919	    // 确保文字位置在容器范围内
920	    var maxX = this.options.width - (this.cssTextElement.offsetWidth || 16);
921	    var maxY = this.options.height - (this.cssTextElement.offsetHeight || 16);
922
923	    var clampedX = Math.max(0, Math.min(screenPos.x, maxX));
924	    var clampedY = Math.max(0, Math.min(screenPos.y, maxY));
925
926	    this.setTextPosition(clampedX, clampedY);
927	  }
928	};
929
930	// 更新旋转角度
931	CompassPlugin.prototype.setRotationAngle = function setRotationAngle (rotationAngle) {
932	  this.options.rotationAngle = rotationAngle || 0;
933	  if (this.scene) {
934	    this.scene.rotation.y = (-this.options.rotationAngle * Math.PI) / 180;
935	  }
936	};
937
938	// 导出插件
939	if ( module.exports) {
940	  module.exports = CompassPlugin;
941	} else if (typeof window !== 'undefined') {
942	  window.CompassPlugin = CompassPlugin;
943	}
944	});
945
946	/*
947	 * @FileAuthor: ghy
948	 * @Date: 2024-07-10 14:27:38
949	 * @Description: qspace中间件
950	 */
951
952	var MiddleWare = function MiddleWare(qspace) {
953	  this.qspace = qspace;
954	  this.commonEvents = qspace.commonEvents;
955	  this.commonExtension = qspace.commonExtension;
956	};
957
958	var prototypeAccessors = { NEED_MODE_CHANGE: { configurable: true },NEED_SWITCH_MODEL: { configurable: true },NEED_SWITCH_MODEL_COMPLETE: { configurable: true },NEED_SWITCH_WAYPOINT_START: { configurable: true },NEED_UPDATE: { configurable: true },NEED_PANORAMA_CAMERA_ROTATE: { configurable: true } };
959	MiddleWare.prototype.getCurrentMode = function getCurrentMode () {
960	  return this.qspace.view.mode;
961	};
962	MiddleWare.prototype.getActiveModelType = function getActiveModelType () {
963	  return this.qspace.model.type;
964	};
965	MiddleWare.prototype.getCurrentLocationId = function getCurrentLocationId () {
966	  return this.qspace.model.waypoint;
967	};
968	MiddleWare.prototype.getWaypointPosition = function getWaypointPosition (id) {
969	  return this.qspace.model.getWaypointPosition(id);
970	};
971	MiddleWare.prototype.getBoundingBox = function getBoundingBox () {
972	  return this.qspace.model.getBoundingBox();
973	};
974	MiddleWare.prototype.sceneAdd = function sceneAdd (obj) {
975	  this.qspace.scene.add(obj);
976	};
977	MiddleWare.prototype.sceneRemove = function sceneRemove (obj) {
978	  this.qspace.scene.remove(obj);
979	};
980	MiddleWare.prototype.getQuaternion = function getQuaternion () {
981	  // return this.qspace.floorplanCamera.quaternion;
982	  return this.qspace.dollhouseCamera.quaternion;
983	};
984
985	prototypeAccessors.NEED_MODE_CHANGE.get = function () {
986	  return this.commonExtension.API.NEED_MODE_CHANGE;
987	};
988	prototypeAccessors.NEED_SWITCH_MODEL.get = function () {
989	  return this.commonExtension.API.NEED_SWITCH_MODEL;
990	};
991	prototypeAccessors.NEED_SWITCH_MODEL_COMPLETE.get = function () {
992	  return this.commonExtension.API.NEED_SWITCH_MODEL_COMPLETE;
993	};
994	prototypeAccessors.NEED_SWITCH_WAYPOINT_START.get = function () {
995	  return this.commonExtension.API.NEED_SWITCH_WAYPOINT_START;
996	};
997	prototypeAccessors.NEED_UPDATE.get = function () {
998	  return this.commonExtension.API.NEED_UPDATE;
999	};
1000	prototypeAccessors.NEED_PANORAMA_CAMERA_ROTATE.get = function () {
1001	  return this.commonExtension.API.NEED_PANORAMA_CAMERA_ROTATE;
1002	};
1003
1004	Object.defineProperties( MiddleWare.prototype, prototypeAccessors );
1005
1006	var middleWare = MiddleWare;
1007
1008	/**
1009	 * 3D指南针管理
1010	 */
1011	function Compass3DPlugin() {
1012
1013	  this.compass3d = null;
1014
1015	  // 方向旋转弧度
1016	  this.radian = 0;
1017
1018	  this.isInstall = false;
1019	  this.quaternion = null;
1020
1021	  this.currentMode = null;
1022	  this.futureMode = null;
1023	  // 显隐控制状态,默认为可见
1024	  this.isVisible = true;
1025	}
1026
1027	Compass3DPlugin.prototype.env = undefined;
1028	Compass3DPlugin.prototype.bundle = "Tue Sep 22 2026 22:09:06 GMT+0800 (China Standard Time)";
1029	Compass3DPlugin.prototype.version = "1.3.0";
1030
1031	/** @type {String} 应用名 */
1032	Compass3DPlugin.prototype.name = 'Compass3D';
1033
1034	/** 支持平台 */
1035	Compass3DPlugin.prototype.supportPlatform = [platform.PC, platform.MOBILE];
1036
1037	/** @type {Object} 注册插槽API */
1038	Compass3DPlugin.prototype.registeredApi = Object.create(null);
1039
1040	/** @type {Object} 监听插槽API */
1041	Compass3DPlugin.prototype.onApi = Object.create(null);
1042
1043	/**
1044	 * 注册
1045	 */
1046	Compass3DPlugin.prototype.register = function () {
1047	  var qspace = this.parent || window.qspace;
1048	  this.middleWare = new middleWare(qspace);
1049
1050	  // this.registeredApi[this.middleWare.NEED_UPDATE] = true;
1051	  // this.registeredApi[this.middleWare.NEED_MODE_CHANGE] = true;
1052
1053	  /** 监听模式改变 */
1054	  // this.onApi[this.middleWare.NEED_MODE_CHANGE] = (data) => {
1055	  //   if (!this.compass3d) return;
1056	  //   switch (data.mode) {
1057	  //     case 'transitioning': {
1058	  //       // this.compass3d.hide();
1059	  //       break;
1060	  //     }
1061	  //     case 'panorama': {
1062	  //       if (this.isVisible) {
1063	  //         this.compass3d.hide();
1064	  //       }
1065	  //       break;
1066	  //     }
1067	  //     case 'dollhouse': {
1068	  //       if (this.isVisible) {
1069	  //         this.compass3d.show();
1070	  //       }
1071	  //       break;
1072	  //     }
1073	  //     case 'floorplan': {
1074	  //       if (this.isVisible) {
1075	  //         this.compass3d.show();
1076	  //       }
1077	  //       break;
1078	  //     }
1079	  //   }
1080	  // };
1081
1082	  /** 监听相机旋转和模型朝向 */
1083	  // this.onApi[this.middleWare.NEED_UPDATE] = (data) => {
1084	  //   if (
1085	  //     this.middleWare.getCurrentMode() === 'dollhouse' ||
1086	  //     this.middleWare.getCurrentMode() === 'floorplan' ||
1087	  //     this.middleWare.getCurrentMode() === 'transitioning'
1088	  //   ) {
1089	  //     // 获取模型的四元数朝向
1090	  //     const modelQuaternion = this.middleWare.getQuaternion();
1091	  //     if (JSON.stringify(this.quaternion) !== JSON.stringify(modelQuaternion)) {
1092	  //       this.quaternion = modelQuaternion;
1093	  //       this.setDirection(modelQuaternion);
1094	  //     }
1095	  //   }
1096	  // };
1097	};
1098
1099	/**
1100	 * 初始化
1101	 * @param {string} id - 容器ID
1102	 * @param {Object} config - 配置对象
1103	 * @param {Object|Array} config.defaultQuaternion - 默认相机朝向四元数
1104	 */
1105	Compass3DPlugin.prototype.init = function (id, config) {
1106	  if ( config === void 0 ) config = {};
1107
1108	  this.compass3d = new compass3d(id, config);
1109	};
1110
1111	Compass3DPlugin.prototype.install = function (cb) {
1112	  if ( cb === void 0 ) cb = function () {};
1113
1114	  if (!this.status) {
1115	    this.status = new status(this);
1116	    this.methods = new methods$1(this);
1117
1118	    hook(this);
1119	    api(this);
1120	  }
1121
1122	  this.isInstall = true;
1123	  this.status.enable = true;
1124
1125	  cb();
1126	};
1127
1128	Compass3DPlugin.prototype.uninstall = function () {
1129	  this.isInstall = false;
1130	  this.status.enable = false;
1131	};
1132
1133	/**
1134	 * 显示指北针
1135	 */
1136	Compass3DPlugin.prototype.show = function () {
1137	  if (this.compass3d) {
1138	    this.compass3d.show();
1139	    this.isVisible = true;
1140	  }
1141	};
1142
1143	/**
1144	 * 隐藏指北针
1145	 */
1146	Compass3DPlugin.prototype.hide = function () {
1147	  if (this.compass3d && this.compass3d) {
1148	    this.compass3d.hide();
1149	    this.isVisible = false;
1150	  }
1151	};
1152
1153	/**
1154	 * 设置指北针方向
1155	 */
1156	Compass3DPlugin.prototype.setDirection = function (quaternion) {
1157	  if (this.compass3d) {
1158	    this.compass3d.updatePose(quaternion);
1159	  }
1160	};
1161
1162	/**
1163	 * 设置显隐状态
1164	 * @param {boolean} visible - 是否可见
1165	 */
1166	Compass3DPlugin.prototype.setVisible = function (visible) {
1167	  this.isVisible = !!visible;
1168	  if (this.compass3d) {
1169	    if (this.isVisible) {
1170	      this.compass3d.show();
1171	    } else {
1172	      this.compass3d.hide();
1173	    }
1174	  }
1175	};
1176
1177	/**
1178	 * 获取当前显隐状态
1179	 * @returns {boolean} 当前显隐状态
1180	 */
1181	Compass3DPlugin.prototype.getVisible = function () {
1182	  return this.isVisible;
1183	};
1184
1185	/**
1186	 * 切换显隐状态
1187	 */
1188	Compass3DPlugin.prototype.toggleVisible = function () {
1189	  this.setVisible(!this.isVisible);
1190	};
1191
1192	/**
1193	 * 设置旋转角度
1194	 * @param {number} rotationAngle - 旋转角度(度数)
1195	 */
1196	Compass3DPlugin.prototype.setRotationAngle = function (rotationAngle) {
1197	  if (this.compass3d) {
1198	    this.compass3d.setRotationAngle(rotationAngle);
1199	  }
1200	};
1201
1202	/**
1203	 * 重置指北针到初始状态
1204	 * 在模型切换时调用,确保指北针恢复到最初始的状态
1205	 * @param {number} rotationAngle - 指北针的旋转角度(可选)
1206	 */
1207	Compass3DPlugin.prototype.reset = function (rotationAngle) {
1208	  if (this.compass3d && this.compass3d.container) {
1209	    // 保存当前配置和容器
1210	    var container = this.compass3d.container;
1211	    var config = this.compass3d.options || {};
1212
1213	    // 如果提供了旋转角度,更新配置
1214	    if (rotationAngle !== undefined && rotationAngle !== null) {
1215	      config.rotationAngle = rotationAngle;
1216	    }
1217
1218	    // 销毁当前的指北针实例
1219	    this.compass3d.destroy();
1220
1221	    // 重新创建指北针实例,恢复到初始状态
1222	    this.compass3d = new compass3d(container, config);
1223
1224	    // 重置四元数状态
1225	    this.quaternion = null;
1226	  }
1227	};
1228
1229	var src = Compass3DPlugin;
1230
1231	return src;
1232
1233})));
1234//# sourceMappingURL=Compass3D.js.map

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.