# 交互式三维查看器（3Dmol）

## 为什么不用静态图

静态 PNG 只能展示一个视角，用户无法放大到残基，也无法确认「这个突变在哪个位置」。以内嵌 3Dmol 为主视图、静态图只在需要出报告 PDF 时使用。

## 资源准备

```bash
curl -sL https://3dmol.csb.pitt.edu/build/3Dmol-min.js -o 数据/蛋白结构/web/3Dmol-min.js   # ≈545 KB，BSD
```

PDB 先瘦身（只留 ATOM/HETATM/TER/END，去掉 ANISOU/CONECT），再以纯文本内嵌：

```python
out=[l.rstrip('\n') for l in open(pdb) if l.startswith(('ATOM','HETATM','TER','END'))]
open('web/X.pdb','w').write('\n'.join(out)+'\n')
```

```html
<script>/* 3Dmol-min.js 全文 */</script>
<script type="text/plain" id="pdb-Taq">ATOM ...</script>
```

## 初始化（按 Tab 懒加载）

```javascript
var V={};
function initV(k){
  if(V[k]) return V[k];
  var el=document.getElementById('v-'+k);
  var v=$3Dmol.createViewer(el,{backgroundColor:'white',antialias:true});
  v.addModel(document.getElementById('pdb-'+k).textContent,'pdb');
  v.setStyle({},{cartoon:{colorfunc:function(a){return colorFor(k,a.resi);}}});
  v.zoomTo(); v.zoom(1.25); v.render();
  v.setClickable({},true,function(a){
    v.removeAllLabels();
    v.addLabel(a.resn+' '+a.resi,{position:a,backgroundColor:'#1F4E79',fontColor:'white',inFront:true});
    v.render();
  });
  V[k]=v; return v;
}
```

隐藏面板里创建 viewer 会得到 0 宽画布，必须等面板 `display:block` 后再 init。

## 残基定位（关键功能）

```javascript
var n=parseInt(input.value,10);
var ats=v.selectedAtoms({resi:n});
v.removeAllLabels();
v.addStyle({resi:n},{stick:{radius:0.30},cartoon:{color:'#C0392B'}});
v.addLabel(ats[0].resn+' '+n,{position:ats[0],backgroundColor:'#C0392B',fontColor:'white',backgroundOpacity:0.9,inFront:true});
v.zoomTo({resi:n}); v.zoom(0.55); v.render();
```

`zoomTo({resi:n})` 后再 `zoom(0.55)` 是为了把上下文也框进来，否则只剩一根侧链、看不出位置。

## 控制按钮

全览 `zoomTo()` ｜ 放大 `zoom(1.3)` ｜ 缩小 `zoom(0.77)` ｜ 侧链 `setStyle` 加/去 stick ｜ 自转 `spin('y')`。

## 编号体系

`colorFor` 用 PDB 的 `resi`。要求：

- Taq 1TAQ / Tth 8XK9 / UNG 3UF7 的编号与 UniProt 基本一致，可直接用；
- MMLV 的 4MH8 是构造编号（24–487），与 UniProt Gag-Pol（741–1320）不同——要么用 AlphaFold 模型（本地编号 + `uniprotStart-1` 偏移），要么先做序列比对求偏移。用错会整段着色错位。

## 验收

```javascript
window.__V[k].getModel().selectedAtoms({}).length   // > 0
```

再实测：Taq 输入 667 → 标签 PHE 667；UNG 输入 64 → ASP 64。截图确认侧链与标签都在。
