gitee:
mainwindow.js:4 Uncaught SyntaxError: The requested module '/3dviewport.js' does not provide an export named 'default'一定要default吗

2025-05-10 14-27-58 专门写了个代码画立方体

javascript
import{ scene,camera,renderer} from './3dviewport';
import {update2DViewport }from './2dviewport';
const sidebar3d = document.createElement('div');
sidebar3d.id = 'sidebar3d';
// 固定侧边栏宽度
sidebar3d.style.padding = '10px';
sidebar3d.style.backgroundColor = '#f0f0f0';
import * as THREE from 'three';
function init_sidebar3d() {
const ox=document.createElement('input');
ox.type='text';
ox.placeholder = '左下角坐标x'; // 改为placeholder提示,避免覆盖用户输入
const oy=document.createElement('input');
oy.type='text';
oy.placeholder = '左下角坐标y';
const oz=document.createElement('input');
oz.type='text';
oz.placeholder = '左下角坐标z';
const sx=document.createElement('input');
sx.type='text';
sx.placeholder = '尺寸x';
const sy=document.createElement('input');
sy.type='text';
sy.placeholder = '尺寸y';
const sz=document.createElement('input');
sz.type='text';
sz.placeholder = '尺寸z';
const createBtn = document.createElement('button');
createBtn.textContent = '确定';
createBtn.style.width = '100%';
createBtn.style.margin = '5px 0';
createBtn.addEventListener('click', () => {
// 获取输入值并转换为数值
const oxVal = parseFloat(ox.value);
const oyVal = parseFloat(oy.value);
const ozVal = parseFloat(oz.value);
const sxVal = parseFloat(sx.value);
const syVal = parseFloat(sy.value);
const szVal = parseFloat(sz.value);
addcube_button(oxVal, oyVal, ozVal, sxVal, syVal, szVal); // 传递参数
});
ox.style.display="none"
oy.style.display="none"
oz.style.display="none"
sx.style.display="none"
sy.style.display="none"
sz.style.display="none"
createBtn.style.display="none"
const addCubeBtn = document.createElement('button');
addCubeBtn.textContent = '添加立方体';
addCubeBtn.style.width = '100%';
addCubeBtn.style.margin = '5px 0';
addCubeBtn.addEventListener('click', () => {
if (ox.style.display=="none"){
ox.style.display="block";
oy.style.display="block";
oz.style.display="block";
sx.style.display="block";
sy.style.display="block";
sz.style.display="block";
createBtn.style.display="block";}
else{ox.style.display="none";
oy.style.display="none";
oz.style.display="none";
sx.style.display="none";
sy.style.display="none";
sz.style.display="none";
createBtn.style.display="none";}
// 点击后更新按钮列表
});
sidebar3d.appendChild(addCubeBtn);
sidebar3d.appendChild(ox);
sidebar3d.appendChild(oy);
sidebar3d.appendChild(oz);
sidebar3d.appendChild(sx);
sidebar3d.appendChild(sy);
sidebar3d.appendChild(sz);
sidebar3d.appendChild(createBtn);
addcube_button(0,0,0,100,100,100);
addcube_button(0,100,0,100,100,100);
addcube_button(100,0,0,100,100,100);
addcube_button(-100,0,0,100,100,100);
// 首次生成按钮
}
// 创建更新侧边栏按钮的函数
function addcube_button(ox,oy,oz,sx,sy,sz){
// 使用输入的尺寸创建几何体(默认值防止未输入时出错)
const geometry = new THREE.BoxGeometry(sx || 100, sy || 100, sz || 100);
const material = new THREE.MeshBasicMaterial({ color: 0x00ff00 });
const cube = new THREE.Mesh(geometry, material);
// 设置位置(默认原点防止未输入时出错)
cube.position.set(ox || 0, oy || 0, oz || 0);
cube.name = 'CustomCube';
scene.add(cube);
renderer.render(scene, camera);
const btn = document.createElement('button');
btn.textContent = `立方体`; // 按钮文本
btn.style.width = '100%'; // 按钮宽度
btn.style.margin = '5px 0'; // 按钮间距
btn.addEventListener('click', () => {
if (deleteBtn.style.display=="none"){
deleteBtn.style.display = 'block';}
else{deleteBtn.style.display = 'none';}
});
const deleteBtn = document.createElement('button');
deleteBtn.textContent = '删除';
deleteBtn.style.width = '100%';
deleteBtn.style.margin = '5px 0';
deleteBtn.addEventListener('click', () => {
scene.remove(cube); // 删除对象
renderer.render(scene, camera);
sidebar3d.removeChild(deleteBtn); // 移除按钮
sidebar3d.removeChild(btn); // 移除对应的按钮
});
deleteBtn.style.display="none"
sidebar3d.appendChild(btn);
sidebar3d.appendChild(deleteBtn);
update2DViewport();
}
// 创建几何体和网格
init_sidebar3d();
// 不再直接添加到body,改为导出供mainwindow管理
export default sidebar3d;
旋转功能
2025-05-10 14-41-38 旋转视图
ai写的我连看都没看
javascript
import * as THREE from 'three';
// 创建 canvas 并导出
const viewportCanvas3d = document.createElement('canvas');
viewportCanvas3d.id = 'scene';
viewportCanvas3d.style.flex = '1';
viewportCanvas3d.style.height = '100vh';
// 创建场景和相机
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(
75,
window.innerWidth / window.innerHeight,
0.1,
1000
);
// 创建渲染器并绑定 canvas
const renderer = new THREE.WebGLRenderer({ canvas: viewportCanvas3d });
renderer.setSize(window.innerWidth, window.innerHeight);
// 设置相机位置
camera.position.z = 500;
// ---------- 新增鼠标中键旋转逻辑 ----------
let isRotating = false;
let startX = 0;
let startY = 0;
const target = new THREE.Vector3(0, 0, 0); // 假设零件中心在场景原点
// 鼠标按下事件(中键触发旋转)
function onMouseDown(event) {
if (event.button === 1) { // 鼠标中键(button=1)
isRotating = true;
startX = event.clientX;
startY = event.clientY;
event.preventDefault(); // 阻止默认滚动行为
}
}
// 鼠标移动事件(旋转相机)
function onMouseMove(event) {
if (!isRotating) return;
const deltaX = event.clientX - startX;
const deltaY = event.clientY - startY;
startX = event.clientX;
startY = event.clientY;
// 计算相机绕目标点的旋转(水平/垂直移动)
const cameraPos = camera.position.clone().sub(target); // 转换为相对目标点的坐标
// 水平移动绕Y轴旋转
const rotateY = new THREE.Quaternion().setFromAxisAngle(new THREE.Vector3(0, 1, 0), deltaX * 0.005);
cameraPos.applyQuaternion(rotateY);
// 垂直移动绕X轴旋转(负号调整方向)
const rotateX = new THREE.Quaternion().setFromAxisAngle(new THREE.Vector3(1, 0, 0), -deltaY * 0.005);
cameraPos.applyQuaternion(rotateX);
camera.position.copy(cameraPos.add(target)); // 转换回世界坐标
camera.lookAt(target); // 始终看向目标点
renderer.render(scene, camera); // 更新渲染
}
// 鼠标释放事件(结束旋转)
function onMouseUp(event) {
if (event.button === 1) isRotating = false;
}
// 绑定事件监听
viewportCanvas3d.addEventListener('mousedown', onMouseDown);
viewportCanvas3d.addEventListener('mousemove', onMouseMove);
viewportCanvas3d.addEventListener('mouseup', onMouseUp);
// ---------- 新增逻辑结束 ----------
export { viewportCanvas3d as default , scene , camera, renderer };

太复杂了让ai减少方法数量





就差亿点了

没毛病
连出来是右视图






const edges = [
[0, 1], [1, 3], [3, 2], [2, 0],
[4, 5], [5, 7], [7, 6], [6, 4],
[1, 4], [0, 5], [2, 7], [3, 6]
];




javascript
import * as THREE from 'three';
import { scene } from './3dviewport.js';
import { DxfWriter, point3d } from '@tarikjabiri/dxf';
// 创建 Canvas 元素
const viewportCanvas2d = document.createElement('canvas');
viewportCanvas2d.width = 900;
viewportCanvas2d.height = 600;
viewportCanvas2d.style.border = '1px solid #000';
const ctx = viewportCanvas2d.getContext('2d');
// 预定义相机集合
const cameras = [
{
camera: new THREE.OrthographicCamera(-450, 450, 300, -300, -1000, 1000),
position: [0, 0, 500],
label: "Front View",
offset: { x: 0, y: 0 },
scale: 0.5,
},
{
// 原参数:-300, 300, 300, -300(水平/垂直范围 600/600)
// 调整后:根据画布宽高比 3:2,将垂直范围调整为 400(600/3*2=400)
camera: new THREE.OrthographicCamera(-450, 450, 300, -300, -1000, 1000),
position: [500, 0, 0],
label: "Right View",
offset: { x: 450, y: 0 },
scale: 0.5,
},
{
camera: new THREE.OrthographicCamera(-450, 450, 300, -300, -1000, 1000),
position: [0, 500, 0],
label: "Top View",
offset: { x: 0, y: 300 },
scale: 0.5,
}
];
// 初始化相机参数
cameras.forEach(({ camera, position }) => {
camera.position.set(...position);
camera.lookAt(0, 0, 0);
});
// 临时变量
const tempV1 = new THREE.Vector3();
const tempV2 = new THREE.Vector3();
const linelist=[];
function update2DViewport() {
ctx.clearRect(0, 0, viewportCanvas2d.width, viewportCanvas2d.height);
for (const config of cameras) {
const { camera, offset, label, scale } = config;
// 获取相机位置
const cameraPos = new THREE.Vector3();
camera.getWorldPosition(cameraPos);
const Edges = [];
// 遍历场景中的立方体
scene.traverse(obj => {
if (!(obj instanceof THREE.Mesh && obj.name === 'CustomCube')) return;
const geometry = obj.geometry;
if (!(geometry instanceof THREE.BoxGeometry)) return;
const vertices = geometry.attributes.position.array;
const edges = [
[0, 1], [1, 3], [3, 2], [2, 0],
[4, 5], [5, 7], [7, 6], [6, 4],
[1, 4], [0, 5], [2, 7], [3, 6]
];
edges.forEach(([v1Idx, v2Idx]) => {
tempV1.fromBufferAttribute(geometry.attributes.position, v1Idx).applyMatrix4(obj.matrixWorld);
tempV2.fromBufferAttribute(geometry.attributes.position, v2Idx).applyMatrix4(obj.matrixWorld);
Edges.push([tempV1.clone(), tempV2.clone()]);
});
});
// 绘制标签
ctx.fillStyle = "#000";
ctx.font = `${12 * scale}px sans-serif`;
ctx.fillText(label, offset.x + 10 * scale, offset.y + 20 * scale);
ctx.strokeStyle = '#000';
ctx.lineWidth = 1;
for (const [p1, p2] of Edges) {
const sp1 = projectPoint(p1, camera, scale);
const sp2 = projectPoint(p2, camera, scale);
ctx.beginPath();
ctx.moveTo(sp1.x + offset.x, sp1.y + offset.y);
ctx.lineTo(sp2.x + offset.x, sp2.y + offset.y);
ctx.stroke();
linelist.push([sp1.x + offset.x, sp1.y + offset.y,sp2.x + offset.x, sp2.y + offset.y])
}
}
}
function export_dxf() {
// 如果是浏览器环境
const dxf = new DxfWriter();
// 添加一个图层(可选)
dxf.addLayer('Lines', 7); // 颜色索引 7 是黑色
// 辅助函数:保留两位小数
function toFixed(num) {
return parseFloat(parseFloat(num).toFixed(2));
}
// 遍历 linelist 添加线段
for (const [p1x, p1y,p2x,p2y] of linelist) {
const start = point3d(toFixed(p1x), toFixed(p1y));
const end = point3d(toFixed(p2x), toFixed(p2y));
dxf.addLine(start, end, 'Lines'); // 'Lines' 图层名
}
// 生成 DXF 字符串内容
const dxfString = dxf.stringify();
// 创建 Blob 并触发下载
const blob = new Blob([dxfString], { type: "application/dxf" });
const url = URL.createObjectURL(blob);
const now = new Date().toISOString()
.replace(/[:.]/g, '') // 移除冒号和点
.replace('T', '_');
const a = document.createElement("a");
a.href = url;
a.download = `${now} output.dxf`;
a.click();
// 释放资源
URL.revokeObjectURL(url);
}
// 投影函数
function projectPoint(point, camera, scale) {
const ndc = point.clone().project(camera);
const x = (ndc.x + 1) * viewportCanvas2d.width / 2 * scale;
const y = (1 - ndc.y) * viewportCanvas2d.height / 2 * scale;
return { x, y };
}
export {viewportCanvas2d as default,update2DViewport,export_dxf} ;

javascript
import {export_dxf} from './2dviewport';
const sidebar2d = document.createElement('div')
sidebar2d.id = 'sidebar2d'
// 固定侧边栏宽度
const export_dxfBtn = document.createElement('button');
export_dxfBtn.textContent = '导出dxf';
export_dxfBtn.style.width = '100%';
export_dxfBtn.style.margin = '5px 0';
export_dxfBtn.addEventListener('click', () => {
export_dxf() // 传递参数
});
sidebar2d.appendChild(export_dxfBtn);
// 不再直接添加到body,改为导出供mainwindow管理
export default sidebar2d
急急国王