From 243fd3e40395dc615b51380fafb11099ebc35416 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?S=C3=A9bastien=20Mischler=20=28aka=20skarab=29?=
 <skarab@bluewin.ch>
Date: Fri, 18 Mar 2016 08:44:53 +0100
Subject: [PATCH] make an clean UI

---
 css/main.css |  56 +++++++++++++-
 index.html   |  24 +++++-
 js/main.js   | 238 ++++++++++++++++++++++++++++++++++++++++++++++++++++-------
 3 files changed, 287 insertions(+), 31 deletions(-)

diff --git a/css/main.css b/css/main.css
index 6b422a6..d44bd8f 100644
--- a/css/main.css
+++ b/css/main.css
@@ -51,10 +51,64 @@
 /* Main */
 #main {
     position: fixed;
-    left: 300px;
+    left: 301px;
+    right: 39px;
+    top: 51px;
+    bottom: 0;
+}
+
+/* Slider */
+#slider {
+    position: fixed;
+    padding: 10px;
+    width: 60px;
     top: 51px;
     bottom: 0;
     right: 0;
+    background-color: #f5f5f5;
+    border-left: 1px solid #eeeeee;
+}
+
+#slider .min,
+#slider .max {
+    padding: 0;
+    height: 20px;
+    display: block;
+    text-align: center;
+}
+
+#slider .max {
+    margin-bottom: 10px;
+}
+
+#slider .min {
+    margin-top: 10px;
+}
+
+#slider .slider {
+    margin-left: 10px;
+}
+
+#slider .slider-handle {
+    border: 1px #cccccc solid;
+    background-color: #ffffff;
+    background-image: -webkit-linear-gradient(top, #eeeeee 0%, #cccccc 100%);
+    background-image: -o-linear-gradient(top, #eeeeee 0%, #cccccc 100%);
+    background-image: linear-gradient(to bottom,#eeeeee 0%, #cccccc 100%);
+    background-repeat: repeat-x;
+    filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#eeeeee', endColorstr='#cccccc', GradientType=0);
+    filter: none;
+}
+
+#slider .slider-track {
+    border: 1px solid #eeeeee;
+}
+
+#slider .slider-track,
+#slider .slider-selection {
+    background-color: #ffffff;
+    background-image: none;
+    filter: none;
 }
 
 /* Button file */
diff --git a/index.html b/index.html
index 8429120..4d1714c 100644
--- a/index.html
+++ b/index.html
@@ -6,6 +6,7 @@
         <meta name="viewport" content="width=device-width, initial-scale=1" />
         <title>SLAcer.js (bêta)</title>
         <link rel="stylesheet" type="text/css" href="vendor/bootstrap/css/bootstrap.min.css" />
+        <link rel="stylesheet" type="text/css" href="vendor/bootstrap-slider/css/bootstrap-slider.min.css" />
         <link rel="stylesheet" type="text/css" href="css/main.css" />
     </head>
     <body>
@@ -61,7 +62,7 @@ <h3 class="panel-title">Mesh</h3>
                             <span class="info-value" id="mesh-faces">0</span>
                         </div>
                         <div class="info">
-                            <span class="info-label">Volume <small>(mm³)</small></span>
+                            <span class="info-label">Volume <small>(ml)</small></span>
                             <span class="info-value" id="mesh-volume">0</span>
                         </div>
                         <div class="info">
@@ -92,7 +93,7 @@ <h3 class="panel-title">Build volume</h3>
                             <input type="number" id="build-volume-z" class="form-control input-sm" placeholder="100" min="0" />
                         </div>
                         <div class="form-group">
-                            <label for="build-volume-unit">unit</small></label>
+                            <label for="build-volume-unit">unit</label>
                             <input type="radio" name="build-volume-unit" id="build-volume-unit-in" value="in" /> in
                             <input type="radio" name="build-volume-unit" id="build-volume-unit-mm" value="mm" checked="checked" /> mm
                         </div>
@@ -135,8 +136,8 @@ <h3 class="panel-title">Screen</h3>
                             <input type="number" id="screen-height" class="form-control input-sm" placeholder="1050" min="0" />
                         </div>
                         <div class="form-group">
-                            <label for="screen-diagonal">Diagonal size</label>
-                            <input type="number" id="screen-diagonal" class="form-control input-sm" placeholder="22" min="0" />
+                            <label for="screen-diagonal-size">Diagonal size</label>
+                            <input type="number" id="screen-diagonal-size" class="form-control input-sm" placeholder="22" min="0" />
                         </div>
                         <div class="form-group">
                             <label for="screen-diagonal-unit">Diagonal unit</label>
@@ -152,11 +153,26 @@ <h3 class="panel-title">Screen</h3>
                 <div id="viewer3d" class="box fl">loading...</div>
             </div><!-- #main -->
 
+            <div id="slider">
+                <span class="max">100</span>
+                <input id="ex4" type="text"
+                    data-slider-min="0"
+                    data-slider-max="100"
+                    data-slider-step="1"
+                    data-slider-value="0"
+                    data-slider-tooltip="always"
+                    data-slider-tooltip-position="left"
+                    data-slider-orientation="vertical" />
+                <span class="min">0</span>
+            </div><!-- #main -->
+
         </div><!-- .body -->
         <script src="vendor/jquery-2.1.4.min.js" type="text/javascript"></script>
         <script src="vendor/bootstrap/js/bootstrap.min.js" type="text/javascript"></script>
+        <script src="vendor/bootstrap-slider/bootstrap-slider.min.js" type="text/javascript"></script>
         <script src="vendor/lodash.min.js" type="text/javascript"></script>
         <script src="vendor/three.min.js" type="text/javascript"></script>
+        <script src="js/slacer/settings.js" type="text/javascript"></script>
         <script src="js/slacer/mesh.js" type="text/javascript"></script>
         <script src="js/slacer/viewer.js" type="text/javascript"></script>
         <script src="vendor/OrbitControls.js" type="text/javascript"></script>
diff --git a/js/main.js b/js/main.js
index 171e223..4f7f259 100644
--- a/js/main.js
+++ b/js/main.js
@@ -1,16 +1,37 @@
 // -----------------------------------------------------------------------------
 // Variables
 // -----------------------------------------------------------------------------
-var meshMaterial = new THREE.MeshPhongMaterial({
-    color: 0xff0000
+var settings = new SLAcer.Settings({
+    buildVolume: {
+        size     : { x: 100,  y: 100,  z: 100 }, // mm
+        unit     : 'mm',                         // mm or in
+        color    : 0xcccccc,
+        opacity  : 0.1,
+        collapsed: false
+    },
+    resin: {
+        density  : 1.1, // g/cm3
+        price    : 50,   // $
+        collapsed: false
+    },
+    viewer3d: {
+        color: 0xffffff
+    },
+    mesh: {
+        color    : 0x333333,
+        collapsed: false
+    },
+    screen: {
+        width    : 1680,
+        height   : 1050,
+        diagonal : { size: 22, unit: 'in' },
+        collapsed: false
+    },
+    file: {
+        collapsed: false
+    }
 });
 
-// -----------------------------------------------------------------------------
-// UI
-// -----------------------------------------------------------------------------
-var $main     = $('#main');
-var $viewer3d = $('#viewer3d');
-
 // -----------------------------------------------------------------------------
 // Error handler
 // -----------------------------------------------------------------------------
@@ -19,25 +40,181 @@ function errorHandler(error) {
 }
 
 // -----------------------------------------------------------------------------
-// 3D viewer
+// Slicer
 // -----------------------------------------------------------------------------
-// 3D viewer instance
-var viewer3d = new SLAcer.Viewer3D({ target: $viewer3d[0] });
-
-// Full screen
-$(window).resize(function(e) {
-    viewer3d.setSize({
-        width : $main.width(),
-        height: $main.height()
-    });
-    viewer3d.render();
-});
-$(window).resize();
+var slicer = new SLAcer.Slicer();
 
 // -----------------------------------------------------------------------------
-// Slicer
+// UI
 // -----------------------------------------------------------------------------
-var slicer = new SLAcer.Slicer();
+// Main container
+var $main = $('#main');
+
+// Viewer 3D
+var $viewer3d = $('#viewer3d');
+var viewer3d  = new SLAcer.Viewer3D({
+    color      : settings.get('viewer3d.color'),
+    buildVolume: settings.get('buildVolume'),
+    target     : $viewer3d[0]
+});
+
+// Slider
+var $sliderInput = $('#slider input');
+
+$sliderInput.slider({ reversed : true }).on('change', function(e) {
+    console.log('slice:', e.value.newValue);
+});
+
+var $sliderElement = $('#slider .slider');
+
+// Init panel
+function initPanel(name) {
+    var id    = _.kebabCase(name);
+    var name  = _.camelCase(name);
+    var $body = $('#' + id + '-body');
+
+    $body.on('hidden.bs.collapse', function () {
+        settings.set(name + '.collapsed', true);
+    });
+
+    $body.on('shown.bs.collapse', function () {
+        settings.set(name + '.collapsed', false);
+    });
+
+    if (settings.get(name + '.collapsed')) {
+        $body.collapse('hide');
+    }
+
+    return $body;
+}
+
+// Unit converter
+function parseUnit(value, unit) {
+    return parseFloat(unit == 'in' ? (value / 25.4) : (value * 25.4));
+}
+
+// File panel
+var $fileBody = initPanel('file');
+
+// Mesh panel
+var $meshBody   = initPanel('mesh');
+var $meshFaces  = $meshBody.find('#mesh-faces');
+var $meshVolume = $meshBody.find('#mesh-volume');
+var $meshWeight = $meshBody.find('#mesh-weight');
+
+function updateMeshInfoUI(mesh) {
+    $meshFaces.html(mesh.geometry.faces.length);
+    $meshVolume.html(parseInt(mesh.getVolume() / 1000)); // cm3/ml
+    $meshWeight.html(0);
+}
+
+// Build volume panel
+var $buildVolumeBody = initPanel('buildVolume');
+var $buildVolumeX    = $buildVolumeBody.find('#build-volume-x');
+var $buildVolumeY    = $buildVolumeBody.find('#build-volume-y');
+var $buildVolumeZ    = $buildVolumeBody.find('#build-volume-z');
+
+function updateBuildVolumeUI() {
+    var buildVolume = settings.get('buildVolume');
+    $buildVolumeX.val(buildVolume.size.x);
+    $buildVolumeY.val(buildVolume.size.y);
+    $buildVolumeZ.val(buildVolume.size.z);
+}
+
+function updateBuildVolumeSettings() {
+    var unit = $('#build-volume input[type=radio]:checked').val();
+
+    if (unit != settings.get('buildVolume.diagonal.unit')) {
+        var size = settings.get('buildVolume.size');
+        $buildVolumeX.val(parseUnit(size.x, unit));
+        $buildVolumeY.val(parseUnit(size.y, unit));
+        $buildVolumeZ.val(parseUnit(size.z, unit));
+    }
+
+    settings.set('buildVolume', {
+        size: {
+            x: $buildVolumeX.val(),
+            y: $buildVolumeY.val(),
+            z: $buildVolumeZ.val()
+        },
+        unit: unit
+    });
+}
+
+$('#build-volume-unit-' + settings.get('buildVolume.unit')).prop('checked', true);
+$('#build-volume input[type=radio]').on('change', updateBuildVolumeSettings);
+$('#build-volume input').on('input', updateBuildVolumeSettings);
+updateBuildVolumeUI();
+
+// Resin panel
+var $resinBody    = initPanel('resin');
+var $resinPrice   = $resinBody.find('#resin-price');
+var $resinDensity = $resinBody.find('#resin-density');
+
+function updateResinUI() {
+    var resin = settings.get('resin');
+
+    $resinDensity.val(resin.density);
+    $resinPrice.val(resin.price);
+}
+
+function updateResinSettings() {
+    settings.set('resin.price'  , $resinPrice.val());
+    settings.set('resin.density', $resinDensity.val());
+}
+
+$('#resin input').on('input', updateResinSettings);
+updateResinUI();
+
+// Screen
+var $screenBody         = initPanel('screen');
+var $screenWidth        = $screenBody.find('#screen-width');
+var $screenHeight       = $screenBody.find('#screen-height');
+var $screenDiagonalSize = $screenBody.find('#screen-diagonal-size');
+
+function updateScreenUI() {
+    var screen = settings.get('screen');
+
+    $screenWidth.val(screen.width);
+    $screenHeight.val(screen.height);
+    $screenDiagonalSize.val(screen.diagonal.size);
+}
+
+function updateScreenSettings() {
+    var unit = $('#screen input[type=radio]:checked').val();
+
+    if (unit != settings.get('screen.diagonal.unit')) {
+        $screenDiagonalSize.val(
+            parseUnit(settings.get('screen.diagonal.size'), unit)
+        );
+    }
+
+    settings.set('screen', {
+        width   : $screenWidth.val(),
+        height  : $screenHeight.val(),
+        diagonal: {
+            size: $screenDiagonalSize.val(),
+            unit: unit
+        }
+    });
+}
+
+$('#screen-diagonal-unit-' + settings.get('screen.diagonal.unit')).prop('checked', true);
+$('#screen input[type=radio]').on('change', updateScreenSettings);
+$('#screen input').on('input', updateScreenSettings);
+updateScreenUI();
+
+// UI resize
+function resizeUI() {
+    var width  = $main.width();
+    var height = $main.height();
+    $sliderElement.height(height - 80);
+    viewer3d.setSize({ width : width, height: height });
+    viewer3d.render();
+}
+
+$(window).resize(resizeUI);
+resizeUI();
 
 // -----------------------------------------------------------------------------
 // STL loader
@@ -52,14 +229,16 @@ loader.onGeometry = function(geometry) {
         slicer.mesh && viewer3d.removeObject(slicer.mesh);
 
         // load new mesh in slicer
-        slicer.loadMesh(new SLAcer.Mesh(geometry, meshMaterial));
+        slicer.loadMesh(new SLAcer.Mesh(geometry, new THREE.MeshPhongMaterial({
+            color: settings.get('mesh.color')
+        })));
 
         // add new mesh and render view
         viewer3d.addObject(slicer.mesh);
         viewer3d.render();
 
         // update mesh info
-        //updateMeshInfo(mesh1);
+        updateMeshInfoUI(slicer.mesh);
 
         // get first slice
         //slice(0);
@@ -75,10 +254,16 @@ loader.onError = errorHandler;
 // -----------------------------------------------------------------------------
 // load example
 // -----------------------------------------------------------------------------
-var xmlhttp = new XMLHttpRequest();
+// example STL file
 var stl = '/stl/Octocat-v2.stl';
 //var stl = '/stl/StressTest.stl';
+
+// Create http request object
+var xmlhttp = new XMLHttpRequest();
+
+// Get the file contents
 xmlhttp.open("GET", window.location + stl);
+
 xmlhttp.onreadystatechange = function() {
     if (xmlhttp.readyState == XMLHttpRequest.DONE) {
         if(xmlhttp.status == 200){
@@ -88,4 +273,5 @@ xmlhttp.onreadystatechange = function() {
         }
     }
 }
+
 xmlhttp.send();
