code cleanup, svgDPI introduced in settings

This commit is contained in:
Teja 2015-01-29 17:21:18 +01:00
parent 06a279b4a4
commit 9bd5a71875
8 changed files with 547 additions and 561 deletions

View file

@ -197,16 +197,16 @@ class LaserCutterProfilesPlugin(octoprint.plugin.SettingsPlugin,
##~~ TemplatePlugin API
def get_template_vars(self):
#selectedProfile = laserCutterProfileManager.get_current_or_default()
d = dict(
_settings_menu_entry="Laser cutter profiles",
)
d = dict()
return d
def get_template_folder(self):
import os
return os.path.join(os.path.dirname(os.path.realpath(__file__)), "templates")
def get_template_configs(self):
return [dict(type = 'settings', name = "Machine Profiles")]
##~~ BlueprintPlugin API
def get_blueprint(self):
@ -226,6 +226,6 @@ def _sanitize_name(name):
sanitized_name = sanitized_name.replace(" ", "_")
return sanitized_name.lower()
__plugin_name__ = "Laser cutter profiles"
__plugin_name__ = "lasercutterprofiles"
__plugin_version__ = "0.1"
__plugin_implementations__ = [LaserCutterProfilesPlugin()]

View file

@ -20,7 +20,8 @@ import octoprint.settings
default_settings = {
"defaultIntensity": 500,
"defaultFeedrate": 300,
"debug_logging": False
"debug_logging": False,
"svgDPI": 90
}
s = octoprint.plugin.plugin_settings("svgtogcode", defaults=default_settings)
@ -142,7 +143,7 @@ class SvgToGcodePlugin(octoprint.plugin.SlicerPlugin,
def get_assets(self):
return {
"js": ["js/svgtogcode.js", "js/convert.js", "js/working_area.js", "js/lib/snap.svg-min.js"],
"js": [ "js/convert.js", "js/working_area.js", "js/lib/snap.svg-min.js"],
"less": ["less/svgtogcode.less"],
"css": ["css/svgtogcode.css", "css/mrbeam.css"]
}
@ -153,14 +154,19 @@ class SvgToGcodePlugin(octoprint.plugin.SlicerPlugin,
return dict(
defaultIntensity=s.get(["defaultIntensity"]),
defaultFeedrate=s.get(["defaultFeedrate"]),
svgDPI=s.get(["svgDPI"]),
debug_logging=s.getBoolean(["debug_logging"])
)
def on_settings_save(self, data):
if "defaultIntensity" in data and data["defaultIntensity"]:
s.set(["defaultIntensity"], data["defaultIntensity"])
intensity = min(max(data["defaultIntensity"], 1), 1000)
s.set(["defaultIntensity"], intensity)
if "defaultFeedrate" in data and data["defaultFeedrate"]:
s.set(["defaultFeedrate"], data["defaultFeedrate"])
feedrate = max(1,data["defaultFeedrate"])
s.set(["defaultFeedrate"], feedrate)
if "svgDPI" in data and data["svgDPI"]:
s.set(["svgDPI"], data["svgDPI"])
if "debug_logging" in data:
old_debug_logging = s.getBoolean(["debug_logging"])
new_debug_logging = data["debug_logging"] in octoprint.settings.valid_boolean_trues
@ -174,13 +180,15 @@ class SvgToGcodePlugin(octoprint.plugin.SlicerPlugin,
##~~ TemplatePlugin API
def get_template_vars(self):
return dict(
_settings_menu_entry="Svg GCode Converter"
)
return dict()
def get_template_folder(self):
import os
return os.path.join(os.path.dirname(os.path.realpath(__file__)), "templates")
#import os
#return os.path.join(os.path.dirname(os.path.realpath(__file__)), "templates")
return os.path.join(self._basefolder, "templates")
def get_template_configs(self):
return [dict(type = 'settings', name = "Svg Conversion", custom_bindings = False)]
##~~ SlicerPlugin API

View file

@ -1,281 +1,292 @@
function VectorConversionViewModel(params) {
var self = this;
self.loginState = params[0];
self.settings = params[1];
self.state = params[2];
self.workingArea = params[3];
self.files = params[4];
self.target = undefined;
self.file = undefined;
self.data = undefined;
self.defaultSlicer = undefined;
self.defaultProfile = undefined;
self.gcodeFilename = ko.observable();
self.laserIntensity = ko.observable(undefined);
self.laserSpeed = ko.observable(undefined);
self.maxSpeed = ko.observable(3000);
self.minSpeed = ko.observable(30);
self.title = ko.observable(undefined);
self.slicer = ko.observable();
self.slicers = ko.observableArray();
self.profile = ko.observable();
self.profiles = ko.observableArray();
$(function(){
self.maxSpeed.subscribe(function(val){
console.log("maxSpeed changed", val);
self._configureFeedrateSlider();
});
// TODO check if still in use
self.show = function(target, file) {
self.target = target;
self.file = file;
self.title(_.sprintf(gettext("Converting %(filename)s"), {filename: self.file}));
self.gcodeFilename(self.file.substr(0, self.file.lastIndexOf(".")));
$("#dialog_vector_graphics_conversion").modal("show");
};
// shows conversion dialog and extracts svg first
self.show_conversion_dialog = function() {
var intensity = self.settings.settings.plugins.svgtogcode.defaultIntensity();
var speed = self.settings.settings.plugins.svgtogcode.defaultIntensity();
self.laserIntensity(intensity);
self.laserSpeed(speed);
function VectorConversionViewModel(params) {
var self = this;
self.svg = self.workingArea.getCompositionSVG();
console.log('conversion', params);
// TODO: js svg conversion
self.title(gettext("Converting"));
var gcodeFile = self.create_gcode_filename(self.workingArea.placedDesigns());
self.gcodeFilename(gcodeFile);
$("#dialog_vector_graphics_conversion").modal("show");
};
self.create_gcode_filename = function(placedDesigns){
if(placedDesigns.length > 0){
var filemap = {};
for(var idx in placedDesigns){
var design = placedDesigns[idx];
var start = design.url.lastIndexOf('/')+1;
var end = design.url.lastIndexOf('.');
var name = design.url.substring(start, end);
if(filemap[name] !== undefined) filemap[name] += 1;
else filemap[name] = 1;
}
var mostPlaced;
var placed = 0;
for(var name in filemap){
if(filemap[name] > placed){
mostPlaced = name;
placed = filemap[name];
self.loginState = params[0];
self.settings = params[1];
self.state = params[2];
self.workingArea = params[3];
self.files = params[4];
self.target = undefined;
self.file = undefined;
self.data = undefined;
self.defaultSlicer = undefined;
self.defaultProfile = undefined;
self.gcodeFilename = ko.observable();
self.laserIntensity = ko.observable(undefined);
self.laserSpeed = ko.observable(undefined);
self.maxSpeed = ko.observable(3000);
self.minSpeed = ko.observable(30);
self.title = ko.observable(undefined);
self.slicer = ko.observable();
self.slicers = ko.observableArray();
self.profile = ko.observable();
self.profiles = ko.observableArray();
self.maxSpeed.subscribe(function(val){
self._configureFeedrateSlider();
});
// TODO check if still in use
self.show = function(target, file) {
self.target = target;
self.file = file;
self.title(_.sprintf(gettext("Converting %(filename)s"), {filename: self.file}));
self.gcodeFilename(self.file.substr(0, self.file.lastIndexOf(".")));
$("#dialog_vector_graphics_conversion").modal("show");
};
// shows conversion dialog and extracts svg first
self.show_conversion_dialog = function() {
var intensity = self.settings.settings.plugins.svgtogcode.defaultIntensity();
var speed = self.settings.settings.plugins.svgtogcode.defaultIntensity();
self.laserIntensity(intensity);
self.laserSpeed(speed);
self.svg = self.workingArea.getCompositionSVG();
// TODO: js svg conversion
self.title(gettext("Converting"));
var gcodeFile = self.create_gcode_filename(self.workingArea.placedDesigns());
self.gcodeFilename(gcodeFile);
$("#dialog_vector_graphics_conversion").modal("show");
};
self.create_gcode_filename = function(placedDesigns){
if(placedDesigns.length > 0){
var filemap = {};
for(var idx in placedDesigns){
var design = placedDesigns[idx];
var start = design.url.lastIndexOf('/')+1;
var end = design.url.lastIndexOf('.');
var name = design.url.substring(start, end);
if(filemap[name] !== undefined) filemap[name] += 1;
else filemap[name] = 1;
}
var mostPlaced;
var placed = 0;
for(var name in filemap){
if(filemap[name] > placed){
mostPlaced = name;
placed = filemap[name];
}
}
var uniqueDesigns = Object.keys(filemap).length;
var gcode_name = mostPlaced;
if(placed > 1) gcode_name += "." + placed + "x";
if(uniqueDesigns > 1){
gcode_name += "_"+(uniqueDesigns-1)+"more";
}
return gcode_name + ".gco";
} else {
return "tmp"+Date.now()+".gco"; // TODO: user should not deal with gcode anymore. go and laser it.
}
var uniqueDesigns = Object.keys(filemap).length;
var gcode_name = mostPlaced;
if(placed > 1) gcode_name += "." + placed + "x";
if(uniqueDesigns > 1){
gcode_name += "_"+(uniqueDesigns-1)+"more";
};
self.slicer.subscribe(function(newValue) {
self.profilesForSlicer(newValue);
});
self.enableConvertButton = ko.computed(function() {
if (self.laserIntensity() === undefined || self.laserSpeed() === undefined || self.gcodeFilename() === undefined) {
return false;
} else {
var tmpIntensity = self.laserIntensity();
var tmpSpeed = self.laserSpeed();
var tmpGcodeFilename = self.gcodeFilename().trim();
return tmpGcodeFilename !== ""
&& tmpIntensity > 0 && tmpIntensity <= 1000 // TODO no magic numbers here!
&& tmpSpeed >= self.minSpeed() && tmpSpeed <= self.maxSpeed();
}
return gcode_name + ".gco";
} else {
return "tmp"+Date.now()+".gco"; // TODO: user should not deal with gcode anymore. go and laser it.
}
};
self.slicer.subscribe(function(newValue) {
self.profilesForSlicer(newValue);
});
self.enableConvertButton = ko.computed(function() {
if (self.laserIntensity() === undefined || self.laserSpeed() === undefined || self.gcodeFilename() === undefined) {
return false;
} else {
var tmpIntensity = self.laserIntensity();
var tmpSpeed = self.laserSpeed();
var tmpGcodeFilename = self.gcodeFilename().trim();
return tmpGcodeFilename !== ""
&& tmpIntensity > 0 && tmpIntensity <= 1000 // TODO no magic numbers here!
&& tmpSpeed >= self.minSpeed() && tmpSpeed <= self.maxSpeed();
}
});
self.requestData = function() {
$.ajax({
url: API_BASEURL + "slicing",
type: "GET",
dataType: "json",
success: self.fromResponse
});
};
self.fromResponse = function(data) {
self.data = data;
var selectedSlicer = undefined;
self.slicers.removeAll();
_.each(_.values(data), function(slicer) {
var name = slicer.displayName;
if (name === undefined) {
name = slicer.key;
}
if (slicer.default) {
selectedSlicer = slicer.key;
}
self.slicers.push({
key: slicer.key,
name: name
});
});
if (selectedSlicer != undefined) {
self.slicer(selectedSlicer);
}
self.defaultSlicer = selectedSlicer;
};
self.profilesForSlicer = function(key) {
if (key == undefined) {
key = self.slicer();
}
if (key == undefined || !self.data.hasOwnProperty(key)) {
return;
}
var slicer = self.data[key];
var selectedProfile = undefined;
self.profiles.removeAll();
_.each(_.values(slicer.profiles), function(profile) {
var name = profile.displayName;
if (name == undefined) {
name = profile.key;
}
if (profile.default) {
selectedProfile = profile.key;
}
self.profiles.push({
key: profile.key,
name: name
})
});
if (selectedProfile != undefined) {
self.profile(selectedProfile);
}
self.defaultProfile = selectedProfile;
};
self.convert = function() {
var gcodeFilename = self._sanitize(self.gcodeFilename());
if (!_.endsWith(gcodeFilename.toLowerCase(), ".gco")
&& !_.endsWith(gcodeFilename.toLowerCase(), ".gcode")
&& !_.endsWith(gcodeFilename.toLowerCase(), ".g")) {
gcodeFilename = gcodeFilename + ".gco";
}
var data = {
command: "convert",
"profile.speed": self.laserSpeed(),
"profile.intensity": self.laserIntensity(),
slicer: "svgtogcode",
gcode: gcodeFilename
};
if(self.svg !== undefined){
data.svg = self.svg;
}
$.ajax({
url: API_BASEURL + "files/convert",
type: "POST",
dataType: "json",
contentType: "application/json; charset=UTF-8",
data: JSON.stringify(data)
});
$("#dialog_vector_graphics_conversion").modal("hide");
self.gcodeFilename(undefined);
//self.slicer(self.defaultSlicer);
//self.profile(self.defaultProfile);
};
self._sanitize = function(name) {
return name.replace(/[^a-zA-Z0-9\-_\.\(\) ]/g, "").replace(/ /g, "_");
};
self.onStartup = function() {
self.requestData();
self.state.conversion = self; // hack! injecting method to avoid circular dependency.
self.files.conversion = self;
self._configureIntensitySlider();
self._configureFeedrateSlider();
};
self._configureIntensitySlider = function() {
self.intensitySlider = $("#svgtogcode_intensity").slider({
id: "svgtogcode_intensity_slider",
reversed: false,
selection: "after",
orientation: "horizontal",
min: 1,
max: 1000,
step: 1,
value: 500,
enabled: true,
formatter: function(value) { return "" + (value/10) +"%"; }
}).on("slideStop", function(ev){
self.laserIntensity(ev.value);
});
self.laserIntensity.subscribe(function(newVal){
self.intensitySlider.slider('setValue', parseInt(newVal));
});
};
self._configureFeedrateSlider = function() {
self.feedrateSlider = $("#svgtogcode_feedrate").slider({
id: "svgtogcode_feedrate_slider",
reversed: false,
selection: "after",
orientation: "horizontal",
min: 0,
max: 1000,
step: 1,
value: 300,
enabled: true,
formatter: function(value) { return "" + Math.round(self._calcRealSpeed(value)) +"mm/min"; }
});
// use the class as a flag to avoid double binding of the slideStop event
if($("#svgtogcode_feedrate").attr('class') === 'uninitialized'){ // somehow hasClass(...) did not work ???
self.feedrateSlider.on("slideStop", function(ev){
self.laserSpeed(self._calcRealSpeed(ev.value));
self.requestData = function() {
$.ajax({
url: API_BASEURL + "slicing",
type: "GET",
dataType: "json",
success: self.fromResponse
});
$("#svgtogcode_feedrate").removeClass('uninitialized');
}
var speedSubscription = self.laserSpeed.subscribe(function(realVal){
var val = (parseInt(realVal) - self.minSpeed()) / (self.maxSpeed() - self.minSpeed());
self.feedrateSlider.slider('setValue', val);
speedSubscription.dispose(); // only do it once
});
};
};
self.fromResponse = function(data) {
self.data = data;
var selectedSlicer = undefined;
self.slicers.removeAll();
_.each(_.values(data), function(slicer) {
var name = slicer.displayName;
if (name === undefined) {
name = slicer.key;
}
if (slicer.default) {
selectedSlicer = slicer.key;
}
self.slicers.push({
key: slicer.key,
name: name
});
});
if (selectedSlicer != undefined) {
self.slicer(selectedSlicer);
}
self.defaultSlicer = selectedSlicer;
};
self.profilesForSlicer = function(key) {
if (key == undefined) {
key = self.slicer();
}
if (key == undefined || !self.data.hasOwnProperty(key)) {
return;
}
var slicer = self.data[key];
var selectedProfile = undefined;
self.profiles.removeAll();
_.each(_.values(slicer.profiles), function(profile) {
var name = profile.displayName;
if (name == undefined) {
name = profile.key;
}
if (profile.default) {
selectedProfile = profile.key;
}
self.profiles.push({
key: profile.key,
name: name
})
});
if (selectedProfile != undefined) {
self.profile(selectedProfile);
}
self.defaultProfile = selectedProfile;
};
self.convert = function() {
var gcodeFilename = self._sanitize(self.gcodeFilename());
if (!_.endsWith(gcodeFilename.toLowerCase(), ".gco")
&& !_.endsWith(gcodeFilename.toLowerCase(), ".gcode")
&& !_.endsWith(gcodeFilename.toLowerCase(), ".g")) {
gcodeFilename = gcodeFilename + ".gco";
}
var data = {
command: "convert",
"profile.speed": self.laserSpeed(),
"profile.intensity": self.laserIntensity(),
slicer: "svgtogcode",
gcode: gcodeFilename
};
if(self.svg !== undefined){
data.svg = self.svg;
}
$.ajax({
url: API_BASEURL + "files/convert",
type: "POST",
dataType: "json",
contentType: "application/json; charset=UTF-8",
data: JSON.stringify(data)
});
$("#dialog_vector_graphics_conversion").modal("hide");
self.gcodeFilename(undefined);
//self.slicer(self.defaultSlicer);
//self.profile(self.defaultProfile);
};
self._sanitize = function(name) {
return name.replace(/[^a-zA-Z0-9\-_\.\(\) ]/g, "").replace(/ /g, "_");
};
self.onStartup = function() {
self.requestData();
self.state.conversion = self; // hack! injecting method to avoid circular dependency.
self.files.conversion = self;
self._configureIntensitySlider();
self._configureFeedrateSlider();
};
self._configureIntensitySlider = function() {
self.intensitySlider = $("#svgtogcode_intensity").slider({
id: "svgtogcode_intensity_slider",
reversed: false,
selection: "after",
orientation: "horizontal",
min: 1,
max: 1000,
step: 1,
value: 500,
enabled: true,
formatter: function(value) { return "" + (value/10) +"%"; }
}).on("slideStop", function(ev){
self.laserIntensity(ev.value);
});
self.laserIntensity.subscribe(function(newVal){
self.intensitySlider.slider('setValue', parseInt(newVal));
});
};
self._configureFeedrateSlider = function() {
self.feedrateSlider = $("#svgtogcode_feedrate").slider({
id: "svgtogcode_feedrate_slider",
reversed: false,
selection: "after",
orientation: "horizontal",
min: 0,
max: 1000,
step: 1,
value: 300,
enabled: true,
formatter: function(value) { return "" + Math.round(self._calcRealSpeed(value)) +"mm/min"; }
});
// use the class as a flag to avoid double binding of the slideStop event
if($("#svgtogcode_feedrate").attr('class') === 'uninitialized'){ // somehow hasClass(...) did not work ???
self.feedrateSlider.on("slideStop", function(ev){
self.laserSpeed(self._calcRealSpeed(ev.value));
});
$("#svgtogcode_feedrate").removeClass('uninitialized');
}
var speedSubscription = self.laserSpeed.subscribe(function(realVal){
var val = (parseInt(realVal) - self.minSpeed()) / (self.maxSpeed() - self.minSpeed());
self.feedrateSlider.slider('setValue', val);
speedSubscription.dispose(); // only do it once
});
};
self._calcRealSpeed = function(sliderVal){
console.log();
return self.minSpeed() + sliderVal/1000 * (self.maxSpeed() - self.minSpeed());
};
}
self._calcRealSpeed = function(sliderVal){
console.log();
return self.minSpeed() + sliderVal/1000 * (self.maxSpeed() - self.minSpeed());
};
ADDITIONAL_VIEWMODELS.push([VectorConversionViewModel, "vectorConversionViewModel",
["loginStateViewModel", "settingsViewModel", "printerStateViewModel", "workingAreaViewModel", "gcodeFilesViewModel"],
document.getElementById("dialog_vector_graphics_conversion")]);
}
});

View file

@ -1,43 +0,0 @@
$(function() {
function SvgToGcodeViewModel(parameters) {
var self = this;
self.loginState = parameters[0];
self.settingsViewModel = parameters[1];
self.slicingViewModel = parameters[2];
self.fileName = ko.observable();
self.placeholderName = ko.observable();
self.placeholderDisplayName = ko.observable();
self.placeholderDescription = ko.observable();
self.profileName = ko.observable();
self.profileDisplayName = ko.observable();
self.profileDescription = ko.observable();
self.profileAllowOverwrite = ko.observable(true);
self.convertSVG2 = function(data) {
if (!data) {
return;
}
return;
};
}
// view model class, parameters for constructor, container to bind to
//ADDITIONAL_VIEWMODELS.push([SvgToGcodeViewModel, ["loginStateViewModel", "settingsViewModel", "slicingViewModel"], null]);
ADDITIONAL_VIEWMODELS.push([WorkingAreaViewModel, "workingAreaViewModel",
["loginStateViewModel", "settingsViewModel", "printerStateViewModel", "gcodeFilesViewModel"],
document.getElementById("area_preview")]);
ADDITIONAL_VIEWMODELS.push([VectorConversionViewModel, "vectorConversionViewModel",
["loginStateViewModel", "settingsViewModel", "printerStateViewModel", "workingAreaViewModel", "gcodeFilesViewModel"],
document.getElementById("dialog_vector_graphics_conversion")]);
});

View file

@ -1,234 +1,245 @@
function WorkingAreaViewModel(params) {
var self = this;
$(function(){
self.loginState = params[0];
self.settings = params[1];
self.state = params[2];
self.files = params[3];
function WorkingAreaViewModel(params) {
console.log('workingaera', params);
var self = this;
self.log = [];
self.loginState = params[0];
self.settings = params[1];
self.state = params[2];
self.files = params[3];
self.conversion = params[4];
self.command = ko.observable(undefined);
self.log = [];
self.isErrorOrClosed = ko.observable(undefined);
self.isOperational = ko.observable(undefined);
self.isPrinting = ko.observable(undefined);
self.isPaused = ko.observable(undefined);
self.isError = ko.observable(undefined);
self.isReady = ko.observable(undefined);
self.isLoading = ko.observable(undefined);
self.availableHeight = ko.observable(undefined);
self.availableWidth = ko.observable(undefined);
self.px2mm_factor = 1; // initial value
self.svgDPI = ko.observable(90); // TODO fetch from settings
self.workingAreaWidthMM = ko.observable(undefined);
self.workingAreaHeightMM = ko.observable(undefined);
self.hwRatio = ko.computed(function(){
// y/x = 297/216 respectively 594/432
var w = self.workingAreaWidthMM();
var h = self.workingAreaHeightMM();
// var h = self.settings.printerProfiles.currentProfileData().volume.depth();
// var w = self.settings.printerProfiles.currentProfileData().volume.width();
var ratio = h / w;
return ratio;
}, self);
self.workingAreaDim = ko.computed(function(){
var maxH = self.availableHeight();
var maxW = self.availableWidth();
var hwRatio = self.hwRatio();
if( hwRatio > 0, maxH > 0, maxW > 0){
var w = 0;
var h = 0;
if( maxH/maxW > hwRatio) {
w = maxW;
h = maxW * hwRatio;
} else {
w = maxH / hwRatio;
h = maxH;
}
var dim = [w,h];
return dim;
}
});
self.workingAreaWidthPx = ko.computed(function(){
var dim = self.workingAreaDim();
return dim ? dim[0] : 1;
}, self);
self.workingAreaHeightPx = ko.computed(function(){
var dim = self.workingAreaDim();
return dim ? dim[1] : 1;
}, self);
self.px2mm_factor = ko.computed(function(){
return self.workingAreaWidthMM() / self.workingAreaWidthPx();
});
self.scaleMatrix = ko.computed(function(){
var m = new Snap.Matrix();
m.scale(25.4/self.svgDPI() * 1/self.px2mm_factor());
return m;
});
self.placedDesigns = ko.observableArray([]);
self.clear = function(){
snap.selectAll('#userContent>*').remove();
self.placedDesigns([]);
};
self.trigger_resize = function(){
self.availableHeight(document.documentElement.clientHeight - $('body>nav').outerHeight() - $('footer>*').outerHeight() - 39); // magic number
self.availableWidth($('#workingarea div.span8').innerWidth());
};
self.command = ko.observable(undefined);
self.move_laser = function(el){
var x = self.px2mm(event.offsetX);
// var y = self.px2mm(event.toElement.offsetHeight - event.offsetY); // toElement.offsetHeight is always 0 on svg>* elements ???
var y = self.px2mm(event.toElement.ownerSVGElement.offsetHeight - event.offsetY); // hopefully this works across browsers
$.ajax({
url: API_BASEURL + "printer/printhead",
type: "POST",
dataType: "json",
contentType: "application/json; charset=UTF-8",
data: JSON.stringify({"command": "position", x:x, y:y})
});
};
self.crosshairX = function(){
var pos = self.state.currentPos();
return pos !== undefined ? (self.mm2px(pos.x) - 15) : -100; // subtract width/2;
};
self.crosshairY = function(){
var h = document.getElementById('area_preview').clientHeight;
var pos = self.state.currentPos();
return pos !== undefined ? (h - self.mm2px(pos.y) - 15) : -100; // subtract height/2;
};
self.px2mm = function(val){
return val * self.px2mm_factor();
};
self.mm2px = function(val){
return val / self.px2mm_factor();
};
self.mm2svgUnits = function(val){
return val * self.svgDPI()/25.4;
};
//self.getDivDimensions(); // init
self.placeSVG = function(file) {
if (file && file["refs"] && file["refs"]["download"]) {
var url = file.refs.download.replace("downloads", "serve");
self.loadSVG(url);
}
};
self.loadSVG = function(url){
Snap.load(url, function (f) {
var namespaces = {};
var root = f.select('svg').node.attributes;
for(var i = 0; i < root.length; i++){
var attr = root[i];
if(attr.name.indexOf("xmlns") === 0){
namespaces[attr.name] = attr.value;
self.isErrorOrClosed = ko.observable(undefined);
self.isOperational = ko.observable(undefined);
self.isPrinting = ko.observable(undefined);
self.isPaused = ko.observable(undefined);
self.isError = ko.observable(undefined);
self.isReady = ko.observable(undefined);
self.isLoading = ko.observable(undefined);
self.availableHeight = ko.observable(undefined);
self.availableWidth = ko.observable(undefined);
self.px2mm_factor = 1; // initial value
self.svgDPI = ko.observable(90); // TODO fetch from settings
self.workingAreaWidthMM = ko.observable(undefined);
self.workingAreaHeightMM = ko.observable(undefined);
self.hwRatio = ko.computed(function(){
// y/x = 297/216 respectively 594/432
var w = self.workingAreaWidthMM();
var h = self.workingAreaHeightMM();
// var h = self.settings.printerProfiles.currentProfileData().volume.depth();
// var w = self.settings.printerProfiles.currentProfileData().volume.width();
var ratio = h / w;
return ratio;
}, self);
self.workingAreaDim = ko.computed(function(){
var maxH = self.availableHeight();
var maxW = self.availableWidth();
var hwRatio = self.hwRatio();
if( hwRatio > 0, maxH > 0, maxW > 0){
var w = 0;
var h = 0;
if( maxH/maxW > hwRatio) {
w = maxW;
h = maxW * hwRatio;
} else {
w = maxH / hwRatio;
h = maxH;
}
var dim = [w,h];
return dim;
}
var newSvg = f.select("g");
newSvg.attr(namespaces);
var id = self.generateId(url);
snap.select("#userContent").append(newSvg);
newSvg.drag();// Making croc draggable. Go ahead drag it around!
// Obviously drag could take event handlers too
var ref = {
id : id,
url : url
};
self.placedDesigns.push(ref);
});
};
self.init = function(){
// init snap.svg
snap = Snap('#area_preview');
self.px2mm_factor.subscribe(function(newVal){
if(!isNaN(newVal))
self.draw_coord_grid();
self.workingAreaWidthPx = ko.computed(function(){
var dim = self.workingAreaDim();
return dim ? dim[0] : 1;
}, self);
self.workingAreaHeightPx = ko.computed(function(){
var dim = self.workingAreaDim();
return dim ? dim[1] : 1;
}, self);
self.px2mm_factor = ko.computed(function(){
return self.workingAreaWidthMM() / self.workingAreaWidthPx();
});
};
self.draw_coord_grid = function(){
var grid = snap.select('#coordGrid');
if(grid.attr('fill') === 'none'){
var w = self.mm2svgUnits(self.workingAreaWidthMM());
var h = self.mm2svgUnits(self.workingAreaHeightMM());
var max_lines = 20;
var linedistMM = Math.floor(Math.max(self.workingAreaWidthMM(), self.workingAreaHeightMM()) / (max_lines * 10))*10;
var yPatternOffset = self.mm2svgUnits(self.workingAreaHeightMM() % linedistMM);
var linedist = self.mm2svgUnits(linedistMM);
var marker = snap.circle(linedist/2, linedist/2, 1).attr({
fill: "#000000",
stroke: "none",
strokeWidth: 1
});
// dot pattern
var p = marker.pattern(0, 0, linedist, linedist);
p.attr({
x: linedist/2,
y: linedist/2 + yPatternOffset
});
grid.attr({
width: w,
height: h,
fill: p
});
}
};
self.generateId = function(url){
var idBase = '_'+url.substring(url.lastIndexOf('/')+1).replace('.', '-'); // _ at first place if filename starts with a digit
var suffix = 0;
var id = idBase + "-" + suffix;
while(snap.select('#'+id) !== null){
suffix += 1;
id = idBase + suffix;
}
return id;
};
self.getCompositionSVG = function(){
// TODO use lasercutterprofiles
var dpiFactor = self.svgDPI()/25.4; // convert mm to pix with 90dpi (inkscape default - TODO use 72 for illustrator svg and fetch from settings)
var w = dpiFactor * self.settings.printerProfiles.currentProfileData().volume.width;
var h = dpiFactor * self.settings.printerProfiles.currentProfileData().volume.depth;
var tmpsvg = snap.select("#userContent").innerSVG(); // get working area
var svg = '<svg height="'+ h +'" version="1.1" width="'+ w +'" xmlns="http://www.w3.org/2000/svg"><defs/>'+ tmpsvg +'</svg>';
return svg;
};
self.onStartup = function(){
self.files.workingArea = self;
$(window).resize(function(){
self.trigger_resize();
self.scaleMatrix = ko.computed(function(){
var m = new Snap.Matrix();
m.scale(25.4/self.svgDPI() * 1/self.px2mm_factor());
return m;
});
self.trigger_resize(); // initialize
self.init();
};
}
self.placedDesigns = ko.observableArray([]);
self.clear = function(){
snap.selectAll('#userContent>*').remove();
self.placedDesigns([]);
};
self.trigger_resize = function(){
self.availableHeight(document.documentElement.clientHeight - $('body>nav').outerHeight() - $('footer>*').outerHeight() - 39); // magic number
self.availableWidth($('#workingarea div.span8').innerWidth());
};
self.move_laser = function(el){
var x = self.px2mm(event.offsetX);
// var y = self.px2mm(event.toElement.offsetHeight - event.offsetY); // toElement.offsetHeight is always 0 on svg>* elements ???
var y = self.px2mm(event.toElement.ownerSVGElement.offsetHeight - event.offsetY); // hopefully this works across browsers
$.ajax({
url: API_BASEURL + "printer/printhead",
type: "POST",
dataType: "json",
contentType: "application/json; charset=UTF-8",
data: JSON.stringify({"command": "position", x:x, y:y})
});
};
self.crosshairX = function(){
var pos = self.state.currentPos();
return pos !== undefined ? (self.mm2px(pos.x) - 15) : -100; // subtract width/2;
};
self.crosshairY = function(){
var h = document.getElementById('area_preview').clientHeight;
var pos = self.state.currentPos();
return pos !== undefined ? (h - self.mm2px(pos.y) - 15) : -100; // subtract height/2;
};
self.px2mm = function(val){
return val * self.px2mm_factor();
};
self.mm2px = function(val){
return val / self.px2mm_factor();
};
self.mm2svgUnits = function(val){
return val * self.svgDPI()/25.4;
};
//self.getDivDimensions(); // init
self.placeSVG = function(file) {
if (file && file["refs"] && file["refs"]["download"]) {
var url = file.refs.download.replace("downloads", "serve");
self.loadSVG(url);
}
};
self.loadSVG = function(url){
Snap.load(url, function (f) {
var namespaces = {};
var root = f.select('svg').node.attributes;
for(var i = 0; i < root.length; i++){
var attr = root[i];
if(attr.name.indexOf("xmlns") === 0){
namespaces[attr.name] = attr.value;
}
}
var newSvg = f.select("g");
newSvg.attr(namespaces);
var id = self.generateId(url);
snap.select("#userContent").append(newSvg);
newSvg.drag();// Making croc draggable. Go ahead drag it around!
// Obviously drag could take event handlers too
var ref = {
id : id,
url : url
};
self.placedDesigns.push(ref);
});
};
self.init = function(){
// init snap.svg
snap = Snap('#area_preview');
self.px2mm_factor.subscribe(function(newVal){
if(!isNaN(newVal))
self.draw_coord_grid();
});
};
self.draw_coord_grid = function(){
var grid = snap.select('#coordGrid');
if(grid.attr('fill') === 'none'){
var w = self.mm2svgUnits(self.workingAreaWidthMM());
var h = self.mm2svgUnits(self.workingAreaHeightMM());
var max_lines = 20;
var linedistMM = Math.floor(Math.max(self.workingAreaWidthMM(), self.workingAreaHeightMM()) / (max_lines * 10))*10;
var yPatternOffset = self.mm2svgUnits(self.workingAreaHeightMM() % linedistMM);
var linedist = self.mm2svgUnits(linedistMM);
var marker = snap.circle(linedist/2, linedist/2, 1).attr({
fill: "#000000",
stroke: "none",
strokeWidth: 1
});
// dot pattern
var p = marker.pattern(0, 0, linedist, linedist);
p.attr({
x: linedist/2,
y: linedist/2 + yPatternOffset
});
grid.attr({
width: w,
height: h,
fill: p
});
}
};
self.generateId = function(url){
var idBase = '_'+url.substring(url.lastIndexOf('/')+1).replace('.', '-'); // _ at first place if filename starts with a digit
var suffix = 0;
var id = idBase + "-" + suffix;
while(snap.select('#'+id) !== null){
suffix += 1;
id = idBase + suffix;
}
return id;
};
self.getCompositionSVG = function(){
// TODO use lasercutterprofiles
var dpiFactor = self.svgDPI()/25.4; // convert mm to pix with 90dpi (inkscape default - TODO use 72 for illustrator svg and fetch from settings)
var w = dpiFactor * self.settings.printerProfiles.currentProfileData().volume.width;
var h = dpiFactor * self.settings.printerProfiles.currentProfileData().volume.depth;
var tmpsvg = snap.select("#userContent").innerSVG(); // get working area
var svg = '<svg height="'+ h +'" version="1.1" width="'+ w +'" xmlns="http://www.w3.org/2000/svg"><defs/>'+ tmpsvg +'</svg>';
return svg;
};
self.onStartup = function(){
self.files.workingArea = self;
self.conversion.workingArea = self;
$(window).resize(function(){
self.trigger_resize();
});
self.trigger_resize(); // initialize
self.init();
};
}
// view model class, parameters for constructor, container to bind to
ADDITIONAL_VIEWMODELS.push([WorkingAreaViewModel, "workingAreaViewModel",
["loginStateViewModel", "settingsViewModel", "printerStateViewModel", "gcodeFilesViewModel", "vectorConversionViewModel"],
document.getElementById("area_preview")]);
});

View file

@ -1,17 +1,23 @@
<div id="settings_plugin_svgtogcode_dialog" data-bind="allowBindings: true">
<div id="settings_plugin_svgtogcode_dialog" xdata-bind="allowBindings: true">
<h4>{{ _('Default settings') }}</h4>
<form class="form-horizontal">
<div class="control-group">
<label class="control-label" for="settings-svgtogcode-defaultIntensity">{{ _('laser intensity') }}</label>
<label class="control-label" for="settings-svgtogcode-defaultIntensity">{{ _('Default Laser Intensity') }}</label>
<div class="controls">
<input type="text" class="input-block-level" data-bind="event: {change: saveall}, value: settings.plugins.svgtogcode.defaultIntensity">
<input type="number" min="1" max="1000" class="input-block-level" data-bind="event: {change: saveall}, value: settings.plugins.svgtogcode.defaultIntensity">
</div>
</div>
<div class="control-group">
<label class="control-label" for="settings-svgtogcode-defaultFeedrate">{{ _('laser speed') }}</label>
<label class="control-label" for="settings-svgtogcode-defaultFeedrate">{{ _('Default Laser Speed') }}</label>
<div class="controls">
<input type="text" class="input-block-level" data-bind="event: {change: saveall}, value: settings.plugins.svgtogcode.defaultFeedrate">
<input type="number" min="1" class="input-block-level" data-bind="event: {change: saveall}, value: settings.plugins.svgtogcode.defaultFeedrate">
</div>
</div>
<div class="control-group">
<label class="control-label" for="settings-svgtogcode-svgDPI">{{ _('SVG dpi') }}</label>
<div class="controls">
<input type="text" class="input-block-level" data-bind="event: {change: saveall}, value: settings.plugins.svgtogcode.svgDPI">
</div>
</div>
<div class="control-group">

View file

@ -163,7 +163,7 @@ function PrinterStateViewModel(loginStateViewModel, timelapseViewModel, vectorCo
if (data.file) {
self.filename(data.file.name);
self.filesize(data.file.size);
self.sd(data.file.origin == "sdcard");
self.sd(data.file.origin === "sdcard");
} else {
self.filename(undefined);
self.filesize(undefined);
@ -174,7 +174,7 @@ function PrinterStateViewModel(loginStateViewModel, timelapseViewModel, vectorCo
self.lastPrintTime(data.lastPrintTime);
var result = [];
if (data.filament && typeof(data.filament) == "object" && _.keys(data.filament).length > 0) {
if (data.filament && typeof(data.filament) === "object" && _.keys(data.filament).length > 0) {
for (var key in data.filament) {
if (!_.startsWith(key, "tool") || !data.filament[key] || !data.filament[key].hasOwnProperty("length") || data.filament[key].length <= 0) continue;

View file

@ -65,7 +65,6 @@ function SettingsViewModel(loginStateViewModel, usersViewModel, printerProfilesV
self.feature_sdAlwaysAvailable = ko.observable(undefined);
self.feature_swallowOkAfterResend = ko.observable(undefined);
self.feature_repetierTargetTemp = ko.observable(undefined);
self.feature_zaxis = ko.observable(undefined);
self.feature_keyboardControl = ko.observable(undefined);
self.serial_port = ko.observable();
@ -90,9 +89,6 @@ function SettingsViewModel(loginStateViewModel, usersViewModel, printerProfilesV
self.cura_path = ko.observable(undefined);
self.cura_config = ko.observable(undefined);
self.svgtogcode_defaultIntensity = ko.observable(undefined);
self.svgtogcode_defaultFeedrate = ko.observable(undefined);
self.temperature_profiles = ko.observableArray(undefined);
self.system_actions = ko.observableArray([]);
@ -150,7 +146,6 @@ function SettingsViewModel(loginStateViewModel, usersViewModel, printerProfilesV
} else {
ko.mapping.fromJS(response, self.settings);
}
self.api_enabled(response.api.enabled);
self.api_key(response.api.key);
self.api_allowCrossOrigin(response.api.allowCrossOrigin);
@ -176,7 +171,6 @@ function SettingsViewModel(loginStateViewModel, usersViewModel, printerProfilesV
self.feature_sdAlwaysAvailable(response.feature.sdAlwaysAvailable);
self.feature_swallowOkAfterResend(response.feature.swallowOkAfterResend);
self.feature_repetierTargetTemp(response.feature.repetierTargetTemp);
self.feature_zaxis(response.feature.zaxis);
self.feature_keyboardControl(response.feature.keyboardControl);
self.serial_port(response.serial.port);
@ -240,7 +234,6 @@ function SettingsViewModel(loginStateViewModel, usersViewModel, printerProfilesV
"sdAlwaysAvailable": self.feature_sdAlwaysAvailable(),
"swallowOkAfterResend": self.feature_swallowOkAfterResend(),
"repetierTargetTemp": self.feature_repetierTargetTemp(),
"zaxis": self.feature_zaxis(),
"keyboardControl": self.feature_keyboardControl()
},
"serial": {