More work on the GCode viewer
- confirmation dialog when trying to visualize large files (different threshold for mobile and "regular" devices, configurable of course, although only via config file right now) - should also help a bit with issues leading to #215 - proper clearing of the viewer area when reconnecting to the backend (e.g. after server restart) Also all of this plus previous commits closes #35
This commit is contained in:
parent
b9f49a83e0
commit
ad556e7413
9 changed files with 250 additions and 171 deletions
|
|
@ -486,7 +486,7 @@ class Printer():
|
|||
self._stateMonitor.setState({"state": self._state, "stateString": self.getStateString(), "flags": self._getStateFlags()})
|
||||
|
||||
def mcSdFiles(self, files):
|
||||
eventManager().fire(Events.UPDATED_FILES, {"type": "gcode", "files": files})
|
||||
eventManager().fire(Events.UPDATED_FILES, {"type": "gcode"})
|
||||
self._sdFilelistAvailable.set()
|
||||
|
||||
def mcFileSelected(self, filename, filesize, sd):
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ def index():
|
|||
"index.jinja2",
|
||||
webcamStream=settings().get(["webcam", "stream"]),
|
||||
enableTimelapse=(settings().get(["webcam", "snapshot"]) is not None and settings().get(["webcam", "ffmpeg"]) is not None),
|
||||
enableGCodeVisualizer=settings().get(["feature", "gCodeVisualizer"]),
|
||||
enableGCodeVisualizer=settings().get(["gcodeViewer", "enabled"]),
|
||||
enableTemperatureGraph=settings().get(["feature", "temperatureGraph"]),
|
||||
enableSystemMenu=settings().get(["system"]) is not None and settings().get(["system", "actions"]) is not None and len(settings().get(["system", "actions"])) > 0,
|
||||
enableAccessControl=userManager is not None,
|
||||
|
|
@ -60,7 +60,9 @@ def index():
|
|||
debug=debug,
|
||||
gitBranch=branch,
|
||||
gitCommit=commit,
|
||||
stylesheet=settings().get(["devel", "stylesheet"])
|
||||
stylesheet=settings().get(["devel", "stylesheet"]),
|
||||
gcodeMobileThreshold=settings().get(["gcodeViewer", "mobileSizeThreshold"]),
|
||||
gcodeThreshold=settings().get(["gcodeViewer", "sizeThreshold"])
|
||||
)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ def getSettings():
|
|||
"flipV": s.getBoolean(["webcam", "flipV"])
|
||||
},
|
||||
"feature": {
|
||||
"gcodeViewer": s.getBoolean(["feature", "gCodeVisualizer"]),
|
||||
"gcodeViewer": s.getBoolean(["gcodeViewer", "enabled"]),
|
||||
"temperatureGraph": s.getBoolean(["feature", "temperatureGraph"]),
|
||||
"waitForStart": s.getBoolean(["feature", "waitForStartOnConnect"]),
|
||||
"alwaysSendChecksum": s.getBoolean(["feature", "alwaysSendChecksum"]),
|
||||
|
|
@ -130,7 +130,7 @@ def setSettings():
|
|||
if "flipV" in data["webcam"].keys(): s.setBoolean(["webcam", "flipV"], data["webcam"]["flipV"])
|
||||
|
||||
if "feature" in data.keys():
|
||||
if "gcodeViewer" in data["feature"].keys(): s.setBoolean(["feature", "gCodeVisualizer"], data["feature"]["gcodeViewer"])
|
||||
if "gcodeViewer" in data["feature"].keys(): s.setBoolean(["gcodeViewer", "enabled"], data["feature"]["gcodeViewer"])
|
||||
if "temperatureGraph" in data["feature"].keys(): s.setBoolean(["feature", "temperatureGraph"], data["feature"]["temperatureGraph"])
|
||||
if "waitForStart" in data["feature"].keys(): s.setBoolean(["feature", "waitForStartOnConnect"], data["feature"]["waitForStart"])
|
||||
if "alwaysSendChecksum" in data["feature"].keys(): s.setBoolean(["feature", "alwaysSendChecksum"], data["feature"]["alwaysSendChecksum"])
|
||||
|
|
|
|||
|
|
@ -55,8 +55,12 @@ default_settings = {
|
|||
"options": {}
|
||||
}
|
||||
},
|
||||
"gcodeViewer": {
|
||||
"enabled": True,
|
||||
"mobileSizeThreshold": 2 * 1024 * 1024, # 2MB
|
||||
"sizeThreshold": 20 * 1024 * 1024, # 20MB
|
||||
},
|
||||
"feature": {
|
||||
"gCodeVisualizer": True,
|
||||
"temperatureGraph": True,
|
||||
"waitForStartOnConnect": False,
|
||||
"alwaysSendChecksum": False,
|
||||
|
|
|
|||
|
|
@ -120,13 +120,12 @@ GCODE.gCodeReader = (function(){
|
|||
// ***** PUBLIC *******
|
||||
return {
|
||||
clear: function() {
|
||||
delete lines;
|
||||
delete gcode;
|
||||
model = [];
|
||||
z_heights = [];
|
||||
},
|
||||
|
||||
loadFile: function(reader){
|
||||
model = [];
|
||||
z_heights = [];
|
||||
this.clear();
|
||||
|
||||
var totalSize = reader.target.result.length;
|
||||
lines = reader.target.result.split(/\n/);
|
||||
|
|
@ -144,7 +143,6 @@ GCODE.gCodeReader = (function(){
|
|||
}
|
||||
}
|
||||
);
|
||||
this.clear();
|
||||
},
|
||||
|
||||
setOption: function(options){
|
||||
|
|
|
|||
|
|
@ -17,10 +17,10 @@ GCODE.renderer = (function(){
|
|||
|
||||
var layerNumStore, progressStore={from: 0, to: -1};
|
||||
var lastX, lastY;
|
||||
var dragStart,dragged;
|
||||
var dragStart, dragged;
|
||||
var scaleFactor = 1.1;
|
||||
var model;
|
||||
var initialized=false;
|
||||
var initialized = false;
|
||||
var renderOptions = {
|
||||
colorGrid: "#bbbbbb",
|
||||
bgColorGrid: "#ffffff",
|
||||
|
|
@ -55,7 +55,6 @@ GCODE.renderer = (function(){
|
|||
var speeds = [];
|
||||
var speedsByLayer = {};
|
||||
|
||||
|
||||
var reRender = function(){
|
||||
var p1 = ctx.transformedPoint(0,0);
|
||||
var p2 = ctx.transformedPoint(canvas.width,canvas.height);
|
||||
|
|
@ -183,8 +182,11 @@ GCODE.renderer = (function(){
|
|||
};
|
||||
|
||||
var drawGrid = function() {
|
||||
console.log("Drawing grid");
|
||||
|
||||
ctx.translate(offsetBedX, offsetBedY);
|
||||
|
||||
ctx.beginPath();
|
||||
var width = renderOptions["bed"]["x"] * zoomFactor;
|
||||
var height = renderOptions["bed"]["y"] * zoomFactor;
|
||||
var origin = {
|
||||
|
|
@ -220,6 +222,8 @@ GCODE.renderer = (function(){
|
|||
};
|
||||
|
||||
var drawLayer = function(layerNum, fromProgress, toProgress, isNotCurrentLayer){
|
||||
console.log("Drawing layer " + layerNum + " from " + fromProgress + " to " + toProgress + " (current: " + !isNotCurrentLayer + ")");
|
||||
|
||||
var i;
|
||||
|
||||
isNotCurrentLayer = typeof isNotCurrentLayer !== 'undefined' ? isNotCurrentLayer : false;
|
||||
|
|
@ -279,7 +283,7 @@ GCODE.renderer = (function(){
|
|||
x = cmds[i].x;
|
||||
}
|
||||
if (typeof(cmds[i].y) === 'undefined' || isNaN(cmds[i].y)) {
|
||||
y=prevY/zoomFactor;
|
||||
y = prevY / zoomFactor;
|
||||
} else {
|
||||
y = -cmds[i].y;
|
||||
}
|
||||
|
|
@ -329,30 +333,58 @@ GCODE.renderer = (function(){
|
|||
ctx.stroke();
|
||||
};
|
||||
|
||||
/*
|
||||
var calculateBedOffset = function(bedDimensions) {
|
||||
if (!bedDimensions) bedDimensions = renderOptions["bed"];
|
||||
|
||||
var max = Math.max(bedDimensions.x, bedDimensions.y);
|
||||
return {
|
||||
x: (max - bedDimensions.x) / 2 * zoomFactor,
|
||||
y: (max - bedDimensions.y) / 2 * zoomFactor
|
||||
};
|
||||
var applyOffsets = function(mdlInfo) {
|
||||
// determine bed and model offsets
|
||||
if (ctx) ctx.translate(-offsetModelX, -offsetModelY);
|
||||
if (renderOptions["centerViewport"] || renderOptions["zoomInOnModel"]) {
|
||||
var canvasCenter = ctx.transformedPoint(canvas.width / 2, canvas.height / 2);
|
||||
if (mdlInfo) {
|
||||
offsetModelX = canvasCenter.x - (mdlInfo.min.x + mdlInfo.modelSize.x / 2) * zoomFactor;
|
||||
offsetModelY = canvasCenter.y + (mdlInfo.min.y + mdlInfo.modelSize.y / 2) * zoomFactor;
|
||||
} else {
|
||||
offsetModelX = 0;
|
||||
offsetModelY = 0;
|
||||
}
|
||||
offsetBedX = 0;
|
||||
offsetBedY = 0;
|
||||
} else if (mdlInfo && renderOptions["moveModel"]) {
|
||||
offsetModelX = (renderOptions["bed"]["x"] / 2 - (mdlInfo.min.x + mdlInfo.modelSize.x / 2)) * zoomFactor;
|
||||
offsetModelY = -1 * (renderOptions["bed"]["y"] / 2 - (mdlInfo.min.y + mdlInfo.modelSize.y / 2)) * zoomFactor;
|
||||
offsetBedX = -1 * (renderOptions["bed"]["x"] / 2 - (mdlInfo.min.x + mdlInfo.modelSize.x / 2)) * zoomFactor;
|
||||
offsetBedY = (renderOptions["bed"]["y"] / 2 - (mdlInfo.min.y + mdlInfo.modelSize.y / 2)) * zoomFactor;
|
||||
} else {
|
||||
offsetModelX = 0;
|
||||
offsetModelY = 0;
|
||||
offsetBedX = 0;
|
||||
offsetBedY = 0;
|
||||
}
|
||||
if (ctx) ctx.translate(offsetModelX, offsetModelY);
|
||||
};
|
||||
|
||||
var applyBedOffset = function(bedDimensions, onlyNew) {
|
||||
if (true) return;
|
||||
var bedOffset = calculateBedOffset(bedDimensions);
|
||||
|
||||
if (offsetBedX == bedOffset.x && offsetBedY == bedOffset.y) return;
|
||||
|
||||
ctx.translate(-offsetBedX, offsetBedY);
|
||||
offsetBedX = bedOffset.x;
|
||||
offsetBedY = bedOffset.y;
|
||||
ctx.translate(bedOffset.x, -bedOffset.y);
|
||||
}
|
||||
*/
|
||||
|
||||
var applyZoom = function(mdlInfo) {
|
||||
var pt = ctx.transformedPoint(canvas.width/2,canvas.height/2);
|
||||
var transform = ctx.getTransform();
|
||||
var scaleF;
|
||||
if (scaleX && scaleY && transform.a && transform.d) {
|
||||
ctx.translate(pt.x, pt.y);
|
||||
ctx.scale(1 / scaleX, 1 / scaleY);
|
||||
ctx.translate(-pt.x, -pt.y);
|
||||
}
|
||||
if (mdlInfo && renderOptions["zoomInOnModel"]) {
|
||||
scaleF = mdlInfo.modelSize.x > mdlInfo.modelSize.y ? (canvas.width - 10) / mdlInfo.modelSize.x : (canvas.height - 10) / mdlInfo.modelSize.y;
|
||||
scaleF /= zoomFactor;
|
||||
if (transform.a && transform.d) {
|
||||
scaleX = scaleF / transform.a;
|
||||
scaleY = scaleF / transform.d;
|
||||
ctx.translate(pt.x,pt.y);
|
||||
ctx.scale(scaleX, scaleY);
|
||||
ctx.translate(-pt.x, -pt.y);
|
||||
}
|
||||
} else {
|
||||
scaleX = 1;
|
||||
scaleY = 1;
|
||||
}
|
||||
};
|
||||
|
||||
// ***** PUBLIC *******
|
||||
return {
|
||||
|
|
@ -366,22 +398,24 @@ GCODE.renderer = (function(){
|
|||
offsetModelY = 0;
|
||||
offsetBedX = 0;
|
||||
offsetBedY = 0;
|
||||
|
||||
//applyBedOffset();
|
||||
},
|
||||
setOption: function(options){
|
||||
var mustRefresh = false;
|
||||
var dirty = false;
|
||||
for (var opt in options) {
|
||||
if (!options.hasOwnProperty(opt)) continue;
|
||||
if (options[opt] === undefined) continue;
|
||||
if (options.hasOwnProperty(opt)) renderOptions[opt] = options[opt];
|
||||
|
||||
dirty = dirty || (renderOptions[opt] != options[opt]);
|
||||
renderOptions[opt] = options[opt];
|
||||
if ($.inArray(opt, ["moveModel", "centerViewport", "zoomInOnModel", "bed"])) {
|
||||
mustRefresh = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!dirty) return;
|
||||
if(initialized) {
|
||||
if (mustRefresh) {
|
||||
//applyBedOffset();
|
||||
this.refresh();
|
||||
} else {
|
||||
reRender();
|
||||
|
|
@ -401,7 +435,7 @@ GCODE.renderer = (function(){
|
|||
var p2 = ctx.transformedPoint(canvas.width, canvas.height);
|
||||
ctx.clearRect(p1.x, p1.y, p2.x - p1.x, p2.y - p1.y);
|
||||
drawGrid();
|
||||
if (model) {
|
||||
if (model && model.length) {
|
||||
if (layerNum < model.length) {
|
||||
if (renderOptions['showNextLayer'] && layerNum < model.length - 1) {
|
||||
drawLayer(layerNum + 1, 0, this.getLayerNumSegments(layerNum + 1), true);
|
||||
|
|
@ -426,68 +460,39 @@ GCODE.renderer = (function(){
|
|||
}
|
||||
},
|
||||
clear: function() {
|
||||
model = undefined;
|
||||
initialized = false;
|
||||
this.render();
|
||||
offsetModelX = 0;
|
||||
offsetModelY = 0;
|
||||
offsetBedX = 0;
|
||||
offsetBedY = 0;
|
||||
scaleX = 1;
|
||||
scaleY = 1;
|
||||
speeds = [];
|
||||
speedsByLayer = {};
|
||||
|
||||
this.doRender([], 0);
|
||||
},
|
||||
doRender: function(mdl, layerNum){
|
||||
model = mdl;
|
||||
if (!model || !model[layerNum]) return;
|
||||
|
||||
var mdlInfo;
|
||||
var mdlInfo = undefined;
|
||||
prevX = 0;
|
||||
prevY = 0;
|
||||
if (!initialized) this.init();
|
||||
|
||||
mdlInfo = GCODE.gCodeReader.getModelInfo();
|
||||
speeds = mdlInfo.speeds;
|
||||
speedsByLayer = mdlInfo.speedsByLayer;
|
||||
|
||||
// determine bed and model offsets
|
||||
if (ctx) ctx.translate(-offsetModelX, -offsetModelY);
|
||||
if (renderOptions["centerViewport"] || renderOptions["zoomInOnModel"]) {
|
||||
var canvasCenter = ctx.transformedPoint(canvas.width / 2, canvas.height / 2);
|
||||
offsetModelX = canvasCenter.x - (mdlInfo.min.x + mdlInfo.modelSize.x / 2) * zoomFactor;
|
||||
offsetModelY = canvasCenter.y + (mdlInfo.min.y + mdlInfo.modelSize.y / 2) * zoomFactor;
|
||||
offsetBedX = 0;
|
||||
offsetBedY = 0;
|
||||
} else if (renderOptions["moveModel"]) {
|
||||
offsetModelX = (renderOptions["bed"]["x"] / 2 - (mdlInfo.min.x + mdlInfo.modelSize.x / 2)) * zoomFactor;
|
||||
offsetModelY = -1 * (renderOptions["bed"]["y"] / 2 - (mdlInfo.min.y + mdlInfo.modelSize.y / 2)) * zoomFactor;
|
||||
offsetBedX = -1 * (renderOptions["bed"]["x"] / 2 - (mdlInfo.min.x + mdlInfo.modelSize.x / 2)) * zoomFactor;
|
||||
offsetBedY = (renderOptions["bed"]["y"] / 2 - (mdlInfo.min.y + mdlInfo.modelSize.y / 2)) * zoomFactor;
|
||||
} else {
|
||||
offsetModelX = 0;
|
||||
offsetModelY = 0;
|
||||
offsetBedX = 0;
|
||||
offsetBedY = 0;
|
||||
}
|
||||
if (ctx) ctx.translate(offsetModelX, offsetModelY);
|
||||
|
||||
var pt = ctx.transformedPoint(canvas.width/2,canvas.height/2);
|
||||
var transform = ctx.getTransform();
|
||||
var scaleF;
|
||||
if (scaleX && scaleY && transform.a && transform.d) {
|
||||
ctx.translate(pt.x, pt.y);
|
||||
ctx.scale(1 / scaleX, 1 / scaleY);
|
||||
ctx.translate(-pt.x, -pt.y);
|
||||
}
|
||||
if (renderOptions["zoomInOnModel"]) {
|
||||
scaleF = mdlInfo.modelSize.x > mdlInfo.modelSize.y ? (canvas.width - 10) / mdlInfo.modelSize.x : (canvas.height - 10) / mdlInfo.modelSize.y;
|
||||
scaleF /= zoomFactor;
|
||||
if (transform.a && transform.d) {
|
||||
scaleX = scaleF / transform.a;
|
||||
scaleY = scaleF / transform.d;
|
||||
ctx.translate(pt.x,pt.y);
|
||||
ctx.scale(scaleX, scaleY);
|
||||
ctx.translate(-pt.x, -pt.y);
|
||||
var toProgress = 1;
|
||||
if (model) {
|
||||
mdlInfo = GCODE.gCodeReader.getModelInfo();
|
||||
speeds = mdlInfo.speeds;
|
||||
speedsByLayer = mdlInfo.speedsByLayer;
|
||||
if (model[layerNum]) {
|
||||
toProgress = model[layerNum].length;
|
||||
}
|
||||
} else {
|
||||
scaleX = 1;
|
||||
scaleY = 1;
|
||||
}
|
||||
|
||||
this.render(layerNum, 0, model[layerNum].length);
|
||||
applyOffsets(mdlInfo);
|
||||
applyZoom(mdlInfo);
|
||||
|
||||
this.render(layerNum, 0, toProgress);
|
||||
},
|
||||
refresh: function(layerNum) {
|
||||
if (!layerNum) layerNum = layerNumStore;
|
||||
|
|
|
|||
|
|
@ -7,8 +7,6 @@
|
|||
var GCODE = {};
|
||||
|
||||
GCODE.ui = (function(){
|
||||
var gCodeLines = {first: 0, last: 0};
|
||||
|
||||
var uiOptions = {
|
||||
container: undefined,
|
||||
toolOffsets: undefined,
|
||||
|
|
@ -28,7 +26,6 @@ GCODE.ui = (function(){
|
|||
if (!onlyInfo) {
|
||||
var segmentCount = GCODE.renderer.getLayerNumSegments(layerNum);
|
||||
GCODE.renderer.render(layerNum, 0, segmentCount - 1);
|
||||
gCodeLines = GCODE.gCodeReader.getGCodeLines(layerNum, 0, segmentCount - 1);
|
||||
}
|
||||
|
||||
if (uiOptions["onLayerSelected"]) {
|
||||
|
|
@ -45,7 +42,6 @@ GCODE.ui = (function(){
|
|||
};
|
||||
|
||||
var switchCommands = function(layerNum, first, last) {
|
||||
gCodeLines = GCODE.gCodeReader.getGCodeLines(layerNum, first, last);
|
||||
GCODE.renderer.render(layerNum, first, last);
|
||||
};
|
||||
|
||||
|
|
@ -166,11 +162,16 @@ GCODE.ui = (function(){
|
|||
},
|
||||
|
||||
clear: function() {
|
||||
GCODE.renderer.clear();
|
||||
GCODE.gCodeReader.clear();
|
||||
delete this.worker;
|
||||
GCODE.renderer.clear();
|
||||
|
||||
this.init(uiOptions);
|
||||
setProgress("", 0);
|
||||
if (uiOptions["onLayerSelected"]) {
|
||||
uiOptions.onLayerSelected();
|
||||
}
|
||||
if (uiOptions["onModelLoaded"]) {
|
||||
uiOptions.onModelLoaded();
|
||||
}
|
||||
},
|
||||
|
||||
updateLayerInfo: function(layerNum){
|
||||
|
|
@ -185,12 +186,10 @@ GCODE.ui = (function(){
|
|||
|
||||
changeSelectedLayer: function(newLayerNum) {
|
||||
switchLayer(newLayerNum);
|
||||
if (callback) callback(newLayerNum, segmentCount);
|
||||
},
|
||||
|
||||
changeSelectedCommands: function(layerNum, first, last) {
|
||||
switchCommands(layerNum, first, last);
|
||||
if (callback) callback(first, last);
|
||||
}
|
||||
}
|
||||
}());
|
||||
|
|
@ -28,6 +28,15 @@ function GcodeViewModel(loginStateViewModel, settingsViewModel) {
|
|||
self.ui_modelInfo = ko.observable("");
|
||||
self.ui_layerInfo = ko.observable("");
|
||||
|
||||
self.enableReload = ko.observable(false);
|
||||
|
||||
self.waitForApproval = ko.observable(false);
|
||||
self.selectedFile = {
|
||||
name: ko.observable(undefined),
|
||||
date: ko.observable(undefined),
|
||||
size: ko.observable(undefined)
|
||||
};
|
||||
|
||||
self.renderer_centerModel = ko.observable(false);
|
||||
self.renderer_centerViewport = ko.observable(false);
|
||||
self.renderer_zoomOnModel = ko.observable(false);
|
||||
|
|
@ -116,6 +125,9 @@ function GcodeViewModel(loginStateViewModel, settingsViewModel) {
|
|||
self.layerSlider = undefined;
|
||||
self.layerCommandSlider = undefined;
|
||||
|
||||
self.currentLayer = undefined;
|
||||
self.currentCommand = undefined;
|
||||
|
||||
self.initialize = function() {
|
||||
self._configureLayerSlider();
|
||||
self._configureLayerCommandSlider();
|
||||
|
|
@ -136,13 +148,16 @@ function GcodeViewModel(loginStateViewModel, settingsViewModel) {
|
|||
|
||||
self.reinitialize = function() {
|
||||
self.enabled = false;
|
||||
self.enableReload(false);
|
||||
self.loadedFilename = undefined;
|
||||
self.loadedFileDate = undefined;
|
||||
GCODE.ui.clear();
|
||||
|
||||
self.initialize();
|
||||
self.clear();
|
||||
};
|
||||
|
||||
self.clear = function() {
|
||||
GCODE.ui.clear();
|
||||
}
|
||||
|
||||
self._configureLayerSlider = function() {
|
||||
self.layerSlider = $("#gcode_slider_layers").slider({
|
||||
id: "gcode_layer_slider",
|
||||
|
|
@ -172,6 +187,7 @@ function GcodeViewModel(loginStateViewModel, settingsViewModel) {
|
|||
};
|
||||
|
||||
self.loadFile = function(filename, date){
|
||||
self.enableReload(false);
|
||||
if (self.status == "idle" && self.errorCount < 3) {
|
||||
self.status = "request";
|
||||
$.ajax({
|
||||
|
|
@ -184,13 +200,14 @@ function GcodeViewModel(loginStateViewModel, settingsViewModel) {
|
|||
self.loadedFilename = filename;
|
||||
self.loadedFileDate = date;
|
||||
self.status = "idle";
|
||||
self.enableReload(true);
|
||||
}
|
||||
},
|
||||
error: function() {
|
||||
self.status = "idle";
|
||||
self.errorCount++;
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -206,7 +223,8 @@ function GcodeViewModel(loginStateViewModel, settingsViewModel) {
|
|||
self.layerCommandSlider.slider("disable");
|
||||
};
|
||||
|
||||
self.refresh = function() {
|
||||
self.reload = function() {
|
||||
if (!self.enableReload()) return;
|
||||
self.loadFile(self.loadedFilename, self.loadedFileDate);
|
||||
};
|
||||
|
||||
|
|
@ -219,19 +237,25 @@ function GcodeViewModel(loginStateViewModel, settingsViewModel) {
|
|||
};
|
||||
|
||||
self._processData = function(data) {
|
||||
if (!self.enabled) return;
|
||||
if (!data.job.file || !data.job.file.name && (self.loadedFilename || self.loadedFileDate)) {
|
||||
self.waitForApproval(false);
|
||||
|
||||
self.loadedFilename = undefined;
|
||||
self.loadedFileDate = undefined;
|
||||
GCODE.renderer.clear();
|
||||
self.selectedFile.name(undefined);
|
||||
self.selectedFile.date(undefined);
|
||||
self.selectedFile.size(undefined);
|
||||
|
||||
self.clear();
|
||||
return;
|
||||
}
|
||||
if (!self.enabled) return;
|
||||
self.currentlyPrinting = data.state.flags && (data.state.flags.printing || data.state.flags.paused);
|
||||
|
||||
if(self.loadedFilename
|
||||
&& self.loadedFilename == data.job.file.name
|
||||
&& self.loadedFileDate == data.job.file.date) {
|
||||
if (self.currentlyPrinting && self.renderer_syncProgress()) {
|
||||
if (self.currentlyPrinting && self.renderer_syncProgress() && !self.waitForApproval()) {
|
||||
var cmdIndex = GCODE.gCodeReader.getCmdIndexForPercentage(data.progress.completion);
|
||||
if(cmdIndex){
|
||||
GCODE.renderer.render(cmdIndex.layer, 0, cmdIndex.cmd);
|
||||
|
|
@ -242,11 +266,31 @@ function GcodeViewModel(loginStateViewModel, settingsViewModel) {
|
|||
}
|
||||
}
|
||||
self.errorCount = 0
|
||||
} else if (data.job.file.name && data.job.file.origin != "sdcard") {
|
||||
self.loadFile(data.job.file.name, data.job.file.date);
|
||||
} else {
|
||||
self.clear();
|
||||
if (data.job.file.name && data.job.file.origin != "sdcard"
|
||||
&& (!self.waitForApproval() || (self.selectedFile.name() != data.job.file.name || self.selectedFile.date() != data.job.file.date))) {
|
||||
self.selectedFile.name(data.job.file.name);
|
||||
self.selectedFile.date(data.job.file.date);
|
||||
self.selectedFile.size(data.job.file.size);
|
||||
|
||||
if (data.job.file.size > CONFIG_GCODE_SIZE_THRESHOLD || ($.browser.mobile && data.job.file.size > CONFIG_GCODE_MOBILE_SIZE_THRESHOLD)) {
|
||||
self.waitForApproval(true);
|
||||
self.loadedFilename = undefined;
|
||||
self.loadedFileDate = undefined;
|
||||
} else {
|
||||
self.waitForApproval(false);
|
||||
self.loadFile(data.job.file.name, data.job.file.date);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
self.approveLargeFile = function() {
|
||||
self.waitForApproval(false);
|
||||
self.loadFile(self.selectedFile.name(), self.selectedFile.date());
|
||||
}
|
||||
|
||||
self._onProgress = function(type, percentage) {
|
||||
self.ui_progress_type(type);
|
||||
self.ui_progress_percentage(percentage);
|
||||
|
|
@ -258,6 +302,7 @@ function GcodeViewModel(loginStateViewModel, settingsViewModel) {
|
|||
self.layerSlider.slider("disable");
|
||||
self.layerSlider.slider("setMax", 1);
|
||||
self.layerSlider.slider("setValue", 0);
|
||||
self.currentLayer = 0;
|
||||
} else {
|
||||
var output = [];
|
||||
output.push("Model size is: " + model.width.toFixed(2) + "mm × " + model.depth.toFixed(2) + "mm × " + model.height.toFixed(2) + "mm");
|
||||
|
|
@ -286,6 +331,7 @@ function GcodeViewModel(loginStateViewModel, settingsViewModel) {
|
|||
self.layerCommandSlider.slider("disable");
|
||||
self.layerCommandSlider.slider("setMax", 1);
|
||||
self.layerCommandSlider.slider("setValue", [0, 1]);
|
||||
self.currentCommand = [0, 1];
|
||||
} else {
|
||||
var output = [];
|
||||
output.push("Layer number: " + layer.number);
|
||||
|
|
@ -312,6 +358,9 @@ function GcodeViewModel(loginStateViewModel, settingsViewModel) {
|
|||
if (self.currentlyPrinting && self.renderer_syncProgress()) self.renderer_syncProgress(false);
|
||||
|
||||
var value = event.value;
|
||||
if (self.currentLayer !== undefined && self.currentLayer == value) return;
|
||||
self.currentLayer = value;
|
||||
|
||||
GCODE.ui.changeSelectedLayer(value);
|
||||
};
|
||||
|
||||
|
|
@ -319,6 +368,9 @@ function GcodeViewModel(loginStateViewModel, settingsViewModel) {
|
|||
if (self.currentlyPrinting && self.renderer_syncProgress()) self.renderer_syncProgress(false);
|
||||
|
||||
var tuple = event.value;
|
||||
if (self.currentCommand !== undefined && self.currentCommand[0] == tuple[0] && self.currentCommand[1] == tuple[1]) return;
|
||||
self.currentCommand = tuple;
|
||||
|
||||
GCODE.ui.changeSelectedCommands(self.layerSlider.slider("getValue"), tuple[0], tuple[1]);
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,18 +7,18 @@
|
|||
<link rel="apple-touch-icon" sizes="114x114" href="{{ url_for('static', filename='img/apple-touch-icon-114x114.png') }}">
|
||||
<link rel="apple-touch-icon" sizes="144x144" href="{{ url_for('static', filename='img/apple-touch-icon-144x144.png') }}">
|
||||
|
||||
{% if stylesheet == "less" %}
|
||||
<link href="{{ url_for('static', filename='less/octoprint.less') }}" rel="stylesheet/less" type="text/css" media="screen">
|
||||
<script src="{{ url_for('static', filename='js/lib/less.min.js') }}" type="text/javascript"></script>
|
||||
{% else %}
|
||||
<link href="{{ url_for('static', filename='css/octoprint.css') }}" rel="stylesheet" type="text/css" media="screen">
|
||||
{% endif %}
|
||||
<link href="{{ url_for('static', filename='css/bootstrap.min.css') }}" rel="stylesheet" media="screen">
|
||||
<link href="{{ url_for('static', filename='css/bootstrap-modal.css') }}" rel="stylesheet" media="screen">
|
||||
<link href="{{ url_for('static', filename='css/bootstrap-slider.css') }}" rel="stylesheet" media="screen">
|
||||
<link href="{{ url_for('static', filename='css/font-awesome.min.css') }}" rel="stylesheet" media="screen">
|
||||
<link href="{{ url_for('static', filename='css/jquery.fileupload-ui.css') }}" rel="stylesheet" media="screen">
|
||||
<link href="{{ url_for('static', filename='css/jquery.pnotify.default.css') }}" rel="stylesheet" media="screen">
|
||||
{% if stylesheet == "less" %}
|
||||
<link href="{{ url_for('static', filename='less/octoprint.less') }}" rel="stylesheet/less" type="text/css" media="screen">
|
||||
<script src="{{ url_for('static', filename='js/lib/less.min.js') }}" type="text/javascript"></script>
|
||||
{% else %}
|
||||
<link href="{{ url_for('static', filename='css/octoprint.css') }}" rel="stylesheet" type="text/css" media="screen">
|
||||
{% endif %}
|
||||
|
||||
<script lang="javascript">
|
||||
var BASEURL = "{{ url_for('index') }}";
|
||||
|
|
@ -33,6 +33,8 @@
|
|||
var CONFIG_SD_SUPPORT = {% if enableSdSupport -%} true; {% else %} false; {%- endif %}
|
||||
var CONFIG_FIRST_RUN = {% if firstRun -%} true; {% else %} false; {%- endif %}
|
||||
var CONFIG_TEMPERATURE_GRAPH = {% if enableTemperatureGraph -%} true; {% else %} false; {%- endif %}
|
||||
var CONFIG_GCODE_SIZE_THRESHOLD = {{ gcodeThreshold }};
|
||||
var CONFIG_GCODE_MOBILE_SIZE_THRESHOLD = {{ gcodeMobileThreshold }};
|
||||
|
||||
var SOCKJS_URI = window.location.protocol.slice(0, -1) + "://" + (window.document ? window.document.domain : window.location.hostname) + ":" + window.location.port + "/sockjs";
|
||||
var SOCKJS_DEBUG = {% if debug -%} true; {% else %} false; {%- endif %}
|
||||
|
|
@ -425,64 +427,80 @@
|
|||
</div>
|
||||
{% if enableGCodeVisualizer %}
|
||||
<div class="tab-pane" id="gcode">
|
||||
<input id="gcode_slider_layers" type="text">
|
||||
<canvas id="gcode_canvas" width="568" height="568"></canvas>
|
||||
<input id="gcode_slider_commands" type="text" style="width: 554px">
|
||||
<div data-bind="visible: !waitForApproval()">
|
||||
<input id="gcode_slider_layers" type="text">
|
||||
<canvas id="gcode_canvas" width="568" height="568"></canvas>
|
||||
<input id="gcode_slider_commands" type="text" style="width: 554px">
|
||||
|
||||
<div class="progress" >
|
||||
<div class="bar" style="width: 0%;" data-bind="text: ui_progress_text, style: { width: ui_progress_percentage() + '%' }"></div>
|
||||
<div class="progress" >
|
||||
<div class="bar" style="width: 0%;" data-bind="text: ui_progress_text, style: { width: ui_progress_percentage() + '%' }"></div>
|
||||
</div>
|
||||
|
||||
<div class="row-fluid">
|
||||
<div class="span7">
|
||||
<h1>Model info</h1>
|
||||
<p data-bind="html: ui_modelInfo"></p>
|
||||
|
||||
<h1>Layer info</h1>
|
||||
<p data-bind="html: ui_layerInfo"></p>
|
||||
</div>
|
||||
<div class="span5">
|
||||
<h1>Renderer options</h1>
|
||||
|
||||
<p>
|
||||
<label class="checkbox">
|
||||
<input type="checkbox" data-bind="checked: renderer_syncProgress">Sync with job progress
|
||||
</label>
|
||||
</p>
|
||||
<p>
|
||||
<label class="checkbox">
|
||||
<input type="checkbox" data-bind="checked: renderer_centerViewport">Center viewport on model
|
||||
</label>
|
||||
<label class="checkbox">
|
||||
<input type="checkbox" data-bind="checked: renderer_zoomOnModel">Zoom in on model
|
||||
</label>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<label class="checkbox">
|
||||
<input type="checkbox" data-bind="checked: renderer_showMoves">Show moves
|
||||
</label>
|
||||
<label class="checkbox">
|
||||
<input type="checkbox" data-bind="checked: renderer_showRetracts">Show retracts
|
||||
</label>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<label class="checkbox">
|
||||
<input type="checkbox" data-bind="checked: renderer_showPrevious">Also show previous layer
|
||||
</label>
|
||||
<label class="checkbox">
|
||||
<input type="checkbox" data-bind="checked: renderer_showNext">Also show next layer
|
||||
</label>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<button class="btn btn-block" data-bind="click: reload, enable: enableReload">Reload</button>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div data-bind="visible: waitForApproval">
|
||||
<h1>Warning</h1>
|
||||
|
||||
<div class="row-fluid">
|
||||
<div class="span7">
|
||||
<h1>Model info</h1>
|
||||
<p data-bind="html: ui_modelInfo"></p>
|
||||
<p>
|
||||
You've selected <strong data-bind="text: selectedFile.name"></strong> for printing which has a size of
|
||||
<strong data-bind="text: formatSize(selectedFile.size())"></strong>. Depending on your machine this
|
||||
might be too large for rendering and cause your browser to become unresponsive or crash.
|
||||
</p>
|
||||
|
||||
<h1>Layer info</h1>
|
||||
<p data-bind="html: ui_layerInfo"></p>
|
||||
</div>
|
||||
<div class="span5">
|
||||
<h1>Renderer options</h1>
|
||||
<p>
|
||||
Are you sure you want to visualize this file nevertheless?
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<label class="checkbox">
|
||||
<input type="checkbox" data-bind="checked: renderer_syncProgress">Sync with job progress
|
||||
</label>
|
||||
</p>
|
||||
<p>
|
||||
<label class="checkbox">
|
||||
<input type="checkbox" data-bind="checked: renderer_centerModel">Center model on bed
|
||||
</label>
|
||||
<label class="checkbox">
|
||||
<input type="checkbox" data-bind="checked: renderer_centerViewport">Center viewport on model
|
||||
</label>
|
||||
<label class="checkbox">
|
||||
<input type="checkbox" data-bind="checked: renderer_zoomOnModel">Zoom in on model
|
||||
</label>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<label class="checkbox">
|
||||
<input type="checkbox" data-bind="checked: renderer_showMoves">Show moves
|
||||
</label>
|
||||
<label class="checkbox">
|
||||
<input type="checkbox" data-bind="checked: renderer_showRetracts">Show retracts
|
||||
</label>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<label class="checkbox">
|
||||
<input type="checkbox" data-bind="checked: renderer_showPrevious">Also show previous layer
|
||||
</label>
|
||||
<label class="checkbox">
|
||||
<input type="checkbox" data-bind="checked: renderer_showNext">Also show next layer
|
||||
</label>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<button class="btn btn-block" data-bind="click: refresh">Refresh</button>
|
||||
</p>
|
||||
</div>
|
||||
<button class="btn btn-warning btn-block" data-bind="click: approveLargeFile">
|
||||
Yes, please visualize <span data-bind="text: selectedFile.name"></span> regardless of its size
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
|
@ -608,6 +626,7 @@
|
|||
<script type="text/javascript" src="{{ url_for('static', filename='js/lib/sockjs-0.3.4.min.js') }}"></script>
|
||||
<script type="text/javascript" src="{{ url_for('static', filename='js/lib/moment.min.js') }}"></script>
|
||||
<script type="text/javascript" src="{{ url_for('static', filename='js/lib/pusher.color.min.js') }}"></script>
|
||||
<script type="text/javascript" src="{{ url_for('static', filename='js/lib/detectmobilebrowser.js') }}"></script>
|
||||
|
||||
<!-- Include OctoPrint files -->
|
||||
<!-- TODO: merge/minimize in the future -->
|
||||
|
|
|
|||
Loading…
Reference in a new issue