Files
Robot_Arm/webapp/js/pick.js
T

127 lines
5.2 KiB
JavaScript
Raw Normal View History

/* 拾取、悬停、隐藏与选中态 */
/* ---- picking & hiding ---- */
const ray = new THREE.Raycaster(); let sel = null, hov = null;
/* 拾取列表与 NDC 向量复用同一实例:旧版每次 pointermove 都 filter 出一个新数组 +
新建 Vector2(高频下纯垃圾)。可见性逐次重算,语义与 filter 完全一致
——three r159 的 Raycaster 不检查 object.visible,只能靠这里过滤。 */
const pickList = [], ndcPick = new THREE.Vector2();
function pick(e) {
const r = cv.getBoundingClientRect();
ndcPick.set(((e.clientX-r.left)/r.width)*2-1, -((e.clientY-r.top)/r.height)*2+1);
ray.setFromCamera(ndcPick, cam);
pickList.length = 0;
for (const m of meshes) if (m.visible) pickList.push(m);
if (window.isHarnessVisible && isHarnessVisible() && window.harnessMeshes) {
for (const m of harnessMeshes) if (m.visible) pickList.push(m);
}
const hit = ray.intersectObjects(pickList, false)[0];
return hit ? hit.object : null;
}
/* BOM 表高亮行只记一行:旧版每次点选/ESC 都要把整张表(13 行零件 + 10 行螺钉)
的 style.background 全刷一遍,纯属多余 DOM 写入。 */
let bomHlRow = null;
function bomHlClear() { if (bomHlRow) { bomHlRow.style.background = ''; bomHlRow = null; } }
function dimsStr(p) {
if (!p.dims) return '';
const f = d => String(Math.round(d * 10) / 10);
return '外形 ' + f(p.dims[0]) + ' × ' + f(p.dims[1]) + ' × ' + f(p.dims[2]) + ' mm(X·Y·Z)';
}
function hover(e) {
const o = pick(e); if (o === hov) return; hov = o;
const n = document.getElementById('note');
if (!o) { n.style.display = 'none'; return; }
const p = o.userData;
n.style.display = 'block';
if (p.harness) {
n.innerHTML = '<b>' + p.cn + '</b><br><small style="color:#fbbf24">' + p.name + '</small>';
} else {
n.innerHTML = '<b>#' + p.idx + ' ' + p.cn + '</b><br><small>' + p.name +
' · ' + (p.printed ? '3D打印件' : '电机/已有件') +
(dimsStr(p) ? '<br>' + dimsStr(p) : '') + '</small>';
}
}
function hidePart(m) {
if (!m) return;
const p = m.userData;
if (m === sel) {
m.material.emissive.setHex(0);
m.material.emissiveIntensity = 0;
sel = null;
}
m.visible = false;
if (m.chk) m.chk.checked = false;
const n = document.getElementById('note');
if (n) n.style.display = 'none';
const hud = document.getElementById('hud');
if (hud) {
hud.innerHTML = '已隐藏:<b>#' + p.idx + ' ' + p.cn + '</b> <span id="unhideBtn" style="color:var(--ac);cursor:pointer;text-decoration:underline;margin-left:6px">撤销</span> <small style="color:var(--dim)">(可在左侧零件树勾选或点击“全选”恢复)</small>';
const ub = document.getElementById('unhideBtn');
if (ub) ub.onclick = () => {
m.visible = true;
if (m.chk) m.chk.checked = true;
hud.textContent = '';
requestRender();
};
}
requestRender();
}
cv.addEventListener('contextmenu', e => {
e.preventDefault();
if (panDist > 6) return; // ignore drag panning
let target = sel;
if (!target) target = pick(e);
if (target) hidePart(target);
});
window.addEventListener('keydown', e => {
if (e.key === 'h' || e.key === 'H' || e.key === 'Delete') {
if (sel) hidePart(sel);
} else if (e.key === 'Escape') {
clearScrewHl();
if (sel) {
sel.material.emissive.setHex(0);
sel.material.emissiveIntensity = 0;
sel = null;
const hud = document.getElementById('hud');
if (hud) hud.textContent = '';
bomHlClear();
requestRender();
}
}
});
cv.addEventListener('click', e => {
const o = pick(e);
if (o === sel) {
if (sel) { sel.material.emissive.setHex(0); sel.material.emissiveIntensity = 0; sel = null; }
bomHlClear();
clearScrewHl();
const hud = document.getElementById('hud'); if (hud) { hud.textContent = ''; delete hud.dataset.scrHl; }
requestRender();
return;
}
if (sel && !sel.userData.screw && !sel.userData.harness) { sel.material.emissive.setHex(0); sel.material.emissiveIntensity = 0; }
sel = o;
if (sel && !sel.userData.screw && !sel.userData.harness) { sel.material.emissive.setHex(0x2f6bff); sel.material.emissiveIntensity = .55; }
const tb = document.querySelector('#bom tbody');
bomHlClear();
const hud = document.getElementById('hud');
hud.textContent = '';
delete hud.dataset.scrHl;
if (sel) {
const u = sel.userData;
if (u.screw) { highlightSpec(u.spec, false); requestRender(); return; } // 点中螺钉 -> 反查 BOM 行并定位
if (u.harness) {
hud.innerHTML = '<b>' + u.cn + '</b> · <span style="color:#f59e0b">' + u.name +
'</span> · 2×CAN通信 + 2×24V供电 · <span style="color:var(--ok)">4芯高柔拖链电缆/T型分接</span>';
requestRender();
return;
}
hud.innerHTML = '<b>#' + u.idx + ' ' + u.cn + '</b> · ' + (u.vol / 1000).toFixed(1) +
' cm3 · ' + (u.printed ? '打印件' : '电机/已有件') +
' <span style="margin-left:8px;color:var(--warn);font-size:11px">[右键单击或按H键隐藏此部件]</span>';
const tr = tb.querySelector('[data-idx="' + u.idx + '"]');
if (tr) { tr.style.background = '#22406b'; bomHlRow = tr; tr.scrollIntoView({block:'nearest'}); }
}
requestRender();
});