Skip to content

Instantly share code, notes, and snippets.

@companje
Last active September 22, 2015 14:47
Show Gist options
  • Save companje/892dea671993493d0c4a to your computer and use it in GitHub Desktop.
Save companje/892dea671993493d0c4a to your computer and use it in GitHub Desktop.
Doodle3D client javascript version 0.10.7 with modification on line 4473 to enable traveling on first two layers
/*
* This file is part of the Doodle3D project (http://doodle3d.com).
*
* Copyright (c) 2013, Doodle3D
* This software is licensed under the terms of the GNU GPL v2 or later.
* See file LICENSE.txt or visit http://www.gnu.org/licenses/gpl.html for full license details.
*/
function ConfigAPI() {
var _wifiboxURL;
var _wifiboxCGIBinURL;
var _timeoutTime = 3000;
var _saveSettingsTimeoutTime = 8000;
var _self = this;
this.init = function(wifiboxURL,wifiboxCGIBinURL) {
//console.log("ConfigAPI:init");
_wifiboxURL = wifiboxURL;
_wifiboxCGIBinURL = wifiboxCGIBinURL;
}
this.loadAll = function(completeHandler,failedHandler) {
//console.log("ConfigAPI:loadAll");
$.ajax({
url: _wifiboxURL + "/config/all",
type: "GET",
dataType: 'json',
timeout: _timeoutTime,
success: function(response){
if(response.status == "error" || response.status == "fail") {
if(failedHandler) failedHandler(response);
} else {
completeHandler(response.data);
}
}
}).fail(function() {
if(failedHandler) failedHandler();
});
};
this.load = function(targetSettings,completeHandler,failedHandler) {
//console.log("ConfigAPI:load");
$.ajax({
url: _wifiboxURL + "/config/",
type: "GET",
dataType: 'json',
data: targetSettings,
timeout: _timeoutTime,
success: function(response){
if(response.status == "error" || response.status == "fail") {
if(failedHandler) failedHandler(response);
} else {
completeHandler(response.data);
}
}
}).fail(function() {
if(failedHandler) failedHandler();
});
};
this.save = function(newSettings,completeHandler,failedHandler) {
//console.log("ConfigAPI:save");
$.ajax({
url: _wifiboxCGIBinURL + "/config",
type: "POST",
data: newSettings,
dataType: 'json',
timeout: _saveSettingsTimeoutTime,
success: function(response){
//console.log("ConfigAPI:save response: ",response);
if(response.status == "error" || response.status == "fail") {
if(failedHandler) failedHandler(response);
} else {
completeHandler(response.data);
}
}
}).fail(function() {
if(failedHandler) failedHandler();
});
};
this.resetAll = function(completeHandler,failedHandler) {
//console.log("ConfigAPI:resetAll");
$.ajax({
url: _wifiboxCGIBinURL + "/config/resetall",
type: "POST",
dataType: 'json',
timeout: _timeoutTime,
success: function(response){
if(response.status == "error" || response.status == "fail") {
if(failedHandler) failedHandler(response);
} else {
completeHandler(response.data);
}
}
}).fail(function() {
if(failedHandler) failedHandler();
});
};
}
/*
* This file is part of the Doodle3D project (http://doodle3d.com).
*
* Copyright (c) 2013, Doodle3D
* This software is licensed under the terms of the GNU GPL v2 or later.
* See file LICENSE.txt or visit http://www.gnu.org/licenses/gpl.html for full license details.
*/
function NetworkAPI() {
NetworkAPI.STATUS = {
CONNECTING_FAILED: -1,
NOT_CONNECTED: 0,
CONNECTING: 1,
CONNECTED: 2,
CREATING: 3,
CREATED: 4
};
var _wifiboxURL;
var _wifiboxCGIBinURL;
var _timeoutTime = 3000;
var _self = this;
this.init = function(wifiboxURL,wifiboxCGIBinURL) {
//console.log("NetworkAPI:init");
//console.log(" wifiboxURL: ",wifiboxURL);
//console.log(" wifiboxCGIBinURL: ",wifiboxCGIBinURL);
_wifiboxURL = wifiboxURL;
_wifiboxCGIBinURL = wifiboxCGIBinURL;
}
this.scan = function(completeHandler,failedHandler) {
//console.log("NetworkAPI:scan");
$.ajax({
url: _wifiboxURL + "/network/scan",
type: "GET",
dataType: 'json',
timeout: _timeoutTime,
success: function(response){
//console.log("NetworkAPI:scan response: ",response);
if(response.status == "error" || response.status == "fail") {
//console.log("NetworkAPI:scan failed: ",response);
if(failedHandler) failedHandler(response);
} else {
completeHandler(response.data);
}
}
}).fail(function() {
//console.log("NetworkAPI:scan failed");
if(failedHandler) failedHandler();
});
};
this.status = function(completeHandler,failedHandler) {
//console.log("NetworkAPI:status");
$.ajax({
url: _wifiboxURL + "/network/status",
type: "GET",
dataType: 'json',
timeout: _timeoutTime,
success: function(response){
//console.log("NetworkAPI:status response: ",response);
if(response.status == "error" || response.status == "fail") {
if(failedHandler) failedHandler(response);
} else {
completeHandler(response.data);
}
}
}).fail(function() {
if(failedHandler) failedHandler();
});
};
this.associate = function(ssid,phrase,recreate) {
//console.log("NetworkAPI:associate");
var postData = {
ssid:ssid,
phrase:phrase,
recreate:recreate
};
$.ajax({
url: _wifiboxCGIBinURL + "/network/associate",
type: "POST",
data: postData,
dataType: 'json',
timeout: _timeoutTime,
success: function(response){
//console.log("NetworkAPI:associate response: ",response);
}
}).fail(function() {
//console.log("NetworkAPI:associate: timeout (normal behavior)");
});
};
this.openAP = function() {
//console.log("NetworkAPI:openAP");
$.ajax({
url: _wifiboxCGIBinURL + "/network/openap",
type: "POST",
dataType: 'json',
timeout: _timeoutTime,
success: function(response){
//console.log("NetworkAPI:openAP response: ",response);
}
}).fail(function() {
//console.log("NetworkAPI:openAP: timeout (normal behavior)");
});
};
this.signin = function() {
$.ajax({
url: _wifiboxCGIBinURL + "/network/signin",
type: "GET",
dataType: 'json',
timeout: _timeoutTime,
success: function(response){
//console.log("NetworkAPI:signin response: ",response);
}
}).fail(function() {
//console.log("NetworkAPI:signin: failed");
});
};
}
/*
* This file is part of the Doodle3D project (http://doodle3d.com).
*
* Copyright (c) 2013, Doodle3D
* This software is licensed under the terms of the GNU GPL v2 or later.
* See file LICENSE.txt or visit http://www.gnu.org/licenses/gpl.html for full license details.
*/
function PrinterAPI() {
var _wifiboxURL;
var _wifiboxCGIBinURL;
var _timeoutTime = 3000;
var _self = this;
this.init = function(wifiboxURL,wifiboxCGIBinURL) {
//console.log("PrinterAPI:init");
//console.log(" wifiboxURL: ",wifiboxURL);
//console.log(" wifiboxCGIBinURL: ",wifiboxCGIBinURL);
_wifiboxURL = wifiboxURL;
_wifiboxCGIBinURL = wifiboxCGIBinURL;
}
this.listAll = function(completeHandler,failedHandler) {
//console.log("PrinterAPI:listAll");
//console.log(" _wifiboxURL: ",_wifiboxURL);
$.ajax({
url: _wifiboxURL + "/printer/listall",
type: "GET",
dataType: 'json',
timeout: _timeoutTime,
success: function(response){
//console.log("PrinterAPI response: ",response);
if(response.status == "error" || response.status == "fail") {
//console.log("PrinterAPI:listAll failed: ",response);
if(failedHandler) failedHandler(response);
} else {
completeHandler(response.data);
}
}
}).fail(function() {
//console.log("PrinterAPI:listAll failed");
if(failedHandler) failedHandler();
});
};
}
/*
* This file is part of the Doodle3D project (http://doodle3d.com).
*
* Copyright (c) 2013, Doodle3D
* This software is licensed under the terms of the GNU GPL v2 or later.
* See file LICENSE.txt or visit http://www.gnu.org/licenses/gpl.html for full license details.
*/
function FormPanel() {
var _configAPI = new ConfigAPI();
var _retryDelay = 2000;
var _retrySaveSettingsDelay;
var _retryLoadAllSettingsDelay;
var _retryLoadSettingsDelay;
var _retryResetSettingsDelay;
// ui elements
var _element;
var _self = this;
this.init = function(wifiboxURL,wifiboxCGIBinURL,panelElement) {
// make _self the scope of which init was called?
// needed to have the subclass instance access the same counter
//_self = this;
//console.log(" _element: ",_element);
_element = panelElement;
//console.log(" >_element: ",_element);
_configAPI.init(wifiboxURL,wifiboxCGIBinURL);
};
//this.readForm = function(form) {
this.readForm = function(form) {
//console.log("FormPanel:readForm");
if(!form) form = _element; // if no form specified, read whole panel form
//console.log("FormPanel");
var settings = {};
// Read all selects
var selects = form.find("select");
selects.each( function(index,element) {
var elem = $(element);
//var fieldName = elem.attr('name');
if(elem.attr('name') != "") {
settings[elem.attr('name')] = elem.val();
}
});
// Read all inputs
var inputs = form.find("input");
inputs.each( function(index,element) {
var elem = $(element);
if(elem.attr('name') != "") {
switch(elem.attr("type")) {
case "text":
case "number":
settings[elem.attr('name')] = elem.val();
break;
case "checkbox":
settings[elem.attr('name')] = elem.prop('checked');
break;
}
}
});
// Read all textareas
var textareas = form.find("textarea");
textareas.each( function(index,element) {
var elem = $(element);
settings[elem.attr('name')] = elem.val();
});
return settings;
};
this.fillForm = function(settings,form) {
//console.log("FormPanel:fillForm");
if(!form) form = _element; // if no form specified, fill whole panel form
//console.log(" form: ",form);
clearValidationErrors();
//fill form with loaded settings
var selects = form.find("select");
selects.each( function(index,element) {
var elem = $(element);
elem.val(settings[elem.attr('name')]);
});
var inputs = form.find("input");
inputs.each( function(index,element) {
var elem = $(element);
//console.log("printer setting input: ",index,element.attr("type"),element.attr('name')); //,element);
switch(elem.attr("type")) {
case "text":
case "number":
elem.val(settings[elem.attr('name')]);
break;
case "checkbox":
elem.prop('checked', settings[elem.attr('name')]);
break;
}
});
var textareas = form.find("textarea");
textareas.each( function(index,element) {
var elem = $(element);
var value = settings[elem.attr('name')];
elem.val(value);
});
};
this.saveSettings = function(newSettings,complete) {
//console.log(" newSettings: ",newSettings);
_configAPI.save(newSettings,function(data) {
var validation = data.validation;
//console.log(" validation: ",validation);
clearValidationErrors();
var validated = true;
$.each(validation, function(key, val) {
if (val != "ok") {
console.log("ERROR: setting '" + key + "' not successfully set. Message: " + val);
displayValidationError(key,val);
validated = false;
}
});
if(complete) complete(validated, data);
}, function() {
console.log("Settings:saveSettings: failed");
clearTimeout(_retrySaveSettingsDelay);
_retrySaveSettingsDelay = setTimeout(function() { _self.saveSettings(newSettings,complete); },_retryDelay); // retry after delay
});
};
function displayValidationError(key,msg) {
var formElement = _element.find("[name|='"+key+"']");
formElement.addClass("error");
var errorMsg = "<p class='errorMsg'>"+msg+"</p>";
formElement.after(errorMsg);
};
function clearValidationErrors() {
_element.find(".errorMsg").remove();
_element.find(".error").removeClass("error");
};
this.loadAllSettings = function(complete) {
_configAPI.loadAll(complete,function() {
clearTimeout(_retryLoadAllSettingsDelay);
_retryLoadAllSettingsDelay = setTimeout(function() { _self.loadAllSettings(complete); },_retryDelay); // retry after delay
});
};
this.loadSettings = function(targetSettings,complete) {
_configAPI.load(targetSettings,complete,function() {
clearTimeout(_retryLoadSettingsDelay);
_retryLoadSettingsDelay = setTimeout(function() { _self.loadSettings(targetSettings,complete); },_retryDelay); // retry after delay
});
};
this.resetAllSettings = function(complete) {
_configAPI.resetAll(complete,function() {
clearTimeout(_retryResetSettingsDelay);
_retryResetSettingsDelay = setTimeout(function() { _self.resetAllSettings(complete); },_retryDelay); // retry after delay
});
};
}
/*
* This file is part of the Doodle3D project (http://doodle3d.com).
*
* Copyright (c) 2013, Doodle3D
* This software is licensed under the terms of the GNU GPL v2 or later.
* See file LICENSE.txt or visit http://www.gnu.org/licenses/gpl.html for full license details.
*/
function NetworkPanel() {
var NOT_CONNECTED = "not connected"; // used as first item in networks list
// network mode
NetworkPanel.NETWORK_MODE = {
NEITHER: "neither",
CLIENT: "clientMode",
ACCESS_POINT: "accessPointMode"
};
var _networkMode = NetworkPanel.NETWORK_MODE.NEITHER;
var _networkModeChangedHandler;
var _form = new FormPanel();
var _api = new NetworkAPI();
var _networks = {};
var _currentNetwork; // the ssid of the network the box is on
var _selectedNetwork; // the ssid of the selected network in the client mode settings
var _substituted_ssid; // the substituted ssid (displayed during creation)
var _currentLocalIP = "";
var _currentAP;
var _currentNetworkStatus;
var _retryDelay = 2000;
//var _retryRefreshNetworksDelay;
var _retryRetrieveStatusDelayTime = 1000;
var _retryRetrieveStatusDelay;
// after switching wifi network or creating a access point we delay the status retrieval
// because the webserver needs time to switch
var _retrieveNetworkStatusDelayTime = 1000;
var _retrieveNetworkStatusDelay;
// ui elements
var _element;
var _networkSelector;
var _apFieldSet;
var _clientFieldSet;
var _apRadioButton;
var _clientRadioButton;
var _btnRefresh
var _btnConnect;
var _btnCreate;
var _passwordField;
var _passwordLabel;
var _clientStateDisplay;
var _apModeStateDisplay;
var _self = this;
this.init = function(wifiboxURL,wifiboxCGIBinURL,panelElement) {
//console.log("NetworkPanel:init");
_form.init(wifiboxURL,wifiboxCGIBinURL,panelElement)
_api.init(wifiboxURL,wifiboxCGIBinURL);
_element = panelElement;
_apRadioButton = _element.find("#ap");
_clientRadioButton = _element.find("#client");
_btnRefresh = _element.find("#refreshNetworks");
_btnConnect = _element.find("#connectToNetwork");
_btnCreate = _element.find("#createAP");
_networkSelector = _element.find("#network");
_apFieldSet = _element.find("#apSettings");
_clientFieldSet = _element.find("#clientSettings");
_passwordField = _element.find("#password");
_passwordLabel = _element.find("#passwordLabel");
_clientStateDisplay = _element.find("#clientModeState");
_apModeStateDisplay = _element.find("#apModeState");
_apRadioButton.parent().on('touchstart mousedown',showAPSettings);
_clientRadioButton.parent().on('touchstart mousedown',showClientSettings);
_btnRefresh.on('touchstart mousedown',onRefreshClick);
_btnConnect.on('touchstart mousedown',_self.connectToNetwork);
_btnCreate.on('touchstart mousedown',_self.createAP);
_networkSelector.change(networkSelectorChanged);
}
/*
* Handlers
*/
function showAPSettings() {
_apFieldSet.show();
_clientFieldSet.hide();
};
function showClientSettings() {
_clientFieldSet.show();
_apFieldSet.hide();
};
function onRefreshClick() {
_btnRefresh.attr("disabled", true);
_self.refreshNetworks(function() {
_btnRefresh.removeAttr("disabled");
})
}
function networkSelectorChanged(e) {
var selectedOption = $(this).find("option:selected");
_self.selectNetwork(selectedOption.val());
};
this.update = function() {
//console.log("NetworkPanel:update");
_self.refreshNetworks();
_self.retrieveNetworkStatus(false);
}
this.refreshNetworks = function(completeHandler) {
//console.log("NetworkPanel:refreshNetworks");
_api.scan(function(data) { // completed
//console.log("NetworkPanel:scanned");
_networks = {};
var foundCurrentNetwork = false;
// fill network selector
_networkSelector.empty();
_networkSelector.append(
$("<option></option>").val(NOT_CONNECTED).html(NOT_CONNECTED)
);
$.each(data.networks, function(index,element) {
if(element.ssid == _currentNetwork) {
foundCurrentNetwork = true;
}
_networkSelector.append(
$("<option></option>").val(element.ssid).html(element.ssid)
);
_networks[element.ssid] = element;
});
if(foundCurrentNetwork) {
_networkSelector.val(_currentNetwork);
_self.selectNetwork(_currentNetwork);
}
if(completeHandler) completeHandler();
}/*,
function() { // failed
clearTimeout(_retryRefreshNetworksDelay);
_retryRetrieveStatusDelay = setTimeout(function() { _self.refreshNetworks(completeHandler); },_retryDelay); // retry after delay
}*/);
};
this.retrieveNetworkStatus = function(connecting) {
//console.log("NetworkPanel:retrieveNetworkStatus");
_api.status(function(data) {
if(data.status === "") {
data.status = NetworkAPI.STATUS.CREATED.toString();
}
if(typeof data.status === 'string') {
data.status = parseInt(data.status);
}
//console.log("NetworkPanel:retrievedStatus status: ",data.status,data.statusMessage);
// if status changed
if(data.status != _currentNetworkStatus) {
// Determine which network mode ui to show
switch(data.status) {
case NetworkAPI.STATUS.NOT_CONNECTED:
setNetworkMode(NetworkPanel.NETWORK_MODE.NEITHER);
break;
case NetworkAPI.STATUS.CONNECTING_FAILED:
case NetworkAPI.STATUS.CONNECTING:
case NetworkAPI.STATUS.CONNECTED:
setNetworkMode(NetworkPanel.NETWORK_MODE.CLIENT);
break;
case NetworkAPI.STATUS.CREATING:
case NetworkAPI.STATUS.CREATED:
setNetworkMode(NetworkPanel.NETWORK_MODE.ACCESS_POINT);
break;
}
// update info
switch(data.status) {
case NetworkAPI.STATUS.CONNECTED:
_currentNetwork = data.ssid;
_currentLocalIP = data.localip;
_self.selectNetwork(data.ssid);
break;
case NetworkAPI.STATUS.CONNECTING_FAILED:
case NetworkAPI.STATUS.CONNECTING:
_currentLocalIP = "";
break;
case NetworkAPI.STATUS.CREATING:
case NetworkAPI.STATUS.CREATED:
_currentNetwork = undefined;
_self.selectNetwork(NOT_CONNECTED);
if(data.ssid && data.status == NetworkAPI.STATUS.CREATED) {
_currentAP = data.ssid;
}
break;
}
// update ui
updateClientModeUI(data.status,data.statusMessage);
updateAPModeUI(data.status,"");
}
// Keep checking for updates?
if(connecting) {
switch(data.status) {
case NetworkAPI.STATUS.CONNECTING:
case NetworkAPI.STATUS.CREATING:
clearTimeout(_retryRetrieveStatusDelay);
_retryRetrieveStatusDelay = setTimeout(function() { _self.retrieveNetworkStatus(connecting); },_retryRetrieveStatusDelayTime); // retry after delay
break;
}
}
_currentNetworkStatus = data.status;
}, function() {
//console.log("NetworkPanel:retrieveStatus failed");
clearTimeout(_retryRetrieveStatusDelay);
_retryRetrieveStatusDelay = setTimeout(function() { _self.retrieveNetworkStatus(connecting); }, _retryRetrieveStatusDelayTime); // retry after delay
});
};
function setNetworkMode(mode) {
//console.log("NetworkPanel:setNetworkMode: ",_networkMode,">",mode);
if(mode == _networkMode) return;
switch(mode) {
case NetworkPanel.NETWORK_MODE.NEITHER:
_apFieldSet.show();
_clientFieldSet.show();
break;
case NetworkPanel.NETWORK_MODE.CLIENT:
_clientRadioButton.prop('checked',true);
_apFieldSet.hide();
_clientFieldSet.show();
break;
case NetworkPanel.NETWORK_MODE.ACCESS_POINT:
_apRadioButton.prop('checked',true);
_apFieldSet.show();
_clientFieldSet.hide();
break;
}
_networkMode = mode;
if(_networkModeChangedHandler) _networkModeChangedHandler(_networkMode);
}
this.selectNetwork = function(ssid) {
//console.log("NetworkPanel:selectNetwork: ",ssid);
if(ssid == "") return;
_selectedNetwork = ssid;
var network = _networks[ssid];
if(network === undefined || network.encryption == "none") {
_passwordLabel.hide();
_passwordField.hide();
} else {
_passwordLabel.show();
_passwordField.show();
}
_passwordField.val("");
};
function updateClientModeUI(state,statusMessage) {
//console.log("NetworkPanel:updateClientModeUI ",state,statusMessage);
var msg = "";
switch(state) {
case NetworkAPI.STATUS.NOT_CONNECTED:
case NetworkAPI.STATUS.CREATING:
case NetworkAPI.STATUS.CREATED:
_btnConnect.removeAttr("disabled");
msg = "Not connected";
_networkSelector.val(NOT_CONNECTED);
break;
case NetworkAPI.STATUS.CONNECTED:
_btnConnect.removeAttr("disabled");
msg = "Connected to: <b>"+_currentNetwork+"</b>.";
if(_currentLocalIP != undefined && _currentLocalIP != "") {
var a = "<a href='http://"+_currentLocalIP+"' target='_black'>"+_currentLocalIP+"</a>";
msg += " (IP: "+a+")";
}
_networkSelector.val(_currentNetwork);
break;
case NetworkAPI.STATUS.CONNECTING:
_btnConnect.attr("disabled", true);
msg = "Connecting... Reconnect by connecting your device to <b>"+_selectedNetwork+"</b> and going to <a href='http://connect.doodle3d.com'>connect.doodle3d.com</a>";
break;
case NetworkAPI.STATUS.CONNECTING_FAILED:
_btnConnect.removeAttr("disabled");
msg = statusMessage;
break;
}
//console.log(" client display msg: ",msg);
_clientStateDisplay.html(msg);
};
function updateAPModeUI(state,statusMessage) {
var msg = "";
switch(state) {
case NetworkAPI.STATUS.CONNECTING_FAILED:
case NetworkAPI.STATUS.NOT_CONNECTED:
case NetworkAPI.STATUS.CONNECTING:
case NetworkAPI.STATUS.CONNECTED:
_btnCreate.removeAttr("disabled");
msg = "Not currently a access point";
break;
case NetworkAPI.STATUS.CREATED:
_btnCreate.removeAttr("disabled");
msg = "Is access point: <b>"+_currentAP+"</b>";
break;
case NetworkAPI.STATUS.CREATING:
_btnCreate.attr("disabled", true);
msg = "Creating access point... Reconnect by connecting your device to <b>"+_substituted_ssid+"</b> and going to <a href='http://draw.doodle3d.com'>draw.doodle3d.com</a>";
break;
}
//console.log(" ap display msg: ",msg);
_apModeStateDisplay.html(msg);
};
this.connectToNetwork = function() {
//console.log("NetworkPanel:connectToNetwork");
if(_selectedNetwork == undefined) return;
// save network related settings and on complete, connect to network
_form.saveSettings(_form.readForm(),function(validated, data) {
if(!validated) return;
updateClientModeUI(NetworkAPI.STATUS.CONNECTING,"");
_api.associate(_selectedNetwork,_passwordField.val(),true);
// after switching wifi network or creating a access point we delay the status retrieval
// because the webserver needs time to switch it's status
clearTimeout(_retrieveNetworkStatusDelay);
_retrieveNetworkStatusDelay = setTimeout(function() { _self.retrieveNetworkStatus(true); }, _retrieveNetworkStatusDelayTime);
});
};
this.createAP = function() {
//console.log("createAP");
// save network related settings and on complete, create access point
_form.saveSettings(_form.readForm(),function(validated, data) {
if(!validated) return;
_substituted_ssid = data.substituted_ssid;
updateAPModeUI(NetworkAPI.STATUS.CREATING,"");
_api.openAP();
// after switching wifi network or creating a access point we delay the status retrieval
// because the webserver needs time to switch it's status
clearTimeout(_retrieveNetworkStatusDelay);
_retrieveNetworkStatusDelay = setTimeout(function() { _self.retrieveNetworkStatus(true); }, _retrieveNetworkStatusDelayTime);
});
};
this.setNetworkModeChangedHandler = function(handler) {
_networkModeChangedHandler = handler;
}
}
/*
* This file is part of the Doodle3D project (http://doodle3d.com).
*
* Copyright (c) 2013, Doodle3D
* This software is licensed under the terms of the GNU GPL v2 or later.
* See file LICENSE.txt or visit http://www.gnu.org/licenses/gpl.html for full license details.
*/
function PrinterPanel() {
this.printerType;
var _api = new PrinterAPI();
var _form = new FormPanel();
// ui elements
var _element;
var _printerSelector;
var _printerSettings;
var _self = this;
this.init = function(wifiboxURL,wifiboxCGIBinURL,panelElement) {
_form.init(wifiboxURL,wifiboxCGIBinURL,panelElement)
_api.init(wifiboxURL,wifiboxCGIBinURL);
_element = panelElement;
_printerSelector = _element.find("#printerType");
_printerSelector.change(_self.printerSelectorChanged);
// we use readForm to get all the settings we need to
// reload after changing printer type
_printerSettings = _form.readForm();
var gcodePanel = _element.find("#gcodePanel");
gcodePanel.coolfieldset({collapsed:true});
}
this.load = function(completeHandler) {
_api.listAll(function(data) {
$.each(data.printers, function(key, value) {
// console.log(key,value);
$('#printerType').append($('<option>').text(value).attr('value', key));
});
completeHandler();
});
}
this.printerSelectorChanged = function(e) {
_self.printerType = _printerSelector.find("option:selected").val();
var settings = {};
settings[_printerSelector.attr("name")] = _self.printerType;
_form.saveSettings(settings,function(validated) {
if(!validated) return;
_form.loadSettings(_printerSettings,function(settings) {
_form.fillForm(settings);
});
});
}
}
/*
* This file is part of the Doodle3D project (http://doodle3d.com).
*
* Copyright (c) 2013, Doodle3D
* This software is licensed under the terms of the GNU GPL v2 or later.
* See file LICENSE.txt or visit http://www.gnu.org/licenses/gpl.html for full license details.
*/
//these settings are defined in the firmware (conf_defaults.lua) and will be initialized in loadSettings()
var settings = {};
var settingsPopup;
//wrapper to prevent scoping issues in showSettings()
function openSettingsWindow() {
settingsWindow.loadSettings(function() { // reload settings
settingsPopup.open();
});
}
function SettingsWindow() {
var _window;
var _btnOK;
var _wifiboxURL;
var _restoredStateHideDelayTime = 3000;
var _restoredStateHideDelay; // setTimout instance
// Events
SettingsWindow.SETTINGS_LOADED = "settingsLoaded";
var _form = new FormPanel();
var _updatePanel = new UpdatePanel();
var _printerPanel = new PrinterPanel();
var _networkPanel = new NetworkPanel();
var _networkAPI = new NetworkAPI();
var _restoreStateField
var self = this;
this.init = function(wifiboxURL,wifiboxCGIBinURL) {
_wifiboxURL = wifiboxURL;
_window = $("#popupSettings");
_btnOK = _window.find(".btnOK");
settingsPopup = new Popup($("#popupSettings"), $("#popupMask"));
settingsPopup.setEnterEnabled(false);
settingsPopup.setAutoCloseEnabled(false);
_btnOK.on('touchstart mousedown',settingsPopup.commit);
$("#popupSettings").bind("onPopupCancel", function() { settingsPopup.close(); } );
$("#popupSettings").bind("onPopupCommit", self.submitwindow);
_networkAPI.init(wifiboxURL,wifiboxCGIBinURL);
// Load external settings.html into SettingsWindow
_window.find("#settingsContainer").load("settings.html", function() {
console.log("Settings:finished loading settings.html");
var formElement = _window.find("form");
formElement.submit(function (e) { self.submitwindow(e); });
_form.init(wifiboxURL,wifiboxCGIBinURL,formElement);
// printer panel
var printerPanelElement = formElement.find("#printerPanel");
_printerPanel.init(wifiboxURL,wifiboxCGIBinURL,printerPanelElement);
// Load printer types list
// First, because after the settings are loaded the printer type need to be selected
_printerPanel.load(function() {
_restoreStateField = formElement.find("#restoreState");
self.btnRestoreSettings = formElement.find("#restoreSettings");
self.btnRestoreSettings.on('touchstart mousedown',self.resetSettings);
// network panel
var $networkPanelElement = formElement.find("#networkPanel");
_networkPanel.init(wifiboxURL,wifiboxCGIBinURL,$networkPanelElement);
// update panel
var updatePanelElement = formElement.find("#updatePanel");
_updatePanel.init(wifiboxURL,updatePanelElement);
_networkPanel.setNetworkModeChangedHandler(function(networkMode) {
var inAccessPointMode = (networkMode == NetworkPanel.NETWORK_MODE.ACCESS_POINT);
_updatePanel.setInAccessPointMode(inAccessPointMode);
});
self.loadSettings();
});
}); //this.window.find
}; //this.init
this.openSettings = function() {
self.loadSettings(function() { // reload settings
settingsPopup.open();
});
};
// this.closeSettings = function(complete) {
// settingsPopup.close(complete);
// };
this.submitwindow = function(e) {
_btnOK.attr("disabled",true);
e.preventDefault();
e.stopPropagation();
var newSettings = _form.readForm();
_form.saveSettings(newSettings,function(validated, data){
if(validated) {
settings = newSettings; // store new settings in global settings
settingsPopup.close();
self.signin();
}
_btnOK.removeAttr("disabled");
});
};
this.loadSettings = function(complete) {
_form.loadAllSettings(function(loadedSettings){
console.log("Settings:loaded settings: ",loadedSettings);
settings = loadedSettings;
_form.fillForm(settings);
$(document).trigger(SettingsWindow.SETTINGS_LOADED);
if(complete) complete();
});
_networkPanel.update();
};
this.resetSettings = function() {
console.log("resetSettings");
self.btnRestoreSettings.attr("disabled", true);
clearTimeout(_restoredStateHideDelay);
self.setRestoreState("Restoring...");
_form.resetAllSettings(function(restoredSettings) {
//console.log(" settings: ",restoredSettings);
settings = restoredSettings;
_form.fillForm(restoredSettings);
$(document).trigger(SettingsWindow.SETTINGS_LOADED);
self.btnRestoreSettings.removeAttr("disabled");
self.setRestoreState("Settings restored");
// auto hide status
clearTimeout(_restoredStateHideDelay);
_restoredStateHideDelay = setTimeout(function() { self.setRestoreState(""); },_restoredStateHideDelayTime);
});
};
this.setRestoreState = function(text) {
_restoreStateField.html(text);
};
this.signin = function() {
_networkAPI.signin();
};
this.downloadlogs = function() {
window.location.href = _wifiboxURL + "/info/logfiles";
};
this.downloadGcode = function() {
var gcode = generate_gcode();
if (gcode!=undefined) {
var blob = new Blob([gcode.join("\n")], {type: "text/plain;charset=utf-8"});
saveAs(blob, "doodle3d.gcode");
}
};
this.downloadSvg = function() {
var svg = saveToSvg();
if (svg!=undefined) {
var blob = new Blob([svg], {type: "text/plain;charset=utf-8"});
saveAs(blob, "doodle3d.svg");
}
};
this.openFileManager = function() {
location.href = "filemanager/"+location.search;
}
}
/*************************
*
*
* 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;
/*
* This file is part of the Doodle3D project (http://doodle3d.com).
*
* Copyright (c) 2013, Doodle3D
* This software is licensed under the terms of the GNU GPL v2 or later.
* See file LICENSE.txt or visit http://www.gnu.org/licenses/gpl.html for full license details.
*/
function UpdatePanel() {
var _form = new FormPanel();
this.wifiboxURL;
this.element;
this.statusCheckInterval = 1000;
this.statusCheckDelayer; // setTimout instance
this.installedDelay = 90*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.currentReleaseDate;
this.newestReleaseDate;
this.progress;
this.imageSize;
var _inAccessPointMode;
// 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 successful 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
var self = this;
this.init = function(wifiboxURL,updatePanelElement) {
_form.init(wifiboxURL,wifiboxURL,updatePanelElement);
this.wifiboxURL = wifiboxURL;
this.element = updatePanelElement;
this.retainCheckbox = this.element.find("#retainConfiguration");
this.includeBetasCheckbox = this.element.find("#includeBetas");
this.btnUpdate = this.element.find("#update");
this.statusDisplay = this.element.find("#updateState");
this.infoDisplay = this.element.find("#updateInfo");
this.retainCheckbox.change(this.retainChanged);
this.includeBetasCheckbox.change(this.includeBetasChanged);
this.btnUpdate.click(this.update);
this.checkStatus(false);
}
this.retainChanged = function(e) {
//console.log("UpdatePanel:retainChanged");
//this call ensures that the update button gets enabled if (!retainChanged && !canUpdate)
self.setState(self.state,true);
}
this.includeBetasChanged = function() {
//console.log("UpdatePanel:includeBetasChanged");
_form.saveSettings(_form.readForm(),function(validated, data) {
if(validated) self.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");
// should personal sketches and settings be retained over update?
var retain = self.retainCheckbox.prop('checked');
console.log(" retain: ",retain);
self.stopCheckingStatus();
postData = {no_retain:!retain}
$.ajax({
url: self.wifiboxURL + "/update/install",
type: "POST",
data: postData,
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);
} else {
console.log("API update/status call returned an error: '" + response.msg + "'");
}
}
}).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");
//status texts and button state might have to be updated if the newest version changes (e.g., after (un)ticking include betas checkbox)
var refreshUI = (self.newestVersion != data.newest_version);
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.currentReleaseDate = data.current_release_date; // not always available (for older versions)
self.newestReleaseDate = data.newest_release_date; // not always available (for older versions)
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, refreshUI);
switch(this.state){
case UpdatePanel.IMAGE_READY:
self.installUpdate();
break;
}
}
this.setState = function(newState,refresh) {
//console.log("UpdatePanel:setState");
if(!refresh && this.state == newState) return;
console.log("UpdatePanel:setState: ",this.state," > ",newState,"(",this.stateText,") (in Access Point Mode: ",_inAccessPointMode,") (newestVersion: ",self.newestVersion,") (refresh: ",refresh,")");
this.state = newState;
// should personal sketches and settings be retained over update?
var retain = self.retainCheckbox.prop('checked');
//console.log(" retain", retain);
// download button
// if there isn't newestVersion data something went wrong,
// probably accessing the internet
//console.log(" self.newestVersion: ",self.newestVersion);
if(self.newestVersion != undefined) {
//console.log(" this.state: ",this.state);
switch(this.state){
case UpdatePanel.NONE:
case UpdatePanel.DOWNLOAD_FAILED:
case UpdatePanel.INSTALL_FAILED:
//console.log(" self.canUpdate: ",self.canUpdate);
if(self.canUpdate || !retain) {
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) {
var currIsBeta = self.versionIsBeta(self.currentVersion);
var newIsBeta = self.versionIsBeta(self.newestVersion);
var relIsNewer = (self.newestReleaseDate && self.currentReleaseDate) ? (self.newestReleaseDate - self.currentReleaseDate > 0) : true;
if (!newIsBeta) {
if (relIsNewer) text = "Update available.";
else text = "You can switch back to the latest stable release."; //this case is always a beta->stable 'downgrade'
} else {
//NOTE: actually, an older beta will never be presented as update by the API
var prefixText = currIsBeta ? "A" : (relIsNewer ? "A newer" : "An older");
text = prefixText + " beta release is 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 reconnect by connecting your device to the access point of your WiFi box and going to <a href='http://draw.doodle3d.com'>draw.doodle3d.com</a>";
text = "Update complete, please <a href='javascript:location.reload(true);'>refresh Page</a>.";
break;
case UpdatePanel.INSTALL_FAILED:
text = "Installing update failed.";
break;
}
} else {
if(_inAccessPointMode) {
text = "Can't access internet in access point mode.";
} else {
text = "Can't access internet.";
}
}
this.statusDisplay.html(text);
}
this.updateInfoDisplay = function() {
var html = 'Current version: ' + self.currentVersion;
if (self.currentReleaseDate) html += '; released: ' + self.formatDate(self.currentReleaseDate);
html += ' (<a target="d3d-curr-relnotes" href="ReleaseNotes.html">release notes</a>).';
if(self.canUpdate) {
html += '<br/>Latest version: ' + self.newestVersion;
if (self.newestReleaseDate) html += '; released: ' + self.formatDate(self.newestReleaseDate);
html += ' (<a target="d3d-new-relnotes" href="http://doodle3d.com/updates/images/ReleaseNotes.md">release notes</a>).';
}
self.infoDisplay.html(html);
}
this.setInAccessPointMode = function(inAccessPointMode) {
_inAccessPointMode = inAccessPointMode;
self.updateStatusDisplay();
}
this.formatDate = function(ts) {
if (!ts || ts.length != 8 || !/^[0-9]+$/.test(ts)) return null;
var fields = [ ts.substr(0, 4), ts.substr(4, 2), ts.substr(6, 2) ];
if (!fields || fields.length != 3 || fields[1] > 12) return null;
var abbrMonths = [ 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec' ];
return abbrMonths[fields[1] - 1] + " " + fields[2] + ", " + fields[0];
}
this.versionIsBeta = function(version) {
return version ? /.*-.*/g.test(version) : null;
}
}
//var shapeResolution=3;
var shapePopup;
function initScanDialog() {
scanPopup = new Popup($("#popupScan"), $("#popupMask"));
$("#btnScanOk").on("onButtonClick", onBtnScanOk);
$("#btnCloseScan").on("onButtonClick", onBtnCloseScan);
}
function onBtnCloseScan() {
$('#imgGuide').hide();
$('#btnCloseScan').hide();
}
function onBtnScanOk() {
scanPopup.commit();
}
function showScanDialog() {
scanPopup.open();
}
function readURL(input) {
if (input.files && input.files[0]) {
var reader = new FileReader();
reader.onload = function (e) {
$('#imgGuide').attr('src', e.target.result);
$('#imgGuide').show();
$('#btnCloseScan').show();
scanPopup.commit();
}
reader.readAsDataURL(input.files[0]);
}
}
$("#fileScan").change(function(){
readURL(this);
});
var shapeResolution=3;
var shapePopup;
function initShapeDialog() {
shapePopup = new Popup($("#popupShape"), $("#popupMask"));
$("#btnShapeOk").on("onButtonClick", shapePopup.commit);
$("#btnShapeCancel").on("onButtonClick", shapePopup.cancel);
$("#popupShape").bind("onPopupCancel", onShapeCancel);
$("#popupShape").bind("onPopupCommit", onShapeOk);
$("#btnShapePlus").on("onButtonHold",onShapePlus);
$("#btnShapeMin").on("onButtonHold",onShapeMin);
updateShapePreview();
}
function showShapeDialog() {
shapePopup.open();
}
function onShapeCancel() {
}
function onShapeOk() {
var res = shapeResolution;
if (res!=undefined) {
if (isNaN(res)) res=3;
if (res<2) res=2;
if (res>100) res=100;
drawCircle(canvasWidth/2,canvasHeight/2,80,res);
}
}
function onShapePlus() {
shapeResolution++;
if (shapeResolution>50) shapeResolution=50;
updateShapePreview();
}
function onShapeMin() {
shapeResolution--;
if (shapeResolution<2) shapeResolution=2;
updateShapePreview();
}
function updateShapePreview() {
$(".lblShapeResolution").text(shapeResolution + " sides");
var canvas = $("#shapePreview")[0];
var c = canvas.getContext('2d');
var w = canvas.width;
var h = canvas.height;
//console.log(w,h);
var r = w/2 - 20;
var x0 = w/2;
var y0 = h/2;
var res = shapeResolution;
var step = Math.PI * 2.0 / res;
c.save();
c.clearRect(0,0,canvas.width, canvas.height);
c.restore();
c.beginPath();
for (var a=0; a<Math.PI*2; a+=step) {
var x = Math.sin(a+Math.PI) * r + x0;
var y = Math.cos(a+Math.PI) * r + y0;
if (a==0) c.moveTo(x,y);
else c.lineTo(x,y);
}
//close shape
var x = Math.sin(0+Math.PI) * r + x0;
var y = Math.cos(0+Math.PI) * r + y0;
c.lineTo(x,y);
//draw shape
c.lineWidth = 2;
c.stroke();
}
/*
* This file is part of the Doodle3D project (http://doodle3d.com).
*
* Copyright (c) 2013, Doodle3D
* This software is licensed under the terms of the GNU GPL v2 or later.
* See file LICENSE.txt or visit http://www.gnu.org/licenses/gpl.html for full license details.
*/
// prototype inheritance
// http://robertnyman.com/2008/10/06/javascript-inheritance-how-and-why/
Button.prototype = new jQuery();
function Button() {
this.enabled = true;
var _clickEnabled = true;
var _downTimerFPS = 20;
var _timer;
var _x,_y;
var _isDown = false;
var _self = this;
// call jQuery constuctor
// http://blog.santoshrajan.com/2008/10/what-john-resig-did-not-tell-you.html
this.constructor.prototype.init.apply(this, arguments);
// prevent multiple event handlers etc
// make sure you do a more general conversion last
if(this.data("isButton")) {
return;
} else {
this.data("isButton",true);
}
this.enable = function() {
if(_self.enabled === true) { return; }
_self.removeClass("disabled");
_self.enabled = true;
};
this.disable = function() {
if(_self.enabled === false) { return; }
_self.addClass("disabled");
_self.enabled = false;
};
// if the element starts with a disable class, we properly disable it
if(this.hasClass("disabled")) {
this.disable();
}
function updateCursor(e) {
// retrieve cursor position relative to element
if (e.offsetX !== undefined) {
_x = e.offsetX;
_y = e.offsetY;
} else {
var offset = _self.offset();
if(e.pageX !== undefined) {
// http://www.quirksmode.org/mobile/tableViewport_desktop.html#t11
_x = e.pageX - offset.left;
_y = e.pageY - offset.top;
} else if(e.originalEvent !== undefined && e.originalEvent.pageX !== undefined) {
//http://css-tricks.com/the-javascript-behind-touch-friendly-sliders/
_x = e.originalEvent.pageX - offset.left;
_y = e.originalEvent.pageY - offset.top;
}
//android+chrome-specific hack
if (e.originalEvent.changedTouches !== undefined) {
_x = e.originalEvent.changedTouches[0].pageX - offset.left;
_y = e.originalEvent.changedTouches[0].pageY - offset.top;
}
}
}
function startDownTimer() {
if (_timer === undefined) {
_timer = setInterval(onDownTimerInterval, 1000/_downTimerFPS);
_isDown = true;
}
}
function stopDownTimer() {
clearInterval(_timer);
_timer = undefined;
_isDown = false;
// _x = undefined;
// _y = undefined;
}
function onDownTimerInterval() {
if(!_self.enabled) { return; }
if (_x !== undefined && _y !== undefined) {
_self.trigger("onButtonHold",{x:_x,y:_y});
} else {
console.log("Button: warning... _x or _y not set...");
}
}
// Event handlers
$(document).mouseup(function(e) {
stopDownTimer();
});
this.on("touchstart", function(e) {
if(!_self.enabled) { return; }
_clickEnabled = false;
updateCursor(e);
startDownTimer();
_self.trigger("onButtonClick",{x:_x,y:_y});
e.preventDefault();
});
this.on("touchend", function(e) {
updateCursor(e);
stopDownTimer();
});
this.on("touchmove", function(e) {
if(!_self.enabled) { return; }
updateCursor(e);
startDownTimer();
});
this.mousedown(function(e) {
if(!_self.enabled) { return; }
updateCursor(e);
startDownTimer();
});
this.mouseup(function(e) {
updateCursor(e);
stopDownTimer();
});
this.mousemove(function(e) {
if(!_self.enabled) { return; }
updateCursor(e);
//if (_isDown) mousedrag(e);
});
//this.mousedrag(function(e) {
// updateCursor(e);
//});
this.contextmenu(function(e) {
e.preventDefault();
});
this.click(function(e) {
if(!_self.enabled || !_clickEnabled) { return; }
updateCursor(e);
stopDownTimer();
_self.trigger("onButtonClick",{x:_x,y:_y});
});
}
// to work with multiple objects we need a jQuery plugin
$.fn.Button = function() {
return $(this).each(function(){
new Button(this);
});
};
/*
* This file is part of the Doodle3D project (http://doodle3d.com).
*
* Copyright (c) 2013, Doodle3D
* This software is licensed under the terms of the GNU GPL v2 or later.
* See file LICENSE.txt or visit http://www.gnu.org/licenses/gpl.html for full license details.
*/
var grandTour;
function GrandTour(_name) {
//console.log("GrandTour");
this.tour = "";
this.name = _name;
this.active = false;
var self = this;
this.init = function() {
//console.log("GrandTour >> f:init()");
this.tour = function() {
$('#help_d3dIntro').joyride({
autoStart: false,
modal: true,
expose: true,
'tipAdjustmentX': 15,
'tipAdjustmentY': 15,
'tipLocation': 'bottom', // 'top' or 'bottom' in relation to parent
'nubPosition': 'auto', // override on a per tooltip bases
'scrollSpeed': 300, // Page scrolling speed in ms
// 'timer': 2000, // 0 = off, all other numbers = time(ms)
// 'startTimerOnClick': true, // true/false to start timer on first click
'nextButton': true, // true/false for next button visibility
'tipAnimation': 'fade', // 'pop' or 'fade' in each tip
// 'pauseAfter': [], // array of indexes where to pause the tour after
'tipAnimationFadeSpeed': 350, // if 'fade'- speed in ms of transition
// 'cookieMonster': true, // true/false for whether cookies are used
// 'cookieDomain': false, // set to false or yoursite.com
// 'cookieName': 'Doodle3DFirstTime', // choose your own cookie name
// 'localStorage': true, //
// 'localStorageKey': 'Doodle3DFirstTime', // choose your own cookie name
'preRideCallback' : self.preRideCallback,
'preStepCallback': self.preStepCallback, // A method to call before each step
'postStepCallback': self.postStepCallback, // A method to call after each step
'postRideCallback': self.postRideCallback // a method to call once the tour closes
});
};
this.tour();
};
this.preRideCallback = function(index, tip) {
//console.log("GrandTour >> f:preRideCallback() >> index: " + index);
if (index == 0 && $.cookie("Doodle3DFirstTime") == "ridden") {
//console.log("GrandTour >> f:preRideCallback() >> we've been here before...");
if ($.cookie("grandTourFinished")) {
// grand tour was previously finished (eh.. is that useful?)
// executing this 3 times because there doesn't seem to be a 'go to step X' method
// $(this).joyride('set_li', false);
$(this).joyride('set_li', false);
// $(this).joyride('set_li', false);
} else {
$(this).joyride('set_li', false);
}
}
// Overrule printer to tour mode, pausing status updates
printer.overruleState(Printer.TOUR_STATE);
// bring up thermometer and progressbar to explain them
thermometer.show();
progressbar.show();
message.hide();
};
this.preStepCallback = function(index, tip) {
// console.log("GrandTour >> f:preStepCallback() >> index: " + index);
// console.log("GrandTour >> f:preStepCallback() >> tip: " , tip);
// console.log("GrandTour >> f:preStepCallback() >> $(this): " , $(this));
// console.log("GrandTour >> f:preStepCallback() >> tipsettings: " , $(this)[0].tipSettings);
var dataset = $(this)[0].$li[0].dataset;
if (dataset.action != undefined) {
switch (dataset.action) {
case "showMessage":
//console.log(" action: showMessage");
message.set("This is a status message...", Message.NOTICE);
break;
}
}
};
this.postStepCallback = function(index, tip) {
//console.log("GrandTour >> f:postStepCallback() >> index: " + index);
// var dataset = $(this)[0].$li[0].dataset;
};
this.postRideCallback = function(index, tip) {
// console.log("GrandTour >> f:postRideCallback() >> index: " + index + ", self.active: " + self.active);
// console.log("GrandTour >> f:postRideCallback() >> this: " , self);
self.active = false;
$(document).trigger(helpTours.TOURFINISHED, self.name);
// hide the elements which were summoned for the purposes of the tour
// thermometer.hide();
// progressbar.hide();
// message.hide();
// after seeing the grand tour for the first time ever, set cookie 'Doodle3DFirstTime' to true
if (!$.cookie("Doodle3DFirstTime")) {
$.cookie("Doodle3DFirstTime", 'ridden', { expires: 365, domain: false, path: '/' });
}
if (index < $(this)[0].$tip_content.length - 1) {
//console.log("GrandTour >> f:postRideCallback() >> tour terminated before its true end");
// tour wasn't finished
// tour was ended prematurely. For only the first few visits, nag the user about being able to revisit the tour..
if (parseInt($.cookie("Doodle3DVisitCounter")) < helpTours.numTimesToShowNagPopup) {
helpTours.startTour(helpTours.INFOREMINDER, helpTours);
}
// infoReminderTour.start();
} else {
// tour was finished
//console.log("GrandTour >> f:postRideCallback() >> tour ended at its true end");
// we should be at the end...
if (!$.cookie("grandTourFinished") && parseInt($.cookie("Doodle3DVisitCounter")) < helpTours.numTimesToShowNagPopup) {
helpTours.startTour(helpTours.INFOREMINDER, helpTours);
}
$.cookie("grandTourFinished", 'yes', { expires: 365, domain: false, path: '/' });
}
};
this.start = function() {
//console.log("GrandTour >> f:start() >> this: " , this);
this.active = true;
$(window).joyride('restart');
// self.tour();
};
}
var infoReminderTour;
function InfoReminderTour(_name) {
//console.log("InfoReminderTour");
this.tour = "";
this.name = _name;
this.active = false;
var self = this;
this.init = function(callback) {
//console.log("InfoReminderTour >> f:init()");
this.tour = function() {
$('#help_InfoReminder').joyride({
autoStart: false,
modal: true,
expose: true,
'tipAdjustmentX': 15,
'tipAdjustmentY': 15,
'tipLocation': 'bottom', // 'top' or 'bottom' in relation to parent
'nubPosition': 'auto', // override on a per tooltip bases
'scrollSpeed': 300, // Page scrolling speed in ms
'nextButton': true, // true/false for next button visibility
'tipAnimation': 'fade', // 'pop' or 'fade' in each tip
'tipAnimationFadeSpeed': 350, // if 'fade'- speed in ms of transition
'preRideCallback' : self.preRideCallback,
'postStepCallback': self.postStepCallback, // A method to call after each step
'postRideCallback': self.postRideCallback // a method to call once the tour closes
});
}
this.tour();
if (callback != undefined) callback();
};
this.preRideCallback = function(index, tip) {
//console.log("InfoReminderTour >> f:preRideCallback() >> index: " + index + ", tip: " , tip);
};
this.postStepCallback = function(index, tip) {
//console.log("InfoReminderTour >> f:postStepCallback() >> index: " + index + ", tip: " , tip);
};
this.postRideCallback = function(index, tip) {
//console.log("InfoReminderTour >> f:postRideCallback() >> index: " + index + ", tip: " , tip);
this.active = false;
$(document).trigger(helpTours.TOURFINISHED, self.name);
};
this.start = function() {
//console.log("InfoReminderTour >> f:start()");
this.active = true;
$(window).joyride('restart');
// self.tour();
};
}
function initHelp() {
//console.log("f:initHelp()");
// track number of visits of this user
if ($.cookie("Doodle3DVisitCounter") == null) {
$.cookie("Doodle3DVisitCounter", '0');
} else {
$.cookie("Doodle3DVisitCounter", parseInt($.cookie("Doodle3DVisitCounter")) + 1);
}
// load the html file which describes the tour contents
$("#helpContainer").load("helpcontent.html", function() {
//console.log("helpContent loaded");
helpTours = new HelpTours();
helpTours.init( function () {
if (parseInt($.cookie("Doodle3DVisitCounter")) < helpTours.numTimesToShowNagPopup) {
//console.log("initHelp >> Doodle3DFirstTime cookie is set, Doodle3DVisitCounter is < 4");
if ($.cookie("Doodle3DFirstTime") != "ridden") {
setTimeout(helpTours.startTour, 750, helpTours.tours.grandTour, helpTours);
} else {
setTimeout(helpTours.startTour, 750, helpTours.tours.infoReminderTour, helpTours);
}
// remind user of our nifty tour
} else if (parseInt($.cookie("Doodle3DVisitCounter")) == helpTours.numTimesToShowNagPopup && $.cookie("Doodle3DFirstTime") != "ridden") {
// remind
setTimeout(helpTours.startTour, 750, helpTours.tours.infoReminderTour, helpTours);
}
// // only trigger starttour if user is seeing Doodle3D for the first time
// if ($.cookie("Doodle3DFirstTime") != "ridden") {
// console.log("initHelp >> intro tour has not been given yet > let's go!");
// setTimeout(helpTours.startTour, 750, helpTours.tours.grandTour, helpTours);
// } else if (parseInt($.cookie("Doodle3DVisitCounter")) < helpTours.numTimesToShowNagPopup) {
// console.log("initHelp >> Doodle3DFirstTime cookie is set, Doodle3DVisitCounter is < 4");
// // remind user of our nifty tour
// setTimeout(helpTours.startTour, 750, helpTours.tours.infoReminderTour, helpTours);
// }
});
});
}
var helpTours;
function HelpTours() {
//console.log("HelpTours");
this.numTimesToShowNagPopup = 2;
this.WELCOMETOUR = "welcometour";
this.INFOREMINDER = "inforeminder";
this.TOURFINISHED = "tourfinished";
this.tours = {
'grandTour' : this.WELCOMETOUR,
'infoReminderTour' : this.INFOREMINDER
};
this.currActiveTour = "";
this.tourActive = false;
var self = this;
this.init = function(callback) {
//console.log("HelpTours >> f:init >> self: " + self);
$(document).on(this.TOURFINISHED, this.tourEnded);
grandTour = new GrandTour(this.WELCOMETOUR);
infoReminderTour = new InfoReminderTour(this.INFOREMINDER);
// this.tours["grandTour"] = self.WELCOMETOUR;
// this.tours["infoReminderTour "]= self.INFOREMINDER;
//console.log("HelpTours >> f:init >> this.tours: " , this.tours);
if (callback != undefined) callback();
};
this.startTour = function(which, scope) {
if (scope == undefined) scope = this;
// console.log("HelpTours >> f:startTour >> scope: " , scope);
// console.log("HelpTours >> f:startTour >> currActiveTour: " , scope.currActiveTour.name);
// console.log("HelpTours >> f:startTour >> currActiveTour.active: " , scope.currActiveTour.active);
// console.log("HelpTours >> f:startTour >> target to start: '" + which);
switch (which) {
case scope.WELCOMETOUR:
// do welcometour
//console.log("HelpTours >> f:startTour >> case this.WELCOMETOUR >> scope.tourActive = " + scope.tourActive);
//console.log("HelpTours >> f:startTour >> case this.WELCOMETOUR");
if (scope.tourActive) {
if (scope.currActiveTour.active == true) {
$(window).joyride('end');
scope.currActiveTour = undefined;
}
scope.tourActive = false;
}
$(window).joyride('destroy');
// var self = this;
grandTour.init();
setTimeout(function(scp) {
grandTour.start();
scp.currActiveTour = grandTour;
scp.tourActive = true;
}, 250, scope);
// $(window).joyride('restart');
break;
case self.INFOREMINDER:
// do info reminder
// console.log("HelpTours >> f:startTour >> case self.INFOREMINDER >> scope.tourActive = " + scope.tourActive);
//console.log("HelpTours >> f:startTour >> case self.INFOREMINDER");
if (scope.tourActive) {
// console.log(" killing previous joyride... ");
if (scope.currActiveTour.active == true) {
$(window).joyride('end');
scope.currActiveTour = undefined;
}
// console.log(" setting tourActive to false....");
scope.tourActive = false;
// console.log(" scope.tourActive: " + scope.tourActive);
}
$(window).joyride('destroy');
// var self = this;
infoReminderTour.init();
setTimeout(function(scp) {
infoReminderTour.start();
scp.currActiveTour = infoReminderTour;
scp.tourActive = true;
}, 250, scope);
break;
}
}
this.tourEnded = function(e, n) {
//console.log("HelpTours >> f:tourEnded >> self.tourActive: " + self.tourActive + ", name: " + n);
$(window).joyride('destroy');
self.currActiveTour = undefined;
self.tourActive = false;
message.hide();
printer.checkStatus();
}
}
var keyboardShortcutsEnabled = true;
var keyboardEscapeEnterEnabled = false;
var wordBuffer = "";
var wordFuncs = {
"idbeholdl": function() {
alert("Light!");
},
"idspispopd": function() {
drawTextOnCanvas("Im in ur kanvas drawin' ur stuffz.");
},
"dia": function() {
var cx = canvasWidth / 2;
var cy = canvasHeight /2;
drawCircle(cx, cy, 50, 4);
shapeMoveTo(cx - 20, cy);
shapeLineTo(cx + 20, cy);
shapeMoveTo(cx, cy - 20);
shapeLineTo(cx, cy + 20);
},
"stats": function() {
var text = "Shape statistics:\nNumber of points: " + _points.length;
alert(text);
},
"pdump": function() {
console.log("points array: " + _points);
}
};
function initKeyboard() {
$(document).keypress(function(event) {
if (keyboardEscapeEnterEnabled) {
switch (event.keyCode) {
case 13:
$(document).trigger("onEnterKey");
break;
case 27:
$(document).trigger("onEscapeKey");
break;
}
}
if (!keyboardShortcutsEnabled) return;
if (event.ctrlKey && event.altKey && ! event.metaKey) processWords(event);
if (event.altKey || event.ctrlKey || event.metaKey) return; //ignore key presses with modifier keys except shift
var ch = String.fromCharCode(event.which);
switch (ch) {
case 'c': newSketch(); break;
case 'n': newSketch(); break;
case 'p': print(); break;
case 'u': oopsUndo(); break;
case 'g': settingsWindow.downloadGcode(); break;
case 'q': stopPrint(); break;
case ',': openSettingsWindow(); break;
case 'h': previewUp(true); break;
case 'H': previewDown(true); break;
case 's': saveSketch(); break;
case 'L': nextSketch(); break;
case 'l': prevSketch(); break;
case '[': previewTwistLeft(); break;
case ']': previewTwistRight(); break;
case '|': resetTwist(); break;
case 't': showWordArtDialog(); break;
case 'i': showShapeDialog(); break;
case 'T': showScanDialog(); break;
case ';': moveShape(-5,0); break;
case '\'': moveShape(5,0); break;
case '-': zoomShape(.95); break;
case '+': zoomShape(1.05); break;
case 'r': rotateShape(.1); break;
case 'R': rotateShape(-.1); break;
//default: console.log("Key: '" + ch + "' (" + event.which + ")");
}
if(event.which != 13) { // don't prevent enter usage, it's used in tour
event.preventDefault(); //prevents the character to end up in a focussed textfield
}
})
}
function processWords(e) {
wordBuffer += String.fromCharCode(e.which);
var match = false;
for (var k in wordFuncs) {
if (k.indexOf(wordBuffer) == 0) {
if (k.length == wordBuffer.length) match = wordFuncs[k];
else match = true;
break;
}
}
if (typeof(match) == 'function') {
match();
wordBuffer = "";
} else if (!match) {
wordBuffer = "";
}
}
/*
* This file is part of the Doodle3D project (http://doodle3d.com).
*
* Copyright (c) 2013, Doodle3D
* This software is licensed under the terms of the GNU GPL v2 or later.
* See file LICENSE.txt or visit http://www.gnu.org/licenses/gpl.html for full license details.
*/
function Message() {
Message.ERROR = "error";
Message.WARNING = "warning";
Message.NOTICE = "notice";
Message.INFO = "info";
this.mode = "";
this.$element;
var self = this;
var autoHideDelay = 5000;
var autohideTimeout;
this.init = function($element) {
this.$element = $element;
}
this.set = function(contents,mode,autoHide,disableEffect) {
console.log("Message:set: ",contents,mode,autoHide,disableEffect);
if(disableEffect) {
self.fill(contents,mode,autoHide)
} else{
self.hide(function() {
self.show();
self.fill(contents,mode,autoHide)
});
}
}
this.fill = function(contents,mode,autoHide) {
//console.log("Message:fill: ",text,mode,autoHide);
self.clear();
self.$element.html(contents);
self.$element.addClass(mode);
self.mode = mode;
clearTimeout(autohideTimeout);
if(autoHide) {
autohideTimeout = setTimeout(function(){ self.hide()},autoHideDelay);
}
}
this.clear = function($element) {
this.$element.html("");
this.$element.removeClass(this.mode);
}
this.show = function() {
this.$element.fadeIn(200);
}
this.hide = function(complete) {
this.$element.fadeOut(200,complete);
}
}
function Popup(element, mask) {
var autoCloseEnabled = true;
var enterEnabled = true;
var self = this;
this.open = function(complete, disableMaskClick) {
mask.fadeIn(POPUP_SHOW_DURATION);
element.fadeIn(POPUP_SHOW_DURATION, complete);
keyboardShortcutsEnabled = false;
keyboardEscapeEnterEnabled = true;
document.body.removeEventListener('touchmove', prevent, false);
mask.bind("onButtonClick", self.cancel);
$(document).bind("onEscapeKey", self.cancel);
if (enterEnabled) $(document).bind("onEnterKey", self.commit);
}
this.close = function(complete) {
mask.fadeOut(POPUP_SHOW_DURATION);
element.fadeOut(POPUP_SHOW_DURATION, complete);
keyboardShortcutsEnabled = true;
keyboardEscapeEnterEnabled = false;
document.body.addEventListener('touchmove', prevent, false);
mask.unbind("onButtonClick", self.cancel);
$(document).unbind("onEscapeKey", self.cancel);
if (enterEnabled) $(document).unbind("onEnterKey", self.commit);
}
this.setEnterEnabled = function(enabled) { enterEnabled = enabled; }
this.setAutoCloseEnabled = function(enabled) { autoCloseEnabled = enabled; }
this.cancel = function() {
$(element).trigger('onPopupCancel');
if (autoCloseEnabled) self.close();
}
this.commit = function() {
$(element).trigger('onPopupCommit');
if (autoCloseEnabled) self.close();
}
}
/*
* This file is part of the Doodle3D project (http://doodle3d.com).
*
* Copyright (c) 2013, Doodle3D
* This software is licensed under the terms of the GNU GPL v2 or later.
* See file LICENSE.txt or visit http://www.gnu.org/licenses/gpl.html for full license details.
*/
/* 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.CONNECTING_STATE = "connecting"; // printer connecting (printer found, but driver has not yet finished setting up the connection)
Printer.IDLE_STATE = "idle"; // printer found and ready to use, 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.TOUR_STATE = "tour"; // when in joyride mode
Printer.ON_BEFORE_UNLOAD_MESSAGE = "You're doodle is still being sent 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 = 500; // max amount of gcode lines per post (limited because WiFi box can't handle too 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
Printer.MAX_GCODE_SIZE = 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");
if (this.state != Printer.IDLE_STATE) return;
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 != "success") {
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 > Printer.MAX_GCODE_SIZE) {
var msg = "Error: Printer:print: gcode file is probably too big ("+gcodeSize+"MB) (max: "+Printer.MAX_GCODE_SIZE+"MB)";
alert(msg);
console.log(msg);
this.overruleState(Printer.IDLE_STATE);
this.startStatusCheckInterval();
message.hide();
self.removeLeaveWarning();
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 sendPercentage = Math.round(sendIndex/this.gcode.length*100);
message.set("Sending doodle to printer: "+sendPercentage+"%",Message.NOTICE,false,true);
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 has been sent to printer...",Message.INFO,true);
//self.targetTemperature = settings["printer.temperature"]; // slight hack
} else {
// only if the state hasn't been 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");
endCode = generateEndCode();
console.log(" endCode: ",endCode);
var postData = { gcode: endCode.join("\n")};
var self = this;
if (communicateWithWifibox) {
$.ajax({
url: this.wifiboxURL + "/printer/stop",
type: "POST",
data: postData,
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:stop() >> 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() {
console.log("WARNING:"+Printer.ON_BEFORE_UNLOAD_MESSAGE);
return Printer.ON_BEFORE_UNLOAD_MESSAGE;
};
}
}
/*
* This file is part of the Doodle3D project (http://doodle3d.com).
*
* Copyright (c) 2013, Doodle3D
* This software is licensed under the terms of the GNU GPL v2 or later.
* See file LICENSE.txt or visit http://www.gnu.org/licenses/gpl.html for full license details.
*/
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;
// To make the progressbar start with a minimal amount of 'progress'
// so that you can visually see that there is progress
this.progressPadding = Math.PI * .1;
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 + this.progressPadding + (progress * (this.twoPI - this.progressPadding)), 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;
}
}
function drawCircle(x0,y0,r,res) {
if (res==undefined) res = 50; //circle resolution
beginShape();
var step = Math.PI * 2.0 / res;
for (var a=0; a<Math.PI*2; a+=step) {
var x = Math.sin(a+Math.PI) * r + x0;
var y = Math.cos(a+Math.PI) * r + y0;
if (a==0) shapeMoveTo(x,y);
else shapeLineTo(x,y);
}
//close shape
var x = Math.sin(0+Math.PI) * r + x0;
var y = Math.cos(0+Math.PI) * r + y0;
shapeLineTo(x,y);
endShape();
}
function beginShape(x,y) {
setSketchModified(true);
}
function shapeMoveTo(x,y) {
_points.push([x, y, true]);
adjustBounds(x, y);
adjustPreviewTransformation();
draw(x, y, .5);
}
function shapeLineTo(x,y) {
_points.push([x, y, false]);
adjustBounds(x, y);
adjustPreviewTransformation();
draw(x, y);
}
function endShape() {
renderToImageDataPreview();
}
function getBounds(points) {
var xMin = Infinity, xMax = -Infinity, yMin = Infinity, yMax = -Infinity;
for (var i=0; i<points.length; i++) {
var p = points[i];
xMin = Math.min(xMin,p[0]);
xMax = Math.max(xMax,p[0]);
yMin = Math.min(yMin,p[1]);
yMax = Math.max(yMax,p[1]);
}
return {x:xMin,y:yMin,width:xMax-xMin,height:yMax-yMin};
}
function translatePoints(points,x,y) {
for (var i=0; i<points.length; i++) {
points[i][0] += x;
points[i][1] += y;
}
}
function scalePoints(points,x,y) {
if (y==undefined) y = x;
for (var i=0; i<points.length; i++) {
points[i][0] *= x;
points[i][1] *= y;
}
}
function rotatePoints(points, radians, cx, cy) {
if (cx==undefined) cx = 0;
if (cy==undefined) cy = 0;
var cos = Math.cos(radians);
var sin = Math.sin(radians);
for (var i=0; i<points.length; i++) {
var x = points[i][0];
var y = points[i][1];
var nx = (cos * (x - cx)) - (sin * (y - cy)) + cx;
var ny = (sin * (x - cx)) + (cos * (y - cy)) + cy;
points[i][0] = nx;
points[i][1] = ny;
}
}
function moveShape(x,y) {
var bounds = getBounds(_points);
var delta = reduceTransformToFit(x, y, 1.0, bounds);
if (delta.x != 0 || delta.y != 0) {
translatePoints(_points, delta.x, delta.y);
updateView();
}
}
//TODO: reduction of zoomValue is still not completely correct (but acceptable?)
//TODO: bounds should be cached and marked dirty on modification of points array; translations could be combined in several places
function zoomShape(zoomValue) {
var bounds = getBounds(_points);
var transform = reduceTransformToFit(0, 0, zoomValue, bounds);
translatePoints(_points, transform.x, transform.y); //move points towards center as far as necessary to avoid clipping
translatePoints(_points, -bounds.x, -bounds.y);
translatePoints(_points, -bounds.width / 2, -bounds.height / 2);
scalePoints(_points, transform.zf, transform.zf);
translatePoints(_points, bounds.width / 2, bounds.height / 2);
translatePoints(_points, bounds.x, bounds.y);
updateView();
}
function rotateShape(radians) {
var bounds = getBounds(_points);
var cx = bounds.x + bounds.width/2;
var cy = bounds.y + bounds.height/2;
rotatePoints(_points, radians, cx, cy);
var bounds = getBounds(_points);
var transform = reduceTransformToFit(0, 0, 1.0, bounds);
translatePoints(_points, transform.x, transform.y);
scalePoints(_points, transform.zf, transform.zf);
updateView();
}
function updateView() {
setSketchModified(true);
redrawDoodle(true);
adjustPreviewTransformation();
renderToImageDataPreview();
if (debugMode) {
var bounds = getBounds(_points);
drawCircleTemp(bounds.x + bounds.width / 2, bounds.y + bounds.height / 2, 5, 'red');
}
}
//when x,y!=0,0: reduces them such that transformed bounds will still fit on canvas (given that they fit prior to the transform)
//otherwise: calculate translation + zoom reduce such that given bounds will fit on canvas after transformation
function reduceTransformToFit(x, y, zf, bounds) {
var zw = bounds.width * zf; zh = bounds.height * zf;
var newBounds = { x: bounds.x - (zw - bounds.width) / 2, y: bounds.y - (zh - bounds.height) / 2, width: zw, height: zh };
// console.log("bounds: " + bounds.x + ", " + bounds.y + ", " + bounds.width + ", " + bounds.height);
// console.log("newBounds: " + newBounds.x + ", " + newBounds.y + ", " + newBounds.width + ", " + newBounds.height);
var ldx = Math.max(x, -newBounds.x);
var rdx = Math.min(x, canvasWidth - (newBounds.x + newBounds.width));
var tdy = Math.max(y, -newBounds.y);
var bdy = Math.min(y, canvasHeight - (newBounds.y + newBounds.height));
if (x != 0 || y != 0) { //movement was requested
return { x: nearestZero(ldx, rdx), y: nearestZero(tdy, bdy) };
} else { //no movement requested
var delta = { x: ldx + rdx, y: tdy + bdy };
if (ldx != 0 && rdx != 0) delta.x /= 2;
if (tdy != 0 && bdy != 0) delta.y /= 2;
delta.x /= zf;
delta.y /= zf;
var zxMax = Math.min(zf, canvasWidth / newBounds.width);
var zyMax = Math.min(zf, canvasHeight / newBounds.height);
// var oldZF = zf;
// var dir = zf >= 1.0 ? 1 : 0;
zf = Math.min(zxMax, zyMax);
// if (dir == 1 && zf < 1.0) zf = 1;
// console.log("orgZF, zxMax, zyMax, finZF: " + oldZF + ", " + zxMax + ", " + zyMax + ", " + zf);
return { x: delta.x, y: delta.y, zf: zf };
}
}
function nearestZero(v1, v2) { return Math.abs(v1) < Math.abs(v2) ? v1 : v2; }
//*draws* a circle (i.e. it is not added as points to shape)
function drawCircleTemp(x, y, r, color) {
ctx.beginPath();
ctx.lineWidth = 1;
ctx.fillStyle = color;
ctx.arc(x, y, r, 0, 2 * Math.PI, false);
ctx.fill();
ctx.stroke();
ctx.fillStyle = 'black';
}
/*
* This file is part of the Doodle3D project (http://doodle3d.com).
*
* Copyright (c) 2013, Doodle3D
* This software is licensed under the terms of the GNU GPL v2 or later.
* See file LICENSE.txt or visit http://www.gnu.org/licenses/gpl.html for full license details.
*/
//SVG validator: http://validator.w3.org/
//SVG viewer: http://svg-edit.googlecode.com/svn/branches/2.6/editor/svg-editor.html
function saveToSvg() {
var lastX = 0, lastY = 0, lastIsMove = false;
var svg = '';
var boundsWidth = doodleBounds[2] - doodleBounds[0];
var boundsHeight = doodleBounds[3] - doodleBounds[1];
svg += '<?xml version="1.0" standalone="no"?>\n';
svg += '<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">\n';
svg += '<svg width="' + boundsWidth + '" height="' + boundsHeight + '" version="1.1" xmlns="http://www.w3.org/2000/svg">\n';
svg += '\t<desc>Doodle 3D sketch</desc>\n';
var data = '';
for (var i = 0; i < _points.length; ++i) {
var x = _points[i][0], y = _points[i][1], isMove = _points[i][2];
var dx = x - lastX, dy = y - lastY;
if (i == 0)
data += 'M'; //emit absolute move on first pair of coordinates
else if (isMove != lastIsMove)
data += isMove ? 'm' : 'l';
data += dx + ',' + dy + ' ';
lastX = x;
lastY = y;
lastIsMove = isMove;
}
svg += '\t<path transform="translate(' + -doodleBounds[0] + ',' + -doodleBounds[1] + ')" d="' + data + '" fill="none" stroke="black" stroke-width="2" />\n';
var fields = JSON.stringify({'height': numLayers, 'outlineShape': VERTICALSHAPE, 'twist': rStep});
svg += '\t<!--<![CDATA[d3d-keys ' + fields + ']]>-->\n';
svg += '</svg>\n';
return svg;
}
//TODO: use local variables instead of _points,numLayers,VERTICALSHAPE and rStep so we can leave a current doodle in tact if an error occurs while parsing
function loadFromSvg(svgData) {
var mode = '', x = 0, y = 0;
console.log("loading " + svgData.length + " bytes of data...");
clearDoodle();
svgData = svgData.replace("M0,0 ",""); //RC: hack
var p = svgData.indexOf("<path");
if (p == -1) { console.log("loadFromSvg: could not find parsing start point"); return false; }
p = svgData.indexOf('d="', p);
if (p == -1) { console.log("loadFromSvg: could not find parsing start point"); return false; }
p += 3; //skip 'd="'
var skipSpace = function() { while (svgData.charAt(p) == ' ') p++; }
var parseCommand = function() {
while (true) {
skipSpace();
var c = svgData.charAt(p);
if (c == 'M' || c == 'm' || c == 'L' || c == 'l') { //new command letter
mode = c;
} else if (c == '"') { //end of command chain
return true;
} else { //something else, must be a pair of coordinates...
var tx = 0, ty = 0, numberEnd = 0, len = 0;
// var firstComma = svgData.indexOf(',', p);
// var firstSpace = svgData.indexOf(' ', p);
numberEnd = svgData.indexOf(',', p);
////// RC: if instead of a comma a space is used between a pair use that as a separator
var firstSpace = svgData.indexOf(' ', p);
if (firstSpace<numberEnd) numberEnd=firstSpace;
//console.log('numberEnd',numberEnd,firstSpace);
////////////////
if (numberEnd == -1) { console.log("could not find comma in coordinate pair"); return false; }
len = numberEnd - p;
tx = parseFloat(svgData.substr(p, len));
p += len + 1;
skipSpace();
numberEnd = svgData.indexOf(' ', p);
if (numberEnd == -1) { console.log("could not find space after coordinate pair"); return false; }
len = numberEnd - p;
ty = parseFloat(svgData.substr(p, len));
p += len;
if (mode == 'M' || mode == 'L') {
x = tx; y = ty;
} else if (mode == 'm' || mode == 'l') {
x += tx; y += ty;
} else {
console.log("loadFromSvg: found coordinate pair but mode was never set");
return false;
}
var isMove = mode == 'm' || mode == 'M';
//TODO: create script-wide function for adding points?
//console.log("inserting "+x+","+y+" ",isMove);
updatePrevX = x;
updatePrevY = y;
_points.push([x, y, isMove]);
adjustBounds(x, y);
adjustPreviewTransformation();
if (isMove) draw(x, y, .5);
else draw(x, y);
}
p++;
}
return true;
};
parseCommand(); //depends on value of p, so don't move this without taking that into consideration
const fieldDefMarker = "<!--<![CDATA[d3d-keys";
p = svgData.indexOf(fieldDefMarker);
if (p == -1) { console.log("loadFromSvg: could not find metadata marker"); return false; }
p += fieldDefMarker.length;
skipSpace();
var endP = svgData.indexOf("]]>-->", p);
if (endP == -1) { console.log("loadFromSvg: could not find metadata end-marker"); return false; }
var metaFields = JSON.parse(svgData.substr(p, endP - p));
//TODO: log error and return false if parsing failed
for (var k in metaFields) {
var v = metaFields[k];
switch (k) {
case "height": numLayers = v; break;
case "outlineShape": VERTICALSHAPE = v; break;
case "twist": rStep = v; break;
}
}
renderToImageDataPreview();
return true;
}
/*
* This file is part of the Doodle3D project (http://doodle3d.com).
*
* Copyright (c) 2013, Doodle3D
* This software is licensed under the terms of the GNU GPL v2 or later.
* See file LICENSE.txt or visit http://www.gnu.org/licenses/gpl.html for full license details.
*/
// 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;
}
}
var wordArtPopup;
function initWordArt() {
$("body").append('<div id="svgfont" style="display:none"></div>');
$("#svgfont").load("img/font.svg?");
wordArtPopup = new Popup($("#popupWordArt"),$("#popupMask"));
$("#btnWordArtOk").on("onButtonClick",wordArtPopup.commit);
$("#btnWordArtCancel").on("onButtonClick",wordArtPopup.cancel);
$("#popupWordArt").bind("onPopupCancel", onWordArtCancel);
$("#popupWordArt").bind("onPopupCommit", onWordArtOk);
}
function showWordArtDialog() {
buttonGroupAdd.hide();
wordArtPopup.open();
$("#txtWordArt").focus();
$("#txtWordArt").val(""); //clear textbox
}
function onWordArtCancel() {
$("#txtWordArt").blur();
}
function onWordArtOk() {
$("#txtWordArt").blur();
var s = $("#txtWordArt").val();
drawTextOnCanvas(s);
}
function drawTextOnCanvas(text) {
if (typeof(text) == 'string') {
var points = getStringAsPoints(text);
var bounds = getBounds(points);
var scaleX = (canvasWidth-50) / bounds.width;
var scaleY = (canvasHeight-50) / bounds.height;
var scale = Math.min(scaleX,scaleY);
scalePoints(points,scale);
var bounds = getBounds(points);
translatePoints(points,-bounds.x,-bounds.y); //left top of text is (0,0)
translatePoints(points,-bounds.width/2,-bounds.height/2); //anchor point center
translatePoints(points,canvasWidth/2,canvasHeight/2); //center in canvas
canvasDrawPoints(canvas,points);
}
}
function getStringAsPoints(text) {
var allPoints = [];
var xPos = 0;
for (var i=0; i<text.length; i++) {
if (text[i]==" ") { //space
xPos += 8;
} else { //other characters
var path = getPathFromChar(text[i]);
var points = getPointsFromPath(path);
if (points.length==0) continue;
translatePoints(points,-points[0][0],0);
var bounds = getBounds(points);
translatePoints(points,-bounds.x,0);
translatePoints(points,xPos,0);
xPos+=bounds.width;
xPos+=2;
for (var j=0; j<points.length; j++) {
allPoints.push(points[j]);
}
}
}
return allPoints;
}
function getPathFromChar(ch) {
var index = ch.charCodeAt(0)-33;
var element = $("#svgfont path")[index];
if (element==undefined) return "";
return $("#svgfont path")[index].attributes["d"].nodeValue;
}
function getPointsFromPath(path) {
var points = [];
var cmds = path.split(' ');
var cursor = { x:0.0, y:0.0 };
var move = false;
var prevCmd = "";
for (var i=0; i<cmds.length; i++) {
var cmd = cmds[i];
var xy = cmd.split(",");
if (cmd=='m') move = true;
if (xy.length==2) { // if there are two parts (a comma) we asume it's a l command. (So L is not supported)
cursor.x += parseFloat(xy[0]);
cursor.y += parseFloat(xy[1]);
points.push([cursor.x,cursor.y,move]);
move = false;
} else if (prevCmd == "h"){
cursor.x += parseFloat(cmd);
points.push([cursor.x,cursor.y,move]);
} else if (prevCmd == "v"){
cursor.y += parseFloat(cmd);
points.push([cursor.x,cursor.y,move]);
} else if (prevCmd == "H"){
cursor.x = parseFloat(cmd);
points.push([cursor.x,cursor.y,move]);
} else if (prevCmd == "V"){
cursor.y = parseFloat(cmd);
points.push([cursor.x,cursor.y,move]);
}
prevCmd = cmd;
}
return points;
}
function canvasDrawPoints(canvas,points) {
beginShape();
for (var i=0; i<points.length; i++) {
var p = points[i];
if (points[i][2]) shapeMoveTo(p[0],p[1]);
else shapeLineTo(p[0],p[1]);
}
endShape();
}
/*
* This file is part of the Doodle3D project (http://doodle3d.com).
*
* Copyright (c) 2013, Doodle3D
* This software is licensed under the terms of the GNU GPL v2 or later.
* See file LICENSE.txt or visit http://www.gnu.org/licenses/gpl.html for full license details.
*/
var twistIncrement = Math.PI/1800;
var btnNew, btnPrevious, btnNext, btnOops, btnStop, btnInfo;
var btnSettings, btnWordArt;
var btnToggleEdit, buttonGroupEdit, btnZoom, btnMove, btnRotate;
var btnToggleVerticalShapes, btnHeight, btnTwist, btnShape, btnConv, btnStraight, btnSine, btnDiv;
var buttonGroupAdd, popupWordArt;
var btnScan, popupScan;
var state;
var prevState;
var hasControl;
var gcodeGenerateDelayer;
var gcodeGenerateDelay = 50;
var preheatDelay;
var preheatDelayTime = 15*1000;
var connectingHintDelay = null;
var connectingHintDelayTime = 20 * 1000;
function initButtonBehavior() {
console.log("f:initButtonBehavior");
btnOops = new Button("#btnOops");
btnInfo = new Button("#btnInfo");
btnSettings = new Button("#btnSettings");
btnNew = new Button("#btnNew");
btnPrint= new Button("#btnPrint");
btnStop = new Button("#btnStop");
btnPrevious = new Button("#btnPrevious");
btnNext = new Button("#btnNext");
btnSave = new Button("#btnSave");
buttonGroupAdd = $("#buttonGroupAdd");
btnShape = new Button("#btnShape");
btnWordArt = new Button("#btnWordArt");
btnScan = new Button("#btnScan");
popupWordArt = $("#popupWordArt");
popupShape = $("#popupShape");
popupScan = $("#popupScan");
popupMask = $("#popupMask");
logoPanel = $("#logopanel");
btnToggleEdit = new Button("#btnToggleEdit");
buttonGroupEdit = $("#buttonGroupEdit");
btnZoom = new Button("#btnZoom");
btnMove = new Button("#btnMove");
btnRotate = new Button("#btnRotate");
btnToggleVerticalShapes = new Button("#btnToggleVerticalShapes");
buttonGroupVerticalShapes = $("#buttonGroupVerticalShapes");
btnHeight = new Button("#btnHeight");
btnTwist = new Button("#btnTwist");
btnStraight = new Button("#btnStraight");
btnDiv = new Button("#btnDiv");
btnConv = new Button("#btnConv");
btnSine = new Button("#btnSine");
btnAdd = new Button("#btnAdd");
$(".btn").Button(); //initalize other buttons
logoPanel.on("onButtonClick", onLogo);
btnNew.on("onButtonClick", onBtnNew);
btnAdd.on("onButtonClick", onBtnAdd);
btnWordArt.on("onButtonClick", onBtnWordArt);
btnShape.on("onButtonClick", onBtnShape);
btnScan.on("onButtonClick", onBtnScan);
btnPrint.on("onButtonClick", print);
btnStop.on("onButtonClick", stopPrint);
btnSave.on("onButtonClick", saveSketch);
btnPrevious.on("onButtonClick", previousSketch);
btnNext.on("onButtonClick", nextSketch);
btnOops.on("onButtonHold", onBtnOops);
// vertical shape buttons
btnToggleVerticalShapes.on("onButtonClick", onBtnToggleVerticalShapes);
btnHeight.on("onButtonHold", onBtnHeight);
btnTwist.on("onButtonHold", onBtnTwist);
btnStraight.on("onButtonClick", onBtnStraight);
btnDiv.on("onButtonClick", onBtnDiv);
btnConv.on("onButtonClick", onBtnConv);
btnSine.on("onButtonClick", onBtnSine);
btnToggleEdit.on("onButtonClick", onBtnToggleEdit);
btnMove.on("onButtonHold", onBtnMove);
btnZoom.on("onButtonHold", onBtnZoom);
btnRotate.on("onButtonHold", onBtnRotate);
//getSavedSketchStatus();
listSketches();
// setSketchModified(false);
// updateSketchButtonStates();
function onBtnToggleVerticalShapes() {
var btnImg;
if (buttonGroupVerticalShapes.is(":hidden")) {
btnImg = "img/buttons/btnArrowClose.png";
} else {
btnImg = "img/buttons/btnArrowOpen.png";
}
btnToggleVerticalShapes.attr("src",btnImg);
buttonGroupVerticalShapes.fadeToggle(BUTTON_GROUP_SHOW_DURATION);
}
function onLogo() {
location.reload();
}
function onBtnAdd() {
buttonGroupAdd.fadeToggle(BUTTON_GROUP_SHOW_DURATION);
}
function onBtnStraight() {
setVerticalShape(verticalShapes.NONE);
}
function onBtnDiv() {
setVerticalShape(verticalShapes.DIVERGING);
}
function onBtnConv() {
setVerticalShape(verticalShapes.CONVERGING);
}
function onBtnSine() {
setVerticalShape(verticalShapes.SINUS);
}
function hitTest(cursor,button,radius) {
return distance(cursor.x,cursor.y,button.x,button.y)<radius;
}
function onBtnToggleEdit() {
var btnImg;
if(buttonGroupEdit.is(":hidden")) {
btnImg = "img/buttons/btnArrowClose.png";
} else {
btnImg = "img/buttons/btnArrowOpen.png";
}
btnToggleEdit.attr("src",btnImg);
buttonGroupEdit.fadeToggle(BUTTON_GROUP_SHOW_DURATION);
}
function onBtnMove(e,cursor) {
var w = btnMove.width();
var h = btnMove.height();
var speedX = (cursor.x-w/2)*0.3;
var speedY = (cursor.y-h/2)*0.3;
//console.log("move speed: ",speedX,speedY);
moveShape(speedX,speedY);
}
function onBtnZoom(e,cursor) {
var h = btnZoom.height();
var multiplier = (h/2-cursor.y)*0.003 + 1;
zoomShape(multiplier);
}
function onBtnRotate(e,cursor) {
var h = btnZoom.height();
var multiplier = (h/2-cursor.y)*0.003;
rotateShape(-multiplier);
}
function onBtnHeight(e,cursor) {
var h = btnHeight.height();
if(cursor.y < h/2) {
previewUp(true);
} else {
previewDown(true);
}
}
function onBtnTwist(e,cursor) {
var h = btnTwist.height();
var multiplier = (cursor.y-h/2)*0.0005;
previewTwist(multiplier,true);
}
function onBtnOops(e) {
oopsUndo();
}
function onBtnNew(e) {
newSketch();
}
function onBtnWordArt(e) {
showWordArtDialog();
}
function onBtnShape(e) {
showShapeDialog();
buttonGroupAdd.fadeOut();
}
function onBtnScan(e) {
showScanDialog();
buttonGroupAdd.fadeOut();
}
btnSettings.on("onButtonClick", openSettingsWindow);
// 29-okt-2013 - we're not doing help for smartphones at the moment
if (clientInfo.isSmartphone) {
btnInfo.disable();
} else {
btnInfo.on("onButtonClick", function(e) {
helpTours.startTour(helpTours.WELCOMETOUR);
});
}
}
function stopPrint() {
console.log("f:stopPrint() >> sendPrintCommands = " + sendPrintCommands);
if (sendPrintCommands) printer.stop();
//setState(Printer.STOPPING_STATE,printer.hasControl);
printer.overruleState(Printer.STOPPING_STATE);
}
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!");
}
// $.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();
// also make new Image, otherwise the previously cached preview can be redrawn with move up/down or twist left/right
doodleImageCapture = new Image();
// 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();
if (clientInfo.isSmartphone) {
// do not recalc the whole preview's bounds during undo if client device is a smartphone
redrawDoodle(false);
} else {
// recalc the whole preview's bounds during if client device is not a smartphone
redrawDoodle(true);
}
redrawPreview();
}
function previewUp(redrawLess) {
// console.log("f:previewUp()");
if (numLayers < maxNumLayers) {
numLayers++;
}
setSketchModified(true);
// redrawPreview(redrawLess);
redrawRenderedPreview(redrawLess);
}
function previewDown(redrawLess) {
// console.log("f:previewDown()");
if (numLayers > minNumLayers) {
numLayers--;
}
setSketchModified(true);
// redrawPreview(redrawLess);
redrawRenderedPreview(redrawLess);
}
function previewTwistLeft(redrawLess) {
previewTwist(-twistIncrement,true)
}
function previewTwistRight(redrawLess) {
previewTwist(twistIncrement,true)
}
function previewTwist(increment,redrawLess) {
console.log("previewTwist: ",increment);
if (redrawLess == undefined) redrawLess = false;
rStep += increment;
if(rStep < -previewRotationLimit) rStep = -previewRotationLimit;
else if(rStep > previewRotationLimit) rStep = previewRotationLimit;
redrawRenderedPreview(redrawLess);
setSketchModified(true);
}
function resetTwist() {
rStep = 0;
redrawRenderedPreview();
setSketchModified(true);
}
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.enable();
} else {
btnPrint.disable();
}
// stop button
var stopEnabled = ((newState == Printer.PRINTING_STATE || newState == Printer.BUFFERING_STATE) && newHasControl);
if(stopEnabled) {
btnStop.enable();
} else {
btnStop.disable();
}
// thermometer
switch(newState) {
case Printer.IDLE_STATE: /* fall-through */
case Printer.BUFFERING_STATE: /* fall-through */
case Printer.PRINTING_STATE: /* fall-through */
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;
}
/* settings button */
switch(newState) {
case Printer.CONNECTING_STATE: /* fall-through */
case Printer.IDLE_STATE:
btnSettings.enable();
break;
case Printer.WIFIBOX_DISCONNECTED_STATE: /* fall-through */
case Printer.BUFFERING_STATE: /* fall-through */
case Printer.PRINTING_STATE: /* fall-through */
case Printer.STOPPING_STATE:
btnSettings.disable();
break;
default:
btnSettings.enable();
break;
}
/* save, next and prev buttons */
switch(newState) {
case Printer.WIFIBOX_DISCONNECTED_STATE:
btnPrevious.disable();
btnNext.disable()
btnSave.disable();
break;
default:
// updatePrevNextButtonState();
updateSketchButtonStates();
if (isModified) btnSave.enable();
break;
}
if(connectingHintDelay && newState != Printer.CONNECTING_STATE) {
clearTimeout(connectingHintDelay);
connectingHintDelay = null;
}
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(newState == Printer.CONNECTING_STATE) {
message.set("Printer connecting...",Message.INFO,false);
if (prevState != Printer.CONNECTING_STATE) { //enable 'watchdog' if we entered from a different state
clearTimeout(connectingHintDelay);
connectingHintDelay = setTimeout(function() {
message.set("Printer still not connected, did you<br/>select the correct printer type?", Message.WARNING, false);
connectingHintDelay = null;
}, connectingHintDelayTime);
}
} else if(prevState == Printer.DISCONNECTED_STATE && newState == Printer.IDLE_STATE ||
prevState == Printer.UNKNOWN_STATE && newState == Printer.IDLE_STATE ||
prevState == Printer.CONNECTING_STATE && newState == Printer.IDLE_STATE) {
message.set("Printer connected",Message.INFO,true);
console.log(" preheat: ",settings["printer.heatup.enabled"]);
if(settings["printer.heatup.enabled"]) {
// HACK: we delay the preheat because the makerbot driver needs time to connect
clearTimeout(preheatDelay);
preheatDelay = setTimeout(printer.preheat,preheatDelayTime); // retry after delay
}
} else if(prevState == Printer.PRINTING_STATE && newState == Printer.STOPPING_STATE) {
console.log("stopmsg show");
message.set("Printer stopping",Message.INFO,false);
} else if(prevState == Printer.STOPPING_STATE && newState == Printer.IDLE_STATE) {
console.log("stopmsg hide");
message.hide();
}
state = newState;
hasControl = newHasControl;
}
/*
* This file is part of the Doodle3D project (http://doodle3d.com).
*
* Copyright (c) 2013, Doodle3D
* This software is licensed under the terms of the GNU GPL v2 or later.
* See file LICENSE.txt or visit http://www.gnu.org/licenses/gpl.html for full license details.
*/
/* * * * * * * * * *
*
* 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;
var isModified = false;
/* * * * * * * * * *
*
* 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("canvasDrawing:draw");
// 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");
//updatePrevNextButtonStateOnClear();
_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();
setSketchModified(false);
// updateSketchButtonStates();
}
function redrawDoodle(recalcBoundsAndTransforms) {
//console.log("canvasDrawing:redrawDoodle");
if (recalcBoundsAndTransforms == undefined) recalcBoundsAndTransforms = false;
// console.log("f:redrawDoodle() >> recalcBoundsAndTransforms = " + recalcBoundsAndTransforms);
if (recalcBoundsAndTransforms == true) {
doodleBounds = [-1, -1, -1, -1]; // left, top, right, bottom
doodleTransform = [0, 0, 1.0, 1.0]; // [ x, y, scaleX, scaleY ]
for (var i = 0; i < _points.length; i++) {
adjustBounds(_points[i][0], _points[i][1]);
adjustPreviewTransformation();
}
}
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]);
}
}
}
// checks if x,y is outside doodleBounds, if so update
function adjustBounds(x, y) {
//console.log("canvasDrawing:adjustBounds");
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;
}
return newPointsOutsideOfCurrentBounds;
}
// does what exactly?
function adjustPreviewTransformation() {
//console.log("canvasDrawing:adjustPreviewTransformation");
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("canvasDrawing:onCanvasMouseDown");
setSketchModified(true);
// console.log("f:onCanvasMouseDown()");
// console.log("onCanvasMouseDown >> e.offsetX,e.offsetY = " + e.offsetX+","+e.offsetY);
// console.log("onCanvasMouseDown >> e.layerX,e.layerY= " + e.layerX+","+e.layerY);
// console.log("onCanvasMouseDown >> e: " , e);
dragging = true;
prevCountingTime = new Date().getTime();
movementCounter = 0
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("canvasDrawing:onCanvasMouseMove");
// console.log("f:onCanvasMouseMove()");
if (!dragging) return;
setSketchModified(true);
// 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(((prevPoint.x - x) * (prevPoint.x - x)) + ((prevPoint.y - y) * (prevPoint.y - y)));
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 {
// this is called once, every time you start to draw a line
_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();
// Keep fully updating the preview if device is not a smartphone.
// (An assumption is made here that anything greater than a smartphone will have sufficient
// performance to always redraw the preview.)
if (_points.length < 50 || !clientInfo.isSmartphone) {
redrawPreview();
} else {
updatePreview(x, y, true);
}
}
}
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) {
setSketchModified(true);
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) {
//console.log("canvasDrawing:onCanvasTouchMove");
setSketchModified(true);
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();
}
/*
* This file is part of the Doodle3D project (http://doodle3d.com).
*
* Copyright (c) 2013, Doodle3D
* This software is licensed under the terms of the GNU GPL v2 or later.
* See file LICENSE.txt or visit http://www.gnu.org/licenses/gpl.html for full license details.
*/
function setTemperature(callback) {
if (callback != undefined) callback();
}
function setTemperature(callback) {
if (callback != undefined) callback();
}
/*
* This file is part of the Doodle3D project (http://doodle3d.com).
*
* Copyright (c) 2013, Doodle3D
* This software is licensed under the terms of the GNU GPL v2 or later.
* See file LICENSE.txt or visit http://www.gnu.org/licenses/gpl.html for full license details.
*/
var MAX_POINTS_TO_PRINT = 200000
var gcode = [];
function generate_gcode() {
console.log("f:generategcode()");
gcode = [];
console.log("settings: ",settings);
var speed = settings["printer.speed"];
var normalSpeed = speed;
var bottomSpeed = settings["printer.bottomLayerSpeed"];
var firstLayerSlow = settings["printer.firstLayerSlow"];
var bottomFlowRate = settings["printer.bottomFlowRate"];
var travelSpeed = settings["printer.travelSpeed"]
var filamentThickness = settings["printer.filamentThickness"];
var wallThickness = settings["printer.wallThickness"];
var screenToMillimeterScale = settings["printer.screenToMillimeterScale"];
var layerHeight = settings["printer.layerHeight"];
var temperature = settings["printer.temperature"];
var bedTemperature = settings["printer.bed.temperature"];
var useSubLayers = settings["printer.useSubLayers"];
var enableTraveling = settings["printer.enableTraveling"];
var retractionEnabled = settings["printer.retraction.enabled"];
var retractionspeed = settings["printer.retraction.speed"];
var retractionminDistance = settings["printer.retraction.minDistance"];
var retractionamount = settings["printer.retraction.amount"];
var preheatTemperature = settings["printer.heatup.temperature"];
var preheatBedTemperature = settings["printer.heatup.bed.temperature"];
var printerDimensionsX = settings["printer.dimensions.x"];
var printerDimensionsY = settings["printer.dimensions.y"];
var printerDimensionsZ = settings["printer.dimensions.z"];
var gCodeOffsetX = printerDimensionsX/2;
var gCodeOffsetY = printerDimensionsY/2;
var startCode = generateStartCode();
var endCode = generateEndCode();
// max amount of real world layers
var layers = printerDimensionsZ / layerHeight; //maxObjectHeight instead of objectHeight
// translate numLayers in preview to objectHeight in real world
objectHeight = Math.round(numLayers/maxNumLayers*printerDimensionsZ);
// translate preview rotation (per layer) to real world rotation
var rStepGCode = rStep * maxNumLayers/layers; ///maxNumLayers*maxObjectHeight;
// correct direction
rStepGCode = -rStepGCode;
// 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));
// add gcode begin commands
gcode = gcode.concat(startCode);
var layers = printerDimensionsZ / 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
}
console.log("f:generategcode() >> layers: " + layers);
if (layers == Infinity) return;
// check feasibility of design
var pointsToPrint = points.length * layers*(objectHeight/printerDimensionsZ)
console.log("pointsToPrint: ",pointsToPrint);
if(pointsToPrint > MAX_POINTS_TO_PRINT) {
alert("Sorry, your doodle is too complex or too high. Please try to simplify it.");
console.log("ERROR: to many points too convert to gcode");
return [];
}
for (var layer = 0; layer < layers; layer++) {
//gcode.push(";LAYER:"+layer); //this will be added in a next release to support GCODE previewing in CURA
var p = JSON.parse(JSON.stringify(points)); // [].concat(points);
if (p.length < 2) return;
var even = (layer % 2 == 0);
var progress = layer / layers;
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);
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]]);
}
}
// loop over the subpaths (the separately drawn lines)
for (var j = 0; j < paths.length; j++) { // TODO paths > subpaths
var commands = paths[j];
// loop over the coordinates of the subpath
for (var i = 0; i < commands.length; i++) {
var last = commands.length - 1;
var to = new Point(); to.set(commands[i][0], commands[i][1]);
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;
var firstPointEver = (layer == 0 && i == 0 && j == 0);
// firstPointEver || layer > 2 &&
if (enableTraveling && isTraveling) { //always travel to first point, then disable traveling for first two layers and use settings for remainder of print
if (!firstPointEver && 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)); //travel
if (!firstPointEver && doRetract) gcode.push("G0 E" + extruder.toFixed(3) + " F" + (retractionspeed * 60).toFixed(3)); // return to normal
} else {
var f = (layer < 2) ? bottomFlowRate : 1;
extruder += prev.distance(to) * wallThickness * layerHeight / (Math.pow((filamentThickness/2), 2) * Math.PI) * f;
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)); //extrude
}
curLayerCommand++;
layerProgress = curLayerCommand/totalLayerCommands;
prev = to;
}
}
if ((layer/layers) > (objectHeight/printerDimensionsZ)) {
console.log("f:generategcode() >> (layer/layers) > (objectHeight/printerDimensionsZ) is true -> breaking at layer " + (layer + 1));
break;
}
}
// add gcode end commands
gcode = gcode.concat(endCode);
return gcode;
}
function generateStartCode() {
var printerType = settings["printer.type"];
var startCode = settings["printer.startcode"];
startCode = subsituteVariables(startCode);
startCode = startCode.split("\n");
return startCode;
}
function generateEndCode() {
var printerType = settings["printer.type"];
var endCode = settings["printer.endcode"];
endCode = subsituteVariables(endCode);
endCode = endCode.split("\n");
return endCode;
}
function subsituteVariables(gcode) {
//,temperature,bedTemperature,preheatTemperature,preheatBedTemperature
var temperature = settings["printer.temperature"];
var bedTemperature = settings["printer.bed.temperature"];
var preheatTemperature = settings["printer.heatup.temperature"];
var preheatBedTemperature = settings["printer.heatup.bed.temperature"];
var printerType = settings["printer.type"];
var heatedbed = settings["printer.heatedbed"];
switch (printerType) {
case "makerbot_replicator2": printerType = "r2"; break;
case "makerbot_replicator2x": printerType = "r2x"; break;
case "makerbot_thingomatic": printerType = "t6"; break;
case "makerbot_generic": printerType = "r2"; break;
case "wanhao_duplicator4": printerType = "r2x"; break;
case "_3Dison_plus": printerType = "r2"; break;
}
var heatedBedReplacement = (heatedbed)? "" : ";";
gcode = gcode.replace(/{printingTemp}/gi ,temperature);
gcode = gcode.replace(/{printingBedTemp}/gi ,bedTemperature);
gcode = gcode.replace(/{preheatTemp}/gi ,preheatTemperature);
gcode = gcode.replace(/{preheatBedTemp}/gi ,preheatBedTemperature);
gcode = gcode.replace(/{printerType}/gi ,printerType);
gcode = gcode.replace(/{if heatedBed}/gi ,heatedBedReplacement);
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);
}
}
/*
* This file is part of the Doodle3D project (http://doodle3d.com).
*
* Copyright (c) 2013, Doodle3D
* This software is licensed under the terms of the GNU GPL v2 or later.
* See file LICENSE.txt or visit http://www.gnu.org/licenses/gpl.html for full license details.
*/
// 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();
}
/*
* This file is part of the Doodle3D project (http://doodle3d.com).
*
* Copyright (c) 2013, Doodle3D
* This software is licensed under the terms of the GNU GPL v2 or later.
* See file LICENSE.txt or visit http://www.gnu.org/licenses/gpl.html for full license details.
*/
//*
var $preview;
var preview;
var previewCtx;
var preview_tmp;
var previewCtx_tmp;
var previewDefaults = {
rotation: 0, //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');
// doodleImageCapture = new Image();
calcPreviewCanvasProperties();
redrawPreview();
// needed to
// doodleImageCapture = new Image();
}
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) {
//console.log("PreviewRendering:redrawPreview");
if (redrawLess == undefined) redrawLess = false;
if (_points.length < 2) {
previewCtx.clearRect(0, 0, preview.width, preview.height);
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("PreviewRendering: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<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;
}
previewCtx.save();
previewCtx.translate(layerCX,layerOffsetY+y);
// previewCtx.scale(1, scaleY)
previewCtx.scale(verticalScaleFactor, scaleY * verticalScaleFactor)
previewCtx.rotate(r);
previewCtx.translate(-layerCX,-layerCY);
previewCtx.drawImage(doodleImageCapture, 0, 0);
y -= yStep;
r += rStep;
previewCtx.restore();
}
};
doodleImageCapture.src = saved_rect_todataurl;
previewCtx.globalAlpha = globalAlpha;
}
// called by the move up/down, twist left/right or new buttons
// it is assumed that the preview has been rendered to an Image object, which will be used to draw the preview with (much better performance)
function redrawRenderedPreview(redrawLess) {
//console.log("PreviewRendering:redrawRenderedPreview");
if (redrawLess == undefined) redrawLess = false;
// console.log("f:redrawRenderedPreview()");
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;
// check if there is preview image data that we can use for the layers
if(!doodleImageCapture.src || doodleImageCapture.src == "") return;
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%2 != 0 && !(i == 0 || i == Math.floor(numLayers/2) || i == numLayers-1) ) {
y -= yStep;
r += rStep;
continue;
}
previewCtx.save();
previewCtx.translate(layerCX,layerOffsetY+y);
// previewCtx.scale(1, scaleY)
previewCtx.scale(verticalScaleFactor, scaleY * verticalScaleFactor);
previewCtx.rotate(r);
previewCtx.translate(-layerCX,-layerCY);
previewCtx.drawImage(doodleImageCapture, 0, 0);
y -= yStep;
r += rStep;
previewCtx.restore();
}
}
function centeredAndScaledDoodlePoint(p) {
var obj = { x: 0, y: 0};
obj.x = (p[0] - ((doodleBounds[2] - doodleBounds[0])/2)) * (globalScale * doodleTransform[2]);
obj.y = (p[1] - ((doodleBounds[3] - doodleBounds[1])/2)) * (globalScale * doodleTransform[3]);
// obj.x = (p[0] - (doodleBounds[2] - doodleBounds[0])) * (globalScale * doodleTransform[2]);
// obj.y = (p[1] - (doodleBounds[3] - doodleBounds[1])) * (globalScale * doodleTransform[3]);
// obj.x = (p[0] - doodleTransform[0]) * (globalScale * doodleTransform[2]);
// obj.y = (p[1] - doodleTransform[1]) * (globalScale * doodleTransform[3]);
return obj;
}
//*
var updatePrevX = -1;
var updatePrevY = -1;
function updatePreview(_x, _y, redrawLess) {
//console.log("PreviewRendering:updatePreview");
if (redrawLess == undefined) redrawLess = false;
redrawLess = false;
if (_points.length < 2) return;
if (updatePrevX == -1 || updatePrevY == -1) {
updatePrevX = _x;
updatePrevY = _y;
return;
}
// if (_points.length < 16 && Math.sqrt(Math.pow((updatePrevX - _x), 2) + Math.pow((updatePrevY - _y), 2)) < 8) return;
var y = 0;
var r = 0;
previewCtx.lineWidth = strokeWidth;
previewCtx.strokeStyle = '#f00'; //"rgba(255,255,0,0)";
for(var i = 0; i < numLayers; i++) {
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.scale(viewerScale, scaleY * viewerScale);
previewCtx.rotate(r);
previewCtx.translate((-doodleTransform[0]) * (globalScale * doodleTransform[2]), (-doodleTransform[1]) * (globalScale * doodleTransform[3]));
previewCtx.beginPath();
var prevPoint = centeredAndScaledDoodlePoint([updatePrevX, updatePrevY]);
previewCtx.moveTo(prevPoint.x, prevPoint.y);
var adjustedDoodlePoint = centeredAndScaledDoodlePoint([_x, _y]);
previewCtx.lineTo(adjustedDoodlePoint.x, adjustedDoodlePoint.y);
previewCtx.stroke();
y -= yStep;
r += rStep;
previewCtx.restore();
}
previewCtx.globalAlpha = globalAlpha;
updatePrevX = _x;
updatePrevY = _y;
}
//*/
/*
* This file is part of the Doodle3D project (http://doodle3d.com).
*
* Copyright (c) 2013, Doodle3D
* This software is licensed under the terms of the GNU GPL v2 or later.
* See file LICENSE.txt or visit http://www.gnu.org/licenses/gpl.html for full license details.
*/
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("<div class='sidebutton'></div>");
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");
}
}
}
/*
* This file is part of the Doodle3D project (http://doodle3d.com).
*
* Copyright (c) 2013, Doodle3D
* This software is licensed under the terms of the GNU GPL v2 or later.
* See file LICENSE.txt or visit http://www.gnu.org/licenses/gpl.html for full license details.
*/
var curSketch = 0;
var sketches = []; //contains fileIDs
function previousSketch(e) {
loadSketch(curSketch-1);
}
function nextSketch(e) {
loadSketch(curSketch+1);
}
function newSketch(e) {
clearDoodle();
curSketch = sketches.length; //index of the last item + 1
updateSketchButtonStates();
}
function listSketches() {
console.log('listSketches')
$.get(wifiboxURL + "/sketch/list", function(data) {
if (data.status=='success') {
sketches = data.data.list;
curSketch = sketches.length-1;
setSketchModified(false);
updateSketchButtonStates();
}
})
}
function setSketchModified(_isModified) {
isModified = _isModified;
updateSketchButtonStates();
}
function updateSketchButtonStates() {
console.log('sketch: isModified',isModified,'curSketch',curSketch,'sketches.length',sketches.length);
if (isModified) {
btnSave.enable();
}
else {
btnSave.disable();
}
if (curSketch<sketches.length-1) {
btnNext.enable();
} else {
btnNext.disable();
}
if (curSketch>0) {
btnPrevious.enable();
} else {
btnPrevious.disable();
}
}
function loadSketch(_curSketch) {
curSketch = _curSketch;
if (curSketch<0) curSketch=0;
if (curSketch>sketches.length-1) curSketch=sketches.length-1;
var id = sketches[curSketch];
console.log('sketch: loadSketch curSketch',curSketch,'id',id);
$.get(wifiboxURL + "/sketch", {id:id}, function(response) {
if (response.status=='success') {
console.log('sketch: loaded',response);
var svgData = response.data.data;
loadFromSvg(svgData);
setSketchModified(false);
} else {
console.log('error loading sketch: ',response);
listSketches();
}
})
}
function saveSketch() {
console.log("sketch: saveSketch");
var svgData = saveToSvg();
$.post(wifiboxURL + "/sketch", {data: svgData}, function(response) {
console.log("sketch: saveSketch: response",response);
listSketches();
})
}
/*
* This file is part of the Doodle3D project (http://doodle3d.com).
*
* Copyright (c) 2013, Doodle3D
* This software is licensed under the terms of the GNU GPL v2 or later.
* See file LICENSE.txt or visit http://www.gnu.org/licenses/gpl.html for full license details.
*/
// http://stackoverflow.com/questions/1403888/get-url-parameter-with-jquery
function getURLParameter(name) {
return decodeURI(
(new RegExp('[&?]'+name + '=' + '(.+?)(&|$)').exec(location.search)||[,null])[1]
);
}
// returns true for all smartphones and tablets
function isMobileDevice() {
return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini|Windows Mobile/i.test(navigator.userAgent);
}
// returns true for smartphones (Android will be a bit dodgy (tablet or phone, all depends on pixels vs devicePixelRatio...)
function isSmartphone() {
var returnBool = false;
if( /Android/i.test(navigator.userAgent) && window.devicePixelRatio > 1) {
var w = $(window).width() / window.devicePixelRatio;
console.log("Android device >> ratio'd width: " + w);
if (w < 480) {
returnBool = true;
}
} else {
returnBool = /Android|webOS|iPhone|iPod|BlackBerry|IEMobile|Opera Mini|Windows Mobile/i.test(navigator.userAgent)
}
return returnBool;
}
function distance(x1, y1, x2, y2) {
return Math.sqrt((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1));
}
var VERTICALSHAPE;
var verticalShapes = {
"NONE": 'none',
"DIVERGING": 'diverging',
"CONVERGING": 'converging',
"SINUS": 'sinus'
};
function setVerticalShape(s) {
VERTICALSHAPE = s;
redrawRenderedPreview();
}
function initVerticalShapes() {
resetVerticalShapes();
}
function resetVerticalShapes() {
setVerticalShape(verticalShapes.NONE);
}
/*
* This file is part of the Doodle3D project (http://doodle3d.com).
*
* Copyright (c) 2013, Doodle3D
* This software is licensed under the terms of the GNU GPL v2 or later.
* See file LICENSE.txt or visit http://www.gnu.org/licenses/gpl.html for full license details.
*/
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;
var clientInfo = {};
var POPUP_SHOW_DURATION = 175;
var BUTTON_GROUP_SHOW_DURATION = 80;
$(function() {
console.log("ready");
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");
var hostname;
if (wifiboxIsRemote) hostname = 'http://192.168.5.1';
if (getURLParameter("wifiboxURL") != "null") hostname = getURLParameter("wifiboxURL");
if (!hostname) hostname = "http://" + window.location.host;
wifiboxURL = hostname+"/d3dapi";
wifiboxCGIBinURL = hostname+"/cgi-bin/d3dapi";
//var api = wifiboxURL+'/d3dapi/sketch/';
// if (wifiboxIsRemote) {
// // var hostname = "http://10.0.0.45";
// var hostname = "http://192.168.5.1";
// wifiboxURL = hostname+"/d3dapi";
// wifiboxCGIBinURL = hostname+"/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);
// rudimentary client info
clientInfo.isMobileDevice = isMobileDevice();
clientInfo.isSmartphone = isSmartphone();
initDoodleDrawing();
initPreviewRendering();
initLayouting();
// initSidebars();
initButtonBehavior();
initKeyboard();
// initVerticalShapes();
initWordArt();
initShapeDialog();
initScanDialog();
disableDragging();
if (!clientInfo.isSmartphone) initHelp();
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 disableDragging() {
$(document).bind("dragstart", function(event) {
console.log("dragstart");
event.preventDefault();
});
}
function showOrHideThermo() {
console.log("f:showOrHideThermo()");
if (showOrHide) {
thermometer.hide();
progressbar.hide();
} else {
thermometer.show();
progressbar.show();
}
showOrHide = !showOrHide;
}
function settingsLoaded() {
console.log("settingsLoaded");
if(firstTimeSettingsLoaded) {
console.log(" preheat: ",settings["printer.heatup.enabled"]);
console.log(" state: ",state);
if(state == Printer.IDLE_STATE && settings["printer.heatup.enabled"]) {
printer.preheat();
}
console.log("doodle3d.tour.enabled: ",settings["doodle3d.tour.enabled"]);
if(settings["doodle3d.tour.enabled"] && !clientInfo.isSmartphone) {
console.log("show tour");
initHelp();
}
firstTimeSettingsLoaded = false;
}
}
function setDebugText(text) {
$("#debug_display").text(text);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment