Merge branch 'master' of github.com:lambdacasserole/avogadrio

This commit is contained in:
Saul Johnson
2020-05-16 15:22:35 +01:00
7 changed files with 1250 additions and 37 deletions
+2 -1
View File
@@ -4,7 +4,7 @@ Worship your favorite molecule by setting it as your wallpaper.
Avogadrio is a web app that will render your favourite molecule as a desktop wallpaper from either a compund name or
[SMILES structure](https://en.wikipedia.org/wiki/Simplified_molecular-input_line-entry_system). Molecule rendering
is designed to be powered by [Sourire](https://github.com/tmoerman/sourire) which itself wraps the
[Indigo cheminformatics toolkit](https://github.com/ggasoftware/indigo). Built on the
[Indigo cheminformatics toolkit](https://github.com/ggasoftware/indigo). Built on the
[Silex](https://github.com/silexphp/Silex) micro-framework.
![Logo](logo.png)
@@ -62,3 +62,4 @@ A big thank you to:
* [Nile Red](https://www.youtube.com/user/TheRedNile) inspired me to build this. I wasn't that big on chemistry until I came across his videos.
* [Jay Holtslander](https://codepen.io/j_holtslander/) put together the hamburger menu/sidebar combo in his [Pen](https://codepen.io/j_holtslander/pen/XmpMEp) on CodePen. I believe it's derived from earlier work by [maridlcrmn](https://bootsnipp.com/maridlcrmn).
* [Thomas Moerman](https://github.com/tmoerman) created [Sourire](https://github.com/tmoerman/sourire), which really simplified the molecule rendering process.
* [Andre Plötze](https://github.com/andrepxx) created [pure-knob](https://github.com/andrepxx/pure-knob), which is used here for the rotation knob/wheel/dial thing.
+30 -4
View File
@@ -16,9 +16,11 @@ class MoleculeRenderer
private $sourireUrl;
private $renderChiralLabels;
private $customLabel;
private $rotation;
/**
* Initializes a new instance of a molecule rendering service.
*
@@ -50,8 +52,8 @@ class MoleculeRenderer
public function renderMolecule($smiles, $color)
{
// Proxy into Sourire for molecule render.
$img = Image::make($this->sourireUrl
. 'molecule/' . rawurlencode($smiles)
$img = Image::make($this->sourireUrl
. 'molecule/' . rawurlencode($smiles)
. '?render-stereo-style=' . ($this->renderChiralLabels ? 'old' : 'none') // Label chiral atoms?
. '&render-comment-offset=16' // Give some space between label and molecule.
. ($this->customLabel === '' ? '' : ('&render-comment=' . rawurlencode($this->customLabel))));
@@ -60,6 +62,7 @@ class MoleculeRenderer
list($r, $g, $b) = sscanf($color, "%02x%02x%02x");
$unit = 100 / 255;
$img->colorize($unit * $r, $unit * $g, $unit * $b);
$img->rotate($this->rotation);
return $img; // Return molecule image.
}
@@ -72,6 +75,7 @@ class MoleculeRenderer
* @param int $canvasWidth the width of the canvas to scale the molecule to
* @param int $canvasHeight the height of the canvas to scale the molecule to
* @param float $proportion the maximum proportion of the canvas the molecule should occupy (in either direction)
* @param float $rotation the angle to rotate the image by
* @return \Intervention\Image\Image
*/
public function renderScaledMolecule($smiles, $color, $canvasWidth, $canvasHeight, $proportion = 0.8)
@@ -165,4 +169,26 @@ class MoleculeRenderer
$this->customLabel = $customLabel;
return $this;
}
/**
* Gets the angle of rotation to apply to the molecule.
*
* @return float
*/
public function getRotation()
{
return $this->rotation;
}
/**
* Sets the angle of rotation to apply to the molecule.
*
* @param float $rotation the angle of rotation to apply
* @return MoleculeRenderer
*/
public function setRotation($rotation)
{
$this->rotation = $rotation;
return $this;
}
}
+56 -20
View File
@@ -7,6 +7,9 @@ $(document).ready ->
foregroundColor = 'ce3838'
backgroundColor = '5f0000'
# Transforms.
rotation = 0
# Custom label for molecule.
customLabel = ''
@@ -22,7 +25,7 @@ $(document).ready ->
# Element to use for wallpaper preview.
previewElement = $ 'body, html'
# Download button element.
downloadButton = $ '.download-btn'
@@ -58,8 +61,10 @@ $(document).ready ->
#
buildUrl = (width, height, foreground, background, name) ->
url = "/api/name/#{width}/#{height}/#{background}/#{foreground}/#{name}"
if customLabel != '' then url += "?label=#{customLabel}"
return url
qs = ""
if customLabel != '' then qs += "label=#{customLabel}"
if rotation != 0 then qs += "rotation=#{rotation}"
return if qs == "" then url else url + "?" + qs
# Builds a URL to generate a molecule-only image from a compound name.
#
@@ -70,8 +75,10 @@ $(document).ready ->
#
buildMoleculeOnlyUrl = (width, height, foreground, name) ->
url = "/api/name/#{width}/#{height}/#{foreground}/#{name}"
if customLabel != '' then url += "?label=#{customLabel}"
return url
qs = ""
if customLabel != '' then qs += "label=#{customLabel}"
if rotation != 0 then qs += "rotation=#{rotation}"
return if qs == "" then url else url + "?" + qs
# Builds a URL to generate a wallpaper image from a SMILES structure.
#
@@ -83,8 +90,10 @@ $(document).ready ->
#
buildSmilesUrl = (width, height, foreground, background, smiles) ->
url = "/api/smiles/#{width}/#{height}/#{background}/#{foreground}/#{smiles}"
if customLabel != '' then url += "?label=#{customLabel}"
return url
qs = ""
if customLabel != '' then qs += "label=#{customLabel}"
if rotation != 0 then qs += "rotation=#{rotation}"
return if qs == "" then url else url + "?" + qs
# Builds a URL to generate a molecule-only image from a SMILES structure.
#
@@ -95,8 +104,10 @@ $(document).ready ->
#
buildSmilesMoleculeOnlyUrl = (width, height, foreground, smiles) ->
url = "/api/smiles/#{width}/#{height}/#{foreground}/#{smiles}"
if customLabel != '' then url += "?label=#{customLabel}"
return url
qs = ""
if customLabel != '' then qs += "label=#{customLabel}"
if rotation != 0 then qs += "rotation=#{rotation}"
return if qs == "" then url else url + "?" + qs
# Checks if a compound name can be converted to SMILES using the configured database.
#
@@ -153,7 +164,8 @@ $(document).ready ->
params = {
'label': customLabel,
'background': backgroundColor,
'foreground': foregroundColor
'foreground': foregroundColor,
'rotation': rotation
}
if smilesMode
params['smiles'] = currentCompoundSmiles
@@ -180,16 +192,16 @@ $(document).ready ->
refreshPreviewCompoundName = ->
currentCompoundName = getCompoundName()
smilesMode = false
url = buildMoleculeOnlyUrl screenWidth, screenHeight, foregroundColor, currentCompoundName
updatePreview previewElement, url, backgroundColor
url = buildMoleculeOnlyUrl screenWidth, screenHeight, foregroundColor, currentCompoundName, rotation
updatePreview previewElement, url, backgroundColor, rotation
# Refreshes the preview using the SMILES structure text box.
#
refreshPreviewSmiles = ->
currentCompoundSmiles = getCompoundSmiles()
smilesMode = true
url = buildSmilesMoleculeOnlyUrl screenWidth, screenHeight, foregroundColor, currentCompoundSmiles
updatePreview previewElement, url, backgroundColor
url = buildSmilesMoleculeOnlyUrl screenWidth, screenHeight, foregroundColor, currentCompoundSmiles, rotation
updatePreview previewElement, url, backgroundColor, rotation
# Refreshes the preview using the compound name or SMILES structure text box depending on mode.
#
@@ -205,7 +217,7 @@ $(document).ready ->
backgroundColor = passedBackground
# Let's initialize the color pickers.
$('.picker-fg').spectrum
color: "##{foregroundColor}"
clickoutFiresChange: true
@@ -219,7 +231,7 @@ $(document).ready ->
preferredFormat: 'hex'
# Set up color picker change events.
$('.picker-fg').on 'change', (e) ->
foregroundColor = $(e.target).val().substring(1)
modeAwareRefreshPreview()
@@ -227,9 +239,28 @@ $(document).ready ->
$('.picker-bg').on 'change', (e) ->
backgroundColor = $(e.target).val().substring(1)
modeAwareRefreshPreview()
# Set up the rotation knob.
rotationKnob = pureknob.createKnob(88, 88)
rotationKnob.setProperty 'angleStart', 0
rotationKnob.setProperty 'angleEnd', Math.PI * 2
rotationKnob.setProperty 'colorFG', '#C0C0C0'
rotationKnob.setProperty 'colorBG', '#505050'
rotationKnob.setProperty 'trackWidth', 0.4
rotationKnob.setProperty 'valMin', 0
rotationKnob.setProperty 'valMax', 359
rotationKnob.setProperty 'needle', true
rotationKnob.setValue 0
rotationKnob.addListener (knob, value) ->
rotation = value
modeAwareRefreshPreview()
knobNode = rotationKnob.node()
knobElem = document.getElementById 'rotation_knob'
knobElem.appendChild knobNode
# Compound name update button should refresh the preview.
$('.update-btn').on 'click', (e) ->
errorRows.hide()
checkMoleculeName getCompoundName(), refreshPreviewCompoundName, failPreview
@@ -245,7 +276,7 @@ $(document).ready ->
customLabel = getCustomLabel()
modeAwareRefreshPreview()
# Put passed parameter values into text boxes if needed.
# Put passed parameter values into UI if needed.
passedCompoundName = getParameterByName 'compound'
if passedCompoundName != null
@@ -261,11 +292,16 @@ $(document).ready ->
if passedLabel != null
customLabelTextBox.val(passedLabel)
# Grab initial values from text boxes.
passedRotation = getParameterByName 'rotation'
if passedRotation != null
rotationKnob.setValue(passedRotation)
# Grab initial values from UI.
currentCompoundName = compoundTextBox.val()
currentCompoundSmiles = smilesTextBox.val()
customLabel = customLabelTextBox.val()
rotation = rotationKnob.getValue()
# Initial update.
modeAwareRefreshPreview()
+1 -1
View File
@@ -28,7 +28,7 @@
@picker-border: #444;
// Width variables.
@sidebar-width: 250px;
@sidebar-width: 325px;
@width2: 100px;
@full-width: 100%;
+24 -9
View File
@@ -31,6 +31,7 @@
<script type="text/javascript" src="/bower_components/jquery/dist/jquery.min.js"></script>
<script type="text/javascript" src="/bower_components/bootstrap/dist/js/bootstrap.min.js"></script>
<script type="text/javascript" src="/bower_components/spectrum/spectrum.js"></script>
<script type="text/javascript" src="/js-lib/pureknob.js"></script>
<script type="text/javascript" src="/js/params.js"></script>
<script type="text/javascript" src="/js/hamburger.js"></script>
<script type="text/javascript" src="/js/main.js"></script>
@@ -110,24 +111,38 @@
<div class="tool-section mtop-10">
<div class="row">
<div class="col-xs-12">
<div class="section-lbl">Colours</div>
<div class="section-lbl">Colors and Rotation</div>
<hr>
</div>
</div>
<div class="row mtop-10">
<div class="col-xs-6">
<div class="picker-lbl">Molecule:</div>
<div class="col-xs-7">
<div class="row">
<div class="col-xs-6">
<div class="picker-lbl">Molecule:</div>
</div>
<div class="col-xs-6">
<input type="text" class="picker picker-fg">
</div>
</div>
<div class="row">
<div class="col-xs-6">
<div class="picker-lbl">Background:</div>
</div>
<div class="col-xs-6">
<input type="text" class="picker picker-bg">
</div>
</div>
</div>
<div class="col-xs-6">
<input type="text" class="picker picker-fg">
<div class="col-xs-5">
<div id="rotation_knob"></div>
</div>
</div>
</div>
<div class="tool-section mtop-10">
<div class="row mtop-10">
<div class="col-xs-6">
<div class="picker-lbl">Background:</div>
</div>
<div class="col-xs-6">
<input type="text" class="picker picker-bg">
<div id="rotation_knob"></div>
</div>
</div>
</div>
+14 -2
View File
@@ -14,7 +14,7 @@ use Avogadrio\MoleculeRenderer;
$app = new Silex\Application();
// Uncomment the line below while debugging your app.
// $app['debug'] = true;
$app['debug'] = true;
// Load config.
$config = Spyc::YAMLLoad(__DIR__ . '/../config/config.yaml');
@@ -52,6 +52,9 @@ $app->get('/api/smiles/{width}/{height}/{background}/{foreground}/{smiles}',
// Add label.
$moleculeRenderer->setCustomLabel($request->get('label'));
// Add rotation.
$moleculeRenderer->setRotation((float) $request->get('rotation'));
// Render molecule with background.
$image = $moleculeRenderer->renderMoleculeWithBackground($smiles, $foreground, $background, $width, $height);
@@ -68,6 +71,9 @@ $app->get('/api/smiles/{width}/{height}/{color}/{smiles}',
// Add label.
$moleculeRenderer->setCustomLabel($request->get('label'));
// Add rotation.
$moleculeRenderer->setRotation((float) $request->get('rotation'));
// Render molecule only.
$image = $moleculeRenderer->renderScaledMolecule($smiles, $color, $width, $height);
@@ -80,7 +86,7 @@ $app->get('/api/smiles/{width}/{height}/{color}/{smiles}',
*/
$app->get('/api/name/{width}/{height}/{background}/{foreground}/{name}',
function (Request $request, $width, $height, $background, $foreground, $name) use ($app, $moleculeRenderer, $smilesConverter) {
// Convert chemical name to SMILES if we can.
$smiles = $smilesConverter->nameToSmiles($name);
@@ -90,6 +96,9 @@ $app->get('/api/name/{width}/{height}/{background}/{foreground}/{name}',
// Add label.
$moleculeRenderer->setCustomLabel($request->get('label'));
// Add rotation.
$moleculeRenderer->setRotation((float) $request->get('rotation'));
// Render molecule with background.
$image = $moleculeRenderer->renderMoleculeWithBackground($smiles, $foreground, $background, $width, $height);
@@ -116,6 +125,9 @@ $app->get('/api/name/{width}/{height}/{color}/{name}',
// Add label.
$moleculeRenderer->setCustomLabel($request->get('label'));
// Add rotation.
$moleculeRenderer->setRotation((float) $request->get('rotation'));
// Render molecule only.
$image = $moleculeRenderer->renderScaledMolecule($smiles, $color, $width, $height);
File diff suppressed because it is too large Load Diff