diff --git a/Gruntfile.js b/Gruntfile.js index 41b4be6..110852f 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -16,21 +16,22 @@ module.exports = function(grunt) { }, dist: { src: [ - 'www/js/SettingsWindow.js', - 'www/js/d3dServerInterfacing.js', - 'www/js/verticalShapes.js', - 'www/js/buttonbehaviors.js', - 'www/js/canvasDrawing.js', - 'www/js/previewRendering.js', - 'www/js/gcodeGenerating.js', - 'www/js/init_layout.js', - 'www/js/Printer.js', - 'www/js/Progressbar.js', - 'www/js/Thermometer.js', - 'www/js/utils.js', - 'www/js/sidebar.js', - 'www/js/message.js', - 'www/js/main.js' + 'js_src/SettingsWindow.js', + 'js_src/UpdatePanel.js', + 'js_src/d3dServerInterfacing.js', + 'js_src/verticalShapes.js', + 'js_src/buttonbehaviors.js', + 'js_src/canvasDrawing.js', + 'js_src/previewRendering.js', + 'js_src/gcodeGenerating.js', + 'js_src/init_layout.js', + 'js_src/Printer.js', + 'js_src/Progressbar.js', + 'js_src/Thermometer.js', + 'js_src/utils.js', + 'js_src/sidebar.js', + 'js_src/Message.js', + 'js_src/main.js' ], dest: 'www/js/<%= pkg.name %>.js' } @@ -38,15 +39,21 @@ module.exports = function(grunt) { uglify: { options: { // banner: '/*! <%= pkg.name %> <%= grunt.template.today("yyyy-mm-dd") %> */\n', - mangle: false, + mangle: true, beautify: false, compress: {}, report: 'min', preserveComments: 'false' }, build: { - src: ['www/js/*.js', '!www/js/<%= pkg.name %>.min.js'], - dest: 'www/js/<%= pkg.name %>.min.js' + files: { +// 'www/js/<%= pkg.name %>.min.js' : ['www/js/*.js', '!www/js/<%= pkg.name %>.min.js', '!www/js/<%= pkg.name %>.js'] + 'www/js/<%= pkg.name %>.min.js' : ['www/js/<%= pkg.name %>.js'] + } +// src: 'www/js/*.js', +// dest: 'www/js/min/blabla.js' +// src: ['www/js/*.js', '!www/js/<%= pkg.name %>.min.js'], +// dest: 'www/js/<%= pkg.name %>.min.js' } }, jshint: { @@ -85,11 +92,11 @@ module.exports = function(grunt) { } }, watch: { -// javascript: { -// files: ["www/js/*", '!www/js/*.min.js'], -// // tasks: ["less", "css_prefix"] -// tasks: ["uglify"] -// }, + javascript: { + files: ["js_src/*", '!www/js/<%= pkg.name %>.min.js', '!www/js/<%= pkg.name %>.js'], + tasks: ["concat", "uglify"] +// tasks: ["jshint", "concat", "uglify"] + }, styles: { files: ["less/*"], tasks: ["less", "autoprefixer", "cssmin"] @@ -133,8 +140,8 @@ module.exports = function(grunt) { 'less', 'autoprefixer', 'cssmin', -// 'concat', -// 'uglify', + 'concat', + 'uglify', // 'jshint', 'watch' ]); diff --git a/www/js/Message.js b/js_src/Message.js similarity index 100% rename from www/js/Message.js rename to js_src/Message.js diff --git a/www/js/Printer.js b/js_src/Printer.js similarity index 100% rename from www/js/Printer.js rename to js_src/Printer.js diff --git a/www/js/Progressbar.js b/js_src/Progressbar.js similarity index 100% rename from www/js/Progressbar.js rename to js_src/Progressbar.js diff --git a/www/js/SettingsWindow.js b/js_src/SettingsWindow.js similarity index 100% rename from www/js/SettingsWindow.js rename to js_src/SettingsWindow.js diff --git a/www/js/Thermometer.js b/js_src/Thermometer.js similarity index 100% rename from www/js/Thermometer.js rename to js_src/Thermometer.js diff --git a/www/js/UpdatePanel.js b/js_src/UpdatePanel.js similarity index 100% rename from www/js/UpdatePanel.js rename to js_src/UpdatePanel.js diff --git a/www/js/buttonbehaviors.js b/js_src/buttonbehaviors.js similarity index 100% rename from www/js/buttonbehaviors.js rename to js_src/buttonbehaviors.js diff --git a/www/js/canvasDrawing.js b/js_src/canvasDrawing.js similarity index 100% rename from www/js/canvasDrawing.js rename to js_src/canvasDrawing.js diff --git a/www/js/d3dServerInterfacing.js b/js_src/d3dServerInterfacing.js similarity index 100% rename from www/js/d3dServerInterfacing.js rename to js_src/d3dServerInterfacing.js diff --git a/www/js/gcodeGenerating.js b/js_src/gcodeGenerating.js similarity index 100% rename from www/js/gcodeGenerating.js rename to js_src/gcodeGenerating.js diff --git a/js_src/init_layout.js b/js_src/init_layout.js new file mode 100644 index 0000000..4191375 --- /dev/null +++ b/js_src/init_layout.js @@ -0,0 +1,62 @@ +// TODO refactor this stuff, there's much to wipe +var drawAreaContainerMinHeight = 300; +var drawAreaContainerMaxHeight = 450; + +function doOnResize() { + // console.log("doOnResize() >> " + new Date().getTime()); + canvas.width = $canvas.width(); + canvas.height = $canvas.height(); // canvas.clientHeight; + + preview.width = $preview.width(); + preview.height = $drawAreaContainer.height(); + + canvasWidth = canvas.width; + canvasHeight = canvas.height; + + console.log(" preview.width: " + preview.width + ", $preview.width(): " + $preview.width()); + + calcPreviewCanvasProperties(); + + drawCanvasTopLeftCoords[0] = drawCanvas.offset().left; + drawCanvasTopLeftCoords[1] = drawCanvas.offset().top; + + redrawDoodle(); + redrawPreview(); + +} + +function initLayouting() { + console.log("f:initLayouting()"); + + $drawAreaContainer = $(".drawareacontainer"); + + canvas.width = $canvas.width(); + canvas.height = $canvas.height(); // canvas.clientHeight; + + preview.width = $preview.width(); + preview.height = $drawAreaContainer.height(); + + canvasWidth = canvas.width; + canvasHeight = canvas.height; + + $drawAreaContainer.show(); + + // window.innerHeight + console.log("window.innerHeight: " + window.innerHeight); + console.log("window.innerWidth: " + window.innerWidth); + console.log("$drawAreaContainer.innerHeight(): " + $drawAreaContainer.innerHeight()); + console.log("$drawAreaContainer.offset().top: " + $drawAreaContainer.offset().top); + + // timeout because it SEEMS to be beneficial for initting the layout + // 2013-09-18 seems beneficial since when? + setTimeout(_startOrientationAndChangeEventListening, 1000); +} + +function _startOrientationAndChangeEventListening() { + // Initial execution if needed + + $(window).on('resize', doOnResize); + + // is it necessary to call these? Aren't they called by the above eventhandlers? + doOnResize(); +} diff --git a/www/js/main.js b/js_src/main.js similarity index 99% rename from www/js/main.js rename to js_src/main.js index fc7ad01..3717a01 100644 --- a/www/js/main.js +++ b/js_src/main.js @@ -17,6 +17,9 @@ var wifiboxCGIBinURL; // CGI-bin, for some network stuff, where it needs to rest var $drawAreaContainer, $doodleCanvas, doodleCanvas, doodleCanvasContext, $previewContainer; +var showhideInterval; +var showOrHide = false; + $(function() { console.log("ready"); @@ -103,9 +106,6 @@ $(function() { } }); -var showhideInterval; -var showOrHide = false; - function showOrHideThermo() { console.log("f:showOrHideThermo()"); if (showOrHide) { diff --git a/www/js/previewRendering.js b/js_src/previewRendering.js similarity index 100% rename from www/js/previewRendering.js rename to js_src/previewRendering.js diff --git a/www/js/sidebar.js b/js_src/sidebar.js similarity index 100% rename from www/js/sidebar.js rename to js_src/sidebar.js diff --git a/www/js/utils.js b/js_src/utils.js similarity index 100% rename from www/js/utils.js rename to js_src/utils.js diff --git a/www/js/verticalShapes.js b/js_src/verticalShapes.js similarity index 100% rename from www/js/verticalShapes.js rename to js_src/verticalShapes.js diff --git a/package.json b/package.json index a0f7f1b..b224a64 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "name": "doodle3dclient", + "name": "doodle3d-client", "version": "0.9.0", "description": "Doodle3D client app", "repository": { diff --git a/www/index.html b/www/index.html index 1b79cea..021e822 100755 --- a/www/index.html +++ b/www/index.html @@ -130,22 +130,24 @@ - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/www/js/doodle3d-client.js b/www/js/doodle3d-client.js new file mode 100644 index 0000000..d36ffa0 --- /dev/null +++ b/www/js/doodle3d-client.js @@ -0,0 +1,3392 @@ +//these settings are defined in the firmware (conf_defaults.lua) and will be initialized in loadSettings() +var settings = { +"network.ap.ssid": "d3d-ap-%%MAC_ADDR_TAIL%%", +"network.ap.address": "192.168.10.1", +"network.ap.netmask": "255.255.255.0", +"printer.temperature": 220, +"printer.maxObjectHeight": 150, +"printer.layerHeight": 0.2, +"printer.wallThickness": 0.7, +"printer.screenToMillimeterScale": 0.3, +"printer.speed": 50, +"printer.travelSpeed": 200, +"printer.filamentThickness": 2.85, +"printer.enableTraveling": true, +"printer.useSubLayers": true, +"printer.firstLayerSlow": true, +"printer.autoWarmUp": true, +"printer.simplify.iterations": 10, +"printer.simplify.minNumPoints": 15, +"printer.simplify.minDistance": 3, +"printer.retraction.enabled": true, +"printer.retraction.speed": 50, +"printer.retraction.minDistance": 1, +"printer.retraction.amount": 5, +"printer.autoWarmUpCommand": "M104 S220 (hardcoded temperature)" +} + + +function SettingsWindow() { + this.wifiboxURL; + this.wifiboxCGIBinURL + this.window; + this.form; + this.timeoutTime = 3000; + this.retryDelay = 2000; // retry setTimout delay + this.retryRetrieveNetworkStatusDelayTime = 1000;// retry setTimout delay + + this.retryLoadSettingsDelay; // retry setTimout instance + this.retrySaveSettingsDelay; // retry setTimout instance + this.retryRetrieveNetworkStatusDelay;// retry setTimout instance + + + this.apFieldSet; + this.clientFieldSet; + this.networks; + this.currentNetwork; // the ssid of the network the box is on + this.selectedNetwork; // the ssid of the selected network in the client mode settings + this.currentLocalIP = ""; + this.clientModeState = SettingsWindow.NOT_CONNECTED; + this.currentAP; + this.apModeState = SettingsWindow.NO_AP; + + // after switching wifi network or creating a access point we delay the status retrieval + // because the webserver needs time to switch + this.retrieveNetworkStatusDelay; // setTimout delay + this.retrieveNetworkStatusDelayTime = 1000; + + // Events + SettingsWindow.SETTINGS_LOADED = "settingsLoaded"; + + // network client mode states + SettingsWindow.NOT_CONNECTED = "not connected"; // also used as first item in networks list + SettingsWindow.CONNECTED = "connected"; + SettingsWindow.CONNECTING = "connecting"; + SettingsWindow.CONNECTING_FAILED = "connecting failed" + + // network access point mode states + SettingsWindow.NO_AP = "no ap"; + SettingsWindow.AP = "ap"; + SettingsWindow.CREATING_AP = "creating ap"; + + SettingsWindow.API_CONNECTING_FAILED = -1 + SettingsWindow.API_NOT_CONNECTED = 0 + SettingsWindow.API_CONNECTING = 1 + SettingsWindow.API_CONNECTED = 2 + SettingsWindow.API_CREATING = 3 + SettingsWindow.API_CREATED = 4 + + // network mode + SettingsWindow.NETWORK_MODE_NEITHER = "neither"; + SettingsWindow.NETWORK_MODE_CLIENT = "clientMode"; + SettingsWindow.NETWORK_MODE_ACCESS_POINT = "accessPointMode"; + + this.networkMode = SettingsWindow.NETWORK_MODE_NEITHER; + + this.updatePanel = new UpdatePanel(); + + var self = this; + + this.init = function(wifiboxURL,wifiboxCGIBinURL) { + this.wifiboxURL = wifiboxURL; + this.wifiboxCGIBinURL = wifiboxCGIBinURL; + + this.window = $("#settings"); + this.window.find(".btnOK").click(this.submitwindow); + this.window.find(".settingsContainer").load("settings.html", function() { + console.log("Settings:finished loading settings.html, now loading settings..."); + + self.form = self.window.find("form"); + self.form.submit(function (e) { self.submitwindow(e) }); + + self.loadSettings(); + + var btnAP = self.form.find("label[for='ap']"); + var btnClient = self.form.find("label[for='client']"); + var btnRefresh = self.form.find("#refreshNetworks"); + var btnConnect = self.form.find("#connectToNetwork"); + var btnCreate = self.form.find("#createAP"); + var networkSelector = self.form.find("#network"); + self.apFieldSet = self.form.find("#apSettings"); + self.clientFieldSet = self.form.find("#clientSettings"); + + btnAP.on('touchstart mousedown',self.showAPSettings); + btnClient.on('touchstart mousedown',self.showClientSettings); + btnRefresh.on('touchstart mousedown',self.refreshNetworks); + btnConnect.on('touchstart mousedown',self.connectToNetwork); + btnCreate.on('touchstart mousedown',self.createAP); + networkSelector.change(self.networkSelectorChanged); + + // update panel + var $updatePanelElement = self.form.find("#updatePanel"); + self.updatePanel.init(wifiboxURL,$updatePanelElement); + }); + } + this.submitwindow = function(e) { + e.preventDefault(); + e.stopPropagation(); + self.saveSettings(self.readForm(),function(){ + self.hideSettings(); + }); + + clearTimeout(self.retryRetrieveNetworkStatusDelay); + } + + this.showSettings = function() { + console.log("f:showSettings()"); + + this.loadSettings(); // reload settings +// this.window.css("display","table"); + $("#contentOverlay").fadeIn(375, function() { + document.body.removeEventListener('touchmove',prevent,false); + }); + } + this.hideSettings = function() { + $("#contentOverlay").fadeOut(375, function() { + document.body.addEventListener('touchmove',prevent,false); +// self.window.css("display","none"); + }); + } + + this.loadSettings = function() { + if (!communicateWithWifibox) { + console.log(" communicateWithWifibox is false: settings aren't being loaded from wifibox...") + return; + } + console.log("Settings:loadSettings() >> getting new data..."); + + $.ajax({ + url: this.wifiboxURL + "/config/all", + dataType: 'json', + timeout: this.timeoutTime, + success: function(response){ + console.log("Settings:loadSettings response: ",response); + settings = response.data; + console.log(" settings: ",settings); + self.fillForm(); + $(document).trigger(SettingsWindow.SETTINGS_LOADED); + } + }).fail(function() { + console.log("Settings:loadSettings: failed"); + clearTimeout(self.retryLoadSettingsDelay); + self.retryLoadSettingsDelay = setTimeout(function() { self.loadSettings() },self.retryDelay); // retry after delay + }); + + this.refreshNetworks(); + this.retrieveNetworkStatus(false); + } + this.fillForm = function() { + console.log("SettingsWindow:fillForm"); + + //fill form with loaded settings + var selects = this.form.find("select"); + selects.each( function(index,element) { + var element = $(element); + element.val(settings[element.attr('name')]); + }); + var inputs = this.form.find("input"); + inputs.each( function(index,element) { + var element = $(element); + //console.log("printer setting input: ",index,element.attr("type"),element.attr('name')); //,element); + switch(element.attr("type")) { + case "text": + case "number": + element.val(settings[element.attr('name')]); + break; + case "checkbox": + element.prop('checked', settings[element.attr('name')]); + break; + } + }); + var textareas = this.form.find("textarea"); + textareas.each( function(index,element) { + var element = $(element); + var value = settings[element.attr('name')]; + element.val(value); + }); + } + + this.saveSettings = function(newSettings,complete) { + settings = newSettings; // store new settings in global settings + if (communicateWithWifibox) { + $.ajax({ + url: this.wifiboxURL + "/config", + type: "POST", + data: newSettings, + dataType: 'json', + timeout: this.timeoutTime, + success: function(response){ + console.log("Settings:saveSettings response: ",response); + if(response.status == "error") { + clearTimeout(self.retrySaveSettingsDelay); + self.retrySaveSettingsDelay = setTimeout(function() { self.saveSettings(settings) },self.retryDelay); // retry after delay + } else { + var data = response.data; + var validation = data.validation; + self.clearValidationErrors(); + var validated = true; + $.each(validation, function(key, val) { + if (val != "ok") { + console.log("ERROR: setting '" + key + "' not successfully set. Message: " + val); + self.displayValidationError(key,val); + validated = false; + } + }); + settings.substituted_ssid = data.substituted_ssid; + if(complete && validated) complete(); + } + } + }).fail(function() { + console.log("Settings:saveSettings: failed"); + clearTimeout(self.retrySaveSettingsDelay); + self.retrySaveSettingsDelay = setTimeout(function() { self.saveSettings(settings) },self.retryDelay); // retry after delay + }); + } + } + this.displayValidationError = function(key,msg) { + var formElement = self.form.find("[name|='"+key+"']"); + console.log("formElement: ",formElement); + formElement.addClass("error"); + var errorMsg = "

"+msg+"

" + formElement.after(errorMsg); + } + this.clearValidationErrors = function() { + var formElements = self.form.find(".error"); + formElements.each( function(index,element) { + $(element).removeClass("error"); + }); + } + + this.readForm = function() { + //console.log("SettingsWindow:readForm"); + var settings = {}; + var selects = self.form.find("select"); + selects.each( function(index,element) { + var element = $(element); + if(element.attr('name') != "network.client.network") { + settings[element.attr('name')] = element.val(); + } + }); + + var inputs = self.form.find("input"); + inputs.each( function(index,element) { + var element = $(element); + switch(element.attr("type")) { + case "text": + case "number": + settings[element.attr('name')] = element.val(); + break; + case "checkbox": + settings[element.attr('name')] = element.prop('checked') + break; + } + }); + + var textareas = self.form.find("textarea"); + textareas.each( function(index,element) { + var element = $(element); + settings[element.attr('name')] = element.val(); + }); + //console.log(settings); + return settings; + } + + /* + * Networks ui + */ + this.showAPSettings = function() { + self.apFieldSet.show(); + self.clientFieldSet.hide(); + } + this.showClientSettings = function() { + self.clientFieldSet.show(); + self.apFieldSet.hide(); + } + this.refreshNetworks = function() { + console.log("Settings:refreshNetworks"); + + if (communicateWithWifibox) { + $.ajax({ + url: self.wifiboxURL + "/network/scan", + type: "GET", + dataType: 'json', + timeout: self.timeoutTime, + success: function(response){ + console.log("Settings:refreshNetworks response: ",response); + if(response.status == "error") { + //clearTimeout(self.retrySaveSettingsDelay); + //self.retrySaveSettingsDelay = setTimeout(function() { self.saveSettings() },self.retryDelay); // retry after delay + } else { + var networks = response.data.networks + self.networks = {}; + var foundCurrentNetwork = false; + var networkSelector = self.form.find("#network"); + networkSelector.empty(); + networkSelector.append( + $("").val(SettingsWindow.NOT_CONNECTED).html("not connected") + ); + $.each(networks, function(index,element) { + if(element.ssid == self.currentNetwork) { + foundCurrentNetwork = true; + } + networkSelector.append( + $("").val(element.ssid).html(element.ssid) + ); + self.networks[element.ssid] = element; + }); + if(foundCurrentNetwork) { + networkSelector.val(self.currentNetwork); + self.selectNetwork(self.currentNetwork); + } + } + } + }).fail(function() { + + }); + } + } + + this.retrieveNetworkStatus = function(connecting) { + //console.log("Settings:retrieveNetworkStatus"); + if (communicateWithWifibox) { + $.ajax({ + url: self.wifiboxURL + "/network/status", + type: "GET", + dataType: 'json', + timeout: self.timeoutTime, + success: function(response){ + console.log("Settings:retrieveNetworkStatus response: ",response); + if(response.status == "error") { + + } else { + var data = response.data; + + if(typeof data.status === 'string') { + data.status = parseInt(data.status); + } + //console.log(" data.status: ",data.status,data.statusMessage); + + // Determine which network settings to show + switch(data.status) { + case SettingsWindow.API_NOT_CONNECTED: + //console.log(" not connected & not a access point"); + self.apFieldSet.show(); + self.clientFieldSet.show(); + + self.networkMode = SettingsWindow.NETWORK_MODE_NEITHER; + break; + case SettingsWindow.API_CONNECTING_FAILED: + case SettingsWindow.API_CONNECTING: + case SettingsWindow.API_CONNECTED: + //console.log(" client mode"); + self.form.find("#client").prop('checked',true); + + self.apFieldSet.hide(); + self.clientFieldSet.show(); + + if(data.status == SettingsWindow.API_CONNECTED) { + var networkSelector = self.form.find("#network"); + networkSelector.val(data.ssid); + + self.currentNetwork = data.ssid; + self.currentLocalIP = data.localip; + self.selectNetwork(data.ssid); + } else { + self.currentLocalIP = "" + } + self.networkMode = SettingsWindow.NETWORK_MODE_CLIENT; + break; + case SettingsWindow.API_CREATING: + case SettingsWindow.API_CREATED: + //console.log(" access point mode"); + self.form.find("#ap").prop('checked',true); + + self.apFieldSet.show(); + self.clientFieldSet.hide(); + + self.currentNetwork = undefined; + self.selectNetwork(SettingsWindow.NOT_CONNECTED); + var networkSelector = self.form.find("#network"); + networkSelector.val(SettingsWindow.NOT_CONNECTED); + + if(data.ssid && data.status == SettingsWindow.API_CREATED) { + self.currentAP = data.ssid; + } + self.networkMode = SettingsWindow.NETWORK_MODE_ACCESS_POINT; + break; + } + self.updatePanel.setNetworkMode(self.networkMode); + + // update status message + switch(data.status) { + case SettingsWindow.API_CONNECTING_FAILED: + self.setClientModeState(SettingsWindow.CONNECTING_FAILED,data.statusMessage); + self.setAPModeState(SettingsWindow.NO_AP,""); + break; + case SettingsWindow.API_NOT_CONNECTED: + self.setClientModeState(SettingsWindow.NOT_CONNECTED,""); + self.setAPModeState(SettingsWindow.NO_AP,""); + break; + case SettingsWindow.API_CONNECTING: + self.setClientModeState(SettingsWindow.CONNECTING,""); + self.setAPModeState(SettingsWindow.NO_AP,""); + break; + case SettingsWindow.API_CONNECTED: + self.setClientModeState(SettingsWindow.CONNECTED,""); + self.setAPModeState(SettingsWindow.NO_AP,""); + break; + case SettingsWindow.API_CREATING: + self.setClientModeState(SettingsWindow.NOT_CONNECTED,""); + self.setAPModeState(SettingsWindow.CREATING_AP,""); + break; + case SettingsWindow.API_CREATED: + self.setClientModeState(SettingsWindow.NOT_CONNECTED,""); + self.setAPModeState(SettingsWindow.AP,""); + break; + } + + // Keep checking for updates? + if(connecting) { + switch(data.status) { + case SettingsWindow.API_CONNECTING: + case SettingsWindow.API_CREATING: + clearTimeout(self.retryRetrieveNetworkStatusDelay); + self.retryRetrieveNetworkStatusDelay = setTimeout(function() { self.retrieveNetworkStatus(connecting) },self.retryRetrieveNetworkStatusDelayTime); // retry after delay + break; + } + } + } + } + }).fail(function() { + console.log("Settings:retrieveNetworkStatus: failed"); + clearTimeout(self.retryRetrieveNetworkStatusDelay); + self.retryRetrieveNetworkStatusDelay = setTimeout(function() { self.retrieveNetworkStatus(connecting) },self.retryDelay); // retry after delay + }); + } + } + + this.networkSelectorChanged = function(e) { + var selectedOption = $(this).find("option:selected"); + self.selectNetwork(selectedOption.val()); + } + + this.selectNetwork = function(ssid) { + console.log("select network: ",ssid); + if(ssid == "") return; + console.log(" checked"); + this.selectedNetwork = ssid; + if(this.networks == undefined || ssid == SettingsWindow.NOT_CONNECTED) { + this.hideWiFiPassword(); + } else { + var network = this.networks[ssid]; + if(network.encryption == "none") { + this.hideWiFiPassword(); + } else { + this.showWiFiPassword(); + } + this.form.find("#password").val(""); + } + } + this.showWiFiPassword = function() { + this.form.find("#passwordLabel").show(); + this.form.find("#password").show(); + } + this.hideWiFiPassword = function() { + this.form.find("#passwordLabel").hide(); + this.form.find("#password").hide(); + } + + this.setClientModeState = function(state,msg) { + var field = this.form.find("#clientModeState"); + var btnConnect = self.form.find("#connectToNetwork"); + switch(state) { + case SettingsWindow.NOT_CONNECTED: + btnConnect.removeAttr("disabled"); + field.html("Not connected"); + break; + case SettingsWindow.CONNECTED: + btnConnect.removeAttr("disabled"); + + var fieldText = "Connected to: "+this.currentNetwork+"."; + if(this.currentLocalIP != undefined && this.currentLocalIP != "") { + var a = ""+this.currentLocalIP+""; + fieldText += " (IP: "+a+")"; + } + field.html(fieldText); + break; + case SettingsWindow.CONNECTING: + btnConnect.attr("disabled", true); + field.html("Connecting... Reconnect by connecting your device to "+this.selectedNetwork+" and going to connect.doodle3d.com"); + break; + case SettingsWindow.CONNECTING_FAILED: + btnConnect.removeAttr("disabled"); + field.html(msg); + break; + } + this.clientModeState = state; + } + this.setAPModeState = function(state,msg) { + var field = this.form.find("#apModeState"); + var btnCreate = this.form.find("#createAP"); + switch(state) { + case SettingsWindow.NO_AP: + btnCreate.removeAttr("disabled"); + field.html("Not currently a access point"); + break; + case SettingsWindow.AP: + btnCreate.removeAttr("disabled"); + field.html("Is access point: "+this.currentAP+""); + break; + case SettingsWindow.CREATING_AP: + btnCreate.attr("disabled", true); + field.html("Creating access point... Reconnect by connecting your device to "+settings.substituted_ssid+" and going to draw.doodle3d.com"); + break; + } + this.apModeState = state; + } + + this.connectToNetwork = function() { + console.log("connectToNetwork"); + if(self.selectedNetwork == undefined) return; + var postData = { + ssid:self.selectedNetwork, + phrase:self.form.find("#password").val(), + recreate:true + } + console.log(" postData: ",postData); + if (communicateWithWifibox) { + + // save network related settings and on complete, connect to network + self.saveSettings(self.readForm(),function() { + + $.ajax({ + url: self.wifiboxCGIBinURL + "/network/associate", + type: "POST", + data: postData, + dataType: 'json', + timeout: self.timeoutTime, + success: function(response){ + console.log("Settings:connectToNetwork response: ",response); + } + }).fail(function() { + console.log("Settings:connectToNetwork: timeout (normal behavior)"); + //clearTimeout(self.retrySaveSettingsDelay); + //self.retrySaveSettingsDelay = setTimeout(function() { self.saveSettings() },self.retryDelay); // retry after delay + }); + }); + } + self.setClientModeState(SettingsWindow.CONNECTING,""); + + // after switching wifi network or creating a access point we delay the status retrieval + // because the webserver needs time to switch + clearTimeout(self.retrieveNetworkStatusDelay); + self.retrieveNetworkStatusDelay = setTimeout(function() { self.retrieveNetworkStatus(true) },self.retrieveNetworkStatusDelayTime); + } + + this.createAP = function() { + console.log("createAP"); + if (communicateWithWifibox) { + + // save network related settings and on complete, create access point + self.saveSettings(self.readForm(),function() { + self.setAPModeState(SettingsWindow.CREATING_AP); // get latest substituted ssid + $.ajax({ + url: self.wifiboxCGIBinURL + "/network/openap", + type: "POST", + dataType: 'json', + timeout: self.timeoutTime, + success: function(response){ + console.log("Settings:createAP response: ",response); + } + }).fail(function() { + console.log("Settings:createAP: timeout (normal behavior)"); + //clearTimeout(self.retrySaveSettingsDelay); + //self.retrySaveSettingsDelay = setTimeout(function() { self.saveSettings() },self.retryDelay); // retry after delay + }); + + self.setAPModeState(SettingsWindow.CREATING_AP,""); + + // after switching wifi network or creating a access point we delay the status retrieval + // because the webserver needs time to switch + clearTimeout(self.retrieveNetworkStatusDelay); + self.retrieveNetworkStatusDelay = setTimeout(function() { self.retrieveNetworkStatus(true) },self.retrieveNetworkStatusDelayTime); + }); + } + } +} + +/************************* + * + * + * FROM DOODLE3D.INI + * + */ +//TODO: find all references to these variables, replace them and finally remove these. +var objectHeight = 20; +var layerHeight = .2; +//var wallThickness = .5; +//var hop = 0; +//var speed = 70; +//var travelSpeed = 200; +var enableTraveling = true; +//var filamentThickness = 2.89; +var minScale = .3; +var maxScale = 1; +var shape = "%"; +var twists = 0; +//var useSubLayers = true; +//var debug = false; // debug moved to main.js +var loglevel = 2; +//var zOffset = 0; +var serverport = 8888; +var autoLoadImage = "hand.txt"; +var loadOffset = [0, 0]; // x en y ? +var showWarmUp = true; +var loopAlways = false; +var firstLayerSlow = true; +var useSubpathColors = false; +var autoWarmUp = true; +//var maxObjectHeight = 150; +var maxScaleDifference = .1; +var frameRate = 60; +var quitOnEscape = true; +var screenToMillimeterScale = .3; // 0.3 +//var targetTemperature = 220; +//var simplifyiterations = 10; +//var simplifyminNumPoints = 15; +//var simplifyminDistance = 3; +//var retractionspeed = 50; +//var retractionminDistance = 5; +//var retractionamount = 3; +var sideis3D = true; +var sidevisible = true; +var sidebounds = [900, 210, 131, 390]; +var sideborder = [880, 169, 2, 471]; +var windowbounds = [0, 0, 800, 500]; +var windowcenter = true; +var windowfullscreen = false; +var autoWarmUpCommand = "M104 S230"; +//var checkTemperatureInterval = 3; +var autoWarmUpDelay = 3; + +function UpdatePanel() { + this.wifiboxURL; + this.element; + + this.statusCheckInterval = 1000; + this.statusCheckDelayer; // setTimout instance + this.installedDelay = 60*1000; // Since we can't retrieve status during installation we show the installed text after a fixed delay + this.installedDelayer; // setTimout instance + this.retryDelay = 1000; + this.retryDelayer; // setTimout instance + //this.timeoutTime = 3000; + + this.canUpdate = false; + this.currentVersion = ""; + this.newestVersion; + this.progress; + this.imageSize; + + // states from api, see Doodle3D firmware src/script/d3d-updater.lua + UpdatePanel.NONE = 1; // default state + UpdatePanel.DOWNLOADING = 2; + UpdatePanel.DOWNLOAD_FAILED = 3; + UpdatePanel.IMAGE_READY = 4; // download successfull and checked + UpdatePanel.INSTALLING = 5; + UpdatePanel.INSTALLED = 6; + UpdatePanel.INSTALL_FAILED = 7; + + this.state; // update state from api + this.stateText = ""; // update state text from api + + this.networkMode; // network modes from SettingsWindow + + var self = this; + + this.init = function(wifiboxURL,updatePanelElement) { + + this.wifiboxURL = wifiboxURL; + + this.element = updatePanelElement; + this.btnUpdate = this.element.find("#update"); + this.statusDisplay = this.element.find("#updateState"); + this.infoDisplay = this.element.find("#updateInfo"); + + this.btnUpdate.click(this.update); + + this.checkStatus(false); + } + + this.update = function() { + console.log("UpdatePanel:update"); + self.downloadUpdate(); + } + this.downloadUpdate = function() { + console.log("UpdatePanel:downloadUpdate"); + $.ajax({ + url: self.wifiboxURL + "/update/download", + type: "POST", + dataType: 'json', + success: function(response){ + console.log("UpdatePanel:downloadUpdate response: ",response); + } + }).fail(function() { + console.log("UpdatePanel:downloadUpdate: failed"); + }); + self.setState(UpdatePanel.DOWNLOADING); + self.startCheckingStatus(); + } + this.installUpdate = function() { + console.log("UpdatePanel:installUpdate"); + self.stopCheckingStatus(); + $.ajax({ + url: self.wifiboxURL + "/update/install", + type: "POST", + dataType: 'json', + success: function(response){ + console.log("UpdatePanel:installUpdate response: ",response); + } + }).fail(function() { + console.log("UpdatePanel:installUpdate: no respons (there shouldn't be)"); + }); + self.setState(UpdatePanel.INSTALLING); + + clearTimeout(self.installedDelayer); + self.installedDelayer = setTimeout(function() { self.setState(UpdatePanel.INSTALLED) },self.installedDelay); + } + + this.startCheckingStatus = function() { + clearTimeout(self.statusCheckDelayer); + clearTimeout(self.retryDelayer); + self.statusCheckDelayer = setTimeout(function() { self.checkStatus(true) },self.statusCheckInterval); + } + this.stopCheckingStatus = function() { + clearTimeout(self.statusCheckDelayer); + clearTimeout(self.retryDelayer); + } + this.checkStatus = function(keepChecking) { + if (!communicateWithWifibox) return; + $.ajax({ + url: self.wifiboxURL + "/update/status", + type: "GET", + dataType: 'json', + //timeout: self.timeoutTime, + success: function(response){ + console.log("UpdatePanel:checkStatus response: ",response); + + // Keep checking ? + if(keepChecking) { + switch(self.state){ + case UpdatePanel.DOWNLOADING: + case UpdatePanel.INSTALLING: + clearTimeout(self.statusCheckDelayer); + self.statusCheckDelayer = setTimeout(function() { self.checkStatus(keepChecking) },self.statusCheckInterval); + break; + } + } + + if(response.status != "error") { + var data = response.data; + self.handleStatusData(data); + } + } + }).fail(function() { + //console.log("UpdatePanel:checkStatus: failed"); + if(keepChecking) { + clearTimeout(self.retryDelayer); + self.retryDelayer = setTimeout(function() { self.checkStatus(keepChecking) },self.retryDelay); // retry after delay + } + }); + } + + this.handleStatusData = function(data) { + //console.log("UpdatePanel:handleStatusData"); + self.canUpdate = data.can_update; + + if(self.currentVersion != data.current_version || self.newestVersion != data.newest_version) { + self.currentVersion = data.current_version; + self.newestVersion = data.newest_version; + self.updateInfoDisplay(); + } + + self.stateText = data.state_text; + self.progress = data.progress; // not always available + self.imageSize = data.image_size; // not always available + + self.setState(data.state_code); + + switch(this.state){ + case UpdatePanel.IMAGE_READY: + self.installUpdate(); + break; + } + } + this.setState = function(newState) { + if(this.state == newState) return; + console.log("UpdatePanel:setState: ",this.state," > ",newState,"(",this.stateText,") (networkMode: ",self.networkMode,") (newestVersion: ",self.newestVersion,")"); + this.state = newState; + + // download button + // if there isn't newestVersion data something went wrong, + // probably accessing the internet + if(self.newestVersion != undefined) { + switch(this.state){ + case UpdatePanel.NONE: + case UpdatePanel.DOWNLOAD_FAILED: + case UpdatePanel.INSTALL_FAILED: + if(self.canUpdate) { + self.btnUpdate.removeAttr("disabled"); + } else { + self.btnUpdate.attr("disabled", true); + } + break; + default: + self.btnUpdate.attr("disabled", true); + break; + } + } else { + self.btnUpdate.attr("disabled", true); + } + this.updateStatusDisplay(); + } + this.updateStatusDisplay = function() { + var text = ""; + if(self.newestVersion != undefined) { + switch(this.state){ + case UpdatePanel.NONE: + if(self.canUpdate) { + text = "Update(s) available."; + } else { + text = "You're up to date."; + } + break; + case UpdatePanel.DOWNLOADING: + text = "Downloading update..."; + break; + case UpdatePanel.DOWNLOAD_FAILED: + text = "Downloading update failed."; + break; + case UpdatePanel.IMAGE_READY: + text = "Update downloaded."; + break; + case UpdatePanel.INSTALLING: + text = "Installing update... (will take a minute)"; + break; + case UpdatePanel.INSTALLED: + text = "Update complete, please refresh Page."; + break; + case UpdatePanel.INSTALL_FAILED: + text = "Installing update failed."; + break; + } + } else { + if(self.networkMode == SettingsWindow.NETWORK_MODE_ACCESS_POINT) { + text = "Can't access internet in access point mode."; + } else { + text = "Can't access internet."; + } + } + this.statusDisplay.html(text); + } + this.updateInfoDisplay = function() { + var text = "Current version: "+self.currentVersion+". "; + if(self.canUpdate) { + text += "Latest version: "+self.newestVersion+"."; + } + self.infoDisplay.text(text); + } + this.setNetworkMode = function(networkMode) { + self.networkMode = networkMode; + } +} +function setTemperature(callback) { + + if (callback != undefined) callback(); + +} +function setTemperature(callback) { + + if (callback != undefined) callback(); + +} +var VERTICALSHAPE; +var verticalShapes = { + "NONE": 'none', + "DIVERGING": 'diverging', + "CONVERGING": 'converging', + "SINUS": 'sinus' +}; + +function initVerticalShapes() { + // TODO give these vertical shapes a better spot + VERTICALSHAPE = verticalShapes.NONE; + $(".verticalShapes, .straight").on('mouseup touchend', function(e) { + e.preventDefault(); + console.log("diverging"); + VERTICALSHAPE = verticalShapes.NONE; + redrawRenderedPreview(); + }) + $(".verticalShapes, .diverging").on('mouseup touchend', function(e) { + e.preventDefault(); + console.log("diverging"); + VERTICALSHAPE = verticalShapes.DIVERGING; + redrawRenderedPreview(); + }) + $(".verticalShapes, .converging").on('mouseup touchend', function(e) { + e.preventDefault(); + console.log("converging"); + VERTICALSHAPE = verticalShapes.CONVERGING; + redrawRenderedPreview(); + }) + $(".verticalShapes, .sinus").on('mouseup touchend', function(e) { + e.preventDefault(); + console.log("sinus"); + VERTICALSHAPE = verticalShapes.SINUS; + redrawRenderedPreview(); + }) + +} + +function resetVerticalShapes() { + VERTICALSHAPE = verticalShapes.NONE; +} +var btnMoveUpInterval; +var btnMoveDownInterval; + +var btnTwistLeftInterval; +var btnTwistRightInterval; +var twistIncrement = Math.PI/1800; + +var btnOopsInterval; + +var btnNew, btnPrevious, btnNext; +var btnOops, btnStop, btnClear; +var btnMoveUp, btnMoveDown, btnTwistLeft, btnTwistRight; +var btnInfo, btnSettings; +//var btnDebug; // debug + +var state; +var prevState; +var hasControl; + +var gcodeGenerateDelayer; +var gcodeGenerateDelay = 50; + +function initButtonBehavior() { + console.log("f:initButtonBehavior"); + +// btnClear= $(".btnClear"); + btnOops = $(".btnOops"); + btnMoveUp = $("#btnMoveUp"); + btnMoveDown = $("#btnMoveDown"); + btnTwistLeft = $("#btnTwistLeft"); + btnTwistRight = $("#btnTwistRight"); + btnInfo = $(".btnInfo"); + btnSettings = $(".btnSettings"); + btnNew = $(".btnNew"); + btnPrint= $(".btnPrint"); + btnStop = $(".btnStop"); + + btnPrevious = $(".btnPrevious"); + btnNext = $(".btnNext"); + + //debug + //btnDebug = $(".debugBtn"); + + btnNew.on('touchstart mousedown', clearDoodle); + btnPrint.on('touchstart mousedown', print); + + // not using these at the moment + $("#btnPrevious").css("opacity", "0.3"); + btnNext.css("opacity", "0.3"); + $("#btnSave").css("opacity", "0.3"); + btnInfo.css("opacity", "0.3"); + +// btnClear.click(function(e) { +// e.preventDefault(); +// // console.log("clear"); +// +// clearDoodle(); +// }); + + function startOops(e) { + // console.log("btnOops mouse down"); + e.preventDefault(); + btnOopsInterval = setInterval( function() { + oopsUndo(); + }, 1000/50); + } + function stopOops(e) { + // console.log("btnOops mouse up"); + e.preventDefault(); + clearInterval(btnOopsInterval); + } + btnOops.on('touchstart', function(e) { startOops(e); }); + btnOops.on('touchend', function(e) { stopOops(e); }); + btnOops.mousedown(function(e) { startOops(e); }); + btnOops.mouseup(function(e) { stopOops(e); }); + + function startMoveUp(e) { + e.preventDefault(); + // console.log("btnMoveUp mouse down"); + previewUp(true); + clearInterval(btnMoveUpInterval); + btnMoveUpInterval = setInterval( function() { + previewUp(true); + }, 1000/30); + } + function stopMoveUp(e) { + e.preventDefault(); + console.log("btnMoveUp mouse up"); + clearInterval(btnMoveUpInterval); + previewUp(); + } + btnMoveUp.mousedown(function(e) { startMoveUp(e) }); + btnMoveUp.mouseup(function(e) { stopMoveUp(e) }); + btnMoveUp.on('touchstart', function(e) { startMoveUp(e) }); + btnMoveUp.on('touchend', function(e) { stopMoveUp(e) }); + + function startMoveDown(e) { + e.preventDefault(); + // console.log("btnMoveDown mouse down"); + previewDown(true); + clearInterval(btnMoveDownInterval); + btnMoveDownInterval = setInterval( function() { + previewDown(true); + }, 1000/30); + } + function stopMoveDown(e) { + e.preventDefault(); + console.log("btnMoveDown mouse up"); + clearInterval(btnMoveDownInterval); + previewDown(); + } + btnMoveDown.mousedown(function(e) { startMoveDown(e) }); + btnMoveDown.mouseup(function(e) { stopMoveDown(e) }); + btnMoveDown.on('touchstart', function(e) { startMoveDown(e) }); + btnMoveDown.on('touchend', function(e) { stopMoveDown(e) }); + + function startTwistLeft(e) { + e.preventDefault(); + // console.log("btnTwistLeft mouse down"); + previewTwistLeft(true); + clearInterval(btnTwistLeftInterval); + btnTwistLeftInterval = setInterval( function() { + previewTwistLeft(true); + }, 1000/30); + } + function stopTwistLeft(e) { + e.preventDefault(); + // console.log("btnTwistLeft mouse up"); + clearInterval(btnTwistLeftInterval); + previewTwistLeft(); + } + btnTwistLeft.mousedown(function(e) { startTwistLeft(e) }); + btnTwistLeft.mouseup(function(e) { stopTwistLeft(e) }); + btnTwistLeft.on('touchstart', function(e) { startTwistLeft(e) }); + btnTwistLeft.on('touchend', function(e) { stopTwistLeft(e) }); + + function startTwistRight(e) { + e.preventDefault(); + // console.log("btnTwistRight mouse down"); + previewTwistRight(true); + clearInterval(btnTwistRightInterval); + btnTwistRightInterval = setInterval( function() { + previewTwistRight(true); + }, 1000/30); + } + function stopTwistRight(e) { + e.preventDefault(); + // console.log("btnTwistRight mouse up"); + clearInterval(btnTwistRightInterval); + previewTwistRight(); + } + btnTwistRight.mousedown(function(e) { startTwistRight(e) }); + btnTwistRight.mouseup(function(e) { stopTwistRight(e) }); + btnTwistRight.on('touchstart', function(e) { startTwistRight(e) }); + btnTwistRight.on('touchend', function(e) { stopTwistRight(e) }); + + /*function openSettings() { + console.log("f:openSettings()"); + $("#contentOverlay").fadeIn(1000, function() { + loadSettings(); + }); + }*/ + btnSettings.bind('touchstart mousedown',function () { + //e.preventDefault(); + //console.log("btnSettings clicked"); + settingsWindow.showSettings(); + }); +// btnSettings.on('touchend', function(e) { +// e.preventDefault(); +// console.log("btnSettings touchend"); +// }); + + btnInfo.mouseup(function(e) { + e.preventDefault(); + console.log("btnInfo mouse up"); + }); + + // DEBUG + /* + // $(".agentInfo").css("display", "none"); + btnDebug.click(function(e) { + console.log("debugClick"); + $(".agentInfo").toggleClass("agentInfoToggle"); + e.preventDefault(); + }) + //*/ + + //btnStop.on('touchstart mousedown',stopPrint); +} +function stopPrint() { + console.log("f:stopPrint() >> sendPrintCommands = " + sendPrintCommands); + //if (!confirm("Weet je zeker dat je huidige print wilt stoppen?")) return; + if (sendPrintCommands) printer.stop(); + //setState(Printer.STOPPING_STATE,printer.hasControl); + printer.overruleState(Printer.STOPPING_STATE); +} + + +function prevDoodle(e) { + console.log("f:prevDoodle()"); + console.log("f:prevDoodle()"); +} +function nextDoodle(e) { + console.log("f:nextDoodle()"); +} + +function print(e) { + console.log("f:print() >> sendPrintCommands = " + sendPrintCommands); + + //$(".btnPrint").css("display","none"); + + if (_points.length > 2) { + + //setState(Printer.BUFFERING_STATE,printer.hasControl); + printer.overruleState(Printer.BUFFERING_STATE); + + btnStop.css("display","none"); // hack + + // we put the gcode generation in a little delay + // so that for example the print button is disabled right away + clearTimeout(gcodeGenerateDelayer); + gcodeGenerateDelayer = setTimeout(function() { + + var gcode = generate_gcode(); + if (sendPrintCommands) { + if(gcode.length > 0) { + printer.print(gcode); + } else { + printer.overruleState(Printer.IDLE_STATE); + printer.startStatusCheckInterval(); + } + } else { + console.log("sendPrintCommands is false: not sending print command to 3dprinter"); + } + + if (debugMode) { + $("#textdump").text(""); + $("#textdump").text(gcode.join("\n")); + } + + }, gcodeGenerateDelay); + } else { + console.log("f:print >> not enough points!"); + } + + //alert("Je tekening zal nu geprint worden"); + //$(".btnPrint").css("display","block"); + + + // $.post("/doodle3d.of", { data:output }, function(data) { + // btnPrint.disabled = false; + // }); +} + + +function clearMainView() { + // console.log("f:clearMainView()"); + ctx.save(); + ctx.clearRect(0,0,canvas.width, canvas.height); + ctx.restore(); +} +function resetPreview() { + // console.log("f:resetPreview()"); + + // clear preview canvas + previewCtx.save(); + previewCtx.clearRect(0,0,canvas.width, canvas.height); + previewCtx.restore(); + + // reset height and rotation to default values + numLayers = previewDefaults.numLayers; // current number of preview layers + rStep = previewDefaults.rotation; // Math.PI/180; //Math.PI/40; // +} + +function oopsUndo() { + // console.log("f:oopsUndo()"); + _points.pop(); + redrawDoodle(); + redrawPreview(); +} +function previewUp(redrawLess) { + // console.log("f:previewUp()"); + if (numLayers < maxNumLayers) { + numLayers++; + } +// redrawPreview(redrawLess); + redrawRenderedPreview(redrawLess); +} +function previewDown(redrawLess) { + // console.log("f:previewDown()"); + if (numLayers > minNumLayers) { + numLayers--; + } +// redrawPreview(redrawLess); + redrawRenderedPreview(redrawLess); +} +function previewTwistLeft(redrawLess) { + if (redrawLess == undefined) redrawLess = false; + // console.log("f:previewTwistLeft()"); + if (rStep > -previewRotationLimit) rStep -= twistIncrement; + // redrawPreview(redrawLess); + redrawRenderedPreview(redrawLess); +} +function previewTwistRight(redrawLess) { + // console.log("f:previewTwistRight()"); + if (rStep < previewRotationLimit) rStep += twistIncrement; + // redrawPreview(redrawLess); + redrawRenderedPreview(redrawLess); +} + + + +function update() { + setState(printer.state,printer.hasControl); + + thermometer.update(printer.temperature, printer.targetTemperature); + progressbar.update(printer.currentLine, printer.totalLines); +} + +function setState(newState,newHasControl) { + if(newState == state && newHasControl == hasControl) return; + + prevState = state; + + console.log("setState: ",prevState," > ",newState," ( ",newHasControl,")"); + setDebugText("State: "+newState); + + // print button + var printEnabled = (newState == Printer.IDLE_STATE && newHasControl); + if(printEnabled) { + btnPrint.removeClass("disabled"); // enable print button + btnPrint.unbind('touchstart mousedown'); + btnPrint.bind('touchstart mousedown',print); + } else { + btnPrint.addClass("disabled"); // disable print button + btnPrint.unbind('touchstart mousedown'); + } + + // stop button + var stopEnabled = ((newState == Printer.PRINTING_STATE || newState == Printer.BUFFERING_STATE) && newHasControl); + if(stopEnabled) { + btnStop.removeClass("disabled"); + btnStop.unbind('touchstart mousedown'); + btnStop.bind('touchstart mousedown',stopPrint); + } else { + btnStop.addClass("disabled"); + btnStop.unbind('touchstart mousedown'); + } + + // thermometer + switch(newState) { + case Printer.IDLE_STATE: + case Printer.BUFFERING_STATE: + case Printer.PRINTING_STATE: + case Printer.STOPPING_STATE: + thermometer.show(); + break; + default: + thermometer.hide(); + break; + } + + // progress indicator + switch(newState) { + case Printer.PRINTING_STATE: + progressbar.show(); + break; + default: + progressbar.hide(); + break; + } + + if(newState == Printer.WIFIBOX_DISCONNECTED_STATE) { + message.set("Lost connection to WiFi box",Message.ERROR); + } else if(prevState == Printer.WIFIBOX_DISCONNECTED_STATE) { + message.set("Connected to WiFi box",Message.INFO,true); + } else if(newState == Printer.DISCONNECTED_STATE) { + message.set("Printer disconnected",Message.WARNING,true); + } else if(prevState == Printer.DISCONNECTED_STATE && newState == Printer.IDLE_STATE || + prevState == Printer.UNKNOWN_STATE && newState == Printer.IDLE_STATE) { + message.set("Printer connected",Message.INFO,true); + } + + state = newState; + hasControl = newHasControl; +} + +/* * * * * * * * * * + * + * VARS + * + * * * * * * * * * */ +var preview; +var previewCtx; + +var svgPathRegExp = /[LM]\d* \d*/ig; +var svgPathParamsRegExp = /([LM])(\d*) (\d*)/; + +var dragging = false; + +var $canvas, canvas, ctx; +var canvasWidth, canvasHeight; + +var drawCanvas; +var drawCanvasTopLeftCoords = [0, 0]; + +var doodleBounds = [-1, -1, -1, -1]; // left, top, right, bottom +// var doodleScaleVals = [[0, 0], [1.0, 1.0]]; // [ [x, y], [scaleX, scaleY] ] +var doodleTransform = [0, 0, 1.0, 1.0]; // [ x, y, scaleX, scaleY ] + +var _points = []; + +var prevCountingTime = 0; +var movementCounter = 0; + +var drawVariableLineWeight = false; // set to true to have the momentum of the mouse/touch movement result in larger/smaller strokes +var lineweight = 2; + +/* * * * * * * * * * + * + * INIT + * + * * * * * * * * * */ +function initDoodleDrawing() { + console.log("f:initDoodleDrawing()"); + + $canvas = $("#mycanvas"); + canvas = $canvas[0]; + ctx = canvas.getContext('2d'); + + canvasWidth = canvas.width; + canvasHeight = canvas.height; + + + //* + //TODO make these jquery eventhandlers (works for all) + if (!canvas.addEventListener) { + canvas.attachEvent('onmousedown',onCanvasMouseDown); + canvas.attachEvent('onmousemove',onCanvasMouseMove); + canvas.attachEvent('onmouseup',onCanvasMouseUp); + canvas.attachEvent('ontouchstart',onCanvasTouchDown); + canvas.attachEvent('ontouchmove',onCanvasTouchMove); + canvas.attachEvent('ontouchend',onCanvasTouchEnd); + document.body.attachEvent('ontouchmove',prevent); + } else { + canvas.addEventListener('mousedown',onCanvasMouseDown,false); + canvas.addEventListener('mousemove',onCanvasMouseMove,false); + canvas.addEventListener('mouseup',onCanvasMouseUp,false); + canvas.addEventListener('touchstart',onCanvasTouchDown,false); + canvas.addEventListener('touchmove',onCanvasTouchMove,false); + canvas.addEventListener('touchend',onCanvasTouchEnd,false); + if (!debugMode) document.body.addEventListener('touchmove',prevent,false); + } + //*/ + +// drawCanvas = $(".drawareacontainer"); + drawCanvas = $("#mycanvasContainer"); // $("#drawAreaContainer") + + console.log("drawCanvasTopLeftCoords: " + drawCanvasTopLeftCoords); +// drawCanvasTopLeftCoords[0] = drawCanvas.css("left").match(/[0-9]/g).join(""); +// drawCanvasTopLeftCoords[1] = drawCanvas.css("top").match(/[0-9]/g).join(""); + drawCanvasTopLeftCoords[0] = drawCanvas.offset().left; + drawCanvasTopLeftCoords[1] = drawCanvas.offset().top; +// drawCanvasTopLeftCoords[0] = drawCanvas[0].offsetParent.offsetLeft; +// drawCanvasTopLeftCoords[1] = drawCanvas[0].offsetParent.offsetTop; + + console.log("f:initDoodleDrawing() >> canvasWidth: " + canvasWidth); + console.log("f:initDoodleDrawing() >> canvasHeight: " + canvasHeight); + +} + +/* * * * * * * * * * + * + * CANVAS DRAWING FUNCTION + * + * * * * * * * * * */ +function draw(_x, _y, _width) { + // console.log("f:draw() >> _width: " + _width); + + if (prevX == 0 && prevY ==0) { + prevX = _x; + prevY = _y; + } + + ctx.beginPath(); + ctx.moveTo(prevX, prevY); + ctx.lineTo(_x, _y); + + if (_width != undefined) { + ctx.lineWidth = _width; + } else { + if (drawVariableLineWeight) { + var dist = Math.sqrt(Math.pow((prevX - _x), 2) + Math.pow((prevY - _y), 2)); + if (dist < 10) { + lineweight += .25; + } else if (dist < 20) { + lineweight += .5; + } else if (dist < 30) { + lineweight += .75; + } else if (dist < 50) { + lineweight += 1; + } else if (dist < 80) { + lineweight += 1.5; + } else if (dist < 120) { + lineweight += 2.25; + } else if (dist < 170) { + lineweight += 3.5; + } else { + lineweight += 2; + } + lineweight = Math.min(lineweight, 30); + lineweight *= 0.90; + lineweight = Math.max(lineweight, 1.0); + } else { + lineweight = 2; + } + + ctx.lineWidth = lineweight; + } + ctx.lineCap = 'round'; + ctx.stroke(); + + prevX = _x; + prevY = _y; +} + + +/* * * * * * * * * * + * + * SUPPORTING FUNCTIONS + * + * * * * * * * * * */ +function clearDoodle() { + console.log("f:clearDoodle"); + + _points = []; + + prevX = 0; + prevY = 0; + + updatePrevX = -1; + updatePrevY = -1; + + doodleBounds = [-1, -1, -1, -1]; // left, top, right, bottom + doodleTransform = [0, 0, 1.0, 1.0]; // [ x, y, scaleX, scaleY ] + + dragging = false; + + clearMainView(); + resetPreview(); + resetVerticalShapes(); +} + +function redrawDoodle() { + console.log("f:redrawDoodle()"); + + clearMainView(); + + prevX = 0; + prevY = 0; + + for (var i = 0; i < _points.length; i++) { + // console.log(" drawing points " + _points[i]); + if (_points[i][2] == true) { + draw(_points[i][0], _points[i][1], 0.5); + } else { + draw(_points[i][0], _points[i][1]); + } + } +} + + function adjustBounds(x, y) { + var newPointsOutsideOfCurrentBounds = false; + console.log("f:adjustBounds("+x+","+y+")"); + + if (doodleBounds[0] == -1) { + // if doodleBounds[0] is -1 then it isn't initted yet, so x and y are both the min and max vals + + doodleBounds[0] = x; + doodleBounds[1] = y; + doodleBounds[2] = x; + doodleBounds[3] = y; + return; + } + + if (x < doodleBounds[0]) { + doodleBounds[0] = x; + newPointsOutsideOfCurrentBounds = true; + } + if (x > doodleBounds[2]) { + doodleBounds[2] = x; + newPointsOutsideOfCurrentBounds = true; + } + if (y < doodleBounds[1]) { + doodleBounds[1] = y; + newPointsOutsideOfCurrentBounds = true; + } + if (y > doodleBounds[3]) { + doodleBounds[3] = y; + newPointsOutsideOfCurrentBounds = true; + } +// doodleBounds[0] = Math.min(doodleBounds[0], x); // left +// doodleBounds[2] = Math.max(doodleBounds[2], x); // right +// +// doodleBounds[1] = Math.min(doodleBounds[1], y); // top +// doodleBounds[3] = Math.max(doodleBounds[3], y); // bottom + + // draw the bounding rect (DEBUG) + /* + ctx.beginPath(); + ctx.rect(doodleBounds[0],doodleBounds[1], doodleBounds[2] - doodleBounds[0], doodleBounds[3] - doodleBounds[1]); + ctx.lineWidth = .2; + ctx.strokeStyle = "#333" + ctx.stroke(); + ctx.closePath(); + //*/ + + // console.log(" new bounds: " + doodleBounds); + + return newPointsOutsideOfCurrentBounds; +} + +// does what exactly? +function adjustPreviewTransformation() { + // console.log("f:adjustPreviewTransformation()"); + +// doodleTransform[0] = doodleBounds[0] - (doodleBounds[2] - doodleBounds[0]) / 2; +// doodleTransform[1] = doodleBounds[1] - (doodleBounds[3] - doodleBounds[1]) / 2; +// doodleTransform[0] = doodleBounds[0] - ((doodleBounds[2] - doodleBounds[0]) / 2); +// doodleTransform[1] = doodleBounds[1] - ((doodleBounds[3] - doodleBounds[1]) / 2); + doodleTransform[0] = doodleBounds[0]; + doodleTransform[1] = doodleBounds[1]; + + var sclX, sclY, finalScl; + if (_points.length < 2) { +// console.log(_points); + sclX = 1.0; + sclY = 1.0; + finalScl = Math.min(sclX, sclY); + } else { + sclX = canvasWidth / (doodleBounds[2] - doodleBounds[0]); + sclY = canvasHeight / (doodleBounds[3] - doodleBounds[1]); + + // TODO this shouldn't be a matter if choosing the smallest but should probably involve maintaining aspect ratio?? + finalScl = Math.min(sclX, sclY); + } + + doodleTransform[2] = finalScl; + doodleTransform[3] = finalScl; +} + + +/* * * * * * * * * * + * + * MOUSE/TOUCH EVENTHANDLERS + * + * * * * * * * * * */ +function onCanvasMouseDown(e) { + // console.log("onmousedown >> e.offsetX,e.offsetY = " + e.offsetX+","+e.offsetY); + // console.log("onmousedown >> e.layerX,e.layerY= " + e.layerX+","+e.layerY); + // console.log("onmousedown >> e: " + e); + // console.log(e); +// console.log("f:onCanvasMouseDown()"); + dragging = true; + + prevCountingTime = new Date().getTime(); + movementCounter = 0 + +// _points.push([e.clientX - canvas.offsetLeft, e.clientY - canvas.offsetTop, true]); +// adjustBounds(e.clientX - canvas.offsetLeft, e.clientY - canvas.offsetTop); +// adjustPreviewTransformation(); +// draw(e.clientX - canvas.offsetLeft, e.clientY - canvas.offsetTop, 0.5); + + var x, y; + if (e.offsetX != undefined) { + x = e.offsetX; + y = e.offsetY; + } else { + x = e.layerX; + y = e.layerY; + } +// console.log(" x: " + x + ", y: " + y); + + _points.push([x, y, true]); + adjustBounds(x, y); + adjustPreviewTransformation(); + draw(x, y, 0.5); +} + +var prevPoint = {x:-1, y:-1}; +function onCanvasMouseMove(e) { +// console.log("f:onCanvasMouseMove()"); + if (!dragging) return; + // console.log("onmousemove"); + + var x, y; + if (e.offsetX != undefined) { + x = e.offsetX; + y = e.offsetY; + } else { + x = e.layerX; + y = e.layerY; + } + + if (prevPoint.x != -1 || prevPoint.y != -1) { + var dist = Math.sqrt(Math.pow((prevPoint.x - x), 2) + Math.pow((prevPoint.y - y), 2)); + if (dist > 5) { // replace by setting: doodle3d.simplify.minDistance + _points.push([x, y, false]); + adjustBounds(x, y) + adjustPreviewTransformation(); + draw(x, y); + prevPoint.x = x; + prevPoint.y = y; + } + } else { + _points.push([x, y, false]); + adjustBounds(x, y) + adjustPreviewTransformation(); + draw(x, y); + prevPoint.x = x; + prevPoint.y = y; + } + + // DEBUG +// $("#textdump").text(""); +// $("#textdump").append("doodlebounds:" + doodleBounds + "\n"); +// $("#textdump").append("doodletransform:" + doodleTransform + "\n"); + + if (new Date().getTime() - prevRedrawTime > redrawInterval) { + // redrawing the whole preview the first X points ensures that the doodleBounds is set well + prevRedrawTime = new Date().getTime(); + if (_points.length < 50) { + redrawPreview(); + } else { + updatePreview(x, y, true); + /* + if (_points.length - prevUpdateFullPreview > prevUpdateFullPreviewInterval) { + console.log("f:onTouchMove >> passed prevUpdateFullPreviewInterval, updating full preview"); + redrawPreview(); + prevUpdateFullPreview = _points.length; + } else { + updatePreview(x, y, true); + } + //*/ +// redrawPreview(); + } + } +} +prevUpdateFullPreview = 0; // 0 is not a timeframe but refers to the _points array +prevUpdateFullPreviewInterval = 25; // refers to number of points, not a timeframe + +function onCanvasMouseUp(e) { +// console.log("f:onCanvasMouseUp()"); + // console.log("onmouseup"); + dragging = false; + console.log("doodleBounds: " + doodleBounds); + console.log("doodleTransform: " + doodleTransform); + // ctx.stroke(); + + console.log("_points.length :" + _points.length); +// console.log(_points); + + // DEBUG +// $("#textdump").text(""); +// $("#textdump").append("doodlebounds:" + doodleBounds + "\n"); +// $("#textdump").append("doodletransform:" + doodleTransform + "\n"); + +// redrawPreview(); + renderToImageDataPreview(); +} + +function onCanvasTouchDown(e) { + e.preventDefault(); + console.log("f:onCanvasTouchDown >> e: " , e); +// var x = e.touches[0].pageX - e.touches[0].target.offsetLeft; +// var y = e.touches[0].pageY - e.touches[0].target.offsetTop; + var x = e.touches[0].pageX - drawCanvasTopLeftCoords[0]; + var y = e.touches[0].pageY - drawCanvasTopLeftCoords[1]; +// var x = e.touches[0].pageX; +// var y = e.touches[0].pageY; +// var x = e.touches[0].layerX; +// var y = e.touches[0].layerY; + + _points.push([x, y, true]); + adjustBounds(x, y); + adjustPreviewTransformation(); + draw(x, y, .5); + + movementCounter = 0; + + prevRedrawTime = new Date().getTime(); +} + +function onCanvasTouchMove(e) { + e.preventDefault(); +// var x = e.touches[0].pageX - e.touches[0].target.offsetLeft; +// var y = e.touches[0].pageY - e.touches[0].target.offsetTop; + var x = e.touches[0].pageX - drawCanvasTopLeftCoords[0]; + var y = e.touches[0].pageY - drawCanvasTopLeftCoords[1]; +// var x = e.touches[0].layerX; +// var y = e.touches[0].layerY; +// var x = e.touches[0].layerX; +// var y = e.touches[0].layerY; + + console.log("f:onCanvasTouchMove >> x,y = "+x+","+y+" , e: " , e); + + if (prevPoint.x != -1 || prevPoint.y != -1) { + var dist = Math.sqrt(Math.pow((prevPoint.x - x), 2) + Math.pow((prevPoint.y - y), 2)); + if (dist > 5) { + _points.push([x, y, false]); + adjustBounds(x, y) + adjustPreviewTransformation(); + draw(x, y); + prevPoint.x = x; + prevPoint.y = y; + } + } else { + _points.push([x, y, false]); + adjustBounds(x, y) + adjustPreviewTransformation(); + draw(x, y); + prevPoint.x = x; + prevPoint.y = y; + } + + // update counter -> this was for getting a handle on how often the Canvas fires a move-event + /* + movementCounter++; + if (new Date().getTime() - prevCountingTime > 1000) { + // console.log("number of moves in 1sec: " + movementCounter) + prevCountingTime= new Date().getTime(); + $("#numtimes").text(movementCounter + " times"); + movementCounter = 0; + } + //*/ + + if (new Date().getTime() - prevRedrawTime > redrawInterval) { + // redrawing the whole preview the first X points ensures that the doodleBounds is set well + if (_points.length < 50) { + redrawPreview(); + } else { + updatePreview(x, y, true); + /* + if (_points.length - prevUpdateFullPreview > prevUpdateFullPreviewInterval) { + console.log("f:onTouchMove >> passed prevUpdateFullPreviewInterval, updating full preview"); + redrawPreview(); + prevUpdateFullPreview = _points.length; + } else { + updatePreview(x, y, true); + } + //*/ + } + prevRedrawTime = new Date().getTime(); + } +} + +function onCanvasTouchEnd(e) { + console.log("f:onCanvasTouchEnd()"); + console.log("doodleBounds: " + doodleBounds); + console.log("doodleTransform: " + doodleTransform); + // ctx.stroke(); + + console.log("_points.length :" + _points.length); + + // redrawPreview(); + renderToImageDataPreview(); +} + +function prevent(e) { + e.preventDefault(); +} +//* +var $preview; +var preview; +var previewCtx; + +var preview_tmp; +var previewCtx_tmp; + +var previewDefaults = { + rotation: Math.PI/90, + numLayers: 10 +} + +var svgPathRegExp = /[LM]\d* \d*/ig; +var svgPathParamsRegExp = /([LM])(\d*) (\d*)/; + +var prevRedrawTime = new Date().getTime(); +var redrawInterval = 1000 / 30; // ms + +function initPreviewRendering() { + console.log("f:initPreviewRendering()"); + + $preview = $("#preview"); + preview = $preview[0]; + previewCtx = preview.getContext('2d'); + + // DEBUG --> mbt preview_tmp (voor de toImageData truc) + var _ratio = preview.width / canvas.width; + preview_tmp = document.getElementById('preview_tmp'); + preview_tmp.width = preview.width; + preview_tmp.height = canvas.height * _ratio; + $("#preview_tmp").css("top", -preview_tmp.height); + + previewCtx_tmp = preview_tmp.getContext('2d'); + + calcPreviewCanvasProperties(); + redrawPreview(); +} + +function calcPreviewCanvasProperties() { + console.log("f:calcPreviewCanvasProperties()"); + + globalScale = preview.width / canvasWidth; + layerCX = (canvasWidth / 2) * globalScale; // defined in canvasDrawing_v01.js + layerCY = (canvasHeight / 2) * globalScale; // defined in canvasDrawing_v01.js +// layerOffsetY = preview.height - 1.75 * layerCY; + layerOffsetY = preview.height * (1 - previewVerticalPadding.bottom); + yStep = (preview.height - (preview.height * (previewVerticalPadding.top + previewVerticalPadding.bottom))) / maxNumLayers; +} + +// TODO (perhaps) : make the twist limit dynamic, depending on what's printable (w.r.t. overlapping) +var previewRotationLimit = Math.PI / 30; // rough estimate + +var numLayers = previewDefaults.numLayers; // current number of preview layers +var maxNumLayers= 100; // maximum number of preview layers +var minNumLayers= 2; // minimum number of preview layers +var globalScale = 0.3; // global scale of preview (width preview / width canvas) +var globalAlpha = 0.20; // global alpha of preview +var scaleY = 0.4; // additional vertical scale per path for 3d effect +var viewerScale = 0.65; // additional scale to fit into preview nicely (otherwise is fills out totally) +var previewVerticalPadding = { "top" : .15, "bottom" : 0.12 }; // % +var strokeWidth = 2; //4; +//var rStep = Math.PI/40; //Math.PI/40; // +var rStep = previewDefaults.rotation; // Math.PI/180; //Math.PI/40; // +var yStep;// = preview.height / 150; // 3; //6; +//var svgWidth = 500; // 650 //parseInt($(svg).css("width")); +//var svgHeight = 450; //450; //parseInt($(svg).css("height")); +var layerCX, layerCY; +//var layerCX = (canvasWidth / 2) * globalScale; // defined in canvasDrawing_v01.js +//var layerCY = (canvasHeight / 2) * globalScale; // defined in canvasDrawing_v01.js +var layerOffsetY; //= preview.height - 1.75 * layerCY; // 330; // previewHeight - 120 +var prevX = 0; +var prevY = 0; +var highlight = true; //highlight bottom, middle and top layers + +var linesRaw = ""; +var debug_redrawSimplification = 6; +function redrawPreview(redrawLess) { + if (redrawLess == undefined) redrawLess = false; + + if (_points.length < 2) return; + + if (!redrawLess) { + //debug_redrawSimplification = Math.round(_points.length / 65); + //* + if (_points.length < 100) { + debug_redrawSimplification = 6; + } else if (_points.length < 250) { + debug_redrawSimplification = 7; + } else if (_points.length < 400) { + debug_redrawSimplification = 8; + } else if (_points.length < 550) { + debug_redrawSimplification = 9; + } else if (_points.length < 700) { + debug_redrawSimplification = 10; + } else { + debug_redrawSimplification = 11; + } + //*/ +// console.log("debug_redrawSimplification: " + debug_redrawSimplification); + } + + var y = 0; + var r = 0; + + //preview.width = preview.width; + previewCtx.clearRect(0, 0, preview.width, preview.height); + previewCtx.lineWidth = strokeWidth; + previewCtx.strokeStyle = '#f00'; //"rgba(255,255,0,0)"; + + for(var i = 0; i < numLayers; i++) { + + var verticalScaleFactor = scaleFunction(i / maxNumLayers); + + if(i == 0 || i == Math.floor(numLayers/2) || i == numLayers-1) { + previewCtx.globalAlpha = 1; + } else { + previewCtx.globalAlpha = globalAlpha; + } + + if (redrawLess && i%debug_redrawSimplification != 0 && !(i == 0 || i == Math.floor(numLayers/2) || i == numLayers-1) ) { + y -= yStep; + r += rStep; + continue; + } + + previewCtx.save(); + +// previewCtx.translate(layerCX, layerOffsetY + layerCY + y); + previewCtx.translate(layerCX, layerOffsetY + y); +// previewCtx.setTransform(1, 0, 0, scaleY, layerCX, layerOffsetY+layerCY+y); + previewCtx.scale(viewerScale * verticalScaleFactor, scaleY * viewerScale * verticalScaleFactor); + previewCtx.rotate(r); + previewCtx.translate((-doodleTransform[0]) * (globalScale * doodleTransform[2]), (-doodleTransform[1]) * (globalScale * doodleTransform[3])); + + var adjustedDoodlePoint = centeredAndScaledDoodlePoint(_points[0]); + + previewCtx.beginPath(); + previewCtx.moveTo(adjustedDoodlePoint.x, adjustedDoodlePoint.y); + for(var j = 1; j < _points.length; j++) { + adjustedDoodlePoint = centeredAndScaledDoodlePoint(_points[j]) + if (redrawLess && j%debug_redrawSimplification != 0 ) continue; + previewCtx.lineTo(adjustedDoodlePoint.x, adjustedDoodlePoint.y); + } + previewCtx.stroke(); + + y -= yStep; + r += rStep; + previewCtx.restore(); + } + previewCtx.globalAlpha = globalAlpha; +} + +function renderToImageDataPreview() { + console.log("f:renderToImageDataPreview()"); + + if (_points.length < 2) return; + + //* + // the first step + previewCtx_tmp.clearRect(0, 0, preview.width, preview.height); + previewCtx_tmp.lineWidth = strokeWidth; + previewCtx_tmp.strokeStyle = '#f00'; //"rgba(255,255,0,0)"; + + previewCtx_tmp.save(); + previewCtx_tmp.translate(layerCX, layerCY); + previewCtx_tmp.scale(viewerScale, viewerScale); + previewCtx_tmp.translate((-doodleTransform[0]) * (globalScale * doodleTransform[2]), (-doodleTransform[1]) * (globalScale * doodleTransform[3])); + + var adjustedDoodlePt = centeredAndScaledDoodlePoint(_points[0]); + + previewCtx_tmp.beginPath(); + previewCtx_tmp.moveTo(adjustedDoodlePt.x, adjustedDoodlePt.y); + for(var j = 1; j < _points.length; j++) { + adjustedDoodlePt = centeredAndScaledDoodlePoint(_points[j]) + previewCtx_tmp.lineTo(adjustedDoodlePt.x, adjustedDoodlePt.y); + } + previewCtx_tmp.stroke(); + previewCtx_tmp.closePath(); + previewCtx_tmp.restore(); + //*/ + + // var saved_rect = previewCtx_tmp.getImageData(0, 0, layerCX*2, layerCY*2); + var saved_rect_todataurl = preview_tmp.toDataURL(); + doodleImageCapture = new Image(); + doodleImageCapture.onload = function() { + + previewCtx.clearRect(0, 0, preview.width, preview.height); + previewCtx.lineWidth = strokeWidth; + previewCtx.strokeStyle = '#f00'; //"rgba(255,255,0,0)"; + + var y = 0; + var r = 0; + + for(var i=0;i> EFFE CHECKEN:"); + console.log(" speed: " + speed); + console.log(" travelSpeed: " + travelSpeed); + console.log(" filamentThickness: " + filamentThickness); + console.log(" wallThickness: " + wallThickness); + console.log(" screenToMillimeterScale: " + screenToMillimeterScale); + console.log(" layerHeight: " + layerHeight); + console.log(" objectHeight: " + objectHeight); + console.log(" maxObjectHeight: " + maxObjectHeight); + console.log(" temperature: " + temperature); + console.log(" maxObjectHeight: " + maxObjectHeight); + console.log(" useSubLayers: " + useSubLayers); + console.log(" enableTraveling: " + enableTraveling); + console.log(" retractionspeed: " + retractionspeed); + console.log(" retractionminDistance: " + retractionminDistance); + console.log(" retractionamount: " + retractionamount); + console.log(""); + //*/ + + // max amount of real world layers + var layers = maxObjectHeight / layerHeight; //maxObjectHeight instead of objectHeight + + // translate numLayers in preview to objectHeight in real world + //objectHeight = Math.ceil(numLayers / 5); // in settings objectHeight = 20, in previewRendering_v01.js numLayers is 100, hence the / 5 + //objectHeight = numLayers; // in settings objectHeight = 20, in previewRendering_v01.js numLayers is 100, hence the / 5 + objectHeight = Math.round(numLayers/maxNumLayers*maxObjectHeight); + + // translate preview rotation (per layer) to real world rotation + var rStepGCode = rStep * maxNumLayers/layers; ///maxNumLayers*maxObjectHeight; + // correct direction + rStepGCode = -rStepGCode; + + // todo hier een array van PATHS maken wat de losse paths zijn + + // copy array without reference -> http://stackoverflow.com/questions/9885821/copying-of-an-array-of-objects-to-another-array-without-object-reference-in-java + var points = JSON.parse(JSON.stringify(_points)); + +// console.log("f:generategcode() >> paths: " + paths.toString()); +// console.log("paths.toString(): " + paths.toString()); +// return; + + //gcode.push("M104 S" + temperature); // set target temperature and do not wait for the extruder to reach it + //gcode.push("M109 S" + temperature); // set target temperature and wait for the extruder to reach it + + // add gcode begin commands + gcode = gcode.concat(startGcode); + + //gcode.push("M109 S" + temperature); // set target temperature and wait for the extruder to reach it + + var layers = maxObjectHeight / layerHeight; //maxObjectHeight instead of objectHeight + var extruder = 0.0; + var prev = new Point(); prev.set(0, 0); + + // replacement (and improvement) for ofxGetCenterofMass + var centerOfDoodle = { + x: doodleBounds[0] + (doodleBounds[2]- doodleBounds[0])/2, + y: doodleBounds[1] + (doodleBounds[3] - doodleBounds[1])/2 +// x: doodleBounds[0], +// y: doodleBounds[1] + } + + console.log("f:generategcode() >> layers: " + layers); + if (layers == Infinity) return; + + // check feasibility of design + var pointsToPrint = points.length * layers*(objectHeight/maxObjectHeight) + //console.log(" points.length: ",points.length); + //console.log(" numLayers: ",(layers*(objectHeight/maxObjectHeight))); + //console.log(" pointsToPrint: ",pointsToPrint); + //console.log(" MAX_POINTS_TO_PRINT: ",MAX_POINTS_TO_PRINT); + + if(pointsToPrint > MAX_POINTS_TO_PRINT) { + alert("Sorry, your doodle to to complex and / or to high"); + console.log("WARNING: to many points to convert to gcode"); + return []; + } + + for (var layer = 0; layer < layers; layer++) { + + var p = JSON.parse(JSON.stringify(points)); // [].concat(points); + + if (p.length < 2) return; + var even = (layer % 2 == 0); + var progress = layer / layers; + + // float layerScale = scaleFunction(float(layer)/layers); // scaleFactor van de layer -> lookup naar vfunc[] voor die scaleVals +// var layerScale = 1.0; + var layerScale = scaleFunction(progress); + + // if begin point this row and end point last row are close enough, isLoop is true + var isLoop = lineLength(points[0][0], points[0][1], points[points.length-1][0], points[points.length-1][1]) < 3; + + // set center of doodle as middle (ie subtract to that) + pointsTranslate(p, -centerOfDoodle.x, -centerOfDoodle.y); + pointsScale(p, screenToMillimeterScale,-screenToMillimeterScale); + pointsScale(p, layerScale, layerScale); + + // sort-of in de buurt van (360/2.5) + // // -> aight.. er zijn 750 lines vs 1000 in de d3d app. 135 = .75 * 180... dit kan je nog rechttrekken als je NET wat slimmer nadenkt :) + // update: NEE, het is niet .75 * 180 want 135 was niet de beste value. + //pointsRotate(p, rStep * progress * 139); + pointsRotate(p, rStepGCode * layer); + + if (layer == 0) { + //gcode.push("M107"); //fan off + if (firstLayerSlow) { + //gcode.push("M220 S20"); //slow speed + speed = bottomSpeed; + //console.log("> speed: ",speed); + } + } else if (layer == 2) { ////////LET OP, pas bij layer 2 weer op normale snelheid ipv layer 1 + gcode.push("M106"); //fan on + //gcode.push("M220 S100"); //normal speed + speed = normalSpeed; + //console.log("> speed: ",speed); + } + + var curLayerCommand = 0; + var totalLayerCommands = p.length; + var layerProgress = 0; + + var paths = []; + var pathCounter = -1; + // var points = []; + + for (var i = 0; i < p.length; i++) { + if (p[i][2] == true) { + pathCounter++; + paths.push([]); + paths[pathCounter].push([p[i][0], p[i][1]]); + } else { + paths[pathCounter].push([p[i][0], p[i][1]]); + } + } +// console.log("f:generategcode() >> paths.length: " + paths.length); + + // loop over the subpaths (the separately drawn lines) + for (var j = 0; j < paths.length; j++) { // TODO paths > subpaths + // this line is probably for drawing efficiency, alternating going from 0->end and end->0 (i.e. to and fro) +// vector &commands = subpaths[even ? j : subpaths.size()-1-j].getCommands(); + var commands = paths[j]; //commands zijn alle points uit subpath j // TODO commands > subpathPoints + + // loop over the coordinates of the subpath + for (var i = 0; i < commands.length; i++) { + var last = commands.length - 1; + + // this line is probably for drawing efficiency, alternating going from 0->end and end->0 (i.e. to and fro) +// ofPoint to = commands[(even || isLoop || loopAlways) ? i : last-i].to; + var to = new Point(); to.set(commands[i][0], commands[i][1]); + + // TODO 2013-09-18 evaluate if this should stay.. + // this was added when Rick mailed us wrt the Ultimaker delivery of Doodle3D + to.x += gCodeOffsetX; + to.y += gCodeOffsetY; + + var sublayer = (layer == 0) ? 0.0 : layer + (useSubLayers ? (curLayerCommand/totalLayerCommands) : 0); + var z = (sublayer + 1) * layerHeight; // 2013-09-06 removed zOffset (seemed to be useless) + + var isTraveling = !isLoop && i==0; + var doRetract = retractionEnabled && prev.distance(to) > retractionminDistance; + + if (enableTraveling && isTraveling) { +// console.log("enableTraveling && isTraveling >> doRetract: " + doRetract + ", retractionspeed: " + retractionspeed); + if (doRetract) gcode.push("G0 E" + (extruder - retractionamount).toFixed(3) + " F" + (retractionspeed * 60).toFixed(3)); //retract + gcode.push("G0 X" + to.x.toFixed(3) + " Y" + to.y.toFixed(3) + " Z" + z.toFixed(3) + " F" + (travelSpeed * 60).toFixed(3)); + if (doRetract) gcode.push("G0 E" + extruder.toFixed(3) + " F" + (retractionspeed * 60).toFixed(3)); // return to normal + } else { +// console.log(" else"); + //extruder += prev.distance(to) * wallThickness * layerHeight / filamentThickness; + extruder += prev.distance(to) * wallThickness * layerHeight / (Math.pow((filamentThickness/2), 2) * Math.PI); + gcode.push("G1 X" + to.x.toFixed(3) + " Y" + to.y.toFixed(3) + " Z" + z.toFixed(3) + " F" + (speed * 60).toFixed(3) + " E" + extruder.toFixed(3)); + } + + curLayerCommand++; + layerProgress = curLayerCommand/totalLayerCommands; + prev = to; + + } + + } + + if ((layer/layers) > (objectHeight/maxObjectHeight)) { + console.log("f:generategcode() >> (layer/layers) > (objectHeight/maxObjectHeight) is true -> breaking at layer " + (layer + 1)); + break; + } + } + // add gcode end commands + gcode = gcode.concat(endGcode); + + return gcode; +} + +function scaleFunction(percent) { + var r = 1.0; + + switch (VERTICALSHAPE) { + case verticalShapes.NONE: + r = 1.0; + break; + case verticalShapes.DIVERGING: + r = .5 + (percent * .5); + break; + case verticalShapes.CONVERGING: + r = 1.0 - (percent * .8); + break; + case verticalShapes.SINUS: + r = (Math.cos(percent * Math.PI * 4) * .25) + .75; + break; + } + +// return 1.0 - (percent *.8); + return r; +} + +pointsTranslate = function(p, x, y) { + for (var i = 0; i < p.length; i++) { + p[i][0] += x; + p[i][1] += y; + } +} + +pointsScale = function(p, sx, sy) { + for (var i = 0; i < p.length; i++) { + p[i][0] *= sx; + p[i][1] *= sy; + } +} + +// rotates around point 0,0 (origin). +// Not the prettiest kind of rotation solution but in our case we're assuming that the points have just been translated to origin +pointsRotate = function(p, ang) { + var _ang, dist; + for (var i = 0; i < p.length; i++) { + dist = Math.sqrt(p[i][0] * p[i][0] + p[i][1] * p[i][1]); + _ang = Math.atan2(p[i][1], p[i][0]); + p[i][0] = Math.cos(_ang + ang) * dist; + p[i][1] = Math.sin(_ang + ang) * dist; + } +} + +//+ Jonas Raoni Soares Silva +//@ http://jsfromhell.com/math/line-length [rev. #1] +lineLength = function(x, y, x0, y0){ + return Math.sqrt((x -= x0) * x + (y -= y0) * y); +}; + +var Point = function() {}; +Point.prototype = { + x: 0, + y: 0, + set: function(_x, _y) { + this.x = _x; + this.y = _y; + }, + distance: function(p) { + var d = -1; + if (p instanceof Point) { + d = Math.sqrt((p.x - this.x) * (p.x - this.x) + (p.y - this.y) * (p.y - this.y)); + } + return d; + }, + toString: function() { + console.log("x:" + this.x + ", y:" + this.y); + } +} + +// TODO refactor this stuff, there's much to wipe +var drawAreaContainerMinHeight = 300; +var drawAreaContainerMaxHeight = 450; + +function doOnResize() { + // console.log("doOnResize() >> " + new Date().getTime()); + canvas.width = $canvas.width(); + canvas.height = $canvas.height(); // canvas.clientHeight; + + preview.width = $preview.width(); + preview.height = $drawAreaContainer.height(); + + canvasWidth = canvas.width; + canvasHeight = canvas.height; + + console.log(" preview.width: " + preview.width + ", $preview.width(): " + $preview.width()); + + calcPreviewCanvasProperties(); + + drawCanvasTopLeftCoords[0] = drawCanvas.offset().left; + drawCanvasTopLeftCoords[1] = drawCanvas.offset().top; + + redrawDoodle(); + redrawPreview(); + +} + +function initLayouting() { + console.log("f:initLayouting()"); + + $drawAreaContainer = $(".drawareacontainer"); + + canvas.width = $canvas.width(); + canvas.height = $canvas.height(); // canvas.clientHeight; + + preview.width = $preview.width(); + preview.height = $drawAreaContainer.height(); + + canvasWidth = canvas.width; + canvasHeight = canvas.height; + + $drawAreaContainer.show(); + + // window.innerHeight + console.log("window.innerHeight: " + window.innerHeight); + console.log("window.innerWidth: " + window.innerWidth); + console.log("$drawAreaContainer.innerHeight(): " + $drawAreaContainer.innerHeight()); + console.log("$drawAreaContainer.offset().top: " + $drawAreaContainer.offset().top); + + // timeout because it SEEMS to be beneficial for initting the layout + // 2013-09-18 seems beneficial since when? + setTimeout(_startOrientationAndChangeEventListening, 1000); +} + +function _startOrientationAndChangeEventListening() { + // Initial execution if needed + + $(window).on('resize', doOnResize); + + // is it necessary to call these? Aren't they called by the above eventhandlers? + doOnResize(); +} + +/* not using this now +var $printProgressContainer = $("#printProgressContainer"); +var $progressbar = $("#progressbar"); +var $progressAmount = $(".progressAmount"); +function setPrintprogress(val) { + if (isNaN(val)) return; +// console.log("f:setPrintprogress() >> val " + val); + $progressbar.css("width", val*100 + "%"); + $progressAmount.text(Math.floor(val*100) + "%"); +} +//*/ + +function Printer() { + + Printer.WIFIBOX_DISCONNECTED_STATE = "wifibox disconnected"; + Printer.UNKNOWN_STATE = "unknown"; // happens when a printer is connection but there isn't communication yet + Printer.DISCONNECTED_STATE = "disconnected"; // printer disconnected + Printer.IDLE_STATE = "idle"; // printer found, but idle + Printer.BUFFERING_STATE = "buffering"; // printer is buffering (recieving) data, but not yet printing + Printer.PRINTING_STATE = "printing"; + Printer.STOPPING_STATE = "stopping"; // when you stop (abort) a print it prints the endcode + + Printer.ON_BEFORE_UNLOAD_MESSAGE = "You're doodle is still being send to the printer, leaving will result in a incomplete 3D print"; + + this.temperature = 0; + this.targetTemperature = 0; + this.currentLine = 0; + this.totalLines = 0; + this.bufferedLines = 0; + this.state = Printer.UNKNOWN_STATE; + this.hasControl = true; // whether this client has control access + + this.wifiboxURL; + + this.checkStatusInterval = 3000; + this.checkStatusDelay; + this.timeoutTime = 3000; + this.sendPrintPartTimeoutTime = 5000; + + this.gcode; // gcode to be printed + this.sendLength = 1500; // max amount of gcode lines per post (limited because WiFi box can't handle to much) + + this.retryDelay = 2000; // retry setTimout delay + this.retrySendPrintPartDelay; // retry setTimout instance + this.retryCheckStatusDelay; // retry setTimout instance + this.retryStopDelay; // retry setTimout instance + this.retryPreheatDelay; // retry setTimout instance + + this.maxGCodeSize = 10; // max size of gcode in MB's (estimation) + + this.stateOverruled = false; + + // Events + Printer.UPDATE = "update"; + + var self = this; + + this.init = function() { + console.log("Printer:init"); + //this.wifiboxURL = "http://" + window.location.host + "/cgi-bin/d3dapi"; + //this.wifiboxURL = "http://192.168.5.1/cgi-bin/d3dapi"; + this.wifiboxURL = wifiboxURL; + //this.wifiboxURL = "proxy5.php"; + console.log(" wifiboxURL: ",this.wifiboxURL); + + if(autoUpdate) { + this.startStatusCheckInterval(); + } + } + + this.preheat = function() { + console.log("Printer:preheat"); + var self = this; + if (communicateWithWifibox) { + $.ajax({ + url: this.wifiboxURL + "/printer/heatup", + type: "POST", + dataType: 'json', + timeout: this.timeoutTime, + success: function(data){ + console.log("Printer:preheat response: ",data); + if(data.status == "error") { + clearTimeout(self.retryPreheatDelay); + self.retryPreheatDelay = setTimeout(function() { self.preheat() },self.retryDelay); // retry after delay + } + } + }).fail(function() { + console.log("Printer:preheat: failed"); + clearTimeout(self.retryPreheatDelay); + self.retryPreheatDelay = setTimeout(function() { self.preheat() },self.retryDelay); // retry after delay + }); + } else { + console.log ("Printer >> f:preheat() >> communicateWithWifibox is false, so not executing this function"); + } + } + + this.print = function(gcode) { + console.log("Printer:print"); + console.log(" gcode total # of lines: " + gcode.length); + + message.set("Sending doodle to printer...",Message.NOTICE); + self.addLeaveWarning(); + + /*for (i = 0; i < gcode.length; i++) { + gcode[i] += " (" + i + ")"; + }*/ + + this.sendIndex = 0; + this.gcode = gcode; + + //console.log(" gcode[20]: ",gcode[20]); + var gcodeLineSize = this.byteSize(gcode[20]); + //console.log(" gcodeLineSize: ",gcodeLineSize); + var gcodeSize = gcodeLineSize*gcode.length/1024/1024; // estimate gcode size in MB's + console.log(" gcodeSize: ",gcodeSize); + + if(gcodeSize > this.maxGCodeSize) { + console.log("Error: Printer:print: gcode file is probably to big ("+gcodeSize+"MB) (max: "+this.maxGCodeSize+"MB)"); + return; + } + + //this.targetTemperature = settings["printer.temperature"]; // slight hack + + this.sendPrintPart(this.sendIndex, this.sendLength); + } + this.byteSize = function(s){ + return~-encodeURI(s).split(/%..|./).length; + } + this.sendPrintPart = function(sendIndex,sendLength) { + console.log("Printer:sendPrintPart sendIndex: " + sendIndex + "/" + this.gcode.length + ", sendLength: " + sendLength); + + var firstOne = (sendIndex == 0)? true : false; + var start = firstOne; // start printing right away + + var completed = false; + if (this.gcode.length < (sendIndex + sendLength)) { + console.log(" sending less than max sendLength (and last)"); + sendLength = this.gcode.length - sendIndex; + //lastOne = true; + completed = true; + } + var gcodePart = this.gcode.slice(sendIndex, sendIndex+sendLength); + + var postData = { gcode: gcodePart.join("\n"), first: firstOne, start: start}; + var self = this; + if (communicateWithWifibox) { + $.ajax({ + url: this.wifiboxURL + "/printer/print", + type: "POST", + data: postData, + dataType: 'json', + timeout: this.sendPrintPartTimeoutTime, + success: function(data){ + console.log("Printer:sendPrintPart response: ",data); + + if(data.status == "success") { + if (completed) { + console.log("Printer:sendPrintPart:gcode sending completed"); + this.gcode = []; + btnStop.css("display","block"); // hack + self.removeLeaveWarning(); + message.set("Doodle is send to printer...",Message.INFO,true); + //self.targetTemperature = settings["printer.temperature"]; // slight hack + } else { + // only if the state hasn't bin changed (by for example pressing stop) we send more gcode + + console.log("Printer:sendPrintPart:gcode part received (state: ",self.state,")"); + if(self.state == Printer.PRINTING_STATE || self.state == Printer.BUFFERING_STATE) { + console.log("Printer:sendPrintPart:sending next part"); + self.sendPrintPart(sendIndex + sendLength, sendLength); + } + } + } + // after we know the first gcode packed has bin received or failed + // (and the driver had time to update the printer.state) + // we start checking the status again + if(sendIndex == 0) { + self.startStatusCheckInterval(); + } + } + }).fail(function() { + console.log("Printer:sendPrintPart: failed"); + clearTimeout(self.retrySendPrintPartDelay); + self.retrySendPrintPartDelay = setTimeout(function() { + console.log("request printer:sendPrintPart failed retry"); + self.sendPrintPart(sendIndex, sendLength) + },self.retryDelay); // retry after delay + + // after we know the gcode packed has bin received or failed + // (and the driver had time to update the printer.state) + // we start checking the status again + self.startStatusCheckInterval(); + }); + } else { + console.log ("Printer >> f:sendPrintPart() >> communicateWithWifibox is false, so not executing this function"); + } + } + + this.stop = function() { + console.log("Printer:stop"); + var self = this; + if (communicateWithWifibox) { + $.ajax({ + url: this.wifiboxURL + "/printer/stop", + type: "POST", + dataType: 'json', + timeout: this.timeoutTime, + success: function(data){ + console.log("Printer:stop response: ", data); + + // after we know the stop has bin received or failed + // (and the driver had time to update the printer.state) + // we start checking the status again + self.startStatusCheckInterval(); + } + }).fail(function() { + console.log("Printer:stop: failed"); + clearTimeout(self.retryStopDelay); + self.retryStopDelay = setTimeout(function() { self.stop() },self.retryDelay); // retry after delay + + // after we know the stop has bin received or failed + // (and the driver had time to update the printer.state) + // we start checking the status again + self.startStatusCheckInterval(); + }); + } else { + console.log ("Printer >> f:communicateWithWifibox() >> communicateWithWifibox is false, so not executing this function"); + } + } + this.startStatusCheckInterval = function() { + console.log("Printer:startStatusCheckInterval"); + self.checkStatus(); + clearTimeout(self.checkStatusDelay); + clearTimeout(self.retryCheckStatusDelay); + self.checkStatusDelay = setTimeout(function() { self.checkStatus() }, self.checkStatusInterval); + } + this.stopStatusCheckInterval = function() { + console.log("Printer:stopStatusCheckInterval"); + clearTimeout(self.checkStatusDelay); + clearTimeout(self.retryCheckStatusDelay); + } + this.checkStatus = function() { + console.log("Printer:checkStatus"); + this.stateOverruled = false; + //console.log(" stateOverruled: ",this.stateOverruled); + var self = this; + if (communicateWithWifibox) { + $.ajax({ + url: this.wifiboxURL + "/info/status", + dataType: 'json', + timeout: this.timeoutTime, + success: function(response){ + //console.log(" Printer:status: ",response.data.state); //," response: ",response); + + self.handleStatusUpdate(response); + + clearTimeout(self.checkStatusDelay); + clearTimeout(self.retryCheckStatusDelay); + self.checkStatusDelay = setTimeout(function() { self.checkStatus() }, self.checkStatusInterval); + } + }).fail(function() { + console.log("Printer:checkStatus: failed"); + self.state = Printer.WIFIBOX_DISCONNECTED_STATE; + clearTimeout(self.checkStatusDelay); + clearTimeout(self.retryCheckStatusDelay); + self.retryCheckStatusDelay = setTimeout(function() { self.checkStatus() },self.retryDelay); // retry after delay + $(document).trigger(Printer.UPDATE); + }); + } else { + console.log ("Printer >> f:checkStatus() >> communicateWithWifibox is false, so not executing this function"); + } + } + this.handleStatusUpdate = function(response) { + console.log("Printer:handleStatusUpdate response: ",response); + var data = response.data; + if(response.status != "success") { + self.state = Printer.UNKNOWN_STATE; + } else { + // state + //console.log(" stateOverruled: ",this.stateOverruled); + if(!this.stateOverruled) { + self.state = data.state; + //console.log(" state > ",self.state); + } + + // temperature + self.temperature = data.hotend; + self.targetTemperature = data.hotend_target; + + // progress + self.currentLine = data.current_line; + self.totalLines = data.total_lines; + self.bufferedLines = data.buffered_lines + + // access + self.hasControl = data.has_control; + + if(self.state == Printer.PRINTING_STATE || self.state == Printer.STOPPING_STATE) { + console.log("progress: ",self.currentLine+"/"+self.totalLines+" ("+self.bufferedLines+") ("+self.state+")"); + } + } + $(document).trigger(Printer.UPDATE); + } + this.overruleState = function(newState) { + this.stateOverruled = true; + console.log(" stateOverruled: ",this.stateOverruled); + + self.state = newState; + + $(document).trigger(Printer.UPDATE); + + this.stopStatusCheckInterval(); + } + + this.removeLeaveWarning = function() { + window.onbeforeunload = null; + } + this.addLeaveWarning = function() { + window.onbeforeunload = function() { + return Printer.ON_BEFORE_UNLOAD_MESSAGE; + }; + } +} +function Progressbar() { + this.currProgress = 0; // default val + + this.progressbarFGImg = new Image(); + this.progressbarFGImgSrc = "img/progress_fg.png"; + this.progressbarBGImg = new Image(); + this.progressbarBGImgSrc = "img/progress_bg.png"; + + this.progressWidth= 93; + this.progressHeight = 82; + + this.quartPI = .5 * Math.PI; + this.twoPI = 2 * Math.PI; + + + this.$canvas; + this.canvas; + this.context; + this.$container; + + this.isInitted = false; + + this.enabled = true; + + this.init = function(targCanvas, targCanvasContainer) { + console.log("Thermometer.init()"); + + this.$container = targCanvasContainer; + + this.$canvas = targCanvas; + this.canvas = this.$canvas[0]; + this.context = this.canvas.getContext('2d'); + + + var self = this; + this.progressbarBGImg.onload = function() { + console.log("progressbarBGImg img loaded"); + // self.isInitted = true; + // self.update(self.currentTemperature, self.targetTemperature); + + self.progressbarFGImg.onload = function() { + console.log("progressbarFGImg img loaded"); + self.isInitted = true; + self.update(0, 100); + }; + self.progressbarFGImg.src = self.progressbarFGImgSrc; + }; + this.progressbarBGImg.src = this.progressbarBGImgSrc; + } + + this.update = function(part, total) { + //console.log("Progressbar.update(" + part + "," + total + ")"); + + var pct = part / total; + if (this.isInitted) { + if (part == undefined) part = 0; + if (total== undefined) total = 100; // prevent divide by zero + + var progress = part / total; + progress = Math.min(progress, 1.0); + progress = Math.max(progress, 0); + //console.log("progressbar >> f:update() >> progress: " + progress); + + // clear + this.context.clearRect(0, 0, this.canvas.width, this.canvas.height); + + this.context.drawImage(this.progressbarBGImg, 0, 0); + + this.context.font = "7pt sans-serif"; + + // draw the progressbar foreground's clipping path + this.context.save(); + this.context.beginPath(); + this.context.moveTo(45, 45); + this.context.lineTo(45, 0); + this.context.arc(45, 45, 45, -this.quartPI, -this.quartPI + (progress * (this.twoPI)), false); // circle bottom of thermometer + this.context.lineTo(45, 45); + this.context.clip(); + + this.context.drawImage(this.progressbarFGImg, 0, 0); + this.context.restore(); + + if (debugMode) { + this.context.fillStyle = '#222'; + this.context.strokeStyle = '#fff'; + this.context.lineWidth = 3; + this.context.textAlign="center"; + this.context.strokeText(part + " / " + total, 45, 45, 90); + this.context.fillText(part + " / " + total, 45, 45, 90); + } + + } else { + console.log("Progressbar.setTemperature() -> thermometer not initialized!"); + } + } + this.show = function() { + this.$container.addClass("progressbarAppear"); + // this.$container.show(); + this.enabled = true; + } + this.hide = function() { + this.$container.removeClass("progressbarAppear"); + // this.$container.hide(); + this.enabled = false; + } +} + +// TODO assess if this var is still necessary +var $displayThermometer = $("#thermometerContainer"); + + +//TODO 2013-09-18 allow displaying temperatures HIGHER than the targTemp (it's now being capped at targTemp). +function Thermometer() { + this.currentTemperature = 0; // default val + this.targetTemperature = 0; // default val + + this.thermoOverlayImg = new Image(); + this.thermoOverlayImgSrc = "img/thermometer_fg_overlay.png"; // ../img/thermometer_fg_overlay.png + + this.thermoWidth= 40; + this.thermoHeight = 100; + + this.$canvas; + this.canvas; + this.context; + this.$container; + + this.isInitted = false; + + this.enabled = true; + + this.thermoColors = [ + [50, 200, 244], // 'cold' + [244, 190, 10], // 'warming up' + [244, 50, 50] // 'ready / hot' + ]; + + this.init = function(targCanvas, targCanvasContainer) { + console.log("Thermometer.init()"); + + this.$container = targCanvasContainer; + + this.$canvas = targCanvas; + this.canvas = this.$canvas[0]; + this.context = this.canvas.getContext('2d'); + + + var self = this; + this.thermoOverlayImg.onload = function() { + console.log("canvasThermoOverlay img loaded"); + self.isInitted = true; + self.update(self.currentTemperature, self.targetTemperature); + }; + this.thermoOverlayImg.src = this.thermoOverlayImgSrc; + } + + this.update = function(curr, targ) { + // console.log("Thermometer.update(" + curr + "," + targ + ")"); + + if (this.isInitted) { + if(!this.enabled) return; + if (curr == undefined) curr = 0; + if (targ== undefined) targ = 180; // prevent divide by zero + + var progress = curr / targ; + + progress = Math.min(progress, 1.0); + progress = Math.max(progress, 0); + + var h = this.thermoHeight; // 94 // px + var paddingUnder = 15; // how far is beginpoint from bottom of thermometer + var paddingAbove = 25; // how far is endpoint from top of thermometer + var endPoint = h * .8; + var p = Math.floor((h - paddingUnder - paddingAbove) * progress); // % + // var tempHeight = + + var currColor = this.thermoColors[0]; + if (progress > 0.98) { + currColor = this.thermoColors[2]; + } else if (progress > 0.25) { + currColor = this.thermoColors[1]; + } + + // clear + this.context.clearRect(0, 0, this.canvas.width, this.canvas.height); + this.context.font = "10pt sans-serif"; + + // draw the thermometer clipping path + this.context.save(); + this.context.beginPath(); + this.context.arc(40, 80, 16, 0, 2 * Math.PI, false); // circle bottom of thermometer + this.context.arc(40, 10, 4, 0, 2 * Math.PI, false); // circle at top of thermometer tube + this.context.rect(36, 11, 8, 70); // thermometer tube + this.context.fillStyle = '#fff'; + this.context.fill(); + this.context.clip(); + + // draw rectangle which represents temperature + // rect will be clipped by the thermometer outlines + this.context.beginPath(); + this.context.rect(20, h - paddingUnder - p, 60, p + paddingUnder); + //console.log(" currColor: " + currColor); + //todo Math.floor?? + this.context.fillStyle = "rgb(" + currColor[0] + "," + currColor[1] + "," + currColor[2] + ")"; + this.context.fill(); + this.context.restore(); + + // additional text labels + this.context.save(); + this.context.beginPath(); + this.context.moveTo(32, paddingAbove); + this.context.lineTo(52, paddingAbove); + this.context.lineWidth = 2; + this.context.strokeStyle = '#000'; + this.context.stroke(); + this.context.fillStyle = '#000'; + this.context.textAlign = "left"; + this.context.textBaseline = "middle"; + this.context.fillText(targ + "°", 55, paddingAbove); + this.context.restore(); + + // the thermometer outline png + this.context.drawImage(this.thermoOverlayImg, 20, 0); + + // text + this.context.fillStyle = '#000'; + this.context.textAlign="center"; + this.context.fillText(curr + "°", 40, h + paddingUnder); + } else { + console.log("Thermometer.setTemperature() -> thermometer not initialized!"); + } + } + this.show = function() { + this.$container.addClass("thermometerAppear"); +// $("#progressbarCanvasContainer").addClass("thermometerAppear"); +// this.$container.show(); + this.enabled = true; + } + this.hide = function() { + this.$container.removeClass("thermometerAppear"); +// $("#progressbarCanvasContainer").removeClass("thermometerAppear"); +// this.$container.hide(); + this.enabled = false; + } +} + + +// http://stackoverflow.com/questions/1403888/get-url-parameter-with-jquery +function getURLParameter(name) { + return decodeURI( + (new RegExp('[&?]'+name + '=' + '(.+?)(&|$)').exec(location.search)||[,null])[1] + ); +} + +var sidebarLeft; +var sidebarRight; + +function initSidebars() { + console.log("f:initSidebars()"); + + sidebarLeft = new SideBar(); + sidebarLeft.init(".leftpanel", "hideleft", function() { + $(".leftpanel").show(); + }); + + sidebarRight = new SideBar(); + sidebarRight.init(".rightpanel", "hideright", function() { + $(".rightpanel").show(); + }); +} + +function SideBar() { + this.initted = false; + this.$contentTarg = undefined; + this.$sideBtn = undefined; + this.contentHidden = false; + this.hideClass = ""; + + this.init = function(targ, hideClass, callback) { + console.log("SideBar >> f:init >> targ: " , $(targ) , ", hideClass: " + hideClass); + this.$contentTarg = $(targ); + this.hideClass = hideClass; + + this.$contentTarg.addClass(this.hideClass); + this.contentHidden = true; + + this.$contentTarg.append("
"); + this.$sideBtn = $(targ +" .sidebutton"); + var self = this; + + this.$sideBtn.on('click', function(e) { + console.log("sidebutton"); + self.toggleShowHide(); + }); + + this.initted = true; + + callback(); + } + + this.toggleShowHide = function() { + if (this.contentHidden) { + this.contentHidden = false; + this.$contentTarg.removeClass(this.hideClass); + // self.$sideBtn.addClass("sidebuttonin"); + this.$sideBtn.addClass("sidebuttonin"); + } else { + this.contentHidden = true; + this.$contentTarg.addClass(this.hideClass); + // self.$sideBtn.removeClass("sidebuttonin"); + this.$sideBtn.removeClass("sidebuttonin"); + + } + } +} + + +function Message() { + + Message.ERROR = "error"; + Message.WARNING = "warning"; + Message.NOTICE = "notice"; + Message.INFO = "info"; + + this.mode = ""; + + this.$element; + + var self = this; + var autoHideDelay = 2000; + var autohideTimeout; + + this.init = function($element) { + console.log("Message:init"); + + this.$element = $element; + console.log("$element: ",$element); + } + + this.set = function(text,mode,autoHide) { + console.log("Message:set: ",text,mode,autoHide); + self.hide(function() { + self.show(); + self.clear(); + + self.$element.text(text); + self.$element.addClass(mode); + self.show(); + + self.mode = mode; + + clearTimeout(autohideTimeout); + if(autoHide) { + autohideTimeout = setTimeout(function(){ self.hide()},autoHideDelay); + } + }); + } + this.clear = function($element) { + this.$element.text(""); + this.$element.removeClass(this.mode); + } + + this.show = function() { + this.$element.fadeIn(200); + } + this.hide = function(complete) { + this.$element.fadeOut(200,complete); + } +} +var debugMode = false; // debug mode +var sendPrintCommands = true; // if Doodle3d should send print commands to the 3d printer +var communicateWithWifibox = true; // if Doodle3d should try interfacing with the wifibox (in case one is not connected) +var wifiboxIsRemote = false; // when you want to run the client on a computer and have it remotely connect to the wifibox +var autoUpdate = true; // auto retrieve updates about temperature and progress from printer + +var printer = new Printer(); +var progressbar = new Progressbar(); +var thermometer = new Thermometer(); +var settingsWindow = new SettingsWindow(); +var message = new Message(); + +var firstTimeSettingsLoaded = true; + +var wifiboxURL; // Using the uhttpd lua handler as default, because of better performance +var wifiboxCGIBinURL; // CGI-bin, for some network stuff, where it needs to restart the webserver for example + +var $drawAreaContainer, $doodleCanvas, doodleCanvas, doodleCanvasContext, $previewContainer; + +var showhideInterval; +var showOrHide = false; + +$(function() { + console.log("ready"); + + + //TODO give this a more logical place in code + + if (getURLParameter("d") != "null") debugMode = (getURLParameter("d") == "1"); + if (getURLParameter("p") != "null") sendPrintCommands = (getURLParameter("p") == "1"); + if (getURLParameter("c") != "null") communicateWithWifibox = (getURLParameter("c") == "1"); + if (getURLParameter("r") != "null") wifiboxIsRemote = (getURLParameter("r") == "1"); + if (getURLParameter("u") != "null") autoUpdate = (getURLParameter("u") == "1"); + + if (wifiboxIsRemote) { + wifiboxURL = "http://192.168.5.1/d3dapi"; + wifiboxCGIBinURL = "http://192.168.5.1/cgi-bin/d3dapi"; + } else { + wifiboxURL = "http://" + window.location.host + "/d3dapi"; + wifiboxCGIBinURL = "http://" + window.location.host + "/cgi-bin/d3dapi"; + } + + if (!communicateWithWifibox) { + sendPrintCommands = false; // 'communicateWithWifibox = false' implies this + } + console.log("debugMode: " + debugMode); + console.log("sendPrintCommands: " + sendPrintCommands); + console.log("communicateWithWifibox: " + communicateWithWifibox); + console.log("wifiboxIsRemote: " + wifiboxIsRemote); + console.log("wifibox URL: " + wifiboxURL); + + initDoodleDrawing(); + initPreviewRendering(); + initLayouting(); + initSidebars(); + initButtonBehavior(); + initVerticalShapes(); + + thermometer.init($("#thermometerCanvas"), $("#thermometerContainer")); + progressbar.init($("#progressbarCanvas"), $("#progressbarCanvasContainer")); + + message.init($("#message")); + + printer.init(); + $(document).on(Printer.UPDATE,update); + + settingsWindow.init(wifiboxURL,wifiboxCGIBinURL); + $(document).on(SettingsWindow.SETTINGS_LOADED, settingsLoaded); + + if(debugMode) { + console.log("debug mode is true"); + $("body").css("overflow", "auto"); + $("#debug_textArea").css("display", "block"); + $("#preview_tmp").css("display", "block"); + + $("#debug_display").css("display", "block"); + + // show and hide the progressguage and thermometer + showhideInterval = setInterval(showOrHideThermo, 2500); + +// $("#debugContainer").css("display", "block"); + + /* TEMP CODE!! -> artificially populates the startgcode and endgcode textareas in the settings window */ + // todo remove this temporary code... + /* + setTimeout(function() { + $("#startgcode").text(""); + $("#startgcode").append("G21 (mm) \n"); + $("#startgcode").append("G91 (relative) \n"); + $("#startgcode").append("G28 X0 Y0 Z0 (physical home) \n"); + $("#startgcode").append("M104 S230 (temperature) \n"); + $("#startgcode").append("G1 E10 F250 (flow) \n"); + $("#startgcode").append("G92 X-100 Y-100 Z0 E10 \n"); + $("#startgcode").append("G1 Z3 F5000 (prevent diagonal line) \n"); + $("#startgcode").append("G90 (absolute) \n"); + $("#startgcode").append("M106 (fan on)"); + console.log("$('#startgcode'): " + $("#startgcode").val()); + + $("#endgcode").text(""); + $("#endgcode").append("G1 X-100 Y-100 F15000 (fast homing) \n"); + $("#endgcode").append("M107 \n"); + $("#endgcode").append("M84 (disable axes) \n"); + console.log("$('#endgcode'): " + $("#endgcode").val()); + }, 1000); + //*/ + } +}); + +function showOrHideThermo() { + console.log("f:showOrHideThermo()"); + if (showOrHide) { + thermometer.hide(); + progressbar.hide(); + } else { + thermometer.show(); + progressbar.show(); + + } + showOrHide = !showOrHide; +} + +function settingsLoaded() { + console.log("settingsLoaded"); + console.log("autoHeatup: ",settings["printer.heatup.enabled"]); + if(settings["printer.heatup.enabled"]) { + if(firstTimeSettingsLoaded) { + printer.preheat(); + firstTimeSettingsLoaded = false; + } + } +} + +function setDebugText(text) { + $("#debug_display").text(text); +} \ No newline at end of file diff --git a/www/js/doodle3d-client.min.js b/www/js/doodle3d-client.min.js new file mode 100644 index 0000000..054e1db --- /dev/null +++ b/www/js/doodle3d-client.min.js @@ -0,0 +1,2 @@ +function SettingsWindow(){this.wifiboxURL,this.wifiboxCGIBinURL,this.window,this.form,this.timeoutTime=3e3,this.retryDelay=2e3,this.retryRetrieveNetworkStatusDelayTime=1e3,this.retryLoadSettingsDelay,this.retrySaveSettingsDelay,this.retryRetrieveNetworkStatusDelay,this.apFieldSet,this.clientFieldSet,this.networks,this.currentNetwork,this.selectedNetwork,this.currentLocalIP="",this.clientModeState=SettingsWindow.NOT_CONNECTED,this.currentAP,this.apModeState=SettingsWindow.NO_AP,this.retrieveNetworkStatusDelay,this.retrieveNetworkStatusDelayTime=1e3,SettingsWindow.SETTINGS_LOADED="settingsLoaded",SettingsWindow.NOT_CONNECTED="not connected",SettingsWindow.CONNECTED="connected",SettingsWindow.CONNECTING="connecting",SettingsWindow.CONNECTING_FAILED="connecting failed",SettingsWindow.NO_AP="no ap",SettingsWindow.AP="ap",SettingsWindow.CREATING_AP="creating ap",SettingsWindow.API_CONNECTING_FAILED=-1,SettingsWindow.API_NOT_CONNECTED=0,SettingsWindow.API_CONNECTING=1,SettingsWindow.API_CONNECTED=2,SettingsWindow.API_CREATING=3,SettingsWindow.API_CREATED=4,SettingsWindow.NETWORK_MODE_NEITHER="neither",SettingsWindow.NETWORK_MODE_CLIENT="clientMode",SettingsWindow.NETWORK_MODE_ACCESS_POINT="accessPointMode",this.networkMode=SettingsWindow.NETWORK_MODE_NEITHER,this.updatePanel=new UpdatePanel;var a=this;this.init=function(b,c){this.wifiboxURL=b,this.wifiboxCGIBinURL=c,this.window=$("#settings"),this.window.find(".btnOK").click(this.submitwindow),this.window.find(".settingsContainer").load("settings.html",function(){console.log("Settings:finished loading settings.html, now loading settings..."),a.form=a.window.find("form"),a.form.submit(function(b){a.submitwindow(b)}),a.loadSettings();var c=a.form.find("label[for='ap']"),d=a.form.find("label[for='client']"),e=a.form.find("#refreshNetworks"),f=a.form.find("#connectToNetwork"),g=a.form.find("#createAP"),h=a.form.find("#network");a.apFieldSet=a.form.find("#apSettings"),a.clientFieldSet=a.form.find("#clientSettings"),c.on("touchstart mousedown",a.showAPSettings),d.on("touchstart mousedown",a.showClientSettings),e.on("touchstart mousedown",a.refreshNetworks),f.on("touchstart mousedown",a.connectToNetwork),g.on("touchstart mousedown",a.createAP),h.change(a.networkSelectorChanged);var i=a.form.find("#updatePanel");a.updatePanel.init(b,i)})},this.submitwindow=function(b){b.preventDefault(),b.stopPropagation(),a.saveSettings(a.readForm(),function(){a.hideSettings()}),clearTimeout(a.retryRetrieveNetworkStatusDelay)},this.showSettings=function(){console.log("f:showSettings()"),this.loadSettings(),$("#contentOverlay").fadeIn(375,function(){document.body.removeEventListener("touchmove",prevent,!1)})},this.hideSettings=function(){$("#contentOverlay").fadeOut(375,function(){document.body.addEventListener("touchmove",prevent,!1)})},this.loadSettings=function(){return communicateWithWifibox?(console.log("Settings:loadSettings() >> getting new data..."),$.ajax({url:this.wifiboxURL+"/config/all",dataType:"json",timeout:this.timeoutTime,success:function(b){console.log("Settings:loadSettings response: ",b),settings=b.data,console.log(" settings: ",settings),a.fillForm(),$(document).trigger(SettingsWindow.SETTINGS_LOADED)}}).fail(function(){console.log("Settings:loadSettings: failed"),clearTimeout(a.retryLoadSettingsDelay),a.retryLoadSettingsDelay=setTimeout(function(){a.loadSettings()},a.retryDelay)}),this.refreshNetworks(),this.retrieveNetworkStatus(!1),void 0):(console.log(" communicateWithWifibox is false: settings aren't being loaded from wifibox..."),void 0)},this.fillForm=function(){console.log("SettingsWindow:fillForm");var a=this.form.find("select");a.each(function(a,b){var b=$(b);b.val(settings[b.attr("name")])});var b=this.form.find("input");b.each(function(a,b){var b=$(b);switch(b.attr("type")){case"text":case"number":b.val(settings[b.attr("name")]);break;case"checkbox":b.prop("checked",settings[b.attr("name")])}});var c=this.form.find("textarea");c.each(function(a,b){var b=$(b),c=settings[b.attr("name")];b.val(c)})},this.saveSettings=function(b,c){settings=b,communicateWithWifibox&&$.ajax({url:this.wifiboxURL+"/config",type:"POST",data:b,dataType:"json",timeout:this.timeoutTime,success:function(b){if(console.log("Settings:saveSettings response: ",b),"error"==b.status)clearTimeout(a.retrySaveSettingsDelay),a.retrySaveSettingsDelay=setTimeout(function(){a.saveSettings(settings)},a.retryDelay);else{var d=b.data,e=d.validation;a.clearValidationErrors();var f=!0;$.each(e,function(b,c){"ok"!=c&&(console.log("ERROR: setting '"+b+"' not successfully set. Message: "+c),a.displayValidationError(b,c),f=!1)}),settings.substituted_ssid=d.substituted_ssid,c&&f&&c()}}}).fail(function(){console.log("Settings:saveSettings: failed"),clearTimeout(a.retrySaveSettingsDelay),a.retrySaveSettingsDelay=setTimeout(function(){a.saveSettings(settings)},a.retryDelay)})},this.displayValidationError=function(b,c){var d=a.form.find("[name|='"+b+"']");console.log("formElement: ",d),d.addClass("error");var e="

"+c+"

";d.after(e)},this.clearValidationErrors=function(){var b=a.form.find(".error");b.each(function(a,b){$(b).removeClass("error")})},this.readForm=function(){var b={},c=a.form.find("select");c.each(function(a,c){var c=$(c);"network.client.network"!=c.attr("name")&&(b[c.attr("name")]=c.val())});var d=a.form.find("input");d.each(function(a,c){var c=$(c);switch(c.attr("type")){case"text":case"number":b[c.attr("name")]=c.val();break;case"checkbox":b[c.attr("name")]=c.prop("checked")}});var e=a.form.find("textarea");return e.each(function(a,c){var c=$(c);b[c.attr("name")]=c.val()}),b},this.showAPSettings=function(){a.apFieldSet.show(),a.clientFieldSet.hide()},this.showClientSettings=function(){a.clientFieldSet.show(),a.apFieldSet.hide()},this.refreshNetworks=function(){console.log("Settings:refreshNetworks"),communicateWithWifibox&&$.ajax({url:a.wifiboxURL+"/network/scan",type:"GET",dataType:"json",timeout:a.timeoutTime,success:function(b){if(console.log("Settings:refreshNetworks response: ",b),"error"==b.status);else{var c=b.data.networks;a.networks={};var d=!1,e=a.form.find("#network");e.empty(),e.append($("").val(SettingsWindow.NOT_CONNECTED).html("not connected")),$.each(c,function(b,c){c.ssid==a.currentNetwork&&(d=!0),e.append($("").val(c.ssid).html(c.ssid)),a.networks[c.ssid]=c}),d&&(e.val(a.currentNetwork),a.selectNetwork(a.currentNetwork))}}}).fail(function(){})},this.retrieveNetworkStatus=function(b){communicateWithWifibox&&$.ajax({url:a.wifiboxURL+"/network/status",type:"GET",dataType:"json",timeout:a.timeoutTime,success:function(c){if(console.log("Settings:retrieveNetworkStatus response: ",c),"error"==c.status);else{var d=c.data;switch("string"==typeof d.status&&(d.status=parseInt(d.status)),d.status){case SettingsWindow.API_NOT_CONNECTED:a.apFieldSet.show(),a.clientFieldSet.show(),a.networkMode=SettingsWindow.NETWORK_MODE_NEITHER;break;case SettingsWindow.API_CONNECTING_FAILED:case SettingsWindow.API_CONNECTING:case SettingsWindow.API_CONNECTED:if(a.form.find("#client").prop("checked",!0),a.apFieldSet.hide(),a.clientFieldSet.show(),d.status==SettingsWindow.API_CONNECTED){var e=a.form.find("#network");e.val(d.ssid),a.currentNetwork=d.ssid,a.currentLocalIP=d.localip,a.selectNetwork(d.ssid)}else a.currentLocalIP="";a.networkMode=SettingsWindow.NETWORK_MODE_CLIENT;break;case SettingsWindow.API_CREATING:case SettingsWindow.API_CREATED:a.form.find("#ap").prop("checked",!0),a.apFieldSet.show(),a.clientFieldSet.hide(),a.currentNetwork=void 0,a.selectNetwork(SettingsWindow.NOT_CONNECTED);var e=a.form.find("#network");e.val(SettingsWindow.NOT_CONNECTED),d.ssid&&d.status==SettingsWindow.API_CREATED&&(a.currentAP=d.ssid),a.networkMode=SettingsWindow.NETWORK_MODE_ACCESS_POINT}switch(a.updatePanel.setNetworkMode(a.networkMode),d.status){case SettingsWindow.API_CONNECTING_FAILED:a.setClientModeState(SettingsWindow.CONNECTING_FAILED,d.statusMessage),a.setAPModeState(SettingsWindow.NO_AP,"");break;case SettingsWindow.API_NOT_CONNECTED:a.setClientModeState(SettingsWindow.NOT_CONNECTED,""),a.setAPModeState(SettingsWindow.NO_AP,"");break;case SettingsWindow.API_CONNECTING:a.setClientModeState(SettingsWindow.CONNECTING,""),a.setAPModeState(SettingsWindow.NO_AP,"");break;case SettingsWindow.API_CONNECTED:a.setClientModeState(SettingsWindow.CONNECTED,""),a.setAPModeState(SettingsWindow.NO_AP,"");break;case SettingsWindow.API_CREATING:a.setClientModeState(SettingsWindow.NOT_CONNECTED,""),a.setAPModeState(SettingsWindow.CREATING_AP,"");break;case SettingsWindow.API_CREATED:a.setClientModeState(SettingsWindow.NOT_CONNECTED,""),a.setAPModeState(SettingsWindow.AP,"")}if(b)switch(d.status){case SettingsWindow.API_CONNECTING:case SettingsWindow.API_CREATING:clearTimeout(a.retryRetrieveNetworkStatusDelay),a.retryRetrieveNetworkStatusDelay=setTimeout(function(){a.retrieveNetworkStatus(b)},a.retryRetrieveNetworkStatusDelayTime)}}}}).fail(function(){console.log("Settings:retrieveNetworkStatus: failed"),clearTimeout(a.retryRetrieveNetworkStatusDelay),a.retryRetrieveNetworkStatusDelay=setTimeout(function(){a.retrieveNetworkStatus(b)},a.retryDelay)})},this.networkSelectorChanged=function(){var b=$(this).find("option:selected");a.selectNetwork(b.val())},this.selectNetwork=function(a){if(console.log("select network: ",a),""!=a)if(console.log(" checked"),this.selectedNetwork=a,void 0==this.networks||a==SettingsWindow.NOT_CONNECTED)this.hideWiFiPassword();else{var b=this.networks[a];"none"==b.encryption?this.hideWiFiPassword():this.showWiFiPassword(),this.form.find("#password").val("")}},this.showWiFiPassword=function(){this.form.find("#passwordLabel").show(),this.form.find("#password").show()},this.hideWiFiPassword=function(){this.form.find("#passwordLabel").hide(),this.form.find("#password").hide()},this.setClientModeState=function(b,c){var d=this.form.find("#clientModeState"),e=a.form.find("#connectToNetwork");switch(b){case SettingsWindow.NOT_CONNECTED:e.removeAttr("disabled"),d.html("Not connected");break;case SettingsWindow.CONNECTED:e.removeAttr("disabled");var f="Connected to: "+this.currentNetwork+".";if(void 0!=this.currentLocalIP&&""!=this.currentLocalIP){var g=""+this.currentLocalIP+"";f+=" (IP: "+g+")"}d.html(f);break;case SettingsWindow.CONNECTING:e.attr("disabled",!0),d.html("Connecting... Reconnect by connecting your device to "+this.selectedNetwork+" and going to connect.doodle3d.com");break;case SettingsWindow.CONNECTING_FAILED:e.removeAttr("disabled"),d.html(c)}this.clientModeState=b},this.setAPModeState=function(a){var b=this.form.find("#apModeState"),c=this.form.find("#createAP");switch(a){case SettingsWindow.NO_AP:c.removeAttr("disabled"),b.html("Not currently a access point");break;case SettingsWindow.AP:c.removeAttr("disabled"),b.html("Is access point: "+this.currentAP+"");break;case SettingsWindow.CREATING_AP:c.attr("disabled",!0),b.html("Creating access point... Reconnect by connecting your device to "+settings.substituted_ssid+" and going to draw.doodle3d.com")}this.apModeState=a},this.connectToNetwork=function(){if(console.log("connectToNetwork"),void 0!=a.selectedNetwork){var b={ssid:a.selectedNetwork,phrase:a.form.find("#password").val(),recreate:!0};console.log(" postData: ",b),communicateWithWifibox&&a.saveSettings(a.readForm(),function(){$.ajax({url:a.wifiboxCGIBinURL+"/network/associate",type:"POST",data:b,dataType:"json",timeout:a.timeoutTime,success:function(a){console.log("Settings:connectToNetwork response: ",a)}}).fail(function(){console.log("Settings:connectToNetwork: timeout (normal behavior)")})}),a.setClientModeState(SettingsWindow.CONNECTING,""),clearTimeout(a.retrieveNetworkStatusDelay),a.retrieveNetworkStatusDelay=setTimeout(function(){a.retrieveNetworkStatus(!0)},a.retrieveNetworkStatusDelayTime)}},this.createAP=function(){console.log("createAP"),communicateWithWifibox&&a.saveSettings(a.readForm(),function(){a.setAPModeState(SettingsWindow.CREATING_AP),$.ajax({url:a.wifiboxCGIBinURL+"/network/openap",type:"POST",dataType:"json",timeout:a.timeoutTime,success:function(a){console.log("Settings:createAP response: ",a)}}).fail(function(){console.log("Settings:createAP: timeout (normal behavior)")}),a.setAPModeState(SettingsWindow.CREATING_AP,""),clearTimeout(a.retrieveNetworkStatusDelay),a.retrieveNetworkStatusDelay=setTimeout(function(){a.retrieveNetworkStatus(!0)},a.retrieveNetworkStatusDelayTime)})}}function UpdatePanel(){this.wifiboxURL,this.element,this.statusCheckInterval=1e3,this.statusCheckDelayer,this.installedDelay=6e4,this.installedDelayer,this.retryDelay=1e3,this.retryDelayer,this.canUpdate=!1,this.currentVersion="",this.newestVersion,this.progress,this.imageSize,UpdatePanel.NONE=1,UpdatePanel.DOWNLOADING=2,UpdatePanel.DOWNLOAD_FAILED=3,UpdatePanel.IMAGE_READY=4,UpdatePanel.INSTALLING=5,UpdatePanel.INSTALLED=6,UpdatePanel.INSTALL_FAILED=7,this.state,this.stateText="",this.networkMode;var a=this;this.init=function(a,b){this.wifiboxURL=a,this.element=b,this.btnUpdate=this.element.find("#update"),this.statusDisplay=this.element.find("#updateState"),this.infoDisplay=this.element.find("#updateInfo"),this.btnUpdate.click(this.update),this.checkStatus(!1)},this.update=function(){console.log("UpdatePanel:update"),a.downloadUpdate()},this.downloadUpdate=function(){console.log("UpdatePanel:downloadUpdate"),$.ajax({url:a.wifiboxURL+"/update/download",type:"POST",dataType:"json",success:function(a){console.log("UpdatePanel:downloadUpdate response: ",a)}}).fail(function(){console.log("UpdatePanel:downloadUpdate: failed")}),a.setState(UpdatePanel.DOWNLOADING),a.startCheckingStatus()},this.installUpdate=function(){console.log("UpdatePanel:installUpdate"),a.stopCheckingStatus(),$.ajax({url:a.wifiboxURL+"/update/install",type:"POST",dataType:"json",success:function(a){console.log("UpdatePanel:installUpdate response: ",a)}}).fail(function(){console.log("UpdatePanel:installUpdate: no respons (there shouldn't be)")}),a.setState(UpdatePanel.INSTALLING),clearTimeout(a.installedDelayer),a.installedDelayer=setTimeout(function(){a.setState(UpdatePanel.INSTALLED)},a.installedDelay)},this.startCheckingStatus=function(){clearTimeout(a.statusCheckDelayer),clearTimeout(a.retryDelayer),a.statusCheckDelayer=setTimeout(function(){a.checkStatus(!0)},a.statusCheckInterval)},this.stopCheckingStatus=function(){clearTimeout(a.statusCheckDelayer),clearTimeout(a.retryDelayer)},this.checkStatus=function(b){communicateWithWifibox&&$.ajax({url:a.wifiboxURL+"/update/status",type:"GET",dataType:"json",success:function(c){if(console.log("UpdatePanel:checkStatus response: ",c),b)switch(a.state){case UpdatePanel.DOWNLOADING:case UpdatePanel.INSTALLING:clearTimeout(a.statusCheckDelayer),a.statusCheckDelayer=setTimeout(function(){a.checkStatus(b)},a.statusCheckInterval)}if("error"!=c.status){var d=c.data;a.handleStatusData(d)}}}).fail(function(){b&&(clearTimeout(a.retryDelayer),a.retryDelayer=setTimeout(function(){a.checkStatus(b)},a.retryDelay))})},this.handleStatusData=function(b){switch(a.canUpdate=b.can_update,(a.currentVersion!=b.current_version||a.newestVersion!=b.newest_version)&&(a.currentVersion=b.current_version,a.newestVersion=b.newest_version,a.updateInfoDisplay()),a.stateText=b.state_text,a.progress=b.progress,a.imageSize=b.image_size,a.setState(b.state_code),this.state){case UpdatePanel.IMAGE_READY:a.installUpdate()}},this.setState=function(b){if(this.state!=b){if(console.log("UpdatePanel:setState: ",this.state," > ",b,"(",this.stateText,") (networkMode: ",a.networkMode,") (newestVersion: ",a.newestVersion,")"),this.state=b,void 0!=a.newestVersion)switch(this.state){case UpdatePanel.NONE:case UpdatePanel.DOWNLOAD_FAILED:case UpdatePanel.INSTALL_FAILED:a.canUpdate?a.btnUpdate.removeAttr("disabled"):a.btnUpdate.attr("disabled",!0);break;default:a.btnUpdate.attr("disabled",!0)}else a.btnUpdate.attr("disabled",!0);this.updateStatusDisplay()}},this.updateStatusDisplay=function(){var b="";if(void 0!=a.newestVersion)switch(this.state){case UpdatePanel.NONE:b=a.canUpdate?"Update(s) available.":"You're up to date.";break;case UpdatePanel.DOWNLOADING:b="Downloading update...";break;case UpdatePanel.DOWNLOAD_FAILED:b="Downloading update failed.";break;case UpdatePanel.IMAGE_READY:b="Update downloaded.";break;case UpdatePanel.INSTALLING:b="Installing update... (will take a minute)";break;case UpdatePanel.INSTALLED:b="Update complete, please refresh Page.";break;case UpdatePanel.INSTALL_FAILED:b="Installing update failed."}else b=a.networkMode==SettingsWindow.NETWORK_MODE_ACCESS_POINT?"Can't access internet in access point mode.":"Can't access internet.";this.statusDisplay.html(b)},this.updateInfoDisplay=function(){var b="Current version: "+a.currentVersion+". ";a.canUpdate&&(b+="Latest version: "+a.newestVersion+"."),a.infoDisplay.text(b)},this.setNetworkMode=function(b){a.networkMode=b}}function setTemperature(a){void 0!=a&&a()}function setTemperature(a){void 0!=a&&a()}function initVerticalShapes(){VERTICALSHAPE=verticalShapes.NONE,$(".verticalShapes, .straight").on("mouseup touchend",function(a){a.preventDefault(),console.log("diverging"),VERTICALSHAPE=verticalShapes.NONE,redrawRenderedPreview()}),$(".verticalShapes, .diverging").on("mouseup touchend",function(a){a.preventDefault(),console.log("diverging"),VERTICALSHAPE=verticalShapes.DIVERGING,redrawRenderedPreview()}),$(".verticalShapes, .converging").on("mouseup touchend",function(a){a.preventDefault(),console.log("converging"),VERTICALSHAPE=verticalShapes.CONVERGING,redrawRenderedPreview()}),$(".verticalShapes, .sinus").on("mouseup touchend",function(a){a.preventDefault(),console.log("sinus"),VERTICALSHAPE=verticalShapes.SINUS,redrawRenderedPreview()})}function resetVerticalShapes(){VERTICALSHAPE=verticalShapes.NONE}function initButtonBehavior(){function a(a){a.preventDefault(),btnOopsInterval=setInterval(function(){oopsUndo()},20)}function b(a){a.preventDefault(),clearInterval(btnOopsInterval)}function c(a){a.preventDefault(),previewUp(!0),clearInterval(btnMoveUpInterval),btnMoveUpInterval=setInterval(function(){previewUp(!0)},1e3/30)}function d(a){a.preventDefault(),console.log("btnMoveUp mouse up"),clearInterval(btnMoveUpInterval),previewUp()}function e(a){a.preventDefault(),previewDown(!0),clearInterval(btnMoveDownInterval),btnMoveDownInterval=setInterval(function(){previewDown(!0)},1e3/30)}function f(a){a.preventDefault(),console.log("btnMoveDown mouse up"),clearInterval(btnMoveDownInterval),previewDown()}function g(a){a.preventDefault(),previewTwistLeft(!0),clearInterval(btnTwistLeftInterval),btnTwistLeftInterval=setInterval(function(){previewTwistLeft(!0)},1e3/30)}function h(a){a.preventDefault(),clearInterval(btnTwistLeftInterval),previewTwistLeft()}function i(a){a.preventDefault(),previewTwistRight(!0),clearInterval(btnTwistRightInterval),btnTwistRightInterval=setInterval(function(){previewTwistRight(!0)},1e3/30)}function j(a){a.preventDefault(),clearInterval(btnTwistRightInterval),previewTwistRight()}console.log("f:initButtonBehavior"),btnOops=$(".btnOops"),btnMoveUp=$("#btnMoveUp"),btnMoveDown=$("#btnMoveDown"),btnTwistLeft=$("#btnTwistLeft"),btnTwistRight=$("#btnTwistRight"),btnInfo=$(".btnInfo"),btnSettings=$(".btnSettings"),btnNew=$(".btnNew"),btnPrint=$(".btnPrint"),btnStop=$(".btnStop"),btnPrevious=$(".btnPrevious"),btnNext=$(".btnNext"),btnNew.on("touchstart mousedown",clearDoodle),btnPrint.on("touchstart mousedown",print),$("#btnPrevious").css("opacity","0.3"),btnNext.css("opacity","0.3"),$("#btnSave").css("opacity","0.3"),btnInfo.css("opacity","0.3"),btnOops.on("touchstart",function(b){a(b)}),btnOops.on("touchend",function(a){b(a)}),btnOops.mousedown(function(b){a(b)}),btnOops.mouseup(function(a){b(a)}),btnMoveUp.mousedown(function(a){c(a)}),btnMoveUp.mouseup(function(a){d(a)}),btnMoveUp.on("touchstart",function(a){c(a)}),btnMoveUp.on("touchend",function(a){d(a)}),btnMoveDown.mousedown(function(a){e(a)}),btnMoveDown.mouseup(function(a){f(a)}),btnMoveDown.on("touchstart",function(a){e(a)}),btnMoveDown.on("touchend",function(a){f(a)}),btnTwistLeft.mousedown(function(a){g(a)}),btnTwistLeft.mouseup(function(a){h(a)}),btnTwistLeft.on("touchstart",function(a){g(a)}),btnTwistLeft.on("touchend",function(a){h(a)}),btnTwistRight.mousedown(function(a){i(a)}),btnTwistRight.mouseup(function(a){j(a)}),btnTwistRight.on("touchstart",function(a){i(a)}),btnTwistRight.on("touchend",function(a){j(a)}),btnSettings.bind("touchstart mousedown",function(){settingsWindow.showSettings()}),btnInfo.mouseup(function(a){a.preventDefault(),console.log("btnInfo mouse up")})}function stopPrint(){console.log("f:stopPrint() >> sendPrintCommands = "+sendPrintCommands),sendPrintCommands&&printer.stop(),printer.overruleState(Printer.STOPPING_STATE)}function prevDoodle(){console.log("f:prevDoodle()"),console.log("f:prevDoodle()")}function nextDoodle(){console.log("f:nextDoodle()")}function print(){console.log("f:print() >> sendPrintCommands = "+sendPrintCommands),_points.length>2?(printer.overruleState(Printer.BUFFERING_STATE),btnStop.css("display","none"),clearTimeout(gcodeGenerateDelayer),gcodeGenerateDelayer=setTimeout(function(){var a=generate_gcode();sendPrintCommands?a.length>0?printer.print(a):(printer.overruleState(Printer.IDLE_STATE),printer.startStatusCheckInterval()):console.log("sendPrintCommands is false: not sending print command to 3dprinter"),debugMode&&($("#textdump").text(""),$("#textdump").text(a.join("\n")))},gcodeGenerateDelay)):console.log("f:print >> not enough points!")}function clearMainView(){ctx.save(),ctx.clearRect(0,0,canvas.width,canvas.height),ctx.restore()}function resetPreview(){previewCtx.save(),previewCtx.clearRect(0,0,canvas.width,canvas.height),previewCtx.restore(),numLayers=previewDefaults.numLayers,rStep=previewDefaults.rotation}function oopsUndo(){_points.pop(),redrawDoodle(),redrawPreview()}function previewUp(a){maxNumLayers>numLayers&&numLayers++,redrawRenderedPreview(a)}function previewDown(a){numLayers>minNumLayers&&numLayers--,redrawRenderedPreview(a)}function previewTwistLeft(a){void 0==a&&(a=!1),rStep>-previewRotationLimit&&(rStep-=twistIncrement),redrawRenderedPreview(a)}function previewTwistRight(a){previewRotationLimit>rStep&&(rStep+=twistIncrement),redrawRenderedPreview(a)}function update(){setState(printer.state,printer.hasControl),thermometer.update(printer.temperature,printer.targetTemperature),progressbar.update(printer.currentLine,printer.totalLines)}function setState(a,b){if(a!=state||b!=hasControl){prevState=state,console.log("setState: ",prevState," > ",a," ( ",b,")"),setDebugText("State: "+a);var c=a==Printer.IDLE_STATE&&b;c?(btnPrint.removeClass("disabled"),btnPrint.unbind("touchstart mousedown"),btnPrint.bind("touchstart mousedown",print)):(btnPrint.addClass("disabled"),btnPrint.unbind("touchstart mousedown"));var d=(a==Printer.PRINTING_STATE||a==Printer.BUFFERING_STATE)&&b;switch(d?(btnStop.removeClass("disabled"),btnStop.unbind("touchstart mousedown"),btnStop.bind("touchstart mousedown",stopPrint)):(btnStop.addClass("disabled"),btnStop.unbind("touchstart mousedown")),a){case Printer.IDLE_STATE:case Printer.BUFFERING_STATE:case Printer.PRINTING_STATE:case Printer.STOPPING_STATE:thermometer.show();break;default:thermometer.hide()}switch(a){case Printer.PRINTING_STATE:progressbar.show();break;default:progressbar.hide()}a==Printer.WIFIBOX_DISCONNECTED_STATE?message.set("Lost connection to WiFi box",Message.ERROR):prevState==Printer.WIFIBOX_DISCONNECTED_STATE?message.set("Connected to WiFi box",Message.INFO,!0):a==Printer.DISCONNECTED_STATE?message.set("Printer disconnected",Message.WARNING,!0):(prevState==Printer.DISCONNECTED_STATE&&a==Printer.IDLE_STATE||prevState==Printer.UNKNOWN_STATE&&a==Printer.IDLE_STATE)&&message.set("Printer connected",Message.INFO,!0),state=a,hasControl=b}}function initDoodleDrawing(){console.log("f:initDoodleDrawing()"),$canvas=$("#mycanvas"),canvas=$canvas[0],ctx=canvas.getContext("2d"),canvasWidth=canvas.width,canvasHeight=canvas.height,canvas.addEventListener?(canvas.addEventListener("mousedown",onCanvasMouseDown,!1),canvas.addEventListener("mousemove",onCanvasMouseMove,!1),canvas.addEventListener("mouseup",onCanvasMouseUp,!1),canvas.addEventListener("touchstart",onCanvasTouchDown,!1),canvas.addEventListener("touchmove",onCanvasTouchMove,!1),canvas.addEventListener("touchend",onCanvasTouchEnd,!1),debugMode||document.body.addEventListener("touchmove",prevent,!1)):(canvas.attachEvent("onmousedown",onCanvasMouseDown),canvas.attachEvent("onmousemove",onCanvasMouseMove),canvas.attachEvent("onmouseup",onCanvasMouseUp),canvas.attachEvent("ontouchstart",onCanvasTouchDown),canvas.attachEvent("ontouchmove",onCanvasTouchMove),canvas.attachEvent("ontouchend",onCanvasTouchEnd),document.body.attachEvent("ontouchmove",prevent)),drawCanvas=$("#mycanvasContainer"),console.log("drawCanvasTopLeftCoords: "+drawCanvasTopLeftCoords),drawCanvasTopLeftCoords[0]=drawCanvas.offset().left,drawCanvasTopLeftCoords[1]=drawCanvas.offset().top,console.log("f:initDoodleDrawing() >> canvasWidth: "+canvasWidth),console.log("f:initDoodleDrawing() >> canvasHeight: "+canvasHeight)}function draw(a,b,c){if(0==prevX&&0==prevY&&(prevX=a,prevY=b),ctx.beginPath(),ctx.moveTo(prevX,prevY),ctx.lineTo(a,b),void 0!=c)ctx.lineWidth=c;else{if(drawVariableLineWeight){var d=Math.sqrt(Math.pow(prevX-a,2)+Math.pow(prevY-b,2));lineweight+=10>d?.25:20>d?.5:30>d?.75:50>d?1:80>d?1.5:120>d?2.25:170>d?3.5:2,lineweight=Math.min(lineweight,30),lineweight*=.9,lineweight=Math.max(lineweight,1)}else lineweight=2;ctx.lineWidth=lineweight}ctx.lineCap="round",ctx.stroke(),prevX=a,prevY=b}function clearDoodle(){console.log("f:clearDoodle"),_points=[],prevX=0,prevY=0,updatePrevX=-1,updatePrevY=-1,doodleBounds=[-1,-1,-1,-1],doodleTransform=[0,0,1,1],dragging=!1,clearMainView(),resetPreview(),resetVerticalShapes()}function redrawDoodle(){console.log("f:redrawDoodle()"),clearMainView(),prevX=0,prevY=0;for(var a=0;a<_points.length;a++)1==_points[a][2]?draw(_points[a][0],_points[a][1],.5):draw(_points[a][0],_points[a][1])}function adjustBounds(a,b){var c=!1;return console.log("f:adjustBounds("+a+","+b+")"),-1==doodleBounds[0]?(doodleBounds[0]=a,doodleBounds[1]=b,doodleBounds[2]=a,doodleBounds[3]=b,void 0):(adoodleBounds[2]&&(doodleBounds[2]=a,c=!0),bdoodleBounds[3]&&(doodleBounds[3]=b,c=!0),c)}function adjustPreviewTransformation(){doodleTransform[0]=doodleBounds[0],doodleTransform[1]=doodleBounds[1];var a,b,c;_points.length<2?(a=1,b=1,c=Math.min(a,b)):(a=canvasWidth/(doodleBounds[2]-doodleBounds[0]),b=canvasHeight/(doodleBounds[3]-doodleBounds[1]),c=Math.min(a,b)),doodleTransform[2]=c,doodleTransform[3]=c}function onCanvasMouseDown(a){dragging=!0,prevCountingTime=(new Date).getTime(),movementCounter=0;var b,c;void 0!=a.offsetX?(b=a.offsetX,c=a.offsetY):(b=a.layerX,c=a.layerY),_points.push([b,c,!0]),adjustBounds(b,c),adjustPreviewTransformation(),draw(b,c,.5)}function onCanvasMouseMove(a){if(dragging){var b,c;if(void 0!=a.offsetX?(b=a.offsetX,c=a.offsetY):(b=a.layerX,c=a.layerY),-1!=prevPoint.x||-1!=prevPoint.y){var d=Math.sqrt(Math.pow(prevPoint.x-b,2)+Math.pow(prevPoint.y-c,2));d>5&&(_points.push([b,c,!1]),adjustBounds(b,c),adjustPreviewTransformation(),draw(b,c),prevPoint.x=b,prevPoint.y=c)}else _points.push([b,c,!1]),adjustBounds(b,c),adjustPreviewTransformation(),draw(b,c),prevPoint.x=b,prevPoint.y=c;(new Date).getTime()-prevRedrawTime>redrawInterval&&(prevRedrawTime=(new Date).getTime(),_points.length<50?redrawPreview():updatePreview(b,c,!0))}}function onCanvasMouseUp(){dragging=!1,console.log("doodleBounds: "+doodleBounds),console.log("doodleTransform: "+doodleTransform),console.log("_points.length :"+_points.length),renderToImageDataPreview()}function onCanvasTouchDown(a){a.preventDefault(),console.log("f:onCanvasTouchDown >> e: ",a);var b=a.touches[0].pageX-drawCanvasTopLeftCoords[0],c=a.touches[0].pageY-drawCanvasTopLeftCoords[1];_points.push([b,c,!0]),adjustBounds(b,c),adjustPreviewTransformation(),draw(b,c,.5),movementCounter=0,prevRedrawTime=(new Date).getTime()}function onCanvasTouchMove(a){a.preventDefault();var b=a.touches[0].pageX-drawCanvasTopLeftCoords[0],c=a.touches[0].pageY-drawCanvasTopLeftCoords[1];if(console.log("f:onCanvasTouchMove >> x,y = "+b+","+c+" , e: ",a),-1!=prevPoint.x||-1!=prevPoint.y){var d=Math.sqrt(Math.pow(prevPoint.x-b,2)+Math.pow(prevPoint.y-c,2));d>5&&(_points.push([b,c,!1]),adjustBounds(b,c),adjustPreviewTransformation(),draw(b,c),prevPoint.x=b,prevPoint.y=c)}else _points.push([b,c,!1]),adjustBounds(b,c),adjustPreviewTransformation(),draw(b,c),prevPoint.x=b,prevPoint.y=c;(new Date).getTime()-prevRedrawTime>redrawInterval&&(_points.length<50?redrawPreview():updatePreview(b,c,!0),prevRedrawTime=(new Date).getTime())}function onCanvasTouchEnd(){console.log("f:onCanvasTouchEnd()"),console.log("doodleBounds: "+doodleBounds),console.log("doodleTransform: "+doodleTransform),console.log("_points.length :"+_points.length),renderToImageDataPreview()}function prevent(a){a.preventDefault()}function initPreviewRendering(){console.log("f:initPreviewRendering()"),$preview=$("#preview"),preview=$preview[0],previewCtx=preview.getContext("2d");var a=preview.width/canvas.width;preview_tmp=document.getElementById("preview_tmp"),preview_tmp.width=preview.width,preview_tmp.height=canvas.height*a,$("#preview_tmp").css("top",-preview_tmp.height),previewCtx_tmp=preview_tmp.getContext("2d"),calcPreviewCanvasProperties(),redrawPreview()}function calcPreviewCanvasProperties(){console.log("f:calcPreviewCanvasProperties()"),globalScale=preview.width/canvasWidth,layerCX=canvasWidth/2*globalScale,layerCY=canvasHeight/2*globalScale,layerOffsetY=preview.height*(1-previewVerticalPadding.bottom),yStep=(preview.height-preview.height*(previewVerticalPadding.top+previewVerticalPadding.bottom))/maxNumLayers}function redrawPreview(a){if(void 0==a&&(a=!1),!(_points.length<2)){a||(debug_redrawSimplification=_points.length<100?6:_points.length<250?7:_points.length<400?8:_points.length<550?9:_points.length<700?10:11);var b=0,c=0;previewCtx.clearRect(0,0,preview.width,preview.height),previewCtx.lineWidth=strokeWidth,previewCtx.strokeStyle="#f00";for(var d=0;numLayers>d;d++){var e=scaleFunction(d/maxNumLayers);if(previewCtx.globalAlpha=0==d||d==Math.floor(numLayers/2)||d==numLayers-1?1:globalAlpha,a&&0!=d%debug_redrawSimplification&&0!=d&&d!=Math.floor(numLayers/2)&&d!=numLayers-1)b-=yStep,c+=rStep;else{previewCtx.save(),previewCtx.translate(layerCX,layerOffsetY+b),previewCtx.scale(viewerScale*e,scaleY*viewerScale*e),previewCtx.rotate(c),previewCtx.translate(-doodleTransform[0]*globalScale*doodleTransform[2],-doodleTransform[1]*globalScale*doodleTransform[3]);var f=centeredAndScaledDoodlePoint(_points[0]);previewCtx.beginPath(),previewCtx.moveTo(f.x,f.y);for(var g=1;g<_points.length;g++)f=centeredAndScaledDoodlePoint(_points[g]),a&&0!=g%debug_redrawSimplification||previewCtx.lineTo(f.x,f.y);previewCtx.stroke(),b-=yStep,c+=rStep,previewCtx.restore()}}previewCtx.globalAlpha=globalAlpha}}function renderToImageDataPreview(){if(console.log("f:renderToImageDataPreview()"),!(_points.length<2)){previewCtx_tmp.clearRect(0,0,preview.width,preview.height),previewCtx_tmp.lineWidth=strokeWidth,previewCtx_tmp.strokeStyle="#f00",previewCtx_tmp.save(),previewCtx_tmp.translate(layerCX,layerCY),previewCtx_tmp.scale(viewerScale,viewerScale),previewCtx_tmp.translate(-doodleTransform[0]*globalScale*doodleTransform[2],-doodleTransform[1]*globalScale*doodleTransform[3]);var a=centeredAndScaledDoodlePoint(_points[0]);previewCtx_tmp.beginPath(),previewCtx_tmp.moveTo(a.x,a.y);for(var b=1;b<_points.length;b++)a=centeredAndScaledDoodlePoint(_points[b]),previewCtx_tmp.lineTo(a.x,a.y);previewCtx_tmp.stroke(),previewCtx_tmp.closePath(),previewCtx_tmp.restore(); +var c=preview_tmp.toDataURL();doodleImageCapture=new Image,doodleImageCapture.onload=function(){previewCtx.clearRect(0,0,preview.width,preview.height),previewCtx.lineWidth=strokeWidth,previewCtx.strokeStyle="#f00";for(var a=0,b=0,c=0;numLayers>c;c++){var d=scaleFunction(c/maxNumLayers);previewCtx.globalAlpha=0==c||c==Math.floor(numLayers/2)||c==numLayers-1?1:globalAlpha,previewCtx.save(),previewCtx.translate(layerCX,layerOffsetY+a),previewCtx.scale(d,scaleY*d),previewCtx.rotate(b),previewCtx.translate(-layerCX,-layerCY),previewCtx.drawImage(doodleImageCapture,0,0),a-=yStep,b+=rStep,previewCtx.restore()}},doodleImageCapture.src=c,previewCtx.globalAlpha=globalAlpha}}function redrawRenderedPreview(a){void 0==a&&(a=!1),console.log("f:redrawRenderedPreview()"),previewCtx.clearRect(0,0,preview.width,preview.height),previewCtx.lineWidth=strokeWidth,previewCtx.strokeStyle="#f00";for(var b=0,c=0,d=0;numLayers>d;d++){var e=scaleFunction(d/maxNumLayers);previewCtx.globalAlpha=0==d||d==Math.floor(numLayers/2)||d==numLayers-1?1:globalAlpha,a&&0!=d%2&&0!=d&&d!=Math.floor(numLayers/2)&&d!=numLayers-1?(b-=yStep,c+=rStep):(previewCtx.save(),previewCtx.translate(layerCX,layerOffsetY+b),previewCtx.scale(e,scaleY*e),previewCtx.rotate(c),previewCtx.translate(-layerCX,-layerCY),previewCtx.drawImage(doodleImageCapture,0,0),b-=yStep,c+=rStep,previewCtx.restore())}}function centeredAndScaledDoodlePoint(a){var b={x:0,y:0};return b.x=(a[0]-(doodleBounds[2]-doodleBounds[0])/2)*globalScale*doodleTransform[2],b.y=(a[1]-(doodleBounds[3]-doodleBounds[1])/2)*globalScale*doodleTransform[3],b}function updatePreview(a,b,c){if(void 0==c&&(c=!1),c=!1,!(_points.length<2)){if(-1==updatePrevX||-1==updatePrevY)return updatePrevX=a,updatePrevY=b,void 0;var d=0,e=0;previewCtx.lineWidth=strokeWidth,previewCtx.strokeStyle="#f00";for(var f=0;numLayers>f;f++)if(previewCtx.globalAlpha=0==f||f==Math.floor(numLayers/2)||f==numLayers-1?1:globalAlpha,c&&0!=f%debug_redrawSimplification&&0!=f&&f!=Math.floor(numLayers/2)&&f!=numLayers-1)d-=yStep,e+=rStep;else{previewCtx.save(),previewCtx.translate(layerCX,layerOffsetY+d),previewCtx.scale(viewerScale,scaleY*viewerScale),previewCtx.rotate(e),previewCtx.translate(-doodleTransform[0]*globalScale*doodleTransform[2],-doodleTransform[1]*globalScale*doodleTransform[3]),previewCtx.beginPath();var g=centeredAndScaledDoodlePoint([updatePrevX,updatePrevY]);previewCtx.moveTo(g.x,g.y);var h=centeredAndScaledDoodlePoint([a,b]);previewCtx.lineTo(h.x,h.y),previewCtx.stroke(),d-=yStep,e+=rStep,previewCtx.restore()}previewCtx.globalAlpha=globalAlpha,updatePrevX=a,updatePrevY=b}}function generate_gcode(){console.log("f:generategcode()");var a=110,b=110;gcode=[],console.log("settings: ",settings);var c=settings["printer.speed"],d=c,e=.5*c,f=settings["printer.travelSpeed"],g=settings["printer.filamentThickness"],h=settings["printer.wallThickness"],i=settings["printer.screenToMillimeterScale"],j=settings["printer.layerHeight"],k=settings["printer.maxObjectHeight"],l=settings["printer.temperature"],m=settings["printer.useSubLayers"],n=settings["printer.enableTraveling"],o=settings["printer.retraction.enabled"],p=settings["printer.retraction.speed"],q=settings["printer.retraction.minDistance"],r=settings["printer.retraction.amount"],s=settings["printer.heatup.temperature"],t=settings["printer.startgcode"];t=t.replace("{printingTemp}",l),t=t.replace("{preheatTemp}",s),t=t.split("\n");var u=settings["printer.endgcode"];u=u.replace("{printingTemp}",l),u=u.replace("{preheatTemp}",s),u=u.split("\n");var v=k/j;objectHeight=Math.round(numLayers/maxNumLayers*k);var w=rStep*maxNumLayers/v;w=-w;var x=JSON.parse(JSON.stringify(_points));gcode=gcode.concat(t);var v=k/j,y=0,z=new Point;z.set(0,0);var A={x:doodleBounds[0]+(doodleBounds[2]-doodleBounds[0])/2,y:doodleBounds[1]+(doodleBounds[3]-doodleBounds[1])/2};if(console.log("f:generategcode() >> layers: "+v),1/0!=v){var B=x.length*v*(objectHeight/k);if(B>MAX_POINTS_TO_PRINT)return alert("Sorry, your doodle to to complex and / or to high"),console.log("WARNING: to many points to convert to gcode"),[];for(var C=0;v>C;C++){var D=JSON.parse(JSON.stringify(x));if(D.length<2)return;var E=C/v,F=scaleFunction(E),G=lineLength(x[0][0],x[0][1],x[x.length-1][0],x[x.length-1][1])<3;pointsTranslate(D,-A.x,-A.y),pointsScale(D,i,-i),pointsScale(D,F,F),pointsRotate(D,w*C),0==C?firstLayerSlow&&(c=e):2==C&&(gcode.push("M106"),c=d);for(var H=0,I=D.length,J=0,K=[],L=-1,M=0;Mq;n&&S?(T&&gcode.push("G0 E"+(y-r).toFixed(3)+" F"+(60*p).toFixed(3)),gcode.push("G0 X"+P.x.toFixed(3)+" Y"+P.y.toFixed(3)+" Z"+R.toFixed(3)+" F"+(60*f).toFixed(3)),T&&gcode.push("G0 E"+y.toFixed(3)+" F"+(60*p).toFixed(3))):(y+=z.distance(P)*h*j/(Math.pow(g/2,2)*Math.PI),gcode.push("G1 X"+P.x.toFixed(3)+" Y"+P.y.toFixed(3)+" Z"+R.toFixed(3)+" F"+(60*c).toFixed(3)+" E"+y.toFixed(3))),H++,J=H/I,z=P}if(C/v>objectHeight/k){console.log("f:generategcode() >> (layer/layers) > (objectHeight/maxObjectHeight) is true -> breaking at layer "+(C+1));break}}return gcode=gcode.concat(u)}}function scaleFunction(a){var b=1;switch(VERTICALSHAPE){case verticalShapes.NONE:b=1;break;case verticalShapes.DIVERGING:b=.5+.5*a;break;case verticalShapes.CONVERGING:b=1-.8*a;break;case verticalShapes.SINUS:b=.25*Math.cos(4*a*Math.PI)+.75}return b}function doOnResize(){canvas.width=$canvas.width(),canvas.height=$canvas.height(),preview.width=$preview.width(),preview.height=$drawAreaContainer.height(),canvasWidth=canvas.width,canvasHeight=canvas.height,console.log(" preview.width: "+preview.width+", $preview.width(): "+$preview.width()),calcPreviewCanvasProperties(),drawCanvasTopLeftCoords[0]=drawCanvas.offset().left,drawCanvasTopLeftCoords[1]=drawCanvas.offset().top,redrawDoodle(),redrawPreview()}function initLayouting(){console.log("f:initLayouting()"),$drawAreaContainer=$(".drawareacontainer"),canvas.width=$canvas.width(),canvas.height=$canvas.height(),preview.width=$preview.width(),preview.height=$drawAreaContainer.height(),canvasWidth=canvas.width,canvasHeight=canvas.height,$drawAreaContainer.show(),console.log("window.innerHeight: "+window.innerHeight),console.log("window.innerWidth: "+window.innerWidth),console.log("$drawAreaContainer.innerHeight(): "+$drawAreaContainer.innerHeight()),console.log("$drawAreaContainer.offset().top: "+$drawAreaContainer.offset().top),setTimeout(_startOrientationAndChangeEventListening,1e3)}function _startOrientationAndChangeEventListening(){$(window).on("resize",doOnResize),doOnResize()}function Printer(){Printer.WIFIBOX_DISCONNECTED_STATE="wifibox disconnected",Printer.UNKNOWN_STATE="unknown",Printer.DISCONNECTED_STATE="disconnected",Printer.IDLE_STATE="idle",Printer.BUFFERING_STATE="buffering",Printer.PRINTING_STATE="printing",Printer.STOPPING_STATE="stopping",Printer.ON_BEFORE_UNLOAD_MESSAGE="You're doodle is still being send to the printer, leaving will result in a incomplete 3D print",this.temperature=0,this.targetTemperature=0,this.currentLine=0,this.totalLines=0,this.bufferedLines=0,this.state=Printer.UNKNOWN_STATE,this.hasControl=!0,this.wifiboxURL,this.checkStatusInterval=3e3,this.checkStatusDelay,this.timeoutTime=3e3,this.sendPrintPartTimeoutTime=5e3,this.gcode,this.sendLength=1500,this.retryDelay=2e3,this.retrySendPrintPartDelay,this.retryCheckStatusDelay,this.retryStopDelay,this.retryPreheatDelay,this.maxGCodeSize=10,this.stateOverruled=!1,Printer.UPDATE="update";var a=this;this.init=function(){console.log("Printer:init"),this.wifiboxURL=wifiboxURL,console.log(" wifiboxURL: ",this.wifiboxURL),autoUpdate&&this.startStatusCheckInterval()},this.preheat=function(){console.log("Printer:preheat");var a=this;communicateWithWifibox?$.ajax({url:this.wifiboxURL+"/printer/heatup",type:"POST",dataType:"json",timeout:this.timeoutTime,success:function(b){console.log("Printer:preheat response: ",b),"error"==b.status&&(clearTimeout(a.retryPreheatDelay),a.retryPreheatDelay=setTimeout(function(){a.preheat()},a.retryDelay))}}).fail(function(){console.log("Printer:preheat: failed"),clearTimeout(a.retryPreheatDelay),a.retryPreheatDelay=setTimeout(function(){a.preheat()},a.retryDelay)}):console.log("Printer >> f:preheat() >> communicateWithWifibox is false, so not executing this function")},this.print=function(b){console.log("Printer:print"),console.log(" gcode total # of lines: "+b.length),message.set("Sending doodle to printer...",Message.NOTICE),a.addLeaveWarning(),this.sendIndex=0,this.gcode=b;var c=this.byteSize(b[20]),d=c*b.length/1024/1024;return console.log(" gcodeSize: ",d),d>this.maxGCodeSize?(console.log("Error: Printer:print: gcode file is probably to big ("+d+"MB) (max: "+this.maxGCodeSize+"MB)"),void 0):(this.sendPrintPart(this.sendIndex,this.sendLength),void 0)},this.byteSize=function(a){return~-encodeURI(a).split(/%..|./).length},this.sendPrintPart=function(a,b){console.log("Printer:sendPrintPart sendIndex: "+a+"/"+this.gcode.length+", sendLength: "+b);var c=0==a?!0:!1,d=c,e=!1;this.gcode.length> f:sendPrintPart() >> communicateWithWifibox is false, so not executing this function")},this.stop=function(){console.log("Printer:stop");var a=this;communicateWithWifibox?$.ajax({url:this.wifiboxURL+"/printer/stop",type:"POST",dataType:"json",timeout:this.timeoutTime,success:function(b){console.log("Printer:stop response: ",b),a.startStatusCheckInterval()}}).fail(function(){console.log("Printer:stop: failed"),clearTimeout(a.retryStopDelay),a.retryStopDelay=setTimeout(function(){a.stop()},a.retryDelay),a.startStatusCheckInterval()}):console.log("Printer >> f:communicateWithWifibox() >> communicateWithWifibox is false, so not executing this function")},this.startStatusCheckInterval=function(){console.log("Printer:startStatusCheckInterval"),a.checkStatus(),clearTimeout(a.checkStatusDelay),clearTimeout(a.retryCheckStatusDelay),a.checkStatusDelay=setTimeout(function(){a.checkStatus()},a.checkStatusInterval)},this.stopStatusCheckInterval=function(){console.log("Printer:stopStatusCheckInterval"),clearTimeout(a.checkStatusDelay),clearTimeout(a.retryCheckStatusDelay)},this.checkStatus=function(){console.log("Printer:checkStatus"),this.stateOverruled=!1;var a=this;communicateWithWifibox?$.ajax({url:this.wifiboxURL+"/info/status",dataType:"json",timeout:this.timeoutTime,success:function(b){a.handleStatusUpdate(b),clearTimeout(a.checkStatusDelay),clearTimeout(a.retryCheckStatusDelay),a.checkStatusDelay=setTimeout(function(){a.checkStatus()},a.checkStatusInterval)}}).fail(function(){console.log("Printer:checkStatus: failed"),a.state=Printer.WIFIBOX_DISCONNECTED_STATE,clearTimeout(a.checkStatusDelay),clearTimeout(a.retryCheckStatusDelay),a.retryCheckStatusDelay=setTimeout(function(){a.checkStatus()},a.retryDelay),$(document).trigger(Printer.UPDATE)}):console.log("Printer >> f:checkStatus() >> communicateWithWifibox is false, so not executing this function")},this.handleStatusUpdate=function(b){console.log("Printer:handleStatusUpdate response: ",b);var c=b.data;"success"!=b.status?a.state=Printer.UNKNOWN_STATE:(this.stateOverruled||(a.state=c.state),a.temperature=c.hotend,a.targetTemperature=c.hotend_target,a.currentLine=c.current_line,a.totalLines=c.total_lines,a.bufferedLines=c.buffered_lines,a.hasControl=c.has_control,(a.state==Printer.PRINTING_STATE||a.state==Printer.STOPPING_STATE)&&console.log("progress: ",a.currentLine+"/"+a.totalLines+" ("+a.bufferedLines+") ("+a.state+")")),$(document).trigger(Printer.UPDATE)},this.overruleState=function(b){this.stateOverruled=!0,console.log(" stateOverruled: ",this.stateOverruled),a.state=b,$(document).trigger(Printer.UPDATE),this.stopStatusCheckInterval()},this.removeLeaveWarning=function(){window.onbeforeunload=null},this.addLeaveWarning=function(){window.onbeforeunload=function(){return Printer.ON_BEFORE_UNLOAD_MESSAGE}}}function Progressbar(){this.currProgress=0,this.progressbarFGImg=new Image,this.progressbarFGImgSrc="img/progress_fg.png",this.progressbarBGImg=new Image,this.progressbarBGImgSrc="img/progress_bg.png",this.progressWidth=93,this.progressHeight=82,this.quartPI=.5*Math.PI,this.twoPI=2*Math.PI,this.$canvas,this.canvas,this.context,this.$container,this.isInitted=!1,this.enabled=!0,this.init=function(a,b){console.log("Thermometer.init()"),this.$container=b,this.$canvas=a,this.canvas=this.$canvas[0],this.context=this.canvas.getContext("2d");var c=this;this.progressbarBGImg.onload=function(){console.log("progressbarBGImg img loaded"),c.progressbarFGImg.onload=function(){console.log("progressbarFGImg img loaded"),c.isInitted=!0,c.update(0,100)},c.progressbarFGImg.src=c.progressbarFGImgSrc},this.progressbarBGImg.src=this.progressbarBGImgSrc},this.update=function(a,b){if(this.isInitted){void 0==a&&(a=0),void 0==b&&(b=100);var c=a/b;c=Math.min(c,1),c=Math.max(c,0),this.context.clearRect(0,0,this.canvas.width,this.canvas.height),this.context.drawImage(this.progressbarBGImg,0,0),this.context.font="7pt sans-serif",this.context.save(),this.context.beginPath(),this.context.moveTo(45,45),this.context.lineTo(45,0),this.context.arc(45,45,45,-this.quartPI,-this.quartPI+c*this.twoPI,!1),this.context.lineTo(45,45),this.context.clip(),this.context.drawImage(this.progressbarFGImg,0,0),this.context.restore(),debugMode&&(this.context.fillStyle="#222",this.context.strokeStyle="#fff",this.context.lineWidth=3,this.context.textAlign="center",this.context.strokeText(a+" / "+b,45,45,90),this.context.fillText(a+" / "+b,45,45,90))}else console.log("Progressbar.setTemperature() -> thermometer not initialized!")},this.show=function(){this.$container.addClass("progressbarAppear"),this.enabled=!0},this.hide=function(){this.$container.removeClass("progressbarAppear"),this.enabled=!1}}function Thermometer(){this.currentTemperature=0,this.targetTemperature=0,this.thermoOverlayImg=new Image,this.thermoOverlayImgSrc="img/thermometer_fg_overlay.png",this.thermoWidth=40,this.thermoHeight=100,this.$canvas,this.canvas,this.context,this.$container,this.isInitted=!1,this.enabled=!0,this.thermoColors=[[50,200,244],[244,190,10],[244,50,50]],this.init=function(a,b){console.log("Thermometer.init()"),this.$container=b,this.$canvas=a,this.canvas=this.$canvas[0],this.context=this.canvas.getContext("2d");var c=this;this.thermoOverlayImg.onload=function(){console.log("canvasThermoOverlay img loaded"),c.isInitted=!0,c.update(c.currentTemperature,c.targetTemperature)},this.thermoOverlayImg.src=this.thermoOverlayImgSrc},this.update=function(a,b){if(this.isInitted){if(!this.enabled)return;void 0==a&&(a=0),void 0==b&&(b=180);var c=a/b;c=Math.min(c,1),c=Math.max(c,0);var d=this.thermoHeight,e=15,f=25,g=Math.floor((d-e-f)*c),h=this.thermoColors[0];c>.98?h=this.thermoColors[2]:c>.25&&(h=this.thermoColors[1]),this.context.clearRect(0,0,this.canvas.width,this.canvas.height),this.context.font="10pt sans-serif",this.context.save(),this.context.beginPath(),this.context.arc(40,80,16,0,2*Math.PI,!1),this.context.arc(40,10,4,0,2*Math.PI,!1),this.context.rect(36,11,8,70),this.context.fillStyle="#fff",this.context.fill(),this.context.clip(),this.context.beginPath(),this.context.rect(20,d-e-g,60,g+e),this.context.fillStyle="rgb("+h[0]+","+h[1]+","+h[2]+")",this.context.fill(),this.context.restore(),this.context.save(),this.context.beginPath(),this.context.moveTo(32,f),this.context.lineTo(52,f),this.context.lineWidth=2,this.context.strokeStyle="#000",this.context.stroke(),this.context.fillStyle="#000",this.context.textAlign="left",this.context.textBaseline="middle",this.context.fillText(b+"°",55,f),this.context.restore(),this.context.drawImage(this.thermoOverlayImg,20,0),this.context.fillStyle="#000",this.context.textAlign="center",this.context.fillText(a+"°",40,d+e)}else console.log("Thermometer.setTemperature() -> thermometer not initialized!")},this.show=function(){this.$container.addClass("thermometerAppear"),this.enabled=!0},this.hide=function(){this.$container.removeClass("thermometerAppear"),this.enabled=!1}}function getURLParameter(a){return decodeURI((new RegExp("[&?]"+a+"="+"(.+?)(&|$)").exec(location.search)||[,null])[1])}function initSidebars(){console.log("f:initSidebars()"),sidebarLeft=new SideBar,sidebarLeft.init(".leftpanel","hideleft",function(){$(".leftpanel").show()}),sidebarRight=new SideBar,sidebarRight.init(".rightpanel","hideright",function(){$(".rightpanel").show()})}function SideBar(){this.initted=!1,this.$contentTarg=void 0,this.$sideBtn=void 0,this.contentHidden=!1,this.hideClass="",this.init=function(a,b,c){console.log("SideBar >> f:init >> targ: ",$(a),", hideClass: "+b),this.$contentTarg=$(a),this.hideClass=b,this.$contentTarg.addClass(this.hideClass),this.contentHidden=!0,this.$contentTarg.append("
"),this.$sideBtn=$(a+" .sidebutton");var d=this;this.$sideBtn.on("click",function(){console.log("sidebutton"),d.toggleShowHide()}),this.initted=!0,c()},this.toggleShowHide=function(){this.contentHidden?(this.contentHidden=!1,this.$contentTarg.removeClass(this.hideClass),this.$sideBtn.addClass("sidebuttonin")):(this.contentHidden=!0,this.$contentTarg.addClass(this.hideClass),this.$sideBtn.removeClass("sidebuttonin"))}}function Message(){Message.ERROR="error",Message.WARNING="warning",Message.NOTICE="notice",Message.INFO="info",this.mode="",this.$element;var a,b=this,c=2e3;this.init=function(a){console.log("Message:init"),this.$element=a,console.log("$element: ",a)},this.set=function(d,e,f){console.log("Message:set: ",d,e,f),b.hide(function(){b.show(),b.clear(),b.$element.text(d),b.$element.addClass(e),b.show(),b.mode=e,clearTimeout(a),f&&(a=setTimeout(function(){b.hide()},c))})},this.clear=function(){this.$element.text(""),this.$element.removeClass(this.mode)},this.show=function(){this.$element.fadeIn(200)},this.hide=function(a){this.$element.fadeOut(200,a)}}function showOrHideThermo(){console.log("f:showOrHideThermo()"),showOrHide?(thermometer.hide(),progressbar.hide()):(thermometer.show(),progressbar.show()),showOrHide=!showOrHide}function settingsLoaded(){console.log("settingsLoaded"),console.log("autoHeatup: ",settings["printer.heatup.enabled"]),settings["printer.heatup.enabled"]&&firstTimeSettingsLoaded&&(printer.preheat(),firstTimeSettingsLoaded=!1)}function setDebugText(a){$("#debug_display").text(a)}var settings={"network.ap.ssid":"d3d-ap-%%MAC_ADDR_TAIL%%","network.ap.address":"192.168.10.1","network.ap.netmask":"255.255.255.0","printer.temperature":220,"printer.maxObjectHeight":150,"printer.layerHeight":.2,"printer.wallThickness":.7,"printer.screenToMillimeterScale":.3,"printer.speed":50,"printer.travelSpeed":200,"printer.filamentThickness":2.85,"printer.enableTraveling":!0,"printer.useSubLayers":!0,"printer.firstLayerSlow":!0,"printer.autoWarmUp":!0,"printer.simplify.iterations":10,"printer.simplify.minNumPoints":15,"printer.simplify.minDistance":3,"printer.retraction.enabled":!0,"printer.retraction.speed":50,"printer.retraction.minDistance":1,"printer.retraction.amount":5,"printer.autoWarmUpCommand":"M104 S220 (hardcoded temperature)"},objectHeight=20,layerHeight=.2,enableTraveling=!0,minScale=.3,maxScale=1,shape="%",twists=0,loglevel=2,serverport=8888,autoLoadImage="hand.txt",loadOffset=[0,0],showWarmUp=!0,loopAlways=!1,firstLayerSlow=!0,useSubpathColors=!1,autoWarmUp=!0,maxScaleDifference=.1,frameRate=60,quitOnEscape=!0,screenToMillimeterScale=.3,sideis3D=!0,sidevisible=!0,sidebounds=[900,210,131,390],sideborder=[880,169,2,471],windowbounds=[0,0,800,500],windowcenter=!0,windowfullscreen=!1,autoWarmUpCommand="M104 S230",autoWarmUpDelay=3,VERTICALSHAPE,verticalShapes={NONE:"none",DIVERGING:"diverging",CONVERGING:"converging",SINUS:"sinus"},btnMoveUpInterval,btnMoveDownInterval,btnTwistLeftInterval,btnTwistRightInterval,twistIncrement=Math.PI/1800,btnOopsInterval,btnNew,btnPrevious,btnNext,btnOops,btnStop,btnClear,btnMoveUp,btnMoveDown,btnTwistLeft,btnTwistRight,btnInfo,btnSettings,state,prevState,hasControl,gcodeGenerateDelayer,gcodeGenerateDelay=50,preview,previewCtx,svgPathRegExp=/[LM]\d* \d*/gi,svgPathParamsRegExp=/([LM])(\d*) (\d*)/,dragging=!1,$canvas,canvas,ctx,canvasWidth,canvasHeight,drawCanvas,drawCanvasTopLeftCoords=[0,0],doodleBounds=[-1,-1,-1,-1],doodleTransform=[0,0,1,1],_points=[],prevCountingTime=0,movementCounter=0,drawVariableLineWeight=!1,lineweight=2,prevPoint={x:-1,y:-1};prevUpdateFullPreview=0,prevUpdateFullPreviewInterval=25;var $preview,preview,previewCtx,preview_tmp,previewCtx_tmp,previewDefaults={rotation:Math.PI/90,numLayers:10},svgPathRegExp=/[LM]\d* \d*/gi,svgPathParamsRegExp=/([LM])(\d*) (\d*)/,prevRedrawTime=(new Date).getTime(),redrawInterval=1e3/30,previewRotationLimit=Math.PI/30,numLayers=previewDefaults.numLayers,maxNumLayers=100,minNumLayers=2,globalScale=.3,globalAlpha=.2,scaleY=.4,viewerScale=.65,previewVerticalPadding={top:.15,bottom:.12},strokeWidth=2,rStep=previewDefaults.rotation,yStep,layerCX,layerCY,layerOffsetY,prevX=0,prevY=0,highlight=!0,linesRaw="",debug_redrawSimplification=6,updatePrevX=-1,updatePrevY=-1,MAX_POINTS_TO_PRINT=4e5,gcode=[];pointsTranslate=function(a,b,c){for(var d=0;d> " + new Date().getTime()); -// $(".container").css("height", window.innerHeight); - - /* 2013-10-09 commented out -> no more need with new layouting - $drawAreaContainer.css("marginLeft", -$drawAreaContainer.width()/2); - $drawAreaContainer.css("marginTop", -$drawAreaContainer.height() *.45); -// $drawAreaContainer.css("marginTop", -parseInt($drawAreaContainer.css("height")) * 0.45); -//*/ - - // canvas.width = $drawAreaContainer.width() - preview.width; // canvas.clientWidth; - // canvas.width = $("#mycanvasContainer").width(); - canvas.width = $canvas.width(); - canvas.height = $canvas.height(); // canvas.clientHeight; - // canvas.height = $drawAreaContainer.height(); // canvas.clientHeight; - - preview.width = $preview.width(); - preview.height = $drawAreaContainer.height(); - - canvasWidth = canvas.width; - canvasHeight = canvas.height; - - console.log(" preview.width: " + preview.width + ", $preview.width(): " + $preview.width()); - - calcPreviewCanvasProperties(); - -// layerOffsetY = preview.height - 1.75 * layerCY; -// yStep = preview.height / 150; -// preview.width = parseInt($preview.css("width"), 10); -// preview.height = parseInt($preview.css("height"), 10); - -// canvasWidth = canvas.width; -// canvasHeight = canvas.height; - - drawCanvasTopLeftCoords[0] = drawCanvas.offset().left; - drawCanvasTopLeftCoords[1] = drawCanvas.offset().top; -// drawCanvasTopLeftCoords[0] = drawCanvas[0].offsetParent.offsetLeft; -// drawCanvasTopLeftCoords[1] = drawCanvas[0].offsetParent.offsetTop; - -// preview.height = $("#previewContainer").height(); -// console.log("f:doOnResize() >> preview.height: " + preview.height); - - redrawDoodle(); - redrawPreview(); - - return; - -// doClientAndOrientationStuff() // <-- is this necessary in this method? - -// console.log("f:doOnResize() >> $('#canvascontainer').innerHeight: " + window.innerHeight); - if (window.innerHeight < 768) { -// $('#drawAreaContainer').innerHeight(window.innerHeight - $("#drawAreaContainer").offset().top - 70); - var newVal = window.innerHeight - $("#drawAreaContainer").offset().top - 100; // what's the 70 ?? - newVal = Math.max(newVal, drawAreaContainerMinHeight); - newVal = Math.min(newVal, drawAreaContainerMaxHeight); - - $('#drawAreaContainer').innerHeight(newVal); - - // canvas drawing area - $canvas.css("height", newVal); - canvas.height = newVal; - canvasWidth = canvas.width; - canvasHeight = canvas.height; - - // preview area - $preview.css("height", newVal); - preview.height = newVal; - layerOffsetY = preview.height - 1.75 * layerCY; - yStep = preview.height / 150; - - redrawDoodle(); - redrawPreview(); - } -} - -function initLayouting() { - console.log("f:initLayouting()"); - - // first set the css width/height and actual width/height of the drawing area - - - - -// $doodleCanvas = $("#mycanvas"); -// doodleCanvas = $("#mycanvas")[0]; -// doodleCanvasContext = doodleCanvas.getContext('2d'); - - $drawAreaContainer = $(".drawareacontainer"); - /* 2013-10-09 commented out -> no more need with new layouting - $drawAreaContainer.css("margin", 0); - $drawAreaContainer.css("marginLeft", -$drawAreaContainer.width()/2); - $drawAreaContainer.css("marginTop", -$drawAreaContainer.height() *.45); - //*/ - -// console.log(" preview.width: " + preview.width + ", $preview.width(): " + $preview.width()); -// canvas.width = $drawAreaContainer.width() - preview.width; // canvas.clientWidth; -// canvas.width = $("#mycanvasContainer").width(); - canvas.width = $canvas.width(); - canvas.height = $canvas.height(); // canvas.clientHeight; -// canvas.height = $drawAreaContainer.height(); // canvas.clientHeight; - - preview.width = $preview.width(); - preview.height = $drawAreaContainer.height(); - - canvasWidth = canvas.width; - canvasHeight = canvas.height; - - $drawAreaContainer.show(); - - // window.innerHeight - console.log("window.innerHeight: " + window.innerHeight); - console.log("window.innerWidth: " + window.innerWidth); - console.log("$drawAreaContainer.innerHeight(): " + $drawAreaContainer.innerHeight()); - console.log("$drawAreaContainer.offset().top: " + $drawAreaContainer.offset().top); - - - /* 2013-07-26 not doing this resizing stuff now, it's not working well yet - if (window.innerHeight < 768) { - $('#drawAreaContainer').innerHeight(window.innerHeight - $("#drawAreaContainer").offset().top - 70); - } - //*/ - - // timeout because it SEEMS to be beneficial for initting the layout - // 2013-09-18 seems beneficial since when? - setTimeout(_startOrientationAndChangeEventListening, 1000); -} - -function _startOrientationAndChangeEventListening() { - // Initial execution if needed - - $(window).on('resize', doOnResize); - - // is it necessary to call these? Aren't they called by the above eventhandlers? -// doClientAndOrientationStuff(); - doOnResize(); -}