* { box-sizing:border-box; }
font-family:'Lucida Sans Unicode';
margin:15px auto auto 30px;
.footer { text-align:right; }
.footer a { color:#53B2C8; }
font-family:'Lucida Sans Unicode';
padding:10px 10px 10px 5px;
border-bottom:1px solid #757575;
input:focus { outline:none; }
transition:0.2s ease all;
-moz-transition:0.2s ease all;
-webkit-transition:0.2s ease all;
input:focus ~ label, input:valid ~ label {
.bar { position:relative; display:block; width:350px; }
.bar:before, .bar:after {
transition:0.2s ease all;
-moz-transition:0.2s ease all;
-webkit-transition:0.2s ease all;
.bar:before { left:50%; }
.bar:after { right:50%; }
input:focus ~ .bar:before, input:focus ~ .bar:after {
input:focus ~ .highlight {
-webkit-animation:inputHighlighter 0.3s ease;
-moz-animation:inputHighlighter 0.3s ease;
animation:inputHighlighter 0.3s ease;
@-webkit-keyframes inputHighlighter {
from { background:#5264AE; }
to { width:0; background:transparent; }
@-moz-keyframes inputHighlighter {
from { background:#5264AE; }
to { width:0; background:transparent; }
@keyframes inputHighlighter {
from { background:#5264AE; }
to { width:0; background:transparent; }
<script src="smiles.js"></script>
<script src="d3.v3.min.js"></script>
<form onsubmit="return false">
<div id="user" class="group">
<input type="text" required value="" onpaste="onclick_handler(this.value)" onkeyup="onkey_handler(event)">
<span class="highlight"></span>
<span class="bar"></span>
<label id="textbox">Input...</label>
<div id="molecularWeight" style="position: absolute; top:35px; left:400px; width:200px; height:25px">""</div>
<div id="examples" style="position: absolute; top:68px; left:46px; width:400px; height:30px">
<p class="examples"><i>examples: </i>
<a href="#" onclick="example_handler('C=O C=O C=O C=O C=O C=O C=O C=O C=O')">formaldehyde</a>,
<a href="#" onclick="example_handler('FH ClH BrH IH FH ClH BrH IH FH ClH BrH IH')">halides</a>,
<a href="#" onclick="example_handler('C=C(C)C=C')">isoprene,</a>
<a href="#" onclick="example_handler('NC(C=O)C=C(O)C(N)C')">default</a>
<a href="https://github.com/chemplexity/molecules" target="_blank">source</a>,
<a href="https://www.opensmiles.org/spec/open-smiles-2-grammar.html" target="_blank">help</a>
* Generate dynamic molecules with HTML/CSS/Javascript
* (C) 2014 by James Dillon
* https://wwww.github.com/chemplexity
var onkey_handler = function(event) {
// Input: 'enter', 'backspace', '=', '0', '9'
if (event.keyCode == 13 || event.keyCode == 8 || event.keyCode == 187 ||
event.keyCode == 48 || event.keycode == 57)
{onclick_handler(document.getElementsByTagName("input")[0].value)}
else if (event.keyCode < 65 || event.keyCode > 90) {return false}
else {onclick_handler(document.getElementsByTagName("input")[0].value)}
var example_handler = function (input) {
document.getElementsByTagName("input")[0].value = input;
var onclick_handler = function(input) { data(input) };
var data = function(input) {
if (input.length == 0) {return false}
// Use custom SMILES converter
var molecule = smiles(input);
// Add size property to atoms
for (i=0; i < molecule.atoms.length; i++) {
if(molecule.atoms[i].element == 1) { molecule.atoms[i].size = 5 }
else if(molecule.atoms[i].element == 9) { molecule.atoms[i].size = 6 }
else if(molecule.atoms[i].element == 35) { molecule.atoms[i].size = 11 }
else if(molecule.atoms[i].element == 53) { molecule.atoms[i].size = 13 }
else { molecule.atoms[i].size = 8 }
// Add source/target fields
for (i=0; i < molecule.bonds.length; i++) {
molecule.bonds[i].source_id = molecule.bonds[i].source;
molecule.bonds[i].target_id = molecule.bonds[i].target;
var margin = {top: 5, right: -5, bottom: 5, left: -5};
var width = 500 - margin.left - margin.right,
height = 375 - margin.top - margin.bottom,
var radius = d3.scale.sqrt()
var svg = d3.select("body").append("svg")
var vis = d3.select("#chart")
var force = d3.layout.force()
.size([width + margin.left + margin.right, height + margin.top + margin.bottom])
// Update graph with new molecule
function update(molecule) {
// Prevent bonds from overlapping
// Create invisible nodes between atoms
molecule.bonds.forEach(function(link) {
source: molecule.atoms[link.source],
target: molecule.atoms[link.target]
// Concatenate invisible nodes with atoms
force.nodes(molecule.atoms.concat(bonding))
force.links(molecule.bonds)
vis.selectAll(".node").remove()
var link = vis.selectAll(".link")
.data(force.links(), function(d) { return d.source +"-"+ d.target; })
.on('mouseover', function (d) {return update_fragment(molecule, d.source, d.target)})
//.on('mouseout', bondType)
.style("stroke-width", function(d) { return (d.order * 3 - 1) * 2 + "px"; })
link.filter(function(d) { return d.order > 1; }).append("line")
.attr("class", "separator");
// Remove bonds from last molecule
var bonding = vis.selectAll(".link-node")
bonding.enter().append("circle")
.attr("class", "link-node")
.attr("visibility", "hidden");
var node = vis.selectAll(".node")
.data(molecule.atoms, function(d) {return d.atom_id})
node.enter().append("circle")
.style("fill", function(d) { return d.color; })
.attr("r", function(d) { return d.size+2 })
.style("stroke", "black")
.style("stroke-width", 3)
.style("stroke-opacity", 0.9);
// Remove atoms from last molecule
.style('fill-opacity', 0)
force.on("tick", function () {
.attr("x1", function(d) { return d.source.x; })
.attr("y1", function(d) { return d.source.y; })
.attr("x2", function(d) { return d.target.x; })
.attr("y2", function(d) { return d.target.y; })
node.attr("cx", function(d) { return d.x = Math.max(r, Math.min(width - r, d.x)); })
.attr("cy", function(d) { return d.y = Math.max(r, Math.min(height - r, d.y)); })
bonding.attr("cx", function(d) { return d.x = (d.source.x + d.target.x) * 0.5; })
.attr("cy", function(d) { return d.y = (d.source.y + d.target.y) * 0.5; });
// Update molecular weight values
// Display molecular weight
function update_text(molecule) {
document.getElementById("molecularWeight").innerHTML = molecule.molecule_weight + " g/mol";
// Display fragmentation molecular weight
function update_fragment(molecule, source, target) {
var bondSelected = d3.select(this).node()
// Calculate molecular weight of fragments
//console.log(findObjects(molecule.bonds, "source_id", source.index));
//var x = findObjects(molecule.bonds, "source_id";
//console.log(source.index)
data("NC(C=O)C=C(O)C(N)C");
function findObjects(array, key, value) {
for (var i = 0; i < array.length; i++) { if (array[i][key] == value) { return array[i]; }}
var bondSelected = d3.select(this).node().__data__
// Calculate molecular weight of fragments
for (i = 0; i < molecule.atoms.length; i++) {
var targetAtom = bondSelected.target;
if (findObjects(totalFragment, "id", targetAtom) == null) {
totalFragment.push({id: bondSelected.target})
// for (i = 0; i < molecule.nodes.length; i++) { linkIndex[i + "," + i] = 1; }
// molecule.links.forEach(function(d) { linkIndex[d.source.index + "," + d.target.index] = 1; });
// function neighboring(a, b) { return linkIndex[a.index + "," + b.index]; }
console.log(d3.select(this).node().__data__)