Post

在blog中渲染chem对象

在blog中渲染chem对象

截图截累了,研究研究怎么基于chemdoodle.js在blog中渲染chem对象。

include

首先是chemdoodle,把js和css放到对应位置,创建_include/chemdoodle.html:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<head>
<link rel="stylesheet" href="/assets/css/ChemDoodleWeb.css" type="text/css">
<link rel="stylesheet" href="/assets/css/jquery-ui-1.11.4.css" type="text/css">

<script src="/assets/js/data/ChemDoodleWeb.js"></script>
<script src="/assets/js/data/ChemDoodleWeb-uis.js"></script>
<script src="/assets/js/data/openchemlib-minimal.js"></script>

<style>
  .molecule-container {
    text-align: center;
    margin: 20px 0;
  }
  
  .canvas-container {
    display: inline-block;
    border: 1px solid #ddd;
    border-radius: 4px;
  }
</style>
</head>

然后是方便引用的liquid模板_include/xyz.html:

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
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
<div class="molecule-container">
  <div class="canvas-container">
    {% assign unique_id = include.id | default: 'mol' %}
    {% unless include.id %}
      {% assign content_hash = include.xyz | append: include.mol | append: include.smiles | append: include.representation | append: include.bgcolor | size %}
      {% assign unique_id = unique_id | append: '_' | append: content_hash | append: '_' | append: include.mode %}
    {% endunless %}
    
    {% if include.mode == '2d' %}
      <canvas id="viewACS_{{ unique_id }}" width="{{ include.width | default: 400 }}" height="{{ include.height | default: 300 }}"></canvas>
    {% elsif include.mode == '3d' %}
      <canvas id="transform3d_{{ unique_id }}" width="{{ include.width | default: 400 }}" height="{{ include.height | default: 400 }}"></canvas>
    {% endif %}
  </div>
</div>

<script>
{% if include.mode == '2d' %}
// 2D Canvas
(function() {
  // Generate truly unique ID at runtime
  var timestamp = Date.now();
  var random = Math.floor(Math.random() * 10000);
  var uniqueCanvasId = 'view2d_' + timestamp + '_' + random;
  
  // Update the canvas element ID
  var originalCanvas = document.getElementById('viewACS_{{ unique_id }}');
  if (originalCanvas) {
    originalCanvas.id = uniqueCanvasId;
    console.log('Canvas ID updated from viewACS_{{ unique_id }} to:', uniqueCanvasId);
  } else {
    console.error('Original canvas not found: viewACS_{{ unique_id }}');
    return;
  }
  
  var canvas = new ChemDoodle.ViewerCanvas(uniqueCanvasId, {{ include.width | default: 400 }}, {{ include.height | default: 300 }});
  canvas.styles.bonds_width_2D = 0.6;
  canvas.styles.bonds_saturationWidthAbs_2D = 2.6;
  canvas.styles.atoms_font_size_2D = 10;
  
  {% if include.smiles %}
  var smiles = '{{ include.smiles }}';
  var molfile = OCL.Molecule.fromSmiles(smiles).toMolfile();
  var molecule = ChemDoodle.readMOL(molfile);
  molecule.scaleToAverageBondLength({{ include.scale | default: 20 }});
  canvas.loadMolecule(molecule);
  {% elsif include.mol %}
  var molData = {{ include.mol | jsonify }};
  var molecule = ChemDoodle.readMOL(molData);
  molecule.scaleToAverageBondLength({{ include.scale | default: 20 }});
  canvas.loadMolecule(molecule);
  {% endif %}
})();

{% elsif include.mode == '3d' %}
// 3D Canvas
(function() {
  // Generate truly unique ID at runtime
  var timestamp = Date.now();
  var random = Math.floor(Math.random() * 10000);
  var uniqueCanvasId = 'transform3d_' + timestamp + '_' + random;
  
  // Update the canvas element ID
  var originalCanvas = document.getElementById('transform3d_{{ unique_id }}');
  if (originalCanvas) {
    originalCanvas.id = uniqueCanvasId;
    console.log('Canvas ID updated from transform3d_{{ unique_id }} to:', uniqueCanvasId);
  } else {
    console.error('Original canvas not found: transform3d_{{ unique_id }}');
    return;
  }
  
  console.log('Starting 3D canvas initialization for:', uniqueCanvasId);
  var canvas = new ChemDoodle.TransformCanvas3D(uniqueCanvasId, {{ include.width | default: 400 }}, {{ include.height | default: 400 }});
  console.log('3D canvas created:', uniqueCanvasId);
  
  canvas.styles.set3DRepresentation('{{ include.representation | default: "Ball and Stick" }}');
  canvas.styles.backgroundColor = '{{ include.bgcolor | default: "black" }}';
  // 调整球的大小
  // canvas.styles.atoms_sphereDiameter_3D = 0.1; // 默认约0.5,可以试试0.8, 1.0, 1.2等
  // 可选:同时调整键的粗细以保持比例协调
  canvas.styles.bonds_cylinderDiameter_3D = 0.2; // 默认约0.25
  console.log('Styles set for:', uniqueCanvasId);
  
  {% if include.xyz %}
  // Parse XYZ coordinate data
  var xyzData = {{ include.xyz | jsonify }};
  var lines = xyzData.trim().split('\n');
  var numAtoms = parseInt(lines[0]);
  var comment = lines[1]; // Skip comment line
  
  var molecule = new ChemDoodle.structures.Molecule();
  
  // Parse atoms from XYZ data
  for (var i = 2; i < 2 + numAtoms; i++) {
    var parts = lines[i].trim().split(/\s+/);
    var element = parts[0];
    var x = parseFloat(parts[1]);
    var y = parseFloat(parts[2]);
    var z = parseFloat(parts[3]);
    
    molecule.atoms.push(new ChemDoodle.structures.Atom(element, x, y, z));
  }
  
  // Auto-generate bonds based on distance (simple approach)
  // You may want to customize this based on your needs
  for (var j = 0; j < molecule.atoms.length; j++) {
    for (var k = j + 1; k < molecule.atoms.length; k++) {
      var atom1 = molecule.atoms[j];
      var atom2 = molecule.atoms[k];
      
      var dx = atom1.x - atom2.x;
      var dy = atom1.y - atom2.y;
      var dz = atom1.z - atom2.z;
      var distance = Math.sqrt(dx*dx + dy*dy + dz*dz);
      
      // Simple bonding criteria based on atomic radii
      var maxBondDistance = 2.0; // Adjust as needed
      if (distance < maxBondDistance) {
        molecule.bonds.push(new ChemDoodle.structures.Bond(atom1, atom2));
      }
    }
  }
  
  console.log('XYZ molecule created for', uniqueCanvasId, 'with', molecule.atoms.length, 'atoms and', molecule.bonds.length, 'bonds');
  canvas.loadMolecule(molecule);
  console.log('XYZ molecule loaded for:', uniqueCanvasId);
  {% elsif include.mol %}
  var molData = {{ include.mol | jsonify }};
  var molecule = ChemDoodle.readMOL(molData);
  console.log('MOL molecule created for', uniqueCanvasId, 'with', molecule.atoms.length, 'atoms');
  canvas.loadMolecule(molecule);
  console.log('MOL molecule loaded for:', uniqueCanvasId);
  {% elsif include.smiles %}
  var smiles = '{{ include.smiles }}';
  var molfile = OCL.Molecule.fromSmiles(smiles).toMolfile();
  var molecule = ChemDoodle.readMOL(molData);
  console.log('SMILES molecule created for', uniqueCanvasId, 'with', molecule.atoms.length, 'atoms');
  canvas.loadMolecule(molecule);
  console.log('SMILES molecule loaded for:', uniqueCanvasId);
  {% endif %}
})();
{% endif %}
</script>

<style>
  .molecule-container {
    text-align: center;
    margin: 20px 0;
  }
  
  .canvas-container {
    display: inline-block;
    border: 1px solid #ddd;
    border-radius: 4px;
  }
</style>

md

首先,需要引用chemdoodle:

1
{% include chemdoodle.html %}

随后可以在blog中用liquid语言加载chemdoodle。

smiles转2d

1
2
3
4
5
{% include xyz.html 
   mode="2d" 
   smiles="CCO" 
   width=300 
   height=250 %}

mol转2d

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
{% include xyz.html 
   mode="2d" 
   mol="
   ChemDraw08232514192D

  6  6  0  0  0  0  0  0  0  0999 V2000
   -0.7145    0.4125    0.0000 C   0  0  0  0  0  0  0  0  0  0  0  0
   -0.7145   -0.4125    0.0000 C   0  0  0  0  0  0  0  0  0  0  0  0
    0.0000   -0.8250    0.0000 C   0  0  0  0  0  0  0  0  0  0  0  0
    0.7145   -0.4125    0.0000 C   0  0  0  0  0  0  0  0  0  0  0  0
    0.7145    0.4125    0.0000 C   0  0  0  0  0  0  0  0  0  0  0  0
    0.0000    0.8250    0.0000 C   0  0  0  0  0  0  0  0  0  0  0  0
  1  2  2  0      
  2  3  1  0      
  3  4  2  0      
  4  5  1  0      
  5  6  2  0      
  6  1  1  0      
M  END"
   id="ethanol" %}

xyz转3d

1
2
3
4
5
6
7
8
9
10
11
{% include xyz.html 
   mode="3d" 
   xyz="
   3
Ethanol
C    0.000    0.000    0.000
C    1.540    0.000    0.000  
O    2.080    1.260    0.000" 
   atom_diameter_3d=0.8 bond_diameter_3d=0.22
   representation="Ball and Stick"
   bgcolor="white" %}

mol转3d

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
{% include xyz.html 
   mode="3d" 
   mol="
   ChemDraw08232514192D

  6  6  0  0  0  0  0  0  0  0999 V2000
   -0.7145    0.4125    0.0000 C   0  0  0  0  0  0  0  0  0  0  0  0
   -0.7145   -0.4125    0.0000 C   0  0  0  0  0  0  0  0  0  0  0  0
    0.0000   -0.8250    0.0000 C   0  0  0  0  0  0  0  0  0  0  0  0
    0.7145   -0.4125    0.0000 C   0  0  0  0  0  0  0  0  0  0  0  0
    0.7145    0.4125    0.0000 C   0  0  0  0  0  0  0  0  0  0  0  0
    0.0000    0.8250    0.0000 C   0  0  0  0  0  0  0  0  0  0  0  0
  1  2  2  0      
  2  3  1  0      
  3  4  2  0      
  4  5  1  0      
  5  6  2  0      
  6  1  1  0      
M  END" 
   atom_diameter_3d=0.5 bond_diameter_3d=0.07
   width=500 
   height=500 %}

mol文件引用

1
2
{% capture mol_text %}{% include_relative mols/48/1.mol %}{% endcapture %}
{% include xyz.html mode="3d" mol=mol_text width=300 height=250 %}
This post is licensed under CC BY 4.0 by the author.
Total hits!