Thingworx开发ThreeJS扩展时widget-content下canvas渲染异常问题
问题根因
你遇到的渲染异常是Thingworx内置的.widget-content样式约束,叠加布局时序、渲染逻辑缺失共同导致的,具体原因和修复方案如下:
- Thingworx默认给
.widget-content类设置了padding、overflow:hidden、固定定位等样式,会挤压canvas的实际渲染区域,导致你初始化时设置的宽高和实际渲染尺寸不匹配,球体被裁剪到可视范围外 - 你在
afterRender阶段获取的宽高是配置项的固定值,此时Thingworx还未完成widget容器的布局渲染,拿到的尺寸和实际容器尺寸不一致,相机宽高比错误 - 仅在控制器触发change事件时才执行渲染,没有持续的渲染循环,场景更新后不会自动重绘,仅交互时才会触发单次渲染
修复方案
1. 修改renderHtml方法,新增自定义类避免样式冲突
// runtime.ts file renderHtml(): string { // 给外层容器加自定义类覆盖默认样式,canvas设置为块级元素撑满容器 let htmlString = '<div class="widget-content three-widget-container"><canvas style="display:block;width:100%;height:100%;"></canvas></div>'; return htmlString; }
2. 新增自定义样式覆盖默认规则
在你的扩展的css文件中添加如下样式,也可以在afterRender中动态插入style标签:
.three-widget-container { position: relative !important; padding: 0 !important; margin: 0 !important; overflow: visible !important; width: 100% !important; height: 100% !important; }
3. 修改afterRender逻辑,适配Thingworx布局时序
afterRender(): void { const OrbitControls = require('three-orbit-controls')(CourseView); const OBJLoader = require('three-obj-loader')(CourseView); const scene = new CourseView.Scene(); // 直接获取容器实际渲染尺寸,而非配置项的固定值 const container = this.jqElement.find(".three-widget-container").get(0); let width = container.clientWidth; let height = container.clientHeight; const color = this.getProperty('SceneColor', '#000000') || "#000000"; const camera = new CourseView.PerspectiveCamera(75, width / height, 0.1, 1000); camera.position.z = 30; const cv = this.jqElement.find("canvas").get(0); this.renderer = new CourseView.WebGLRenderer({canvas: cv, antialias: true}); this.renderer.setSize(width, height); this.renderer.setClearColor("#0000ff"); const control = new OrbitControls(camera, this.renderer.domElement); control.update(); const geometry = new CourseView.SphereGeometry( 15, 32, 16 ); const material = new CourseView.MeshBasicMaterial( { color: 0xff00ff, wireframe: true } ); const sphere = new CourseView.Mesh( geometry, material ); scene.add( sphere ); // 新增渲染循环,保证场景自动更新 const animate = () => { requestAnimationFrame(animate); control.update(); this.renderer.render(scene, camera); } animate(); // 监听容器尺寸变化,同步更新渲染参数 const resizeObserver = new ResizeObserver(entries => { const { width: newWidth, height: newHeight } = entries[0].contentRect; camera.aspect = newWidth / newHeight; camera.updateProjectionMatrix(); this.renderer.setSize(newWidth, newHeight); }); resizeObserver.observe(container); } myRender(scene, camera) { this.renderer.render(scene, camera); }
内容的提问来源于stack exchange,提问作者CaipiDE
相关产品推荐
相关产品推荐

