使用する技術
- SMILES
- RDKit
- Molfile
- OpenChemLib(OCL)
手順のチートシート
以下のファイルをダウンロードする。
https://unpkg.com/@rdkit/rdkit@2023.9.2-1.0.0/Code/MinimalLib/dist/RDKit_minimal.js
https://unpkg.com/@rdkit/rdkit@2023.9.2-1.0.0/Code/MinimalLib/dist/RDKit_minimal.wasm
上記2つのURLをブラウザで検索するだけでダウンロード可能
ダウンロードしたファイルをリポジトリ内に配置する
それぞれ、リポジトリ内のstatic/jsというディレクトリ内に配置する。
static/js/rdkit/RDKit_minimal.js
static/js/rdkit/RDKit_minimal.wasm
以下の設定ファイルを作成する
リポジトリ内にlayouts/partials/head/custom.htmlというファイルを作成する。
内容は以下をコピペ。
1
2
3
4
5
|
<script src="/js/rdkit/RDKit_minimal.js?v=20250920a"></script>
<script>window.RDKIT_BASE='/js/rdkit/';</script>
<script src="/js/chem-render.js?v=20250920a" defer></script>
|
v=~はキャッシュ潰しのため適宜変更可。
static/js/chem-render.jsを作成
static/js/chem-render.jsというファイルを作成し、下記のコードをそのままコピペする。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
|
// ファイル先頭付近に追加
window.MOL_DEBUG = false;
(function () {
// ---- 画面上に診断を出す ----
function diag(msg){
if(!window.MOL_DEBUG) return; // ← OFFなら何もしない
let d = document.getElementById('rdkit-diag');
if(!d){
d = document.createElement('div');
d.id='rdkit-diag';
d.style.cssText='position:fixed;z-index:99999;left:8px;bottom:8px;background:#111;color:#0f0;font:12px/1.4 monospace;padding:6px 8px;border-radius:6px;opacity:.9;max-width:90vw;word-break:break-all';
document.body.appendChild(d);
}
d.textContent = String(msg);
}
// ---- ユーティリティ ----
function W(el,d){ return parseInt(el.getAttribute('data-w')||d,10)||d; }
function H(el,d){ return parseInt(el.getAttribute('data-h')||d,10)||d; }
const tick = () => new Promise(r=>setTimeout(r,0));
// ---- RDKit 初期化(WASMの場所は window.RDKIT_BASE から)----
async function rdkitReady(){
if (window.__RDKIT_READY__) return window.__RDKIT_READY__;
if (window.__RDKIT_PROMISE__) return await window.__RDKIT_PROMISE__;
if (typeof initRDKitModule !== 'function'){
diag('initRDKitModule 未定義:JSが読み込めていません');
return null;
}
var base = (window.RDKIT_BASE || '/js/rdkit/').replace(/\/?$/,'/');
diag('WASM fetch base = '+base);
window.__RDKIT_PROMISE__ = initRDKitModule({
locateFile: f => base + f
}).then(mod=>{
window.__RDKIT_READY__ = mod;
diag('RDKit init: OK');
return mod;
}).catch(e=>{
diag('RDKit init error: '+ e);
window.__RDKIT_READY__ = null;
return null;
});
return await window.__RDKIT_PROMISE__;
}
// ---- 1分子描画(RDKit → SVG)----
async function drawOne(el){
try{
el.textContent = '描画準備中…';
const RD = await rdkitReady();
if(!RD){ el.textContent = 'RDKit初期化に失敗しました'; return; }
const t = el.querySelector('.molblock');
const smiles = (el.dataset.smiles || '').trim();
const input = (t && t.textContent.trim()) ? t.textContent.trim() : smiles;
if(!input){ el.textContent = '構造データがありません'; return; }
let mol;
try{
mol = RD.get_mol(input);
}catch(e){
el.textContent = 'get_mol 例外: ' + e;
return;
}
if(!mol){ el.textContent = '構造の解釈に失敗しました'; return; }
let svg;
try{
svg = mol.get_svg();
}catch(e){
el.textContent = 'get_svg 例外: ' + e;
mol.delete();
return;
}
mol.delete();
if (!/(<path|<line|<polygon)\b/i.test(svg)){
el.textContent = '描画結果が空でした';
return;
}
el.innerHTML = svg;
const s = el.querySelector('svg');
if (s){
s.setAttribute('width', W(el,320));
s.setAttribute('height', H(el,220));
s.style.background = '#fff';
}
}catch(e){
el.textContent = '描画に失敗しました: ' + e;
}
}
// ---- 逐次描画(iPhone対策:1つずつ)----
async function renderAll(){
const nodes = Array.from(document.querySelectorAll('div.mol'));
diag('targets: '+nodes.length);
for(const el of nodes){ await drawOne(el); await tick(); }
}
if (document.readyState === 'loading'){
document.addEventListener('DOMContentLoaded', renderAll);
} else {
renderAll();
}
})();
|
記事に化学構造式を書く
* オランザピンの例
1
|
<div class="mol" data-smiles="CN1CCN(CC1)C/2=N/c4ccccc4Nc3sc(C)cc\23" data-w="320" data-h="220"></div>
|
w, hは縦横の長さ。化学式はSMILESの記法で記載する。
↓下のように表示される。
それぞれの技術の解説
了解。いまの「OCLを使わない=RDKitだけで描画」版に合わせて、説明をまるっと書き直しました。
それぞれの技術の解説
SMILESとは
SMILES = 構造式を文字で書く記法。
例
・ベンゼン:c1ccccc1
・アスピリン:CC(=O)OC1=CC=CC=C1C(=O)O
・オランザピン:CN1CCN(CC1)C/2=N/c4ccccc4Nc3sc(C)cc\23
・ブレクスピプラゾール:O=C5/C=C\c4ccc(OCCCCN3CCN(c1cccc2sccc12)CC3)cc4N5
RDKit(RDKit.js, WASM)とは
SMILESを“正確に”解釈して、そのままSVGに描くブラウザ用ライブラリ(WebAssembly 版)。
RDKit単体で
get_mol(smiles) … SMILESを解析(E/Z・立体情報も保持)
get_svg() … 2DのSVGを直接生成(外部画像なし)
まで完結する。
※必要に応じて get_molblock() で **Molfile(後述)**も取り出せる。
Molfileとは
**Molfile(MDL Molfile)**は「座標付きの分子テキスト」。E/Zや立体情報も保持できる。
RDKitは Molfile入力も可能なので、SMILESの代わりに Molfileを直に貼って描画もできる。
1
2
3
4
5
6
|
<div class="mol" data-w="320" data-h="220">
<textarea class="molblock" hidden>
[ここにMolfileの本文]
M END
</textarea>
</div>
|
描画全体の流れ
「SMILESを書く → RDKitが解釈 → RDKitがSVGを生成 → その場に差し込む」
-
ページの <head> で、ローカル配信の
/js/rdkit/RDKit_minimal.js(+ 同ディレクトリの RDKit_minimal.wasm)を読み込む。
取得先は window.RDKIT_BASE='/js/rdkit/' で絶対パス固定。
-
chem-render.v2.js が、記事中の <div class="mol" …> を集め、
RDKitの初期化完了を待ってから、1件ずつ順番に描画。
-
各要素に対して:
data-smiles があれば get_mol(SMILES) → get_svg()
<textarea.molblock> があれば(Molfile優先) get_mol(Molfile) → get_svg()
-
返ってきた SVG文字列をその要素に innerHTML で差し込み、
width/height を data-w/data-h で指定したサイズに整える。
ポイント
- 外部画像を一切使わない/SMILESも改変しない。
- 初期化を待って逐次描画するので、iPhone/Safariでも安定。
- SVGはテキストなので、拡大しても滲まず、CSSで線の太さ・色を調整可能。
記事側の“文法”(あなたが書くのはこれだけ)
SMILESで描く
1
|
<div class="mol" data-smiles="CN1CCN(CC1)C/2=N/c4ccccc4Nc3sc(C)cc\23" data-w="320" data-h="220"></div>
|
Molfileで描く(任意)
1
2
3
4
5
6
|
<div class="mol" data-w="320" data-h="220">
<textarea class="molblock" hidden>
[Molfile本文]
M END
</textarea>
</div>
|