一、Kekule.js 概述
1. 简介
Kekule.js 是MIT 开源的纯前端化学信息学 JS 工具库,无后端依赖,可在浏览器 /electron 运行,核心能力:
- 分子、反应式数据模型(原子、键、环、手性、立体化学)
- 多格式 IO:SMILES、CML、MDL Mol/Mol2000、Kekule JSON/XML、InChI(扩展)
- 2D/3D 分子渲染、骨架式 / 球棍 / 填充模型切换
- 可视化组件:Viewer(只读展示)、Composer(交互式绘图编辑器)
- 子结构检索、分子对比、芳香环识别、2D 自动布局
- 快捷键、撤销重做、复制粘贴、自定义工具栏
2. 模块划分
| 模块 | 核心功能 |
|---|---|
| Core | 化学基础对象:Atom、Bond、Molecule、Reaction、坐标、立体结构 |
| IO | 分子格式读写、字符串 / 文件 / URL 加载导出 |
| Render | 2D/3D 渲染器,样式、显示模型配置 |
| Widget | 基础 UI 控件(弹窗、下拉、表格) |
| ChemWidget | 化学专用组件:Viewer、Composer、周期表 |
| Editor | Composer 编辑器绘图工具逻辑 |
| Extra | 扩展:InChI、OpenBabel 适配器、自动 2D 布局 |
3. 官方文档地址
- 教程:https://partridgejiang.github.io/Kekule.js/documents/tutorial/
- 主页:https://partridgejiang.github.io/Kekule.js/
二、安装与引入(3 种方式)
方式 1:CDN 直接引入(快速 demo 推荐)
<!-- 样式必须先引入 -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/kekule/dist/themes/default/kekule.css"/>
<!-- 核心JS -->
<script src="https://cdn.jsdelivr.net/npm/kekule/dist/kekule.min.js"></script>
方式 2:NPM 工程(Vue/React/ 原生工程)
npm install --save kekule
ES Module:
import { Kekule } from 'kekule'
// 使用Viewer/Composer必须导入主题样式
import 'kekule/theme/default'
console.log(Kekule.VERSION)
CommonJS:
const { Kekule } = require('kekule')
require('kekule/theme/default')
方式 3:本地文件部署
将dist/kekule.min.js、dist/themes/复制到项目静态目录:
<link rel="stylesheet" href="./static/kekule/themes/default/kekule.css"/>
<script src="./static/kekule/kekule.min.js"></script>
三、基础分子对象操作(Core 模块)
1. 手动创建分子(环氧乙烷示例)
// 1. 创建分子容器
const mol = new Kekule.Molecule()
// 2. 创建原子,链式设置元素、2D坐标
const C1 = new Kekule.Atom().setSymbol('C').setCoord2D({x:-0.4, y:0.23})
const C2 = new Kekule.Atom().setSymbol('C').setCoord2D({x:0.4, y:0.23})
const O1 = new Kekule.Atom().setSymbol('O').setCoord2D({x:0, y:-0.46})
// 3. 原子加入分子
mol.appendNode(C1)
mol.appendNode(C2)
mol.appendNode(O1)
// 4. 创建化学键(键级1单键、2双键、3三键)
const b1 = new Kekule.Bond().setBondOrder(1).setConnectedObjs([C1, C2])
const b2 = new Kekule.Bond().setBondOrder(1).setConnectedObjs([C2, O1])
const b3 = new Kekule.Bond().setBondOrder(1).setConnectedObjs([O1, C1])
mol.appendNode(b1)
mol.appendNode(b2)
mol.appendNode(b3)
2. 遍历原子 / 键、提取分子式
// 遍历所有原子
mol.eachAtom(atom=>{
console.log(atom.getSymbol(), atom.getCoord2D())
})
// 遍历所有键
mol.eachBond(bond=>{
console.log('键级', bond.getBondOrder())
})
// 获取分子式
const formula = mol.getFormula()
console.log('分子式', formula)
四、IO 模块:分子导入导出(核心)
支持格式
smiles / cml / mol / mol2000 / kekule-json / kekule-xml
1. 从字符串加载分子
// SMILES转分子对象
const smi = 'CCO'
const ethanol = Kekule.IO.loadFormatData(smi, 'smiles')
// CML字符串加载
const cmlStr = `<cml xmlns="http://www.xml-cml.org/schema"><molecule id="m1"/></cml>`
const emptyMol = Kekule.IO.loadFormatData(cmlStr, 'cml')
2. 分子导出为字符串
const mol = ethanol
// 导出SMILES
const smiOut = Kekule.IO.saveFormatData(mol, 'smiles')
// 导出CML
const cmlOut = Kekule.IO.saveFormatData(mol, 'cml')
// 导出Mol文件
const molFile = Kekule.IO.saveFormatData(mol, 'mol')
3. 远程 URL 加载分子(异步)
Kekule.IO.loadUrlData('./data/ethanol.mol', (mol, success)=>{
if(success){
console.log('加载成功', mol)
}else{
console.error('文件加载失败')
}
})
4. 本地文件上传加载(File 对象)
const fileInput = document.getElementById('file')
fileInput.onchange = e=>{
const file = e.target.files[0]
Kekule.IO.loadFileData(file, (mol, ok)=>{
if(ok) viewer.setChemObj(mol)
})
}
五、ChemWidget.Viewer:只读分子查看器
用于展示分子、支持缩放 / 平移 / 3D 旋转,不可编辑。
1. 快速创建 Viewer
<div id="viewerWrap" style="width:700px;height:450px;border:1px solid #ccc;"></div>
// 实例化,挂载到DOM
const viewer = new Kekule.ChemWidget.Viewer(document.getElementById('viewerWrap'))
// 设置宽高
viewer.setDimension('700px', '450px')
// 加载乙醇分子
const mol = Kekule.IO.loadFormatData('CCO', 'smiles')
viewer.setChemObj(mol)
2. 关键配置属性
// 2D/3D切换
viewer.setRenderType(Kekule.Render.rendererType.R2D)
// viewer.setRenderType(Kekule.Render.rendererType.R3D)
// 2D显示模式:骨架式/简式
viewer.setMoleculeDisplayType(Kekule.Render.Molecule2DDisplayType.SKELETAL)
// viewer.setMoleculeDisplayType(Kekule.Render.Molecule2DDisplayType.CONDENSED)
// 3D模型:线框/棍状/球棍/空间填充
// WIRE / STICKS / BALL_STICK / SPACE_FILL
viewer.setMoleculeDisplayType(Kekule.Render.Molecule3DDisplayType.BALL_STICK)
// 启用顶部工具栏
viewer.setEnableToolbar(true)
// 自定义工具栏按钮
viewer.setToolButtons(['zoomIn','zoomOut','resetView','switch2D3D'])
// 鼠标交互缩放平移
viewer.setEnableMouseControl(true)
// 允许双击打开编辑器
viewer.setEnableEdit(false)
// 自适应尺寸
viewer.setAutoSize(false)
六、Editor.Composer:交互式分子绘图编辑器(最常用)
网页版化学结构式绘制面板,支持手绘、快捷键、撤销、复制粘贴。
1. 创建编辑器
<div id="composerBox" style="width:800px;height:500px;border:1px solid #999;"></div>
// 创建编辑器实例
const composer = new Kekule.Editor.Composer()
// 设置尺寸并挂载DOM
composer.setDimension('800px','500px')
composer.appendToElem(document.getElementById('composerBox'))
// 自定义顶部工具栏
composer.setCommonToolButtons([
'undo','redo','cut','copy','paste',
'zoomIn','zoomOut','reset','clearAll'
])
// 初始加载分子(可选)
const initMol = Kekule.IO.loadFormatData('C6H6', 'smiles')
composer.setChemObj(initMol)
2. 获取编辑器内分子、导出格式
// 获取当前画布分子对象
const currentMol = composer.getChemObj()
// 导出SMILES
const smi = Kekule.IO.saveFormatData(currentMol, 'smiles')
console.log('绘制结果SMILES:', smi)
// 导出CML
const cml = Kekule.IO.saveFormatData(currentMol, 'cml')
3. Composer 全局快捷键(编辑器获焦点生效)
绘图快捷键
| 按键 | 功能 |
|---|---|
| A | 添加碳原子 |
| O/N/S/P | 添加氧 / 氮 / 硫 / 磷 |
| 1/2/3 | 单键 / 双键 / 三键 |
| W | 实楔键(向前立体) |
| Shift+W | 虚楔键(向后立体) |
| T | 任意单键 |
编辑通用快捷键
| 快捷键 | 功能 |
|---|---|
| Ctrl+A | 全选原子 / 键 |
| Delete / Backspace | 删除选中对象 |
| Ctrl+Z | 撤销 |
| Ctrl+Shift+Z / Ctrl+Y | 重做 |
| Ctrl+C | 复制 |
| Ctrl+X | 剪切 |
| Ctrl+V | 粘贴 |
| 鼠标滚轮 | 缩放画布 |
七、渲染样式自定义
1. 修改原子、键颜色
// 获取渲染配置
const renderCfg = viewer.getRenderConfig()
// 碳元素颜色
renderCfg.elementColors['C'] = '#222222'
// 氧红色
renderCfg.elementColors['O'] = '#ff3333'
// 键粗细
renderCfg.bondLineWidth = 2
viewer.setRenderConfig(renderCfg)
2. 隐藏氢原子(骨架图常用)
const renderCfg = composer.getRenderConfig()
renderCfg.showHydrogen = false
composer.setRenderConfig(renderCfg)
八、分子高级功能
1. 子结构检索
// 母分子:乙醇 CCO
const parent = Kekule.IO.loadFormatData('CCO','smiles')
// 子结构模板:羟基 -OH
const subTemplate = Kekule.IO.loadFormatData('O','smiles')
// 执行子结构匹配
const matcher = new Kekule.MolSearch.SubstructureMatcher(parent)
const matchResult = matcher.match(subTemplate)
console.log('匹配数量', matchResult.length)
2. 分子相等对比
const mol1 = Kekule.IO.loadFormatData('CCO','smiles')
const mol2 = Kekule.IO.loadFormatData('OCC','smiles')
const isSame = Kekule.MolCompare.isIsomorphic(mol1, mol2)
console.log('分子同分等价', isSame) // true
3. 芳香环自动识别
const benzene = Kekule.IO.loadFormatData('c1ccccc1','smiles')
const rings = benzene.getRings()
rings.forEach(ring=>{
if(ring.isAromatic()) console.log('芳香环', ring.getAtomCount())
})
九、Web Component 标签式使用(零 JS 初始化)
无需写 JS,DOM 属性直接创建 Viewer/Composer:
<!-- Viewer查看器 -->
<div style="width:600px;height:400px"
data-widget="Kekule.ChemWidget.Viewer"
data-render-type="R2D"
data-chem-data="CCO"
data-chem-format="smiles">
</div>
<!-- Composer编辑器 -->
<div style="width:800px;height:500px"
data-widget="Kekule.Editor.Composer"
data-tool-buttons="undo,redo,copy,paste,zoomIn,zoomOut">
</div>
<script>
// 自动初始化页面所有data-widget组件
Kekule.Widget.autoBindWidgets()
</script>
十、React/Vue 集成说明
React:kekule-react 封装
npm install kekule kekule-react
import { Kekule } from 'kekule'
import 'kekule/theme/default'
import { KekuleReact } from 'kekule-react'
// 包装编辑器组件
const Composer = KekuleReact.Utils.wrapWidget(Kekule.Editor.Composer)
function MolEditor(){
return (
<Composer
style={{width:'800px', height:'500px'}}
toolButtons={['undo','redo','clearAll']}
onChange={(widget)=>{
const mol = widget.getChemObj()
const smi = Kekule.IO.saveFormatData(mol, 'smiles')
console.log(smi)
}}
/>
)
}
Vue 原生封装思路
- 在
mounted生命周期实例化 Composer/Viewer beforeUnmount销毁组件释放内存- 通过 ref 获取 DOM 容器挂载编辑器
十一、常见问题与排错
- 编辑器空白、样式丢失 未引入
kekule.css,必须先加载样式再加载 JS。 - SMILES 加载失败 检查 SMILES 合法性,或改用
mol/cml格式测试。 - 快捷键不生效 点击编辑器画布获取焦点后再按快捷键。
- 跨域无法加载本地 mol 文件 本地文件协议
file://会触发 AJAX 跨域,需部署本地 web 服务。 - 3D 渲染卡顿 降低分子原子数量,切换 WIRE 线框模式。
- NPM 打包报错找不到 theme 确认导入路径:
import 'kekule/theme/default',部分打包器需配置静态资源复制。
十二、完整最小可运行 Demo(复制直接打开)
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>Kekule Demo</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/kekule/dist/themes/default/kekule.css"/>
</head>
<body>
<h3>分子编辑器</h3>
<div id="editBox" style="width:800px;height:480px;border:1px solid #666;"></div>
<button id="exportBtn">导出SMILES</button>
<div id="result"></div>
<script src="https://cdn.jsdelivr.net/npm/kekule/dist/kekule.min.js"></script>
<script>
// 创建编辑器
const composer = new Kekule.Editor.Composer()
composer.setDimension('800px','480px')
composer.appendToElem(document.getElementById('editBox'))
composer.setCommonToolButtons(['undo','redo','copy','paste','zoomIn','zoomOut','clearAll'])
// 导出按钮
document.getElementById('exportBtn').onclick = ()=>{
const mol = composer.getChemObj()
const smi = Kekule.IO.saveFormatData(mol, 'smiles')
document.getElementById('result').innerText = 'SMILES:' + smi
}
// 初始加载苯
const benzene = Kekule.IO.loadFormatData('c1ccccc1', 'smiles')
composer.setChemObj(benzene)
</script>
</body>
</html>