Integrated eslint and reformatted all of the JS/TS

This commit is contained in:
David Carley
2022-09-02 00:04:31 +00:00
parent 868258cfa7
commit c6a3732750
49 changed files with 8535 additions and 5675 deletions

82
.eslintrc.yml Normal file
View File

@@ -0,0 +1,82 @@
env:
es2021: true
node: true
browser: true
extends:
- eslint:recommended
- plugin:@typescript-eslint/recommended
overrides: []
parser: "@typescript-eslint/parser"
parserOptions:
ecmaVersion: latest
sourceType: module
plugins:
- "@typescript-eslint"
globals:
Vue: readonly
THREE: readonly
SvelteComponents: readonly
$: readonly
Clusterize: readonly
SockJS: readonly
rules:
indent:
- off
"@typescript-eslint/indent":
- error
- 4
linebreak-style:
- error
- unix
quotes:
- error
- double
- allowTemplateLiterals: true
avoidEscape: true
semi:
- error
- always
"@typescript-eslint/no-explicit-any":
- off
"@typescript-eslint/no-unused-vars":
- error
- argsIgnorePattern: _.*
no-unused-vars:
- error
no-trailing-spaces:
- error
key-spacing:
- error
space-before-blocks:
- error
block-spacing:
- error
brace-style:
- error
curly:
- error
keyword-spacing:
- error
"@typescript-eslint/no-var-requires":
- off
no-multiple-empty-lines:
- error
- max: 1
func-call-spacing:
- error
- never
padding-line-between-statements:
- error
- blankLine: always
prev: function
next: function
no-var:
- error
no-unused-expressions:
- error
prefer-const:
- error
prefer-template:
- error
template-curly-spacing:
- error

2914
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -8,7 +8,14 @@
"postinstall": "cd src/svelte-components && npm i"
},
"dependencies": {
"@typescript-eslint/eslint-plugin": "^5.36.1",
"@typescript-eslint/parser": "^5.36.1",
"browserify": "^17.0.0",
"eslint": "^8.23.0",
"eslint-config-standard-with-typescript": "^22.0.0",
"eslint-plugin-import": "^2.26.0",
"eslint-plugin-n": "^15.2.5",
"eslint-plugin-promise": "^6.0.1",
"jshint": "^2.13.4",
"jstransformer-escape-html": "^1.1.0",
"jstransformer-scss": "^2.0.0",

View File

@@ -1,32 +1,6 @@
/******************************************************************************\
This file is part of the Buildbotics firmware.
Copyright (c) 2015 - 2018, Buildbotics LLC
All rights reserved.
This file ("the software") is free software: you can redistribute it
and/or modify it under the terms of the GNU General Public License,
version 2 as published by the Free Software Foundation. You should
have received a copy of the GNU General Public License, version 2
along with the software. If not, see <http://www.gnu.org/licenses/>.
The software is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the software. If not, see
<http://www.gnu.org/licenses/>.
For information regarding this software email:
"Joseph Coffland" <joseph@buildbotics.com>
\******************************************************************************/
'use strict'
"use strict";
const api = require("./api");
const merge = require("lodash.merge");
const config_defaults = require("../resources/onefinity_defaults.json");
@@ -38,34 +12,32 @@ const variant_defaults = {
journeyman_x50: require("../resources/onefinity_journeyman_x50_defaults.json")
};
const api = require('./api');
module.exports = {
template: '#admin-general-view-template',
props: ['config', 'state'],
template: "#admin-general-view-template",
props: ["config", "state"],
data: function () {
return {
confirmReset: false,
autoCheckUpgrade: true,
reset_variant: ''
}
reset_variant: ""
};
},
ready: function () {
this.autoCheckUpgrade = this.config.admin['auto-check-upgrade']
this.autoCheckUpgrade = this.config.admin["auto-check-upgrade"];
},
methods: {
backup: function () {
document.getElementById('download-target').src = '/api/config/download';
document.getElementById("download-target").src = "/api/config/download";
},
restore_config: function () {
// If we don't reset the form the browser may cache file if name is same
// even if contents have changed
$('.restore-config')[0].reset();
$('.restore-config input').click();
$(".restore-config")[0].reset();
$(".restore-config input").click();
},
restore: function (e) {
@@ -85,13 +57,16 @@ module.exports = {
}
try {
await api.put('config/save', config);
this.$dispatch('update');
SvelteComponents.showDialog("Message", { title: "Success", message: "Configuration restored" })
await api.put("config/save", config);
this.$dispatch("update");
SvelteComponents.showDialog("Message", {
title: "Success",
message: "Configuration restored"
});
} catch (error) {
api.alert('Restore failed', error);
}
api.alert("Restore failed", error);
}
};
fileReader.readAsText(files[0]);
},
@@ -104,40 +79,45 @@ module.exports = {
);
try {
await api.put('config/save', config)
await api.put("config/save", config);
this.confirmReset = false;
this.$dispatch('update');
SvelteComponents.showDialog("Message", { title: "Success", message: "Configuration restored" })
this.$dispatch("update");
SvelteComponents.showDialog("Message", {
title: "Success",
message: "Configuration restored"
});
} catch (err) {
api.alert('Restore failed');
console.error('Restore failed', err);
api.alert("Restore failed");
console.error("Restore failed", err);
}
},
check: function () {
this.$dispatch('check')
this.$dispatch("check");
},
upgrade: function () {
this.$dispatch('upgrade')
this.$dispatch("upgrade");
},
upload_firmware: function () {
// If we don't reset the form the browser may cache file if name is same
// even if contents have changed
$('.upload-firmware')[0].reset();
$('.upload-firmware input').click();
$(".upload-firmware")[0].reset();
$(".upload-firmware input").click();
},
upload: function (e) {
var files = e.target.files || e.dataTransfer.files;
if (!files.length) return;
this.$dispatch('upload', files[0]);
const files = e.target.files || e.dataTransfer.files;
if (!files.length) {
return;
}
this.$dispatch("upload", files[0]);
},
change_auto_check_upgrade: function () {
this.config.admin['auto-check-upgrade'] = this.autoCheckUpgrade;
this.$dispatch('config-changed');
this.config.admin["auto-check-upgrade"] = this.autoCheckUpgrade;
this.$dispatch("config-changed");
}
}
}
};

View File

@@ -1,77 +1,37 @@
'use strict'
"use strict";
function api_cb(method, url, data, config) {
config = $.extend({
type: method,
url: '/api/' + url,
dataType: 'json',
cache: false
}, config);
if (typeof data == 'object') {
config.data = JSON.stringify(data);
config.contentType = 'application/json; charset=utf-8';
}
var d = $.Deferred();
$.ajax(config).success(function (data, status, xhr) {
d.resolve(data, status, xhr);
}).error(function (xhr, status, error) {
var text = xhr.responseText;
try {text = $.parseJSON(xhr.responseText)} catch(e) {}
if (!text) text = error;
d.reject(text, xhr, status, error);
console.debug('API Error: ' + url + ': ' + text);
async function callApi(method, url, body) {
try {
const response = await fetch(`/api/${url}`, {
method,
headers: {
"Content-Type": "application/json"
},
body
});
return d.promise();
}
if (response.ok) {
return response.json();
}
throw new Error(await response.text());
} catch (error) {
console.debug(`API Error: ${url}: ${error}`);
throw error;
}
}
module.exports = {
get: function (url, config) {
return api_cb('GET', url, undefined, config);
get: function (url) {
return callApi("GET", url);
},
put: function(url, data, config) {
return api_cb('PUT', url, data, config);
put: function(url, body = undefined) {
return callApi("PUT", url, body);
},
post: function(url, data, config) {
return api_cb('POST', url, data, config);
},
upload: function(url, data, config) {
config = $.extend({
processData: false,
contentType: false,
cache: false,
data: data
}, config);
return api_cb('PUT', url, undefined, config);
},
'delete': function (url, config) {
return api_cb('DELETE', url, undefined, config);
},
alert: function (msg, error) {
if (typeof error != 'undefined') {
if (typeof error.message != 'undefined')
msg += '\n' + error.message;
else msg += '\n' + JSON.stringify(error);
delete: function (url) {
return callApi("DELETE", url);
}
alert(msg);
}
}
};

View File

@@ -23,8 +23,7 @@ function is_newer_version(current, latest) {
const patch = latestParts[3] - currentParts[3];
// If current is a pre-release, and latest is a release
const betaToRelease =
latestParts[4].length === 0 && currentParts[4].length > 0;
const betaToRelease = latestParts[4].length === 0 && currentParts[4].length > 0;
switch (true) {
case major > 0:
@@ -41,24 +40,36 @@ function is_newer_version(current, latest) {
function is_object(o) {
return o !== null && typeof o == "object";
}
function is_array(o) {
return Array.isArray(o);
}
function update_array(dst, src) {
while (dst.length) dst.pop();
for (var i = 0; i < src.length; i++) Vue.set(dst, i, src[i]);
while (dst.length) {
dst.pop();
}
for (let i = 0; i < src.length; i++) {
Vue.set(dst, i, src[i]);
}
}
function hasOwnProperty(obj, key) {
return Object.prototype.hasOwnProperty.call(obj, key);
}
function update_object(dst, src, remove) {
var props, index, key, value;
let props, index, key, value;
if (remove) {
props = Object.getOwnPropertyNames(dst);
for (index in props) {
key = props[index];
if (!src.hasOwnProperty(key)) Vue.delete(dst, key);
if (!hasOwnProperty(src, key)) {
Vue.delete(dst, key);
}
}
}
@@ -67,11 +78,13 @@ function update_object(dst, src, remove) {
key = props[index];
value = src[key];
if (is_array(value) && dst.hasOwnProperty(key) && is_array(dst[key]))
if (is_array(value) && hasOwnProperty(dst, key) && is_array(dst[key])) {
update_array(dst[key], value);
else if (is_object(value) && dst.hasOwnProperty(key) && is_object(dst[key]))
} else if (is_object(value) && hasOwnProperty(dst, key) && is_object(dst[key])) {
update_object(dst[key], value, remove);
else Vue.set(dst, key, value);
} else {
Vue.set(dst, key, value);
}
}
}
@@ -181,8 +194,9 @@ module.exports = new Vue({
error: function (msg) {
// Honor user error blocking
if (Date.now() - this.errorTimeoutStart < this.errorTimeout * 1000)
if (Date.now() - this.errorTimeoutStart < this.errorTimeout * 1000) {
return;
}
// Wait at least 1 sec to pop up repeated errors
if (1 < msg.repeat && Date.now() - msg.ts < 1000) {
@@ -225,9 +239,12 @@ module.exports = new Vue({
this.errorShow = false;
},
toggle_video: function (e) {
if (this.video_size == "small") this.video_size = "large";
else if (this.video_size == "large") this.video_size = "small";
toggle_video: function () {
if (this.video_size == "small") {
this.video_size = "large";
} else if (this.video_size == "large") {
this.video_size = "small";
}
cookie.set("video-size", this.video_size);
},
@@ -238,8 +255,11 @@ module.exports = new Vue({
},
estop: function () {
if (this.state.xx == "ESTOPPED") api.put("clear");
else api.put("estop");
if (this.state.xx == "ESTOPPED") {
api.put("clear");
} else {
api.put("estop");
}
},
upgrade_confirmed: async function () {
@@ -302,8 +322,10 @@ module.exports = new Vue({
if (!this.checkedUpgrade) {
this.checkedUpgrade = true;
var check = this.config.admin["auto-check-upgrade"];
if (typeof check == "undefined" || check) this.$emit("check");
const check = this.config.admin["auto-check-upgrade"];
if (typeof check == "undefined" || check) {
this.$emit("check");
}
}
SvelteComponents.handleConfigUpdate(this.config);
@@ -328,10 +350,7 @@ module.exports = new Vue({
if (typeof this.sid == "undefined") {
this.sid = e.data.sid;
} else if (this.sid != e.data.sid) {
if (
typeof this.hostname !== "undefined" &&
location.hostname !== "localhost"
) {
if (this.hostname && location.hostname !== "localhost") {
location.hostname = this.hostname;
}
@@ -362,16 +381,18 @@ module.exports = new Vue({
},
parse_hash: function () {
var hash = location.hash.substr(1);
const hash = location.hash.substr(1);
if (!hash.trim().length) {
location.hash = "control";
return;
}
var parts = hash.split(":");
const parts = hash.split(":");
if (parts.length == 2) this.index = parts[1];
if (parts.length == 2) {
this.index = parts[1];
}
this.currentView = parts[0];
},
@@ -402,12 +423,17 @@ module.exports = new Vue({
},
close_messages: function (action) {
if (action == "stop") api.put("stop");
if (action == "continue") api.put("unpause");
if (action == "stop") {
api.put("stop");
}
if (action == "continue") {
api.put("unpause");
}
// Acknowledge messages
if (this.state.messages.length) {
var id = this.state.messages.slice(-1)[0].id;
const id = this.state.messages.slice(-1)[0].id;
api.put("message/" + id + "/ack");
}
},

View File

@@ -1,65 +1,37 @@
/******************************************************************************\
This file is part of the Buildbotics firmware.
Copyright (c) 2015 - 2018, Buildbotics LLC
All rights reserved.
This file ("the software") is free software: you can redistribute it
and/or modify it under the terms of the GNU General Public License,
version 2 as published by the Free Software Foundation. You should
have received a copy of the GNU General Public License, version 2
along with the software. If not, see <http://www.gnu.org/licenses/>.
The software is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the software. If not, see
<http://www.gnu.org/licenses/>.
For information regarding this software email:
"Joseph Coffland" <joseph@buildbotics.com>
\******************************************************************************/
'use strict'
"use strict";
module.exports = {
template: '#axis-control-template',
props: ['axes', 'colors', 'enabled', 'adjust', 'step'],
template: "#axis-control-template",
props: ["axes", "colors", "enabled", "adjust", "step"],
methods: {
jog: function (axis, ring, direction) {
var value = direction * this.value(ring);
this.$dispatch(this.step ? 'step' : 'jog', this.axes[axis], value);
const value = direction * this.value(ring);
this.$dispatch(this.step ? "step" : "jog", this.axes[axis], value);
},
back2zero: function(axis0,axis1) {
this.$dispatch('back2zero',this.axes[axis0],this.axes[axis1])
this.$dispatch("back2zero",this.axes[axis0],this.axes[axis1]);
},
release: function (axis) {
if (!this.step) this.$dispatch('jog', this.axes[axis], 0)
if (!this.step) {
this.$dispatch("jog", this.axes[axis], 0);
}
},
value: function (ring) {
var adjust = [0.01, 0.1, 1][this.adjust];
if (this.step) return adjust * [0.1, 1, 10, 100][ring];
const adjust = [0.01, 0.1, 1][this.adjust];
if (this.step) {
return adjust * [0.1, 1, 10, 100][ring];
}
return adjust * [0.1, 0.25, 0.5, 1][ring];
},
text: function (ring) {
var value = this.value(ring) * (this.step ? 1 : 100);
let value = this.value(ring) * (this.step ? 1 : 100);
value = parseFloat(value.toFixed(3));
return value + (this.step ? '' : '%');
return value + (this.step ? "" : "%");
}
}
}
};

View File

@@ -1,17 +1,40 @@
'use strict'
"use strict";
module.exports = {
props: ['state', 'config'],
props: ["state", "config"],
computed: {
metric: function () { this.$root.display_units === "METRIC" },
x: function () { return this._compute_axis('x') },
y: function () { return this._compute_axis('y') },
z: function () { return this._compute_axis('z') },
a: function () { return this._compute_axis('a') },
b: function () { return this._compute_axis('b') },
c: function () { return this._compute_axis('c') },
axes: function () { return this._compute_axes() }
metric: function () {
return this.$root.display_units === "METRIC";
},
x: function () {
return this._compute_axis("x");
},
y: function () {
return this._compute_axis("y");
},
z: function () {
return this._compute_axis("z");
},
a: function () {
return this._compute_axis("a");
},
b: function () {
return this._compute_axis("b");
},
c: function () {
return this._compute_axis("c");
},
axes: function () {
return this._compute_axes();
}
},
methods: {
@@ -22,98 +45,115 @@ module.exports = {
},
_length_str: function (value) {
return this._convert_length(value).toLocaleString() +
(this.metric ? ' mm' : ' in');
return this._convert_length(value).toLocaleString() + (this.metric ? " mm" : " in");
},
_compute_axis: function (axis) {
var abs = this.state[axis + 'p'] || 0;
var off = this.state['offset_' + axis];
var motor_id = this._get_motor_id(axis);
var motor = motor_id == -1 ? {} : this.config.motors[motor_id];
var enabled = typeof motor.enabled != 'undefined' && motor.enabled;
var homingMode = motor['homing-mode']
var homed = this.state[motor_id + 'homed'];
var min = this.state[motor_id + 'tn'];
var max = this.state[motor_id + 'tm'];
var dim = max - min;
var pathMin = this.state['path_min_' + axis];
var pathMax = this.state['path_max_' + axis];
var pathDim = pathMax - pathMin;
var under = pathMin + off < min;
var over = max < pathMax + off;
var klass = (homed ? 'homed' : 'unhomed') + ' axis-' + axis;
var state = 'UNHOMED';
var icon = 'question-circle';
var fault = this.state[motor_id + 'df'] & 0x1f;
var shutdown = this.state.power_shutdown;
var title;
var ticon = 'question-circle';
var tstate = 'NO FILE';
var toolmsg;
var tklass = (homed ? 'homed' : 'unhomed') + ' axis-' + axis;
const abs = this.state[`${axis}p`] || 0;
const off = this.state[`offset_${axis}`];
const motor_id = this._get_motor_id(axis);
const motor = motor_id == -1 ? {} : this.config.motors[motor_id];
const enabled = typeof motor.enabled != "undefined" && motor.enabled;
const homingMode = motor["homing-mode"];
const homed = this.state[`${motor_id}homed`];
const min = this.state[`${motor_id}tn`];
const max = this.state[`${motor_id}tm`];
const dim = max - min;
const pathMin = this.state[`path_min_${axis}`];
const pathMax = this.state[`path_max_${axis}`];
const pathDim = pathMax - pathMin;
const under = pathMin + off < min;
const over = max < pathMax + off;
let klass = `${homed ? "homed" : "unhomed"} axis-${axis}`;
let state = "UNHOMED";
let icon = "question-circle";
const fault = this.state[`${motor_id}df`] & 0x1f;
const shutdown = this.state.power_shutdown;
let title;
let ticon = "question-circle";
let tstate = "NO FILE";
let toolmsg;
let tklass = `${homed ? "homed" : "unhomed"} axis-${axis}`;
if (fault || shutdown) {
state = shutdown ? 'SHUTDOWN' : 'FAULT';
klass += ' error';
icon = 'exclamation-circle';
state = shutdown ? "SHUTDOWN" : "FAULT";
klass += " error";
icon = "exclamation-circle";
} else if (homed) {
state = 'HOMED';
icon = 'check-circle';
state = "HOMED";
icon = "check-circle";
}
if (0 < dim && dim < pathDim) {
tstate = 'NO FIT';
tklass += ' error';
ticon = 'ban';
tstate = "NO FIT";
tklass += " error";
ticon = "ban";
} else {
if (over || under) {
tstate = over ? 'OVER' : 'UNDER';
tklass += ' warn';
ticon = 'exclamation-circle';
tstate = over ? "OVER" : "UNDER";
tklass += " warn";
ticon = "exclamation-circle";
} else {
tstate = 'OK';
ticon = 'check-circle';
tstate = "OK";
ticon = "check-circle";
}
}
switch (state) {
case 'UNHOMED': title = 'Click the home button to home axis.'; break;
case 'HOMED': title = 'Axis successfuly homed.'; break;
case 'FAULT':
title = 'Motor driver fault. A potentially damaging electrical ' +
'condition was detected and the motor driver was shutdown. ' +
'Please power down the controller and check your motor cabling. ' +
'See the "Motor Faults" table on the "Indicators" tab for more ' +
'information.';
case "UNHOMED":
title = "Click the home button to home axis.";
break;
case 'SHUTDOWN':
title = 'Motor power fault. All motors in shutdown. ' +
'See the "Power Faults" table on the "Indicators" tab for more ' +
'information. Reboot controller to reset.';
case "HOMED":
title = "Axis successfuly homed.";
break;
case "FAULT":
title = [
`Motor driver fault. A potentially damaging electrical`,
`condition was detected and the motor driver was shutdown.`,
`Please power down the controller and check your motor cabling.`,
`See the "Motor Faults" table on the "Indicators" tab for more`,
`information.`,
].join(" ");
break;
case "SHUTDOWN":
title = [
`Motor power fault. All motors in shutdown.`,
`See the "Power Faults" table on the "Indicators" tab for more`,
`information. Reboot controller to reset.`
].join(" ");
break;
}
switch (tstate) {
case 'OVER':
toolmsg = 'Caution: The current tool path file would move ' +
this._length_str(pathMax + off - max) + ' above axis limit with the current offset.';
case "OVER":
toolmsg = [
`Caution: The current tool path file would move`,
`${this._length_str(pathMax + off - max)}`,
`above axis limit with the current offset.`
].join(" ");
break;
case 'UNDER':
toolmsg = 'Caution: The current tool path file would move ' +
this._length_str(min - pathMin - off) + ' below limit with the current offset.';
case "UNDER":
toolmsg = [
`Caution: The current tool path file would move`,
`${this._length_str(min - pathMin - off)}`,
`below limit with the current offset.`
].join(" ");
break;
case 'NO FIT':
toolmsg = 'Warning: The current tool path dimensions (' +
this._length_str(pathDim) + ') exceed axis dimensions (' +
this._length_str(dim) + ') by ' +
this._length_str(pathDim - dim) + '.';
case "NO FIT":
toolmsg = [
`Warning: The current tool path dimensions`,
`(${this._length_str(pathDim)}) exceed axis dimensions`,
`(${this._length_str(dim)}) by ${this._length_str(pathDim - dim)}.`
].join(" ");
break;
default:
toolmsg = 'Tool path ' + axis + ' dimensions OK.';
toolmsg = `Tool path ${axis} dimensions OK.`;
break;
}
@@ -139,44 +179,64 @@ module.exports = {
tstate: tstate,
toolmsg: toolmsg,
tklass: tklass
}
};
},
_get_motor_id: function (axis) {
for (var i = 0; i < this.config.motors.length; i++) {
var motor = this.config.motors[i];
if (motor.axis.toLowerCase() == axis) return i;
for (let i = 0; i < this.config.motors.length; i++) {
const motor = this.config.motors[i];
if (motor.axis.toLowerCase() == axis) {
return i;
}
}
return -1;
},
_compute_axes: function () {
var homed = false;
let homed = false;
for (var name of 'xyzabc') {
var axis = this[name];
for (const name of "xyzabc") {
const axis = this[name];
if (!axis.enabled) {
continue;
}
if (!axis.homed) {
homed = false; break;
}
if (!axis.enabled) continue
if (!axis.homed) { homed = false; break }
homed = true;
}
var error = false;
var warn = false;
let error = false;
let warn = false;
if (homed)
for (name of 'xyzabc') {
axis = this[name];
if (homed) {
for (const name of "xyzabc") {
const axis = this[name];
if (!axis.enabled) continue;
if (axis.klass.indexOf('error') != -1) error = true;
if (axis.klass.indexOf('warn') != -1) warn = true;
if (!axis.enabled) {
continue;
}
var klass = homed ? 'homed' : 'unhomed';
if (error) klass += ' error';
else if (warn) klass += ' warn';
if (axis.klass.indexOf("error") != -1) {
error = true;
}
if (axis.klass.indexOf("warn") != -1) {
warn = true;
}
}
}
let klass = homed ? "homed" : "unhomed";
if (error) {
klass += " error";
} else if (warn) {
klass += " warn";
}
if (!homed && this.ask_home) {
this.ask_home = false;
@@ -188,7 +248,7 @@ module.exports = {
return {
homed: homed,
klass: klass
};
}
}
}
}
};

View File

@@ -1,87 +1,72 @@
/******************************************************************************\
This file is part of the Buildbotics firmware.
Copyright (c) 2015 - 2018, Buildbotics LLC
All rights reserved.
This file ("the software") is free software: you can redistribute it
and/or modify it under the terms of the GNU General Public License,
version 2 as published by the Free Software Foundation. You should
have received a copy of the GNU General Public License, version 2
along with the software. If not, see <http://www.gnu.org/licenses/>.
The software is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the software. If not, see
<http://www.gnu.org/licenses/>.
For information regarding this software email:
"Joseph Coffland" <joseph@buildbotics.com>
\******************************************************************************/
'use strict'
"use strict";
function _msg_equal(a, b) {
return a.level == b.level && a.source == b.source && a.where == b.where &&
a.msg == b.msg;
return a.level == b.level
&& a.source == b.source
&& a.where == b.where
&&a.msg == b.msg;
}
// Shared among all instances
var messages = [];
const messages = [];
module.exports = {
template: '#console-template',
template: "#console-template",
data: function () {
return {messages: messages}
return {
messages
};
},
events: {
log: function (msg) {
// There may be multiple instances of this module so ignore messages
// that have already been processed.
if (msg.logged) return;
if (msg.logged) {
return;
}
msg.logged = true;
// Make sure we have a message level
msg.level = msg.level || 'info';
msg.level = msg.level || "info";
// Add to message log and count and collapse repeats
var repeat = messages.length && _msg_equal(msg, messages[0]);
if (repeat) messages[0].repeat++;
else {
const repeat = messages.length && _msg_equal(msg, messages[0]);
if (repeat) {
messages[0].repeat++;
} else {
msg.repeat = msg.repeat || 1;
messages.unshift(msg);
while (256 < messages.length) messages.pop();
while (256 < messages.length) {
messages.pop();
}
}
msg.ts = Date.now();
// Write message to browser console for debugging
var text = JSON.stringify(msg);
if (msg.level == 'error' || msg.level == 'critical') console.error(text);
else if (msg.level == 'warning') console.warn(text);
else if (msg.level == 'debug' && console.debug) console.debug(text);
else console.log(text);
const text = JSON.stringify(msg);
if (msg.level == "error" || msg.level == "critical") {
console.error(text);
} else if (msg.level == "warning") {
console.warn(text);
} else if (msg.level == "debug" && console.debug) {
console.debug(text);
} else {
console.log(text);
}
// Event on errors
if (msg.level == 'error' || msg.level == 'critical')
this.$dispatch('error', msg);
if (msg.level == "error" || msg.level == "critical") {
this.$dispatch("error", msg);
}
}
},
methods: {
clear: function () {messages.splice(0, messages.length);},
clear: function () {
messages.splice(0, messages.length);
},
}
}
};

View File

@@ -1,22 +1,22 @@
'use strict'
"use strict";
var api = require('./api');
var cookie = require('./cookie')('bbctrl-');
const api = require("./api");
const cookie = require("./cookie")("bbctrl-");
module.exports = {
template: '#control-view-template',
props: ['config', 'template', 'state'],
template: "#control-view-template",
props: ["config", "template", "state"],
data: function () {
return {
current_time: "",
mach_units: this.$root.state.metric ? "METRIC" : "IMPERIAL",
mdi: '',
mdi: "",
last_file: undefined,
last_file_time: undefined,
toolpath: {},
toolpath_progress: 0,
axes: 'xyzabc',
axes: "xyzabc",
history: [],
speed_override: 1,
feed_override: 1,
@@ -34,20 +34,20 @@ module.exports = {
large: 5,
}
},
jog_incr: localStorage.getItem("jog_incr") || 'small',
jog_step: cookie.get_bool('jog-step'),
jog_adjust: parseInt(cookie.get('jog-adjust', 2)),
jog_incr: localStorage.getItem("jog_incr") || "small",
jog_step: cookie.get_bool("jog-step"),
jog_adjust: parseInt(cookie.get("jog-adjust", 2)),
deleteGCode: false,
tab: 'auto',
tab: "auto",
ask_home: true,
showGcodeMessage: false
}
};
},
components: {
'axis-control': require('./axis-control'),
'path-viewer': require('./path-viewer'),
'gcode-viewer': require('./gcode-viewer')
"axis-control": require("./axis-control"),
"path-viewer": require("./path-viewer"),
"gcode-viewer": require("./gcode-viewer")
},
watch: {
@@ -55,31 +55,31 @@ module.exports = {
localStorage.setItem("jog_incr", value);
},
'state.metric': {
"state.metric": {
handler: function (metric) {
this.mach_units = metric
? 'METRIC'
: 'IMPERIAL';
? "METRIC"
: "IMPERIAL";
},
immediate: true
},
'state.line': function () {
if (this.mach_state != 'HOMING') {
this.$broadcast('gcode-line', this.state.line);
"state.line": function () {
if (this.mach_state != "HOMING") {
this.$broadcast("gcode-line", this.state.line);
}
},
'state.selected_time': function () {
"state.selected_time": function () {
this.load();
},
jog_step: function () {
cookie.set_bool('jog-step', this.jog_step);
cookie.set_bool("jog-step", this.jog_step);
},
jog_adjust: function () {
cookie.set('jog-adjust', this.jog_adjust);
cookie.set("jog-adjust", this.jog_adjust);
}
},
@@ -99,63 +99,61 @@ module.exports = {
},
mach_state: function () {
var cycle = this.state.cycle;
var state = this.state.xx;
const cycle = this.state.cycle;
const state = this.state.xx;
if (typeof cycle != 'undefined' && state != 'ESTOPPED' &&
(cycle == 'jogging' || cycle == 'homing')) {
if (state != "ESTOPPED" && (cycle == "jogging" || cycle == "homing")) {
return cycle.toUpperCase();
}
return state || ''
return state || "";
},
pause_reason: function () {
return this.state.pr
return this.state.pr;
},
is_running: function () {
return this.mach_state == 'RUNNING' || this.mach_state == 'HOMING';
return this.mach_state == "RUNNING" || this.mach_state == "HOMING";
},
is_stopping: function () {
return this.mach_state == 'STOPPING'
return this.mach_state == "STOPPING";
},
is_holding: function () {
return this.mach_state == 'HOLDING'
return this.mach_state == "HOLDING";
},
is_ready: function () {
return this.mach_state == 'READY'
return this.mach_state == "READY";
},
is_idle: function () {
return this.state.cycle == 'idle'
return this.state.cycle == "idle";
},
is_paused: function () {
return this.is_holding &&
(this.pause_reason == 'User pause' ||
this.pause_reason == 'Program pause')
return this.is_holding && (this.pause_reason == "User pause" || this.pause_reason == "Program pause");
},
can_mdi: function () {
return this.is_idle || this.state.cycle == 'mdi'
return this.is_idle || this.state.cycle == "mdi";
},
can_set_axis: function () {
return this.is_idle
return this.is_idle;
// TODO allow setting axis position during pause
return this.is_idle || this.is_paused
// return this.is_idle || this.is_paused;
},
message: function () {
if (this.mach_state == 'ESTOPPED') {
if (this.mach_state == "ESTOPPED") {
return this.state.er;
}
if (this.mach_state == 'HOLDING') {
if (this.mach_state == "HOLDING") {
return this.state.pr;
}
@@ -163,15 +161,15 @@ module.exports = {
return this.state.messages.slice(-1)[0].text;
}
return '';
return "";
},
highlight_state: function () {
return this.mach_state == 'ESTOPPED' || this.mach_state == 'HOLDING';
return this.mach_state == "ESTOPPED" || this.mach_state == "HOLDING";
},
plan_time: function () {
return this.state.plan_time
return this.state.plan_time;
},
plan_time_remaining: function () {
@@ -179,16 +177,16 @@ module.exports = {
return 0;
}
return this.toolpath.time - this.plan_time
return this.toolpath.time - this.plan_time;
},
eta: function () {
if (this.mach_state != 'RUNNING') {
return '';
if (this.mach_state != "RUNNING") {
return "";
}
var remaining = this.plan_time_remaining;
var d = new Date();
const remaining = this.plan_time_remaining;
const d = new Date();
d.setSeconds(d.getSeconds() + remaining);
return d.toLocaleString();
},
@@ -198,16 +196,16 @@ module.exports = {
return 0;
}
var p = this.plan_time / this.toolpath.time;
return p < 1 ? p : 1;
const p = this.plan_time / this.toolpath.time;
return Math.max(1, p);
}
},
events: {
jog: function (axis, power) {
var data = { ts: new Date().getTime() };
const data = { ts: new Date().getTime() };
data[axis] = power;
api.put('jog', data);
api.put("jog", data);
},
back2zero: function (axis0, axis1) {
@@ -243,19 +241,19 @@ module.exports = {
methods: {
getJogIncrStyle(value) {
const weight = `font-weight:${this.jog_incr === value ? 'bold' : 'normal'}`;
const weight = `font-weight:${this.jog_incr === value ? "bold" : "normal"}`;
const color = this.jog_incr === value ? "color:#0078e7" : "";
return [weight, color].join(';');
return [weight, color].join(";");
},
jog_fn: function (x_jog, y_jog, z_jog, a_jog) {
const amount = this.jog_incr_amounts[this.display_units][this.jog_incr];
var xcmd = "X" + x_jog * amount;
var ycmd = "Y" + y_jog * amount;
var zcmd = "Z" + z_jog * amount;
var acmd = "A" + a_jog * amount;
const xcmd = `X${x_jog * amount}`;
const ycmd = `Y${y_jog * amount}`;
const zcmd = `Z${z_jog * amount}`;
const acmd = `A${a_jog * amount}`;
this.send(`
G91
@@ -265,12 +263,12 @@ module.exports = {
},
send: function (msg) {
this.$dispatch('send', msg)
this.$dispatch("send", msg);
},
load: function () {
var file_time = this.state.selected_time;
var file = this.state.selected;
const file_time = this.state.selected_time;
const file = this.state.selected;
if (this.last_file == file && this.last_file_time == file_time) {
return;
}
@@ -278,8 +276,8 @@ module.exports = {
this.last_file = file;
this.last_file_time = file_time;
this.$broadcast('gcode-load', file);
this.$broadcast('gcode-line', this.state.line);
this.$broadcast("gcode-load", file);
this.$broadcast("gcode-line", this.state.line);
this.toolpath_progress = 0;
this.load_toolpath(file, file_time);
},
@@ -297,8 +295,8 @@ module.exports = {
const toolpath = await api.get(`path/${file}`);
this.toolpath_progress = toolpath.progress;
if (toolpath.progress === 1 || typeof toolpath.progress == 'undefined') {
this.showGcodeMessage = false
if (toolpath.progress === 1 || typeof toolpath.progress == "undefined") {
this.showGcodeMessage = false;
if (toolpath.bounds) {
toolpath.filename = file;
@@ -306,9 +304,9 @@ module.exports = {
this.toolpath = toolpath;
const state = this.$root.state;
for (let axis of 'xyzabc') {
Vue.set(state, 'path_min_' + axis, toolpath.bounds.min[axis]);
Vue.set(state, 'path_max_' + axis, toolpath.bounds.max[axis]);
for (const axis of "xyzabc") {
Vue.set(state, `path_min_${axis}`, toolpath.bounds.min[axis]);
Vue.set(state, `path_max_${axis}`, toolpath.bounds.max[axis]);
}
}
}
@@ -322,13 +320,13 @@ module.exports = {
this.history.unshift(this.mdi);
}
this.mdi = '';
this.mdi = "";
},
mdi_start_pause: function () {
if (this.state.xx == 'RUNNING') {
if (this.state.xx == "RUNNING") {
this.pause();
} else if (this.state.xx == 'STOPPING' || this.state.xx == 'HOLDING') {
} else if (this.state.xx == "STOPPING" || this.state.xx == "HOLDING") {
this.unpause();
} else {
this.submit_mdi();
@@ -339,11 +337,11 @@ module.exports = {
this.mdi = this.history[index];
},
open: function (e) {
open: function () {
// If we don't reset the form the browser may cache file if name is same
// even if contents have changed
$('.gcode-file-input')[0].reset();
$('.gcode-file-input input').click();
$(".gcode-file-input")[0].reset();
$(".gcode-file-input input").click();
},
upload: async function (e) {
@@ -371,42 +369,42 @@ module.exports = {
file,
onComplete: () => {
this.last_file_time = undefined; // Force reload
this.$broadcast('gcode-reload', file.name);
this.$broadcast("gcode-reload", file.name);
}
});
},
delete_current: function () {
if (this.state.selected) {
api.delete('file/' + this.state.selected);
api.delete(`file/${this.state.selected}`);
}
this.deleteGCode = false;
},
delete_all: function () {
api.delete('file');
api.delete("file");
this.deleteGCode = false;
},
home: function (axis) {
this.ask_home = false;
if (typeof axis == 'undefined') {
api.put('home');
} else if (this[axis].homingMode != 'manual') {
api.put('home/' + axis);
if (typeof axis == "undefined") {
api.put("home");
} else if (this[axis].homingMode != "manual") {
api.put(`home/${axis}`);
} else {
SvelteComponents.showDialog("ManualHomeAxis", { axis });
}
},
set_home: function (axis, position) {
api.put('home/' + axis + '/set', { position: parseFloat(position) });
api.put(`home/${axis}/set`, { position: parseFloat(position) });
},
unhome: function (axis) {
api.put('home/' + axis + '/clear');
api.put(`home/${axis}/clear`);
},
show_set_position: function (axis) {
@@ -422,11 +420,11 @@ module.exports = {
},
set_position: function (axis, position) {
api.put('position/' + axis, { 'position': parseFloat(position) });
api.put(`position/${axis}`, { "position": parseFloat(position) });
},
zero_all: function () {
for (var axis of 'xyzabc') {
for (const axis of "xyzabc") {
if (this[axis].enabled) {
this.zero(axis);
}
@@ -434,7 +432,7 @@ module.exports = {
},
zero: function (axis) {
if (typeof axis == 'undefined') {
if (typeof axis == "undefined") {
this.zero_all();
} else {
this.set_position(axis, 0);
@@ -442,9 +440,9 @@ module.exports = {
},
start_pause: function () {
if (this.state.xx == 'RUNNING') {
if (this.state.xx == "RUNNING") {
this.pause();
} else if (this.state.xx == 'STOPPING' || this.state.xx == 'HOLDING') {
} else if (this.state.xx == "STOPPING" || this.state.xx == "HOLDING") {
this.unpause();
} else {
this.start();
@@ -452,45 +450,45 @@ module.exports = {
},
start: function () {
api.put('start')
api.put("start");
},
pause: function () {
api.put('pause')
api.put("pause");
},
unpause: function () {
api.put('unpause')
api.put("unpause");
},
optional_pause: function () {
api.put('pause/optional')
api.put("pause/optional");
},
stop: function () {
api.put('stop')
api.put("stop");
},
step: function () {
api.put('step')
api.put("step");
},
override_feed: function () {
api.put('override/feed/' + this.feed_override)
api.put(`override/feed/${this.feed_override}`);
},
override_speed: function () {
api.put('override/speed/' + this.speed_override)
api.put(`override/speed/${this.speed_override}`);
},
current: function (axis, value) {
var x = value / 32.0;
if (this.state[axis + 'pl'] == x) {
const x = value / 32.0;
if (this.state[`${axis}pl`] == x) {
return;
}
var data = {};
data[axis + 'pl'] = x;
const data = {};
data[`${axis}pl`] = x;
this.send(JSON.stringify(data));
},
@@ -499,5 +497,5 @@ module.exports = {
}
},
mixins: [require('./axis-vars')]
}
mixins: [require("./axis-vars")]
};

View File

@@ -1,69 +1,49 @@
/******************************************************************************\
Copyright 2018. Buildbotics LLC
All Rights Reserved.
For information regarding this software email:
Joseph Coffland
joseph@buildbotics.com
This software is free software: you clan redistribute it and/or
modify it under the terms of the GNU Lesser General Public License
as published by the Free Software Foundation, either version 2.1 of
the License, or (at your option) any later version.
This software is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the C! library. If not, see
<http://www.gnu.org/licenses/>.
\******************************************************************************/
'use strict'
"use strict";
module.exports = function (prefix) {
if (typeof prefix == 'undefined') prefix = '';
if (typeof prefix == "undefined") {
prefix = "";
}
var cookie = {
const cookie = {
get: function (name, defaultValue) {
var decodedCookie = decodeURIComponent(document.cookie);
var ca = decodedCookie.split(';');
name = prefix + name + '=';
const decodedCookie = decodeURIComponent(document.cookie);
const ca = decodedCookie.split(";");
name = `${prefix + name}=`;
for (var i = 0; i < ca.length; i++) {
var c = ca[i];
while (c.charAt(0) == ' ') c = c.substring(1);
if (!c.indexOf(name)) return c.substring(name.length, c.length);
for (let i = 0; i < ca.length; i++) {
let c = ca[i];
while (c.charAt(0) == " ") {
c = c.substring(1);
}
if (!c.indexOf(name)) {
return c.substring(name.length, c.length);
}
}
return defaultValue;
},
set: function (name, value, days) {
var offset = 2147483647; // Max value
if (typeof days != 'undefined') offset = days * 24 * 60 * 60 * 1000;
var d = new Date();
d.setTime(d.getTime() + offset);
var expires = 'expires=' + d.toUTCString();
document.cookie = prefix + name + '=' + value + ';' + expires + ';path=/';
},
let offset = 2147483647; // Max value
if (typeof days != "undefined") {
offset = days * 24 * 60 * 60 * 1000;
}
const d = new Date();
d.setTime(d.getTime() + offset);
const expires = `expires=${d.toUTCString()}`;
document.cookie = `${prefix}${name}=${value};${expires};path=/`;
},
set_bool: function (name, value) {
cookie.set(name, value ? 'true' : 'false');
cookie.set(name, value ? "true" : "false");
},
get_bool: function (name, defaultValue) {
return cookie.get(name, defaultValue ? 'true' : 'false') == 'true';
}
return cookie.get(name, defaultValue ? "true" : "false") == "true";
}
};
return cookie;
}
};

View File

@@ -1,97 +1,76 @@
/******************************************************************************\
This file is part of the Buildbotics firmware.
Copyright (c) 2015 - 2018, Buildbotics LLC
All rights reserved.
This file ("the software") is free software: you can redistribute it
and/or modify it under the terms of the GNU General Public License,
version 2 as published by the Free Software Foundation. You should
have received a copy of the GNU General Public License, version 2
along with the software. If not, see <http://www.gnu.org/licenses/>.
The software is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the software. If not, see
<http://www.gnu.org/licenses/>.
For information regarding this software email:
"Joseph Coffland" <joseph@buildbotics.com>
\******************************************************************************/
'use strict'
var api = require('./api');
var entityMap = {
'&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;', "'": '&#39;',
'/': '&#x2F;', '`': '&#x60;', '=': '&#x3D;'}
"use strict";
const entityMap = {
"&": "&amp;", "<": "&lt;", ">": "&gt;", '"': "&quot;", "'": "&#39;",
"/": "&#x2F;", "`": "&#x60;", "=": "&#x3D;"};
function escapeHTML(s) {
return s.replace(/[&<>"'`=\/]/g, function (c) {return entityMap[c]})
return s.replace(/[&<>"'`=\\/]/g, function (c) {
return entityMap[c];
});
}
module.exports = {
template: '#gcode-viewer-template',
template: "#gcode-viewer-template",
data: function () {
return {
empty: true,
file: '',
file: "",
line: -1,
scrolling: false
}
};
},
events: {
'gcode-load': function (file) {this.load(file)},
'gcode-clear': function () {this.clear()},
'gcode-reload': function (file) {this.reload(file)},
'gcode-line': function (line) {this.update_line(line)}
"gcode-load": function (file) {
this.load(file);
},
"gcode-clear": function () {
this.clear();
},
"gcode-reload": function (file) {
this.reload(file);
},
"gcode-line": function (line) {
this.update_line(line);
}
},
ready: function () {
this.clusterize = new Clusterize({
rows: [],
scrollElem: $(this.$el).find('.clusterize-scroll')[0],
contentElem: $(this.$el).find('.clusterize-content')[0],
no_data_text: 'GCode view...',
scrollElem: $(this.$el).find(".clusterize-scroll")[0],
contentElem: $(this.$el).find(".clusterize-content")[0],
no_data_text: "GCode view...",
callbacks: {clusterChanged: this.highlight}
});
},
attached: function () {
if (typeof this.clusterize != 'undefined')
if (typeof this.clusterize != "undefined") {
this.clusterize.refresh(true);
}
},
methods: {
load: async function(file) {
if (file == this.file) return;
if (file == this.file) {
return;
}
this.clear();
this.file = file;
if (!file) return;
if (!file) {
return;
}
const response = await fetch(`/api/file/${file}?${Math.random()}`);
const text = await response.text();
if (text.length > 20e6) {
this.clusterize.update(['File is large - gcode view disabled']);
this.clusterize.update(["File is large - gcode view disabled"]);
} else {
const lines = escapeHTML(text.trimRight())
.split(/[\r\n]/)
@@ -105,64 +84,77 @@ module.exports = {
Vue.nextTick(this.update_line);
},
clear: function () {
this.empty = true;
this.file = '';
this.file = "";
this.line = -1;
this.clusterize.clear();
},
reload: function (file) {
if (file != this.file) return;
if (file != this.file) {
return;
}
this.clear();
this.load(file);
},
highlight: function () {
var e = $(this.$el).find('.highlight');
if (e.length) e.removeClass('highlight');
let e = $(this.$el).find(".highlight");
if (e.length) {
e.removeClass("highlight");
}
e = $(this.$el).find('.ln' + this.line);
if (e.length) e.addClass('highlight');
e = $(this.$el).find(`.ln${this.line}`);
if (e.length) {
e.addClass("highlight");
}
},
update_line: function(line) {
if (typeof line != 'undefined') {
if (this.line == line) return;
if (typeof line != "undefined") {
if (this.line == line) {
return;
}
this.line = line;
} else {
line = this.line;
}
} else line = this.line;
const totalLines = this.clusterize.getRowsAmount();
var totalLines = this.clusterize.getRowsAmount();
if (line <= 0) {
line = 1;
}
if (line <= 0) line = 1;
if (totalLines < line) line = totalLines;
if (totalLines < line) {
line = totalLines;
}
var e = $(this.$el).find('.clusterize-scroll');
const e = $(this.$el).find(".clusterize-scroll");
var lineHeight = e[0].scrollHeight / totalLines;
var linesPerPage = Math.floor(e[0].clientHeight / lineHeight);
var current = e[0].scrollTop / lineHeight;
var target = line - 1 - Math.floor(linesPerPage / 2);
const lineHeight = e[0].scrollHeight / totalLines;
const linesPerPage = Math.floor(e[0].clientHeight / lineHeight);
const current = e[0].scrollTop / lineHeight;
const target = line - 1 - Math.floor(linesPerPage / 2);
// Update scroll position
if (!this.scrolling) {
if (target < current - 20 || current + 20 < target)
if (target < current - 20 || current + 20 < target) {
e[0].scrollTop = target * lineHeight;
else {
} else {
this.scrolling = true;
e.animate({scrollTop: target * lineHeight}, {
complete: function () {this.scrolling = false}.bind(this)
})
complete: function () {
this.scrolling = false;
}.bind(this)
});
}
}
Vue.nextTick(this.highlight);
}
}
}
};

View File

@@ -1,65 +1,44 @@
/******************************************************************************\
This file is part of the Buildbotics firmware.
Copyright (c) 2015 - 2018, Buildbotics LLC
All rights reserved.
This file ("the software") is free software: you can redistribute it
and/or modify it under the terms of the GNU General Public License,
version 2 as published by the Free Software Foundation. You should
have received a copy of the GNU General Public License, version 2
along with the software. If not, see <http://www.gnu.org/licenses/>.
The software is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the software. If not, see
<http://www.gnu.org/licenses/>.
For information regarding this software email:
"Joseph Coffland" <joseph@buildbotics.com>
\******************************************************************************/
'use strict'
var modbus = require('./modbus.js');
"use strict";
const modbus = require("./modbus.js");
module.exports = {
template: '#indicators-template',
props: ['state'],
template: "#indicators-template",
props: ["state"],
computed: {
modbus_status: function () {return modbus.status_to_string(this.state.mx)},
modbus_status: function () {
return modbus.status_to_string(this.state.mx);
},
sense_error: function () {
var error = '';
let error = "";
if (this.state.motor_voltage_sense_error) error += 'Motor voltage\n';
if (this.state.motor_current_sense_error) error += 'Motor current\n';
if (this.state.load1_sense_error) error += 'Load 1\n';
if (this.state.load2_sense_error) error += 'Load 2\n';
if (this.state.vdd_current_sense_error) error += 'Vdd current\n';
if (this.state.motor_voltage_sense_error) {
error += "Motor voltage\n";
}
if (this.state.motor_current_sense_error) {
error += "Motor current\n";
}
if (this.state.load1_sense_error) {
error += "Load 1\n";
}
if (this.state.load2_sense_error) {
error += "Load 2\n";
}
if (this.state.vdd_current_sense_error) {
error += "Vdd current\n";
}
return error;
}
},
methods: {
is_motor_enabled: function (motor) {
return typeof this.state[motor + 'me'] != 'undefined' &&
this.state[motor + 'me'];
return typeof this.state[`${motor}me`] != "undefined" && this.state[`${motor}me`];
},
get_min_pin: function (motor) {
switch (motor) {
case 0: return 3;
@@ -69,7 +48,6 @@ module.exports = {
}
},
get_max_pin: function (motor) {
switch (motor) {
case 0: return 4;
@@ -79,29 +57,38 @@ module.exports = {
}
},
motor_fault_class: function (motor, bit) {
if (typeof motor == 'undefined') {
var status = this.state['fa'];
if (typeof status == 'undefined') return 'fa-question';
return 'fa-thumbs-' + (status ? 'down error' : 'up success')
if (typeof motor == "undefined") {
const status = this.state["fa"];
if (typeof status == "undefined") {
return "fa-question";
}
var flags = this.state[motor + 'df'];
if (typeof flags == 'undefined') return 'fa-question';
return (flags & (1 << bit)) ? 'fa-thumbs-down error' :
'fa-thumbs-up success';
return `fa-thumbs-${status ? "down error" : "up success"}`;
}
const flags = this.state[`${motor}df`];
if (typeof flags == "undefined") {
return "fa-question";
}
return (flags & (1 << bit)) ? "fa-thumbs-down error" :
"fa-thumbs-up success";
},
motor_reset: function (motor) {
if (typeof motor == 'undefined') {
var cmd = '';
for (var i = 0; i < 4; i++)
cmd += '\\$' + i + 'df=0\n';
this.$dispatch('send', cmd);
if (typeof motor == "undefined") {
let cmd = "";
for (let i = 0; i < 4; i++) {
cmd += `\\$${i}df=0\n`;
}
} else this.$dispatch('send', '\\$' + motor + 'df=0');
this.$dispatch("send", cmd);
} else {
this.$dispatch("send", `\\$${motor}df=0`);
}
}
}
}
};

View File

@@ -1,177 +1,155 @@
/******************************************************************************\
This file is part of the Buildbotics firmware.
Copyright (c) 2015 - 2018, Buildbotics LLC
All rights reserved.
This file ("the software") is free software: you can redistribute it
and/or modify it under the terms of the GNU General Public License,
version 2 as published by the Free Software Foundation. You should
have received a copy of the GNU General Public License, version 2
along with the software. If not, see <http://www.gnu.org/licenses/>.
The software is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the software. If not, see
<http://www.gnu.org/licenses/>.
For information regarding this software email:
"Joseph Coffland" <joseph@buildbotics.com>
\******************************************************************************/
'use strict'
"use strict";
module.exports = {
template: "#io-indicator-template",
props: ['name', 'state'],
props: ["name", "state"],
computed: {
klass: function () {
if (this.name == 'min-switch-0') return this.get_motor_min_class(0);
if (this.name == 'min-switch-1') return this.get_motor_min_class(1);
if (this.name == 'min-switch-2') return this.get_motor_min_class(2);
if (this.name == 'min-switch-3') return this.get_motor_min_class(3);
if (this.name == 'max-switch-0') return this.get_motor_max_class(0);
if (this.name == 'max-switch-1') return this.get_motor_max_class(1);
if (this.name == 'max-switch-2') return this.get_motor_max_class(2);
if (this.name == 'max-switch-3') return this.get_motor_max_class(3);
if (this.name == 'estop') return this.get_input_class('ew', 'et');
if (this.name == 'probe') return this.get_input_class('pw', 'pt');
if (this.name == 'load-1') return this.get_output_class('1');
if (this.name == 'load-2') return this.get_output_class('2');
if (this.name == 'fault') return this.get_output_class('f');
if (this.name == 'tool-enable-mode') return this.get_output_class('e');
if (this.name == 'tool-direction-mode') return this.get_output_class('d');
},
tooltip: function () {
if (this.name == 'min-switch-0') return this.get_motor_min_tooltip(0);
if (this.name == 'min-switch-1') return this.get_motor_min_tooltip(1);
if (this.name == 'min-switch-2') return this.get_motor_min_tooltip(2);
if (this.name == 'min-switch-3') return this.get_motor_min_tooltip(3);
if (this.name == 'max-switch-0') return this.get_motor_max_tooltip(0);
if (this.name == 'max-switch-1') return this.get_motor_max_tooltip(1);
if (this.name == 'max-switch-2') return this.get_motor_max_tooltip(2);
if (this.name == 'max-switch-3') return this.get_motor_max_tooltip(3);
if (this.name == 'estop') return this.get_input_tooltip('ew', 'et');
if (this.name == 'probe') return this.get_input_tooltip('pw', 'pt');
if (this.name == 'load-1') return this.get_output_tooltip('1');
if (this.name == 'load-2') return this.get_output_tooltip('2');
if (this.name == 'fault') return this.get_output_tooltip('f');
if (this.name == 'tool-direction-mode')
return this.get_output_tooltip('d');
if (this.name == 'tool-enable-mode')
return this.get_output_tooltip('e');
switch (this.name) {
case "min-switch-0": return this.get_motor_min_class(0);
case "min-switch-1": return this.get_motor_min_class(1);
case "min-switch-2": return this.get_motor_min_class(2);
case "min-switch-3": return this.get_motor_min_class(3);
case "max-switch-0": return this.get_motor_max_class(0);
case "max-switch-1": return this.get_motor_max_class(1);
case "max-switch-2": return this.get_motor_max_class(2);
case "max-switch-3": return this.get_motor_max_class(3);
case "estop": return this.get_input_class("ew", "et");
case "probe": return this.get_input_class("pw", "pt");
case "load-1": return this.get_output_class("1");
case "load-2": return this.get_output_class("2");
case "fault": return this.get_output_class("f");
case "tool-enable-mode": return this.get_output_class("e");
case "tool-direction-mode": return this.get_output_class("d");
}
},
tooltip: function () {
switch (this.name) {
case "min-switch-0": return this.get_motor_min_tooltip(0);
case "min-switch-1": return this.get_motor_min_tooltip(1);
case "min-switch-2": return this.get_motor_min_tooltip(2);
case "min-switch-3": return this.get_motor_min_tooltip(3);
case "max-switch-0": return this.get_motor_max_tooltip(0);
case "max-switch-1": return this.get_motor_max_tooltip(1);
case "max-switch-2": return this.get_motor_max_tooltip(2);
case "max-switch-3": return this.get_motor_max_tooltip(3);
case "estop": return this.get_input_tooltip("ew", "et");
case "probe": return this.get_input_tooltip("pw", "pt");
case "load-1": return this.get_output_tooltip("1");
case "load-2": return this.get_output_tooltip("2");
case "fault": return this.get_output_tooltip("f");
case "tool-direction-mode": return this.get_output_tooltip("d");
case "tool-enable-mode": return this.get_output_tooltip("e");
}
}
},
methods: {
get_io_state_class: function (active, state) {
if (typeof active == 'undefined' || typeof state == 'undefined')
return 'fa-exclamation-triangle warn';
if (typeof active == "undefined" || typeof state == "undefined") {
return "fa-exclamation-triangle warn";
}
if (state == 2) return 'fa-circle-o';
if (state == 2) {
return "fa-circle-o";
}
return (state ? 'fa-plus-circle' : 'fa-minus-circle') + ' ' +
(active ? 'active' : 'inactive');
const icon = state ? "fa-plus-circle" : "fa-minus-circle";
return `${icon} ${active ? "active" : "inactive"}`;
},
get_input_active: function (stateCode, typeCode) {
var type = this.state[typeCode];
var state = this.state[stateCode];
const type = this.state[typeCode];
const state = this.state[stateCode];
if (type == 1) return !state; // Normally open
else if (type == 2) return state; // Normally closed
if (type == 1) {
return !state; // Normally open
} else if (type == 2) {
return state; // Normally closed
}
return false
return false;
},
get_input_class: function (stateCode, typeCode) {
return this.get_io_state_class(this.get_input_active(stateCode, typeCode),
this.state[stateCode]);
return this.get_io_state_class(this.get_input_active(stateCode, typeCode), this.state[stateCode]);
},
get_output_class: function (output) {
return this.get_io_state_class(this.state[output + 'oa'],
this.state[output + 'os']);
return this.get_io_state_class(this.state[`${output}oa`], this.state[`${output}os`]);
},
get_motor_min_class: function (motor) {
return this.get_input_class(motor + 'lw', motor + 'ls');
return this.get_input_class(`${motor}lw`, `${motor}ls`);
},
get_motor_max_class: function (motor) {
return this.get_input_class(motor + 'xw', motor + 'xs');
return this.get_input_class(`${motor}xw`, `${motor}xs`);
},
get_tooltip: function (mode, active, state) {
if (typeof mode == 'undefined' || typeof active == 'undefined' ||
typeof state == 'undefined') return 'Invalid';
if (typeof mode == "undefined" || typeof active == "undefined" || typeof state == "undefined") {
return "Invalid";
}
if (state == 0) state = 'Lo/Gnd';
else if (state == 1) state = 'Hi/+3.3v';
else if (state == 2) state = 'Tristated';
else return 'Invalid';
if (state == 0) {
state = "Lo/Gnd";
} else if (state == 1) {
state = "Hi/+3.3v";
} else if (state == 2) {
state = "Tristated";
} else {
return "Invalid";
}
return 'Mode: ' + mode + '\nActive: ' + (active ? 'True' : 'False') +
'\nLevel: ' + state;
return `Mode: ${mode}\nActive: ${active ? "True" : "False"}\nLevel: ${state}`;
},
get_input_tooltip: function (stateCode, typeCode) {
var type = this.state[typeCode];
if (type == 0) return 'Disabled';
else if (type == 1) type = 'Normally open';
else if (type == 2) type = 'Normally closed';
let type = this.state[typeCode];
if (type == 0) {
return "Disabled";
} else if (type == 1) {
type = "Normally open";
} else if (type == 2) {
type = "Normally closed";
}
var active = this.get_input_active(stateCode, typeCode);
var state = this.state[stateCode];
const active = this.get_input_active(stateCode, typeCode);
const state = this.state[stateCode];
return this.get_tooltip(type, active, state);
},
get_output_tooltip: function (output) {
var mode = this.state[output + 'om'];
if (mode == 0) return 'Disabled';
else if (mode == 1) mode = 'Lo/Hi';
else if (mode == 2) mode = 'Hi/Lo';
else if (mode == 3) mode = 'Tri/Lo';
else if (mode == 4) mode = 'Tri/Hi';
else if (mode == 5) mode = 'Lo/Tri';
else if (mode == 6) mode = 'Hi/Tri';
else mode = undefined;
let mode = this.state[`${output}om`];
var active = this.state[output + 'oa'];
var state = this.state[output + 'os'];
switch (mode) {
case 0: return "Disabled";
case 1: mode = "Lo/Hi"; break;
case 2: mode = "Hi/Lo"; break;
case 3: mode = "Tri/Lo"; break;
case 4: mode = "Tri/Hi"; break;
case 5: mode = "Lo/Tri"; break;
case 6: mode = "Hi/Tri"; break;
default:
mode = undefined;
}
const active = this.state[`${output}oa`];
const state = this.state[`${output}os`];
return this.get_tooltip(mode, active, state);
},
get_motor_min_tooltip: function (motor) {
return this.get_input_tooltip(motor + 'lw', motor + 'ls');
return this.get_input_tooltip(`${motor}lw`, `${motor}ls`);
},
get_motor_max_tooltip: function (motor) {
return this.get_input_tooltip(motor + 'xw', motor + 'xs');
return this.get_input_tooltip(`${motor}xw`, `${motor}xs`);
}
}
}
};

View File

@@ -1,42 +1,13 @@
/******************************************************************************\
This file is part of the Buildbotics firmware.
Copyright (c) 2015 - 2018, Buildbotics LLC
All rights reserved.
This file ("the software") is free software: you can redistribute it
and/or modify it under the terms of the GNU General Public License,
version 2 as published by the Free Software Foundation. You should
have received a copy of the GNU General Public License, version 2
along with the software. If not, see <http://www.gnu.org/licenses/>.
The software is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the software. If not, see
<http://www.gnu.org/licenses/>.
For information regarding this software email:
"Joseph Coffland" <joseph@buildbotics.com>
\******************************************************************************/
'use strict'
"use strict";
module.exports = {
template: '#io-view-template',
props: ['config', 'template', 'state'],
template: "#io-view-template",
props: ["config", "template", "state"],
events: {
'input-changed': function() {
this.$dispatch('config-changed');
"input-changed": function() {
this.$dispatch("config-changed");
return false;
}
}
}
};

View File

@@ -1,13 +1,13 @@
'use strict';
"use strict";
function cookie_get(name) {
var decodedCookie = decodeURIComponent(document.cookie);
var ca = decodedCookie.split(';');
name = name + '=';
const decodedCookie = decodeURIComponent(document.cookie);
const ca = decodedCookie.split(";");
name = `${name}=`;
for (var i = 0; i < ca.length; i++) {
var c = ca[i];
while (c.charAt(0) == ' ') {
for (let i = 0; i < ca.length; i++) {
let c = ca[i];
while (c.charAt(0) == " ") {
c = c.substring(1);
}
@@ -18,101 +18,101 @@ function cookie_get(name) {
}
function cookie_set(name, value, days) {
var d = new Date();
const d = new Date();
d.setTime(d.getTime() + days * 24 * 60 * 60 * 1000);
var expires = 'expires=' + d.toUTCString();
document.cookie = name + '=' + value + ';' + expires + ';path=/';
const expires = `expires=${d.toUTCString()}`;
document.cookie = `${name}=${value};${expires};path=/`;
}
var uuid_chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_+';
const uuid_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_+";
function uuid(length) {
if (typeof length == 'undefined') {
if (typeof length == "undefined") {
length = 52;
}
var s = '';
for (var i = 0; i < length; i++) {
let s = "";
for (let i = 0; i < length; i++) {
s += uuid_chars[Math.floor(Math.random() * uuid_chars.length)];
}
return s
return s;
}
$(function () {
if (typeof cookie_get('client-id') == 'undefined') {
cookie_set('client-id', uuid(), 10000);
if (typeof cookie_get("client-id") == "undefined") {
cookie_set("client-id", uuid(), 10000);
}
// Register global components
Vue.component('templated-input', require('./templated-input'));
Vue.component('message', require('./message'));
Vue.component('indicators', require('./indicators'));
Vue.component('io-indicator', require('./io-indicator'));
Vue.component('console', require('./console'));
Vue.component('unit-value', require('./unit-value'));
Vue.component("templated-input", require("./templated-input"));
Vue.component("message", require("./message"));
Vue.component("indicators", require("./indicators"));
Vue.component("io-indicator", require("./io-indicator"));
Vue.component("console", require("./console"));
Vue.component("unit-value", require("./unit-value"));
Vue.filter('number', function (value) {
Vue.filter("number", function (value) {
if (isNaN(value)) {
return 'NaN';
return "NaN";
}
return value.toLocaleString();
});
Vue.filter('percent', function (value, precision) {
if (typeof value == 'undefined') {
return '';
Vue.filter("percent", function (value, precision) {
if (typeof value == "undefined") {
return "";
}
if (typeof precision == 'undefined') {
if (typeof precision == "undefined") {
precision = 2;
}
return (value * 100.0).toFixed(precision) + '%';
return `${(value * 100.0).toFixed(precision)}%`;
});
Vue.filter('non_zero_percent', function (value, precision) {
Vue.filter("non_zero_percent", function (value, precision) {
if (!value) {
return '';
return "";
}
if (typeof precision == 'undefined') {
if (typeof precision == "undefined") {
precision = 2;
}
return (value * 100.0).toFixed(precision) + '%';
return `${(value * 100.0).toFixed(precision)}%`;
});
Vue.filter('fixed', function (value, precision) {
if (typeof value == 'undefined') {
return '0';
Vue.filter("fixed", function (value, precision) {
if (typeof value == "undefined") {
return "0";
}
return parseFloat(value).toFixed(precision)
return parseFloat(value).toFixed(precision);
});
Vue.filter('upper', function (value) {
if (typeof value == 'undefined') {
return '';
Vue.filter("upper", function (value) {
if (typeof value == "undefined") {
return "";
}
return value.toUpperCase()
return value.toUpperCase();
});
Vue.filter('time', function (value, precision) {
Vue.filter("time", function (value, precision) {
if (isNaN(value)) {
return '';
return "";
}
if (isNaN(precision)) {
precision = 0;
}
var MIN = 60;
var HR = MIN * 60;
var DAY = HR * 24;
var parts = [];
const MIN = 60;
const HR = MIN * 60;
const DAY = HR * 24;
const parts = [];
if (DAY <= value) {
parts.push(Math.floor(value / DAY));
@@ -133,16 +133,16 @@ $(function () {
parts.push(value);
for (var i = 0; i < parts.length; i++) {
for (let i = 0; i < parts.length; i++) {
parts[i] = parts[i].toFixed(i == parts.length - 1 ? precision : 0);
if (i && parts[i] < 10) {
parts[i] = '0' + parts[i];
parts[i] = `0${parts[i]}`;
}
}
return parts.join(':');
return parts.join(":");
});
// Vue app
require('./app');
require("./app");
});

View File

@@ -1,35 +1,7 @@
/******************************************************************************\
This file is part of the Buildbotics firmware.
Copyright (c) 2015 - 2018, Buildbotics LLC
All rights reserved.
This file ("the software") is free software: you can redistribute it
and/or modify it under the terms of the GNU General Public License,
version 2 as published by the Free Software Foundation. You should
have received a copy of the GNU General Public License, version 2
along with the software. If not, see <http://www.gnu.org/licenses/>.
The software is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the software. If not, see
<http://www.gnu.org/licenses/>.
For information regarding this software email:
"Joseph Coffland" <joseph@buildbotics.com>
\******************************************************************************/
'use strict'
"use strict";
module.exports = {
template: '#message-template',
template: "#message-template",
props: {
show: {
@@ -44,4 +16,4 @@ module.exports = {
twoWay: false
}
}
}
};

View File

@@ -1,48 +1,20 @@
/******************************************************************************\
This file is part of the Buildbotics firmware.
Copyright (c) 2015 - 2018, Buildbotics LLC
All rights reserved.
This file ("the software") is free software: you can redistribute it
and/or modify it under the terms of the GNU General Public License,
version 2 as published by the Free Software Foundation. You should
have received a copy of the GNU General Public License, version 2
along with the software. If not, see <http://www.gnu.org/licenses/>.
The software is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the software. If not, see
<http://www.gnu.org/licenses/>.
For information regarding this software email:
"Joseph Coffland" <joseph@buildbotics.com>
\******************************************************************************/
'use strict'
"use strict";
module.exports = {
replace: true,
template: '#modbus-reg-view-template',
props: ['index', 'model', 'template', 'enable'],
template: "#modbus-reg-view-template",
props: ["index", "model", "template", "enable"],
computed: {
has_user_value: function () {
var type = this.model['reg-type'];
return type.indexOf('write') != -1 || type.indexOf('fixed') != -1;
const type = this.model["reg-type"];
return type.indexOf("write") != -1 || type.indexOf("fixed") != -1;
}
},
methods: {
change: function () {this.$dispatch('input-changed')}
change: function () {
this.$dispatch("input-changed");
}
}
}
};

View File

@@ -1,35 +1,7 @@
/******************************************************************************\
This file is part of the Buildbotics firmware.
Copyright (c) 2015 - 2018, Buildbotics LLC
All rights reserved.
This file ("the software") is free software: you can redistribute it
and/or modify it under the terms of the GNU General Public License,
version 2 as published by the Free Software Foundation. You should
have received a copy of the GNU General Public License, version 2
along with the software. If not, see <http://www.gnu.org/licenses/>.
The software is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the software. If not, see
<http://www.gnu.org/licenses/>.
For information regarding this software email:
"Joseph Coffland" <joseph@buildbotics.com>
\******************************************************************************/
'use strict'
"use strict";
// Must match modbus.c
var exports = {
const exports = {
DISCONNECTED: 0,
OK: 1,
CRC: 2,
@@ -37,15 +9,15 @@ var exports = {
TIMEDOUT: 4
};
exports.status_to_string =
function (status) {
if (status == exports.OK) return 'Ok';
if (status == exports.CRC) return 'CRC error';
if (status == exports.INVALID) return 'Invalid response';
if (status == exports.TIMEDOUT) return 'Timedout';
return 'Disconnected';
switch (status) {
case exports.OK: return "Ok";
case exports.CRC: return "CRC error";
case exports.INVALID: return "Invalid response";
case exports.TIMEDOUT: return "Timedout";
default: return "Disconnected";
}
};
module.exports = exports;

View File

@@ -1,8 +1,8 @@
'use strict'
"use strict";
module.exports = {
template: '#motor-view-template',
props: ['index', 'config', 'template', 'state'],
template: "#motor-view-template",
props: ["index", "config", "template", "state"],
computed: {
metric: function () {
@@ -10,7 +10,7 @@ module.exports = {
},
is_slave: function () {
for (var i = 0; i < this.index; i++) {
for (let i = 0; i < this.index; i++) {
if (this.motor.axis == this.config.motors[i].axis) {
return true;
}
@@ -20,76 +20,76 @@ module.exports = {
},
motor: function () {
return this.config.motors[this.index]
return this.config.motors[this.index];
},
invalidMaxVelocity: function () {
return this.maxMaxVelocity < this.motor['max-velocity'];
return this.maxMaxVelocity < this.motor["max-velocity"];
},
maxMaxVelocity: function () {
return 1 * (15 * this.umPerStep / this.motor['microsteps']).toFixed(3);
return 1 * (15 * this.umPerStep / this.motor["microsteps"]).toFixed(3);
},
ustepPerSec: function () {
return this.rpm * this.stepsPerRev * this.motor['microsteps'] / 60;
return this.rpm * this.stepsPerRev * this.motor["microsteps"] / 60;
},
rpm: function () {
return 1000 * this.motor['max-velocity'] / this.motor['travel-per-rev'];
return 1000 * this.motor["max-velocity"] / this.motor["travel-per-rev"];
},
gForce: function () {
return this.motor['max-accel'] * 0.0283254504
return this.motor["max-accel"] * 0.0283254504;
},
gForcePerMin: function () {
return this.motor['max-jerk'] * 0.0283254504
return this.motor["max-jerk"] * 0.0283254504;
},
stepsPerRev: function () {
return 360 / this.motor['step-angle']
return 360 / this.motor["step-angle"];
},
umPerStep: function () {
return this.motor['travel-per-rev'] * this.motor['step-angle'] / 0.36
return this.motor["travel-per-rev"] * this.motor["step-angle"] / 0.36;
},
milPerStep: function () {
return this.umPerStep / 25.4
return this.umPerStep / 25.4;
},
invalidStallVelocity: function () {
if (!this.motor['homing-mode'].startsWith('stall-')) {
if (!this.motor["homing-mode"].startsWith("stall-")) {
return false;
}
return this.maxStallVelocity < this.motor['search-velocity'];
return this.maxStallVelocity < this.motor["search-velocity"];
},
stallRPM: function () {
var v = this.motor['search-velocity'];
return 1000 * v / this.motor['travel-per-rev'];
const v = this.motor["search-velocity"];
return 1000 * v / this.motor["travel-per-rev"];
},
maxStallVelocity: function () {
var maxRate = 900000 / this.motor['stall-sample-time'];
var ustep = this.motor['stall-microstep'];
var angle = this.motor['step-angle'];
var travel = this.motor['travel-per-rev'];
var maxStall = maxRate * 60 / 360 / 1000 * angle / ustep * travel;
const maxRate = 900000 / this.motor["stall-sample-time"];
const ustep = this.motor["stall-microstep"];
const angle = this.motor["step-angle"];
const travel = this.motor["travel-per-rev"];
const maxStall = maxRate * 60 / 360 / 1000 * angle / ustep * travel;
return 1 * maxStall.toFixed(3);
},
stallUStepPerSec: function () {
var ustep = this.motor['stall-microstep'];
const ustep = this.motor["stall-microstep"];
return this.stallRPM * this.stepsPerRev * ustep / 60;
}
},
events: {
'input-changed': function () {
"input-changed": function () {
Vue.nextTick(function () {
// Limit max-velocity
if (this.invalidMaxVelocity) {
@@ -101,8 +101,8 @@ module.exports = {
this.$set('motor["search-velocity"]', this.maxStallVelocity);
}
this.$dispatch('config-changed');
}.bind(this))
this.$dispatch("config-changed");
}.bind(this));
return false;
}
@@ -114,7 +114,7 @@ module.exports = {
return true;
}
return templ.hmodes.indexOf(this.motor['homing-mode']) != -1;
return templ.hmodes.indexOf(this.motor["homing-mode"]) != -1;
}
}
}
};

View File

@@ -7,7 +7,7 @@
* @author jcoffland / https://buildbotics.com/
*/
'use strict'
"use strict";
// This set of controls performs orbiting, dollying (zooming), and panning.
// Unlike TrackballControls, it maintains the "up" direction object.up
@@ -17,8 +17,42 @@
// Zoom - middle mouse, or mousewheel / touch: two-finger spread or squish
// Pan - right mouse, or arrow keys / touch: two-finger move
const OrbitControls = function (object, domElement) {
// internals
// eslint-disable-next-line @typescript-eslint/no-this-alias
const scope = this;
const changeEvent = {type: "change"};
const startEvent = {type: "start"};
const endEvent = {type: "end"};
const STATE = {
NONE: -1, ROTATE: 0, DOLLY: 1, PAN: 2, TOUCH_ROTATE: 3, TOUCH_DOLLY_PAN: 4
};
let state = STATE.NONE;
const EPS = 0.000001;
// current position in spherical coordinates
const spherical = new THREE.Spherical();
const sphericalDelta = new THREE.Spherical();
let scale = 1;
const panOffset = new THREE.Vector3();
let zoomChanged = false;
const rotateStart = new THREE.Vector2();
const rotateEnd = new THREE.Vector2();
const rotateDelta = new THREE.Vector2();
const panStart = new THREE.Vector2();
const panEnd = new THREE.Vector2();
const panDelta = new THREE.Vector2();
const dollyStart = new THREE.Vector2();
const dollyEnd = new THREE.Vector2();
const dollyDelta = new THREE.Vector2();
var OrbitControls = function (object, domElement) {
this.object = object;
this.domElement = domElement != undefined ? domElement : document;
@@ -85,16 +119,19 @@ var OrbitControls = function (object, domElement) {
this.zoom0 = this.object.zoom;
// public methods
this.getPolarAngle = function () {return spherical.phi}
this.getAzimuthalAngle = function () {return spherical.theta}
this.getPolarAngle = function () {
return spherical.phi;
};
this.getAzimuthalAngle = function () {
return spherical.theta;
};
this.saveState = function () {
scope.target0.copy(scope.target);
scope.position0.copy(scope.object.position);
scope.zoom0 = scope.object.zoom;
}
};
this.reset = function () {
scope.target.copy(scope.target0);
@@ -106,22 +143,20 @@ var OrbitControls = function (object, domElement) {
scope.update();
state = STATE.NONE;
}
};
this.update = function () {
var offset = new THREE.Vector3();
const offset = new THREE.Vector3();
// so camera.up is the orbit axis
var quat = new THREE.Quaternion()
.setFromUnitVectors(object.up, new THREE.Vector3(0, 1, 0));
var quatInverse = quat.clone().inverse();
const quat = new THREE.Quaternion().setFromUnitVectors(object.up, new THREE.Vector3(0, 1, 0));
const quatInverse = quat.clone().inverse();
var lastPosition = new THREE.Vector3();
var lastQuaternion = new THREE.Quaternion();
const lastPosition = new THREE.Vector3();
const lastQuaternion = new THREE.Quaternion();
return function update() {
var position = scope.object.position;
const position = scope.object.position;
offset.copy(position).sub(scope.target);
@@ -131,28 +166,24 @@ var OrbitControls = function (object, domElement) {
// angle from z-axis around y-axis
spherical.setFromVector3(offset);
if (scope.autoRotate && state == STATE.NONE)
if (scope.autoRotate && state == STATE.NONE) {
rotateLeft(getAutoRotationAngle());
}
spherical.theta += sphericalDelta.theta;
spherical.phi += sphericalDelta.phi;
// restrict theta to be between desired limits
spherical.theta =
Math.max(scope.minAzimuthAngle,
Math.min(scope.maxAzimuthAngle, spherical.theta));
spherical.theta = Math.max(scope.minAzimuthAngle, Math.min(scope.maxAzimuthAngle, spherical.theta));
// restrict phi to be between desired limits
spherical.phi =
Math.max(scope.minPolarAngle,
Math.min(scope.maxPolarAngle, spherical.phi));
spherical.phi = Math.max(scope.minPolarAngle, Math.min(scope.maxPolarAngle, spherical.phi));
spherical.makeSafe();
spherical.radius *= scale;
// restrict radius to be between desired limits
spherical.radius =
Math.max(10, Math.min(scope.object.far * 0.8, spherical.radius));
spherical.radius = Math.max(10, Math.min(scope.object.far * 0.8, spherical.radius));
// move target to panned location
scope.target.add(panOffset);
@@ -178,9 +209,10 @@ var OrbitControls = function (object, domElement) {
// update condition is:
// min(camera displacement, camera rotation in radians)^2 > EPS
// using small-angle approximation cos(x/2) = 1 - x^2 / 8
if (zoomChanged || scale != 1 ||
lastPosition.distanceToSquared(scope.object.position) > EPS ||
8 * (1 - lastQuaternion.dot(scope.object.quaternion)) > EPS) {
if (zoomChanged
|| scale != 1
|| lastPosition.distanceToSquared(scope.object.position) > EPS
|| 8 * (1 - lastQuaternion.dot(scope.object.quaternion)) > EPS) {
scope.dispatchEvent(changeEvent);
@@ -193,187 +225,150 @@ var OrbitControls = function (object, domElement) {
}
return false;
}
}()
};
}();
this.dispose = function () {
scope.domElement.removeEventListener('contextmenu', onContextMenu, false);
scope.domElement.removeEventListener('mousedown', onMouseDown, false);
scope.domElement.removeEventListener('wheel', onMouseWheel, false);
scope.domElement.removeEventListener('touchstart', onTouchStart, false);
scope.domElement.removeEventListener('touchend', onTouchEnd, false);
scope.domElement.removeEventListener('touchmove', onTouchMove, false);
document.removeEventListener('mousemove', onMouseMove, false);
document.removeEventListener('mouseup', onMouseUp, false);
window.removeEventListener('keydown', onKeyDown, false);
}
// internals
var scope = this;
var changeEvent = {type: 'change'};
var startEvent = {type: 'start'};
var endEvent = {type: 'end'};
var STATE = {
NONE: -1, ROTATE: 0, DOLLY: 1, PAN: 2, TOUCH_ROTATE: 3, TOUCH_DOLLY_PAN: 4
scope.domElement.removeEventListener("contextmenu", onContextMenu, false);
scope.domElement.removeEventListener("mousedown", onMouseDown, false);
scope.domElement.removeEventListener("wheel", onMouseWheel, false);
scope.domElement.removeEventListener("touchstart", onTouchStart, false);
scope.domElement.removeEventListener("touchend", onTouchEnd, false);
scope.domElement.removeEventListener("touchmove", onTouchMove, false);
document.removeEventListener("mousemove", onMouseMove, false);
document.removeEventListener("mouseup", onMouseUp, false);
window.removeEventListener("keydown", onKeyDown, false);
};
var state = STATE.NONE;
var EPS = 0.000001;
// current position in spherical coordinates
var spherical = new THREE.Spherical();
var sphericalDelta = new THREE.Spherical();
var scale = 1;
var panOffset = new THREE.Vector3();
var zoomChanged = false;
var rotateStart = new THREE.Vector2();
var rotateEnd = new THREE.Vector2();
var rotateDelta = new THREE.Vector2();
var panStart = new THREE.Vector2();
var panEnd = new THREE.Vector2();
var panDelta = new THREE.Vector2();
var dollyStart = new THREE.Vector2();
var dollyEnd = new THREE.Vector2();
var dollyDelta = new THREE.Vector2();
function getAutoRotationAngle() {
return 2 * Math.PI / 60 / 60 * scope.autoRotateSpeed;
}
function getZoomScale() {
return Math.pow(0.95, scope.zoomSpeed);
}
function getZoomScale() {return Math.pow(0.95, scope.zoomSpeed)}
function rotateLeft(angle) {sphericalDelta.theta -= angle}
function rotateUp(angle) {sphericalDelta.phi -= angle}
function rotateLeft(angle) {
sphericalDelta.theta -= angle;
}
function rotateUp(angle) {
sphericalDelta.phi -= angle;
}
var panLeft = function () {
var v = new THREE.Vector3();
const panLeft = function () {
const v = new THREE.Vector3();
return function panLeft(distance, objectMatrix) {
v.setFromMatrixColumn(objectMatrix, 0); // get X column of objectMatrix
v.multiplyScalar(-distance);
panOffset.add(v);
}
}()
};
}();
var panUp = function () {
var v = new THREE.Vector3();
const panUp = function () {
const v = new THREE.Vector3();
return function panUp(distance, objectMatrix) {
if (scope.screenSpacePanning) v.setFromMatrixColumn(objectMatrix, 1);
else {
if (scope.screenSpacePanning) {
v.setFromMatrixColumn(objectMatrix, 1);
} else {
v.setFromMatrixColumn(objectMatrix, 0);
v.crossVectors(scope.object.up, v);
}
v.multiplyScalar(distance);
panOffset.add(v);
}
}()
};
}();
function unknownCamera() {
console.warn('WARNING: OrbitControls.js encountered an unknown camera ' +
'type - pan & zoom disabled.');
console.warn("WARNING: OrbitControls.js encountered an unknown camera type - pan & zoom disabled.");
scope.enablePan = false;
scope.enableZoom = false;
}
// deltaX and deltaY are in pixels; right and down are positive
var pan = function () {
var offset = new THREE.Vector3();
const pan = function () {
const offset = new THREE.Vector3();
return function pan(deltaX, deltaY) {
var element = scope.domElement === document ?
scope.domElement.body : scope.domElement;
const element = scope.domElement === document
? scope.domElement.body
: scope.domElement;
if (scope.object.isPerspectiveCamera) {
// perspective
offset.copy(scope.object.position).sub(scope.target);
var targetDistance = offset.length();
let targetDistance = offset.length();
// half of the fov is center to top of screen
targetDistance *= Math.tan((scope.object.fov / 2) * Math.PI / 180.0);
// we use only clientHeight here so aspect ratio does not distort speed
panLeft(2 * deltaX * targetDistance / element.clientHeight,
scope.object.matrix);
panUp(2 * deltaY * targetDistance / element.clientHeight,
scope.object.matrix);
panLeft(2 * deltaX * targetDistance / element.clientHeight, scope.object.matrix);
panUp(2 * deltaY * targetDistance / element.clientHeight, scope.object.matrix);
} else if (scope.object.isOrthographicCamera) {
// orthographic
panLeft(deltaX * (scope.object.right - scope.object.left) /
scope.object.zoom / element.clientWidth, scope.object.matrix);
panUp(deltaY * (scope.object.top - scope.object.bottom) /
scope.object.zoom / element.clientHeight, scope.object.matrix);
panLeft(deltaX * (scope.object.right - scope.object.left) / scope.object.zoom / element.clientWidth, scope.object.matrix);
panUp(deltaY * (scope.object.top - scope.object.bottom) / scope.object.zoom / element.clientHeight, scope.object.matrix);
} else unknownCamera();
} else {
unknownCamera();
}
}()
};
}();
function dollyIn(dollyScale) {
if (scope.object.isPerspectiveCamera) scale /= dollyScale;
else if (scope.object.isOrthographicCamera) {
if (scope.object.isPerspectiveCamera) {
scale /= dollyScale;
} else if (scope.object.isOrthographicCamera) {
scope.object.zoom =
Math.max(scope.minZoom,
Math.min(scope.maxZoom, scope.object.zoom * dollyScale));
scope.object.updateProjectionMatrix();
zoomChanged = true;
} else unknownCamera();
} else {
unknownCamera();
}
}
function dollyOut(dollyScale) {
if (scope.object.isPerspectiveCamera) scale *= dollyScale;
else if (scope.object.isOrthographicCamera) {
if (scope.object.isPerspectiveCamera) {
scale *= dollyScale;
} else if (scope.object.isOrthographicCamera) {
scope.object.zoom =
Math.max(scope.minZoom,
Math.min(scope.maxZoom, scope.object.zoom / dollyScale));
scope.object.updateProjectionMatrix();
zoomChanged = true;
} else unknownCamera();
} else {
unknownCamera();
}
}
// event callbacks - update the object state
function handleMouseDownRotate(event) {
rotateStart.set(event.clientX, event.clientY);
}
function handleMouseDownDolly(event) {
dollyStart.set(event.clientX, event.clientY);
}
function handleMouseDownPan(event) {
panStart.set(event.clientX, event.clientY);
}
function handleMouseMoveRotate(event) {
rotateEnd.set(event.clientX, event.clientY);
rotateDelta.subVectors(rotateEnd, rotateStart)
.multiplyScalar(scope.rotateSpeed);
var element = scope.domElement === document ?
const element = scope.domElement === document ?
scope.domElement.body : scope.domElement;
// yes, height
@@ -385,19 +380,20 @@ var OrbitControls = function (object, domElement) {
scope.update();
}
function handleMouseMoveDolly(event) {
dollyEnd.set(event.clientX, event.clientY);
dollyDelta.subVectors(dollyEnd, dollyStart);
if (dollyDelta.y > 0) dollyIn(getZoomScale());
else if (dollyDelta.y < 0) dollyOut(getZoomScale());
if (dollyDelta.y > 0) {
dollyIn(getZoomScale());
} else if (dollyDelta.y < 0) {
dollyOut(getZoomScale());
}
dollyStart.copy(dollyEnd);
scope.update();
}
function handleMouseMovePan(event) {
panEnd.set(event.clientX, event.clientY);
panDelta.subVectors(panEnd, panStart).multiplyScalar(scope.panSpeed);
@@ -406,18 +402,16 @@ var OrbitControls = function (object, domElement) {
scope.update();
}
function handleMouseUp(event) {}
function handleMouseWheel(event) {
if (event.deltaY < 0) dollyOut(getZoomScale());
else if (event.deltaY > 0) dollyIn(getZoomScale());
if (event.deltaY < 0) {
dollyOut(getZoomScale());
} else if (event.deltaY > 0) {
dollyIn(getZoomScale());
}
scope.update();
}
function handleKeyDown(event) {
switch (event.keyCode) {
case scope.keys.UP:
@@ -442,35 +436,32 @@ var OrbitControls = function (object, domElement) {
}
}
function handleTouchStartRotate(event) {
rotateStart.set(event.touches[0].pageX, event.touches[0].pageY);
}
function handleTouchStartDollyPan(event) {
if (scope.enableZoom) {
var dx = event.touches[0].pageX - event.touches[1].pageX;
var dy = event.touches[0].pageY - event.touches[1].pageY;
var distance = Math.sqrt(dx * dx + dy * dy);
const dx = event.touches[0].pageX - event.touches[1].pageX;
const dy = event.touches[0].pageY - event.touches[1].pageY;
const distance = Math.sqrt(dx * dx + dy * dy);
dollyStart.set(0, distance);
}
if (scope.enablePan) {
var x = 0.5 * (event.touches[0].pageX + event.touches[1].pageX);
var y = 0.5 * (event.touches[0].pageY + event.touches[1].pageY);
const x = 0.5 * (event.touches[0].pageX + event.touches[1].pageX);
const y = 0.5 * (event.touches[0].pageY + event.touches[1].pageY);
panStart.set(x, y);
}
}
function handleTouchMoveRotate(event) {
rotateEnd.set(event.touches[0].pageX, event.touches[0].pageY);
rotateDelta.subVectors(rotateEnd, rotateStart)
.multiplyScalar(scope.rotateSpeed);
var element = scope.domElement === document ?
const element = scope.domElement === document ?
scope.domElement.body : scope.domElement;
// yes, height
@@ -480,12 +471,11 @@ var OrbitControls = function (object, domElement) {
scope.update();
}
function handleTouchMoveDollyPan(event) {
if (scope.enableZoom) {
var dx = event.touches[0].pageX - event.touches[1].pageX;
var dy = event.touches[0].pageY - event.touches[1].pageY;
var distance = Math.sqrt(dx * dx + dy * dy);
const dx = event.touches[0].pageX - event.touches[1].pageX;
const dy = event.touches[0].pageY - event.touches[1].pageY;
const distance = Math.sqrt(dx * dx + dy * dy);
dollyEnd.set(0, distance);
dollyDelta.set(0, Math.pow(dollyEnd.y / dollyStart.y, scope.zoomSpeed));
@@ -493,10 +483,9 @@ var OrbitControls = function (object, domElement) {
dollyStart.copy(dollyEnd);
}
if (scope.enablePan) {
var x = 0.5 * (event.touches[0].pageX + event.touches[1].pageX);
var y = 0.5 * (event.touches[0].pageY + event.touches[1].pageY);
const x = 0.5 * (event.touches[0].pageX + event.touches[1].pageX);
const y = 0.5 * (event.touches[0].pageY + event.touches[1].pageY);
panEnd.set(x, y);
panDelta.subVectors(panEnd, panStart).multiplyScalar(scope.panSpeed);
@@ -507,82 +496,94 @@ var OrbitControls = function (object, domElement) {
scope.update();
}
function handleTouchEnd(event) {}
// event handlers - listen for events and reset state
function onMouseDown(event) {
if (!scope.enabled) return;
if (!scope.enabled) {
return;
}
event.preventDefault();
switch (event.button) {
case scope.mouseButtons.ORBIT:
if (!scope.enableRotate) return;
if (!scope.enableRotate) {
return;
}
handleMouseDownRotate(event);
state = STATE.ROTATE;
break;
case scope.mouseButtons.ZOOM:
if (!scope.enableZoom) return;
if (!scope.enableZoom) {
return;
}
handleMouseDownDolly(event);
state = STATE.DOLLY;
break;
case scope.mouseButtons.PAN:
if (!scope.enablePan) return;
if (!scope.enablePan) {
return;
}
handleMouseDownPan(event);
state = STATE.PAN;
break;
}
if (state != STATE.NONE) {
document.addEventListener('mousemove', onMouseMove, false);
document.addEventListener('mouseup', onMouseUp, false);
document.addEventListener("mousemove", onMouseMove, false);
document.addEventListener("mouseup", onMouseUp, false);
scope.dispatchEvent(startEvent);
}
}
function onMouseMove(event) {
if (!scope.enabled) return;
if (!scope.enabled) {
return;
}
event.preventDefault();
switch (state) {
case STATE.ROTATE:
if (!scope.enableRotate) return;
if (!scope.enableRotate) {
return;
}
handleMouseMoveRotate(event);
break;
case STATE.DOLLY:
if (!scope.enableZoom) return;
if (!scope.enableZoom) {
return;
}
handleMouseMoveDolly(event);
break;
case STATE.PAN:
if (!scope.enablePan) return;
if (!scope.enablePan) {
return;
}
handleMouseMovePan(event);
break;
}
}
function onMouseUp() {
if (!scope.enabled) {
return;
}
function onMouseUp(event) {
if (!scope.enabled) return;
handleMouseUp(event);
document.removeEventListener('mousemove', onMouseMove, false);
document.removeEventListener('mouseup', onMouseUp, false);
document.removeEventListener("mousemove", onMouseMove, false);
document.removeEventListener("mouseup", onMouseUp, false);
scope.dispatchEvent(endEvent);
state = STATE.NONE;
}
function onMouseWheel(event) {
if (!scope.enabled || !scope.enableZoom ||
(state != STATE.NONE && state != STATE.ROTATE)) return;
(state != STATE.NONE && state != STATE.ROTATE)) {
return;
}
event.preventDefault();
event.stopPropagation();
@@ -591,28 +592,34 @@ var OrbitControls = function (object, domElement) {
scope.dispatchEvent(endEvent);
}
function onKeyDown(event) {
if (!scope.enabled || !scope.enableKeys || !scope.enablePan) return;
if (!scope.enabled || !scope.enableKeys || !scope.enablePan) {
return;
}
handleKeyDown(event);
}
function onTouchStart(event) {
if (!scope.enabled) return;
if (!scope.enabled) {
return;
}
event.preventDefault();
switch (event.touches.length) {
case 1: // one-fingered touch: rotate
if (!scope.enableRotate) return;
if (!scope.enableRotate) {
return;
}
handleTouchStartRotate(event);
state = STATE.TOUCH_ROTATE;
break;
case 2: // two-fingered touch: dolly-pan
if (!scope.enableZoom && !scope.enablePan) return;
if (!scope.enableZoom && !scope.enablePan) {
return;
}
handleTouchStartDollyPan(event);
state = STATE.TOUCH_DOLLY_PAN;
break;
@@ -620,27 +627,38 @@ var OrbitControls = function (object, domElement) {
default: state = STATE.NONE;
}
if (state != STATE.NONE) scope.dispatchEvent(startEvent);
if (state != STATE.NONE) {
scope.dispatchEvent(startEvent);
}
}
function onTouchMove(event) {
if (!scope.enabled) return;
if (!scope.enabled) {
return;
}
event.preventDefault();
event.stopPropagation();
switch (event.touches.length) {
case 1: // one-fingered touch: rotate
if (!scope.enableRotate) return;
if (state != STATE.TOUCH_ROTATE) return; // is this needed?
if (!scope.enableRotate) {
return;
}
if (state != STATE.TOUCH_ROTATE) {
return;
} // is this needed?
handleTouchMoveRotate(event);
break;
case 2: // two-fingered touch: dolly-pan
if (!scope.enableZoom && !scope.enablePan) return;
if (state != STATE.TOUCH_DOLLY_PAN) return; // is this needed?
if (!scope.enableZoom && !scope.enablePan) {
return;
}
if (state != STATE.TOUCH_DOLLY_PAN) {
return;
} // is this needed?
handleTouchMoveDollyPan(event);
break;
@@ -649,33 +667,32 @@ var OrbitControls = function (object, domElement) {
}
}
function onTouchEnd() {
if (!scope.enabled) {
return;
}
function onTouchEnd(event) {
if (!scope.enabled) return;
handleTouchEnd(event);
scope.dispatchEvent(endEvent);
state = STATE.NONE;
}
function onContextMenu(event) {
if (!scope.enabled) return;
if (!scope.enabled) {
return;
}
event.preventDefault();
}
scope.domElement.addEventListener('contextmenu', onContextMenu, false);
scope.domElement.addEventListener('mousedown', onMouseDown, false);
scope.domElement.addEventListener('wheel', onMouseWheel, false);
scope.domElement.addEventListener('touchstart', onTouchStart, false);
scope.domElement.addEventListener('touchend', onTouchEnd, false);
scope.domElement.addEventListener('touchmove', onTouchMove, false);
window .addEventListener('keydown', onKeyDown, false);
scope.domElement.addEventListener("contextmenu", onContextMenu, false);
scope.domElement.addEventListener("mousedown", onMouseDown, false);
scope.domElement.addEventListener("wheel", onMouseWheel, false);
scope.domElement.addEventListener("touchstart", onTouchStart, false);
scope.domElement.addEventListener("touchend", onTouchEnd, false);
scope.domElement.addEventListener("touchmove", onTouchMove, false);
window.addEventListener("keydown", onKeyDown, false);
this.update(); // force an update at start
}
};
OrbitControls.prototype = Object.create(THREE.EventDispatcher.prototype);
OrbitControls.prototype.constructor = OrbitControls;

View File

@@ -1,58 +1,32 @@
/******************************************************************************\
"use strict";
Copyright 2018. Buildbotics LLC
All Rights Reserved.
For information regarding this software email:
Joseph Coffland
joseph@buildbotics.com
This software is free software: you clan redistribute it and/or
modify it under the terms of the GNU Lesser General Public License
as published by the Free Software Foundation, either version 2.1 of
the License, or (at your option) any later version.
This software is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the C! library. If not, see
<http://www.gnu.org/licenses/>.
\******************************************************************************/
'use strict'
var orbit = require('./orbit');
var cookie = require('./cookie')('bbctrl-');
var font = require('./helvetiker_regular.typeface.json')
const orbit = require("./orbit");
const cookie = require("./cookie")("bbctrl-");
const font = require("./helvetiker_regular.typeface.json");
module.exports = {
template: '#path-viewer-template',
props: ['toolpath'],
template: "#path-viewer-template",
props: ["toolpath"],
data: function () {
return {
enabled: false,
loading: false,
dirty: true,
snapView: cookie.get('snap-view', 'isometric'),
small: cookie.get_bool('small-path-view', true),
surfaceMode: 'cut',
showPath: cookie.get_bool('show-path', true),
showTool: cookie.get_bool('show-tool', true),
showBBox: cookie.get_bool('show-bbox', true),
showAxes: cookie.get_bool('show-axes', true),
showIntensity: cookie.get_bool('show-intensity', false)
}
snapView: cookie.get("snap-view", "isometric"),
small: cookie.get_bool("small-path-view", true),
surfaceMode: "cut",
showPath: cookie.get_bool("show-path", true),
showTool: cookie.get_bool("show-tool", true),
showBBox: cookie.get_bool("show-bbox", true),
showAxes: cookie.get_bool("show-axes", true),
showIntensity: cookie.get_bool("show-intensity", false)
};
},
computed: {
target: function () {
return $(this.$el).find('.path-viewer-content')[0]
return $(this.$el).find(".path-viewer-content")[0];
},
webglAvailable: function() {
@@ -69,61 +43,64 @@ module.exports = {
}
},
watch: {
toolpath: function () {Vue.nextTick(this.update)},
surfaceMode: function (mode) {this.update_surface_mode(mode)},
toolpath: function () {
Vue.nextTick(this.update);
},
surfaceMode: function (mode) {
this.update_surface_mode(mode);
},
small: function (enable) {
cookie.set_bool('small-path-view', enable);
Vue.nextTick(this.update_view)
cookie.set_bool("small-path-view", enable);
Vue.nextTick(this.update_view);
},
showPath: function (enable) {
cookie.set_bool('show-path', enable);
this.set_visible(this.pathView, enable)
cookie.set_bool("show-path", enable);
this.set_visible(this.pathView, enable);
},
showTool: function (enable) {
cookie.set_bool('show-tool', enable);
this.set_visible(this.toolView, enable)
cookie.set_bool("show-tool", enable);
this.set_visible(this.toolView, enable);
},
showAxes: function (enable) {
cookie.set_bool('show-axes', enable);
this.set_visible(this.axesView, enable)
cookie.set_bool("show-axes", enable);
this.set_visible(this.axesView, enable);
},
showIntensity: function (enable) {
cookie.set_bool('show-intensity', enable);
Vue.nextTick(this.update)
cookie.set_bool("show-intensity", enable);
Vue.nextTick(this.update);
},
showBBox: function (enable) {
cookie.set_bool('show-bbox', enable);
cookie.set_bool("show-bbox", enable);
this.set_visible(this.bboxView, enable);
this.set_visible(this.envelopeView, enable);
},
x: function () {this.axis_changed()},
y: function () {this.axis_changed()},
z: function () {this.axis_changed()}
x: function () {
this.axis_changed();
},
y: function () {
this.axis_changed();
},
z: function () {
this.axis_changed();
}
},
ready: function () {
this.graphics();
Vue.nextTick(this.update);
},
methods: {
update: async function () {
if (!this.webglAvailable) {
@@ -140,7 +117,9 @@ module.exports = {
this.draw_loading();
}
if (!this.enabled || !this.toolpath.filename) return;
if (!this.enabled || !this.toolpath.filename) {
return;
}
async function get(url) {
const response = await fetch(`${url}?${Math.random()}`);
@@ -150,11 +129,11 @@ module.exports = {
}
const [positions, speeds] = await Promise.all([
get('/api/path/' + this.toolpath.filename + '/positions'),
get('/api/path/' + this.toolpath.filename + '/speeds')
get(`/api/path/${this.toolpath.filename}/positions`),
get(`/api/path/${this.toolpath.filename}/speeds`)
]);
this.positions = positions
this.positions = positions;
this.speeds = speeds;
this.loading = false;
@@ -166,22 +145,22 @@ module.exports = {
this.update_view();
},
update_surface_mode: function (mode) {
if (!this.enabled) return;
if (!this.enabled) {
return;
}
if (typeof this.surfaceMaterial != 'undefined') {
this.surfaceMaterial.wireframe = mode == 'wire';
if (typeof this.surfaceMaterial != "undefined") {
this.surfaceMaterial.wireframe = mode == "wire";
this.surfaceMaterial.needsUpdate = true;
}
this.set_visible(this.surfaceMesh, mode == 'cut' || mode == 'wire');
this.set_visible(this.workpieceMesh, mode == 'solid');
this.set_visible(this.surfaceMesh, mode == "cut" || mode == "wire");
this.set_visible(this.workpieceMesh, mode == "solid");
},
load_surface: function (surface) {
if (typeof surface == 'undefined') {
if (typeof surface == "undefined") {
this.vertices = undefined;
this.normals = undefined;
return;
@@ -191,30 +170,35 @@ module.exports = {
// Expand normals
this.normals = [];
for (var i = 0; i < surface.normals.length / 3; i++)
for (var j = 0; j < 3; j++)
for (var k = 0; k < 3; k++)
for (let i = 0; i < surface.normals.length / 3; i++) {
for (let j = 0; j < 3; j++) {
for (let k = 0; k < 3; k++) {
this.normals.push(surface.normals[i * 3 + k]);
}
}
}
},
set_visible: function (target, visible) {
if (typeof target != 'undefined') target.visible = visible;
if (typeof target != "undefined") {
target.visible = visible;
}
this.dirty = true;
},
get_dims: function () {
var t = $(this.target);
var width = t.innerWidth();
var height = t.innerHeight();
const t = $(this.target);
const width = t.innerWidth();
const height = t.innerHeight();
return {width: width, height: height};
},
update_view: function () {
if (!this.enabled) return;
var dims = this.get_dims();
if (!this.enabled) {
return;
}
const dims = this.get_dims();
this.camera.aspect = dims.width / dims.height;
this.camera.updateProjectionMatrix();
@@ -229,47 +213,59 @@ module.exports = {
this.dirty = true;
},
update_tool: function (tool) {
if (!this.enabled) return;
if (typeof tool == 'undefined') tool = this.toolView;
if (typeof tool == 'undefined') return;
if (!this.enabled) {
return;
}
if (typeof tool == "undefined") {
tool = this.toolView;
}
if (typeof tool == "undefined") {
return;
}
tool.position.x = this.x.pos;
tool.position.y = this.y.pos;
tool.position.z = this.z.pos;
},
update_envelope: function (envelope) {
if (!this.enabled || !this.axes.homed) return;
if (typeof envelope == 'undefined') envelope = this.envelopeView;
if (typeof envelope == 'undefined') return;
if (!this.enabled || !this.axes.homed) {
return;
}
var min = new THREE.Vector3();
var max = new THREE.Vector3();
if (typeof envelope == "undefined") {
envelope = this.envelopeView;
}
for (var axis of 'xyz') {
if (typeof envelope == "undefined") {
return;
}
const min = new THREE.Vector3();
const max = new THREE.Vector3();
for (const axis of "xyz") {
min[axis] = this[axis].min - this[axis].off;
max[axis] = this[axis].max - this[axis].off;
}
var bounds = new THREE.Box3(min, max);
const bounds = new THREE.Box3(min, max);
if (bounds.isEmpty()) {
envelope.geometry = this.create_empty_geom();
}
else {
} else {
envelope.geometry = this.create_bbox_geom(bounds);
}
},
axis_changed: function () {
this.update_tool();
this.update_envelope();
this.dirty = true;
},
graphics: function () {
if (!this.webglAvailable) {
return;
@@ -283,7 +279,7 @@ module.exports = {
this.target.appendChild(this.renderer.domElement);
} catch (e) {
console.log('WebGL not supported: ', e);
console.log("WebGL not supported: ", e);
return;
}
@@ -295,15 +291,13 @@ module.exports = {
// Lighting
this.ambient = new THREE.AmbientLight(0xffffff, 0.5);
var keyLight = new THREE.DirectionalLight
(new THREE.Color('hsl(30, 100%, 75%)'), 0.75);
const keyLight = new THREE.DirectionalLight(new THREE.Color("hsl(30, 100%, 75%)"), 0.75);
keyLight.position.set(-100, 0, 100);
var fillLight = new THREE.DirectionalLight
(new THREE.Color('hsl(240, 100%, 75%)'), 0.25);
const fillLight = new THREE.DirectionalLight(new THREE.Color("hsl(240, 100%, 75%)"), 0.25);
fillLight.position.set(100, 0, 100);
var backLight = new THREE.DirectionalLight(0xffffff, 0.5);
const backLight = new THREE.DirectionalLight(0xffffff, 0.5);
backLight.position.set(100, 0, -100).normalize();
this.lights = new THREE.Group();
@@ -322,7 +316,7 @@ module.exports = {
this.controls.enableZoom = true;
// Move lights with scene
this.controls.addEventListener('change', function (scope) {
this.controls.addEventListener("change", function (scope) {
return function () {
keyLight.position.copy(scope.camera.position);
fillLight.position.copy(scope.camera.position);
@@ -331,17 +325,16 @@ module.exports = {
fillLight.lookAt(scope.controls.target);
backLight.lookAt(scope.controls.target);
scope.dirty = true;
}
}(this))
};
}(this));
// Events
window.addEventListener('resize', this.update_view, false);
window.addEventListener("resize", this.update_view, false);
// Start it
this.render();
},
create_surface_material: function () {
return new THREE.MeshPhongMaterial({
specular: 0x111111,
@@ -351,11 +344,10 @@ module.exports = {
});
},
draw_loading: function () {
this.scene = new THREE.Scene();
var geometry = new THREE.TextGeometry('Loading 3D View...', {
const geometry = new THREE.TextGeometry("Loading 3D View...", {
font: new THREE.Font(font),
size: 40,
height: 5,
@@ -367,8 +359,7 @@ module.exports = {
});
geometry.computeBoundingBox();
var center = geometry.center();
var mesh = new THREE.Mesh(geometry, this.surfaceMaterial);
const mesh = new THREE.Mesh(geometry, this.surfaceMaterial);
this.scene.add(mesh);
this.scene.add(this.ambient);
@@ -376,21 +367,22 @@ module.exports = {
this.update_view();
},
draw_workpiece: function (scene, material) {
if (typeof this.workpiece == 'undefined') return;
if (typeof this.workpiece == "undefined") {
return;
}
var min = this.workpiece.min;
var max = this.workpiece.max;
let min = this.workpiece.min;
let max = this.workpiece.max;
min = new THREE.Vector3(min[0], min[1], min[2]);
max = new THREE.Vector3(max[0], max[1], max[2]);
var dims = max.clone().sub(min);
const dims = max.clone().sub(min);
var geometry = new THREE.BoxGeometry(dims.x, dims.y, dims.z)
var mesh = new THREE.Mesh(geometry, material);
const geometry = new THREE.BoxGeometry(dims.x, dims.y, dims.z);
const mesh = new THREE.Mesh(geometry, material);
var offset = dims.clone();
const offset = dims.clone();
offset.divideScalar(2);
offset.add(min);
@@ -403,16 +395,15 @@ module.exports = {
return mesh;
},
draw_surface: function (scene, material) {
if (typeof this.vertices == 'undefined') return;
if (typeof this.vertices == "undefined") {
return;
}
var geometry = new THREE.BufferGeometry();
const geometry = new THREE.BufferGeometry();
geometry.addAttribute
('position', new THREE.Float32BufferAttribute(this.vertices, 3));
geometry.addAttribute
('normal', new THREE.Float32BufferAttribute(this.normals, 3));
geometry.addAttribute("position", new THREE.Float32BufferAttribute(this.vertices, 3));
geometry.addAttribute("normal", new THREE.Float32BufferAttribute(this.normals, 3));
geometry.computeBoundingSphere();
geometry.computeBoundingBox();
@@ -420,15 +411,16 @@ module.exports = {
return new THREE.Mesh(geometry, material);
},
draw_tool: function (scene, bbox) {
// Tool size is relative to bounds
var size = bbox.getSize(new THREE.Vector3());
var length = (size.x + size.y + size.z) / 24;
const size = bbox.getSize(new THREE.Vector3());
let length = (size.x + size.y + size.z) / 24;
if (length < 1) length = 1;
if (length < 1) {
length = 1;
}
var material = new THREE.MeshPhongMaterial({
const material = new THREE.MeshPhongMaterial({
transparent: true,
opacity: 0.75,
specular: 0x161616,
@@ -436,30 +428,33 @@ module.exports = {
color: 0xffa500 // Orange
});
var geometry = new THREE.CylinderGeometry(length / 2, 0, length, 128);
const geometry = new THREE.CylinderGeometry(length / 2, 0, length, 128);
geometry.translate(0, length / 2, 0);
geometry.rotateX(0.5 * Math.PI);
var mesh = new THREE.Mesh(geometry, material);
const mesh = new THREE.Mesh(geometry, material);
this.update_tool(mesh);
mesh.visible = this.showTool;
scene.add(mesh);
return mesh;
},
draw_axis: function (axis, up, length, radius) {
var color;
let color;
if (axis == 0) color = 0xff0000; // Red
else if (axis == 1) color = 0x00ff00; // Green
else if (axis == 2) color = 0x0000ff; // Blue
if (axis == 0) {
color = 0xff0000;
} else if (axis == 1) {
color = 0x00ff00;
} else if (axis == 2) {
color = 0x0000ff;
}
var group = new THREE.Group();
var material = new THREE.MeshPhongMaterial({
const group = new THREE.Group();
const material = new THREE.MeshPhongMaterial({
specular: 0x161616, shininess: 10, color: color
});
var geometry = new THREE.CylinderGeometry(radius, radius, length, 128);
let geometry = new THREE.CylinderGeometry(radius, radius, length, 128);
geometry.translate(0, -length / 2, 0);
group.add(new THREE.Mesh(geometry, material));
@@ -467,28 +462,35 @@ module.exports = {
geometry.translate(0, -length - radius, 0);
group.add(new THREE.Mesh(geometry, material));
if (axis == 0) group.rotateZ((up ? 0.5 : 1.5) * Math.PI);
else if (axis == 1) group.rotateX((up ? 0 : 1 ) * Math.PI);
else if (axis == 2) group.rotateX((up ? 1.5 : 0.5) * Math.PI);
if (axis == 0) {
group.rotateZ((up ? 0.5 : 1.5) * Math.PI);
} else if (axis == 1) {
group.rotateX((up ? 0 : 1 ) * Math.PI);
} else if (axis == 2) {
group.rotateX((up ? 1.5 : 0.5) * Math.PI);
}
return group;
},
draw_axes: function (scene, bbox) {
var size = bbox.getSize(new THREE.Vector3());
var length = (size.x + size.y + size.z) / 3;
const size = bbox.getSize(new THREE.Vector3());
let length = (size.x + size.y + size.z) / 3;
length /= 10;
if (length < 1) length = 1;
if (length < 1) {
length = 1;
}
var radius = length / 20;
const radius = length / 20;
var group = new THREE.Group();
const group = new THREE.Group();
for (var axis = 0; axis < 3; axis++)
for (var up = 0; up < 2; up++)
for (let axis = 0; axis < 3; axis++) {
for (let up = 0; up < 2; up++) {
group.add(this.draw_axis(axis, up, length, radius));
}
}
group.visible = this.showAxes;
scene.add(group);
@@ -496,40 +498,42 @@ module.exports = {
return group;
},
get_color: function (speed) {
if (isNaN(speed)) return [255, 0, 0]; // Rapid
if (isNaN(speed)) {
return [255, 0, 0];
} // Rapid
let intensity = speed / this.toolpath.maxSpeed;
if (typeof speed == "undefined" || !this.showIntensity) {
intensity = 1;
}
var intensity = speed / this.toolpath.maxSpeed;
if (typeof speed == 'undefined' || !this.showIntensity) intensity = 1;
return [0, 255 * intensity, 127 * (1 - intensity)];
},
draw_path: function (scene) {
var geometry = new THREE.BufferGeometry();
var material =
new THREE.LineBasicMaterial({
const geometry = new THREE.BufferGeometry();
const material = new THREE.LineBasicMaterial({
vertexColors: THREE.VertexColors,
linewidth: 1.5
});
var positions = new THREE.Float32BufferAttribute(this.positions, 3);
geometry.addAttribute('position', positions);
const positions = new THREE.Float32BufferAttribute(this.positions, 3);
geometry.addAttribute("position", positions);
var colors = [];
for (var i = 0; i < this.speeds.length; i++) {
var color = this.get_color(this.speeds[i]);
let colors = [];
for (let i = 0; i < this.speeds.length; i++) {
const color = this.get_color(this.speeds[i]);
Array.prototype.push.apply(colors, color);
}
colors = new THREE.Uint8BufferAttribute(colors, 3, true);
geometry.addAttribute('color', colors);
geometry.addAttribute("color", colors);
geometry.computeBoundingSphere();
geometry.computeBoundingBox();
var line = new THREE.Line(geometry, material);
const line = new THREE.Line(geometry, material);
line.visible = this.showPath;
scene.add(line);
@@ -537,17 +541,15 @@ module.exports = {
return line;
},
create_empty_geom: function () {
var geometry = new THREE.BufferGeometry();
geometry.addAttribute('position',
const geometry = new THREE.BufferGeometry();
geometry.addAttribute("position",
new THREE.Float32BufferAttribute([], 3));
return geometry;
},
create_bbox_geom: function (bbox) {
var vertices = [];
const vertices = [];
if (!bbox.isEmpty()) {
// Top
@@ -581,19 +583,18 @@ module.exports = {
vertices.push(bbox.min.x, bbox.max.y, bbox.max.z);
}
var geometry = new THREE.BufferGeometry();
const geometry = new THREE.BufferGeometry();
geometry.addAttribute('position',
geometry.addAttribute("position",
new THREE.Float32BufferAttribute(vertices, 3));
return geometry;
},
draw_bbox: function (scene, bbox) {
var geometry = this.create_bbox_geom(bbox);
var material = new THREE.LineBasicMaterial({color: 0xffffff});
var line = new THREE.LineSegments(geometry, material);
const geometry = this.create_bbox_geom(bbox);
const material = new THREE.LineBasicMaterial({color: 0xffffff});
const line = new THREE.LineSegments(geometry, material);
line.visible = this.showBBox;
@@ -602,11 +603,10 @@ module.exports = {
return line;
},
draw_envelope: function (scene) {
var geometry = this.create_empty_geom();
var material = new THREE.LineBasicMaterial({color: 0x00f7ff});
var line = new THREE.LineSegments(geometry, material);
const geometry = this.create_empty_geom();
const material = new THREE.LineBasicMaterial({color: 0x00f7ff});
const line = new THREE.LineSegments(geometry, material);
line.visible = this.showBBox;
@@ -616,7 +616,6 @@ module.exports = {
return line;
},
draw: function (scene) {
// Lights
scene.add(this.ambient);
@@ -629,7 +628,7 @@ module.exports = {
this.update_surface_mode(this.surfaceMode);
// Compute bounding box
var bbox = this.get_model_bounds();
const bbox = this.get_model_bounds();
// Tool, axes & bounds
this.toolView = this.draw_tool(scene, bbox);
@@ -638,10 +637,12 @@ module.exports = {
this.envelopeView = this.draw_envelope(scene);
},
render: function () {
window.requestAnimationFrame(this.render);
if (typeof this.scene == 'undefined') return;
if (typeof this.scene == "undefined") {
return;
}
if (this.controls.update() || this.dirty) {
this.dirty = false;
@@ -649,14 +650,13 @@ module.exports = {
}
},
get_model_bounds: function () {
var bbox = new THREE.Box3(new THREE.Vector3(0, 0, 0),
const bbox = new THREE.Box3(new THREE.Vector3(0, 0, 0),
new THREE.Vector3(0.00001, 0.00001, 0.00001));
function add(o) {
if (typeof o != 'undefined') {
var oBBox = new THREE.Box3();
if (typeof o != "undefined") {
const oBBox = new THREE.Box3();
oBBox.setFromObject(o);
bbox.union(oBBox);
}
@@ -669,45 +669,53 @@ module.exports = {
return bbox;
},
snap: function (view) {
if (this.loading) return;
if (view != this.snapView) {
this.snapView = view;
cookie.set('snap-view', view);
if (this.loading) {
return;
}
var bbox = this.get_model_bounds();
if (view != this.snapView) {
this.snapView = view;
cookie.set("snap-view", view);
}
const bbox = this.get_model_bounds();
this.controls.reset();
bbox.getCenter(this.controls.target);
this.update_view();
// Compute new camera position
var center = bbox.getCenter(new THREE.Vector3());
var offset = new THREE.Vector3();
const center = bbox.getCenter(new THREE.Vector3());
const offset = new THREE.Vector3();
switch (view) {
case "isometric": offset.y -= 1; offset.z += 1; break;
case "front": offset.y -= 1; break;
case "back": offset.y += 1; break;
case "left": offset.x -= 1; break;
case "right": offset.x += 1; break;
case "top": offset.z += 1; break;
case "bottom": offset.z -= 1; break;
}
if (view == 'isometric') {offset.y -= 1; offset.z += 1;}
if (view == 'front') offset.y -= 1;
if (view == 'back') offset.y += 1;
if (view == 'left') offset.x -= 1;
if (view == 'right') offset.x += 1;
if (view == 'top') offset.z += 1;
if (view == 'bottom') offset.z -= 1;
offset.normalize();
// Initial camera position
var position = new THREE.Vector3().copy(center).add(offset);
const position = new THREE.Vector3().copy(center).add(offset);
this.camera.position.copy(position);
this.camera.lookAt(center); // Get correct camera orientation
var theta = this.camera.fov / 180 * Math.PI; // View angle
var cameraLine = new THREE.Line3(center, position);
var cameraUp = new THREE.Vector3().copy(this.camera.up)
const theta = this.camera.fov / 180 * Math.PI; // View angle
const cameraLine = new THREE.Line3(center, position);
const cameraUp = new THREE.Vector3()
.copy(this.camera.up)
.applyQuaternion(this.camera.quaternion);
var cameraLeft =
new THREE.Vector3().copy(offset).cross(cameraUp).normalize();
const cameraLeft = new THREE.Vector3()
.copy(offset)
.cross(cameraUp)
.normalize();
var corners = [
const corners = [
new THREE.Vector3(bbox.min.x, bbox.min.y, bbox.min.z),
new THREE.Vector3(bbox.min.x, bbox.min.y, bbox.max.z),
new THREE.Vector3(bbox.min.x, bbox.max.y, bbox.min.z),
@@ -716,39 +724,37 @@ module.exports = {
new THREE.Vector3(bbox.max.x, bbox.min.y, bbox.max.z),
new THREE.Vector3(bbox.max.x, bbox.max.y, bbox.min.z),
new THREE.Vector3(bbox.max.x, bbox.max.y, bbox.max.z),
]
];
var dist = this.camera.near; // Min camera dist
let dist = this.camera.near; // Min camera dist
for (var i = 0; i < corners.length; i++) {
for (let i = 0; i < corners.length; i++) {
// Project on to camera line
var p1 = cameraLine
.closestPointToPoint(corners[i], false, new THREE.Vector3());
const p1 = cameraLine.closestPointToPoint(corners[i], false, new THREE.Vector3());
// Compute distance from projection to center
var d = p1.distanceTo(center);
if (cameraLine.closestPointToPointParameter(p1, false) < 0) d = -d;
let d = p1.distanceTo(center);
if (cameraLine.closestPointToPointParameter(p1, false) < 0) {
d = -d;
}
// Compute up line
var up =
new THREE.Line3(p1, new THREE.Vector3().copy(p1).add(cameraUp));
const up = new THREE.Line3(p1, new THREE.Vector3().copy(p1).add(cameraUp));
// Project on to up line
var p2 = up.closestPointToPoint(corners[i], false, new THREE.Vector3());
const p2 = up.closestPointToPoint(corners[i], false, new THREE.Vector3());
// Compute length
var l = p1.distanceTo(p2);
let l = p1.distanceTo(p2);
// Update min camera distance
dist = Math.max(dist, d + l / Math.tan(theta / 2));
// Compute left line
var left =
new THREE.Line3(p1, new THREE.Vector3().copy(p1).add(cameraLeft));
const left = new THREE.Line3(p1, new THREE.Vector3().copy(p1).add(cameraLeft));
// Project on to left line
var p3 =
left.closestPointToPoint(corners[i], false, new THREE.Vector3());
const p3 = left.closestPointToPoint(corners[i], false, new THREE.Vector3());
// Compute length
l = p1.distanceTo(p3);
@@ -761,6 +767,5 @@ module.exports = {
}
},
mixins: [require('./axis-vars')]
}
mixins: [require("./axis-vars")]
};

View File

@@ -1,38 +1,16 @@
/******************************************************************************\
"use strict";
This file is part of the Buildbotics firmware.
const Sock = function (url, retry, timeout) {
if (!(this instanceof Sock)) {
return new Sock(url, retry);
}
Copyright (c) 2015 - 2018, Buildbotics LLC
All rights reserved.
This file ("the software") is free software: you can redistribute it
and/or modify it under the terms of the GNU General Public License,
version 2 as published by the Free Software Foundation. You should
have received a copy of the GNU General Public License, version 2
along with the software. If not, see <http://www.gnu.org/licenses/>.
The software is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the software. If not, see
<http://www.gnu.org/licenses/>.
For information regarding this software email:
"Joseph Coffland" <joseph@buildbotics.com>
\******************************************************************************/
'use strict'
var Sock = function (url, retry, timeout) {
if (!(this instanceof Sock)) return new Sock(url, retry);
if (typeof retry == 'undefined') retry = 2000;
if (typeof timeout == 'undefined') timeout = 16000;
if (typeof retry == "undefined") {
retry = 2000;
}
if (typeof timeout == "undefined") {
timeout = 16000;
}
this.url = url;
this.retry = retry;
@@ -41,87 +19,88 @@ var Sock = function (url, retry, timeout) {
this.count = 0;
this.connect();
}
};
Sock.prototype.onmessage = function () {
// Ignore
};
Sock.prototype.onmessage = function () {}
Sock.prototype.onopen = function () {}
Sock.prototype.onclose = function () {}
Sock.prototype.onopen = function () {
// Ignore
};
Sock.prototype.onclose = function () {
// Ignore
};
Sock.prototype.connect = function () {
console.debug('connecting to', this.url);
console.debug("connecting to", this.url);
this.close();
this._sock = new SockJS(this.url);
this._sock.onmessage = function (e) {
console.debug('msg:', e.data);
this.heartbeat('msg');
console.debug("msg:", e.data);
this.heartbeat("msg");
this.onmessage(e);
}.bind(this);
this._sock.onopen = function () {
console.debug('connected');
this.heartbeat('open');
console.debug("connected");
this.heartbeat("open");
this.onopen();
}.bind(this);
this._sock.onclose = function () {
console.debug('disconnected');
console.debug("disconnected");
this._cancel_timeout();
this.onclose();
if (typeof this._sock != 'undefined')
if (typeof this._sock != "undefined") {
setTimeout(this.connect.bind(this), this.retry);
}
}.bind(this);
}
};
Sock.prototype._timedout = function () {
// Divide timeout so slow browser doesn't trigger timeouts when the
// connection is good.
if (this.divisions <= ++this.count) {
console.debug('connection timedout');
console.debug("connection timedout");
this._timeout = undefined;
this._sock.close();
} else this._set_timeout();
}
} else {
this._set_timeout();
}
};
Sock.prototype._cancel_timeout = function () {
clearTimeout(this._timeout);
this._timeout = undefined;
this.count = 0;
}
};
Sock.prototype._set_timeout = function () {
this._timeout = setTimeout(this._timedout.bind(this),
this.timeout / this.divisions);
}
};
Sock.prototype.heartbeat = function (msg) {
//console.debug('heartbeat ' + new Date().toLocaleTimeString() + ' ' + msg);
Sock.prototype.heartbeat = function () {
this._cancel_timeout();
this._set_timeout();
}
};
Sock.prototype.close = function () {
if (typeof this._sock != 'undefined') {
var sock = this._sock;
if (typeof this._sock != "undefined") {
const sock = this._sock;
this._sock = undefined;
sock.close();
}
}
};
Sock.prototype.send = function (msg) {
this._sock.send(msg);
};
Sock.prototype.send = function (msg) {this._sock.send(msg)}
module.exports = Sock
module.exports = Sock;

View File

@@ -1,12 +1,12 @@
'use strict'
"use strict";
module.exports = {
replace: true,
template: '#templated-input-template',
props: ['name', 'model', 'template'],
template: "#templated-input-template",
props: ["name", "model", "template"],
data: function () {
return { view: '' }
return { view: "" };
},
computed: {
@@ -33,10 +33,10 @@ module.exports = {
},
title: function () {
var s = `Default :${this.template.default} ${(this.template.unit || '')}`;
let s = `Default :${this.template.default} ${(this.template.unit || "")}`;
if (typeof this.template.help != 'undefined') {
s = this.template.help + '\n' + s;
if (typeof this.template.help != "undefined") {
s = `${this.template.help}\n${s}`;
}
return s;
@@ -45,7 +45,7 @@ module.exports = {
watch: {
_view: function () {
this.view = this._view
this.view = this._view;
},
view: function () {
@@ -58,12 +58,12 @@ module.exports = {
},
ready: function () {
this.view = this._view
this.view = this._view;
},
methods: {
change: function () {
this.$dispatch('input-changed')
this.$dispatch("input-changed");
}
}
}
};

View File

@@ -1,39 +1,12 @@
/******************************************************************************\
"use strict";
This file is part of the Buildbotics firmware.
Copyright (c) 2015 - 2018, Buildbotics LLC
All rights reserved.
This file ("the software") is free software: you can redistribute it
and/or modify it under the terms of the GNU General Public License,
version 2 as published by the Free Software Foundation. You should
have received a copy of the GNU General Public License, version 2
along with the software. If not, see <http://www.gnu.org/licenses/>.
The software is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the software. If not, see
<http://www.gnu.org/licenses/>.
For information regarding this software email:
"Joseph Coffland" <joseph@buildbotics.com>
\******************************************************************************/
'use strict';
const api = require('./api');
const modbus = require('./modbus.js');
const api = require("./api");
const modbus = require("./modbus.js");
const merge = require("lodash.merge");
module.exports = {
template: '#tool-view-template',
props: ['config', 'template', 'state'],
template: "#tool-view-template",
props: ["config", "template", "state"],
data: function () {
return {
@@ -110,20 +83,22 @@ module.exports = {
unsupported: true
}
]
}
};
},
components: {
'modbus-reg': require('./modbus-reg.js')
"modbus-reg": require("./modbus-reg.js")
},
watch: {
'state.mr': function () { this.value = this.state.mr }
"state.mr": function () {
this.value = this.state.mr;
}
},
events: {
'input-changed': function () {
this.$dispatch('config-changed');
"input-changed": function () {
this.$dispatch("config-changed");
return false;
},
@@ -135,19 +110,19 @@ module.exports = {
computed: {
regs_tmpl: function () {
return this.template['modbus-spindle'].regs;
return this.template["modbus-spindle"].regs;
},
tool_type: function () {
return this.config.tool['tool-type'].toUpperCase();
return this.config.tool["tool-type"].toUpperCase();
},
selected_tool: function () {
return this.config.tool['selected-tool'];
return this.config.tool["selected-tool"];
},
is_pwm_spindle: function () {
return this.selected_tool == 'pwm';
return this.selected_tool == "pwm";
},
is_modbus: function () {
@@ -170,13 +145,13 @@ module.exports = {
methods: {
change_selected_tool: function () {
const selectedToolSettings = this.config['selected-tool-settings'] || {};
const selectedToolSettings = this.config["selected-tool-settings"] || {};
const settings = selectedToolSettings[this.selected_tool] || {};
this.config.tool = merge({}, this.config.tool, settings['tool']);
this.config['pwm-spindle'] = merge({}, this.config['pwm-spindle'], settings['pwm-spindle']);
this.config['modbus-spindle'] = merge({}, this.config['modbus-spindle'], settings['modbus-spindle']);
this.config.tool = merge({}, this.config.tool, settings["tool"]);
this.config["pwm-spindle"] = merge({}, this.config["pwm-spindle"], settings["pwm-spindle"]);
this.config["modbus-spindle"] = merge({}, this.config["modbus-spindle"], settings["modbus-spindle"]);
const tool = this.toolList.find(tool => tool.id == this.config.tool['selected-tool']);
const tool = this.toolList.find(tool => tool.id == this.config.tool["selected-tool"]);
this.config.tool["tool-type"] = tool.type || tool.name;
this.$dispatch("config-changed");
@@ -207,71 +182,71 @@ module.exports = {
},
get_reg_type: function (reg) {
return this.regs_tmpl.template['reg-type'].values[this.state[reg + 'vt']];
return this.regs_tmpl.template["reg-type"].values[this.state[`${reg}vt`]];
},
get_reg_addr: function (reg) {
return this.state[reg + 'va'];
return this.state[`${reg}va`];
},
get_reg_value: function (reg) {
return this.state[reg + 'vv'];
return this.state[`${reg}vv`];
},
get_reg_fails: function (reg) {
const fails = this.state[reg + 'vr']
return fails == 255 ? 'Max' : fails;
const fails = this.state[`${reg}vr`];
return fails == 255 ? "Max" : fails;
},
show_modbus_field: function (key) {
return key != 'regs' &&
(key != 'multi-write' || this.tool_type == 'CUSTOM MODBUS VFD');
return key != "regs" && (key != "multi-write" || this.tool_type == "CUSTOM MODBUS VFD");
},
read: function (e) {
e.preventDefault();
api.put('modbus/read', { address: this.address });
api.put("modbus/read", { address: this.address });
},
write: function (e) {
e.preventDefault();
api.put('modbus/write', { address: this.address, value: this.value });
api.put("modbus/write", { address: this.address, value: this.value });
},
customize: function (e) {
e.preventDefault();
this.config.tool['tool-type'] = 'Custom Modbus VFD';
this.config.tool["tool-type"] = "Custom Modbus VFD";
const regs = this.config['modbus-spindle'].regs;
const regs = this.config["modbus-spindle"].regs;
for (let i = 0; i < regs.length; i++) {
const reg = this.regs_tmpl.index[i];
regs[i]['reg-type'] = this.get_reg_type(reg);
regs[i]['reg-addr'] = this.get_reg_addr(reg);
regs[i]['reg-value'] = this.get_reg_value(reg);
regs[i]["reg-type"] = this.get_reg_type(reg);
regs[i]["reg-addr"] = this.get_reg_addr(reg);
regs[i]["reg-value"] = this.get_reg_value(reg);
}
this.$dispatch('config-changed');
this.$dispatch("config-changed");
},
clear: function (e) {
e.preventDefault();
this.config.tool['tool-type'] = 'Custom Modbus VFD';
this.config.tool["tool-type"] = "Custom Modbus VFD";
const regs = this.config['modbus-spindle'].regs;
const regs = this.config["modbus-spindle"].regs;
for (let i = 0; i < regs.length; i++) {
regs[i]['reg-type'] = 'disabled';
regs[i]['reg-addr'] = 0;
regs[i]['reg-value'] = 0;
regs[i]["reg-type"] = "disabled";
regs[i]["reg-addr"] = 0;
regs[i]["reg-value"] = 0;
}
this.$dispatch('config-changed');
this.$dispatch("config-changed");
},
reset_failures: function (e) {
e.preventDefault();
const regs = this.config['modbus-spindle'].regs;
for (let reg = 0; reg < regs.length; reg++)
this.$dispatch('send', '\$' + reg + 'vr=0');
const regs = this.config["modbus-spindle"].regs;
for (let reg = 0; reg < regs.length; reg++) {
this.$dispatch("send", `$${reg}vr=0`);
}
}
}
}
};

View File

@@ -1,9 +1,9 @@
'use strict'
"use strict";
module.exports = {
replace: true,
template: '{{text}}<span class="unit">{{metric ? unit : iunit}}</span>',
props: ['value', 'precision', 'unit', 'iunit', 'scale'],
props: ["value", "precision", "unit", "iunit", "scale"],
computed: {
metric: {
@@ -14,9 +14,9 @@ module.exports = {
},
text: function () {
var value = this.value;
if (typeof value == 'undefined') {
return '';
let value = this.value;
if (typeof value == "undefined") {
return "";
}
if (!this.metric) {
@@ -28,20 +28,20 @@ module.exports = {
},
ready: function () {
if (typeof this.precision == 'undefined') {
if (typeof this.precision == "undefined") {
this.precision = 0;
}
if (typeof this.unit == 'undefined') {
this.unit = 'mm';
if (typeof this.unit == "undefined") {
this.unit = "mm";
}
if (typeof this.iunit == 'undefined') {
this.iunit = 'in';
if (typeof this.iunit == "undefined") {
this.iunit = "in";
}
if (typeof this.scale == 'undefined') {
if (typeof this.scale == "undefined") {
this.scale = 25.4;
}
}
}
};

9
src/js/utils.js Normal file
View File

@@ -0,0 +1,9 @@
function clickFileInput(formClass) {
const form = document.querySelector(`.${formClass}`);
form.reset();
form.querySelector("input").click();
}
module.exports = {
clickFileInput
};

View File

@@ -99,20 +99,26 @@
{#each $networkInfo.wifi.networks as network}
<Item
class="wifi-network"
on:SMUI:action={() => onNetworkSelected(network)}
on:SMUI:action={() =>
onNetworkSelected(network)}
>
<Graphic
class="strength {$networkInfo.wifi.ssid === network.Name
class="strength {$networkInfo.wifi
.ssid === network.Name
? 'active'
: ''}"
>
<span class="fa fa-wifi background" />
<span
class="fa fa-wifi"
style={getWifiStrengthStyle(network)}
style={getWifiStrengthStyle(
network
)}
/>
</Graphic>
<Text style="margin-right: 20px;">{network.Name}</Text>
<Text style="margin-right: 20px;"
>{network.Name}</Text
>
{#if network.Encryption !== "Open"}
<Meta>
<span class="fa fa-lock" />

View File

@@ -66,21 +66,21 @@
</fieldset>
<p>
Lower <tt>max-deviation</tt> to follow the programmed path more precisely but
at a slower speed.
Lower <tt>max-deviation</tt> to follow the programmed path more precisely
but at a slower speed.
</p>
<p>
In order to improve traversal speed, the path planner may merge consecutive
moves or round off sharp corners if doing so would deviate from the program
path by less than <tt>max-deviation</tt>.
In order to improve traversal speed, the path planner may merge
consecutive moves or round off sharp corners if doing so would deviate
from the program path by less than <tt>max-deviation</tt>.
</p>
<p>
GCode commands
<a href={`${gcodeURL}#gcode:g61`} target="_blank">G61, G61.1</a>
and <a href={`${gcodeURL}#gcode:g64`} target="_blank"> G64</a> also affect path
planning accuracy.
and <a href={`${gcodeURL}#gcode:g64`} target="_blank"> G64</a> also affect
path planning accuracy.
</p>
<h2>Cornering Speed (Advanced)</h2>
@@ -91,7 +91,7 @@
<p>
Junction acceleration limits the cornering speed the planner will allow.
Increasing this value will allow for faster traversal of corners but may
cause the planner to violate axis jerk limits and stall the motors. Use with
caution.
cause the planner to violate axis jerk limits and stall the motors. Use
with caution.
</p>
</div>

View File

@@ -1,5 +1,10 @@
<script lang="ts">
import Dialog, { Title, Content, Actions, InitialFocus } from "@smui/dialog";
import Dialog, {
Title,
Content,
Actions,
InitialFocus,
} from "@smui/dialog";
import Button, { Label } from "@smui/button";
import TextField from "@smui/textfield";
import MessageDialog from "$dialogs/MessageDialog.svelte";
@@ -88,7 +93,11 @@
<Button>
<Label>Cancel</Label>
</Button>
<Button defaultAction on:click={onConfirm} disabled={hostname.length === 0}>
<Button
defaultAction
on:click={onConfirm}
disabled={hostname.length === 0}
>
<Label>Confirm & Reboot</Label>
</Button>
</Actions>

View File

@@ -46,7 +46,8 @@
axis: string;
};
const SetAxisPositionDialogProps = writable<SetAxisPositionDialogPropsType>();
const SetAxisPositionDialogProps =
writable<SetAxisPositionDialogPropsType>();
type SetAxisPositionDialogPropsType = {
open: boolean;
axis: string;
@@ -190,12 +191,14 @@
);
keyboardObserver = new MutationObserver(() => {
const open = virtualKeyboard.getAttribute("_state") === "open";
const open =
virtualKeyboard.getAttribute("_state") === "open";
const keyboardHeight = Number.parseFloat(
virtualKeyboardOverlay.style.height
);
const dialogContainers = document.querySelectorAll<HTMLDivElement>(
const dialogContainers =
document.querySelectorAll<HTMLDivElement>(
".mdc-dialog .mdc-dialog__container"
);

View File

@@ -1,5 +1,10 @@
<script lang="ts">
import Dialog, { Title, Content, Actions, InitialFocus } from "@smui/dialog";
import Dialog, {
Title,
Content,
Actions,
InitialFocus,
} from "@smui/dialog";
import Button, { Label } from "@smui/button";
export let open;

View File

@@ -1,5 +1,10 @@
<script lang="ts">
import Dialog, { Title, Content, Actions, InitialFocus } from "@smui/dialog";
import Dialog, {
Title,
Content,
Actions,
InitialFocus,
} from "@smui/dialog";
import TextField from "@smui/textfield";
import Button, { Label } from "@smui/button";
import { ControllerMethods } from "$lib/RegisterControllerMethods";
@@ -21,9 +26,10 @@
aria-labelledby="manual-home-axis-dialog-title"
aria-describedby="manual-home-axis-dialog-content"
>
<Title id="manual-home-axis-dialog-title"
>Manually Home {axis.toUpperCase()} Axis</Title
>
<Title id="manual-home-axis-dialog-title">
Manually Home {axis.toUpperCase()} Axis
</Title>
<Content id="manual-home-axis-dialog-content">
<p>Set axis absolute position</p>

View File

@@ -1,5 +1,10 @@
<script lang="ts">
import Dialog, { Title, Content, Actions, InitialFocus } from "@smui/dialog";
import Dialog, {
Title,
Content,
Actions,
InitialFocus,
} from "@smui/dialog";
import Button, { Label } from "@smui/button";
export let open: boolean;

View File

@@ -50,6 +50,7 @@
"1/16 in",
"1/32 in",
];
const metricBits: `${number} mm`[] = [
"12 mm",
"10 mm",
@@ -289,17 +290,21 @@
<Content id="probe-dialog-content" style="overflow: visible;">
<div class="steps">
<p><b>Step {steps.indexOf(currentStep) + 1} of {steps.length}</b></p>
<p>
<b>Step {steps.indexOf(currentStep) + 1} of {steps.length}</b>
</p>
<ul>
{#each steps as step}
<li class:active={currentStep === step}>{stepLabels[step]}</li>
<li class:active={currentStep === step}>
{stepLabels[step]}
</li>
{/each}
</ul>
</div>
<p>
{#if currentStep === "CheckProbe"}
Attach the probe magnet to the collet, then touch the probe block to the
bit.
Attach the probe magnet to the collet, then touch the probe
block to the bit.
{:else if currentStep === "BitDimensions"}
<TextFieldWithOptions
label="Cutter diameter"
@@ -313,13 +318,17 @@
/>
{:else if currentStep === "PlaceProbeBlock"}
{#if probeType === "xyz"}
Place the probe block face up, on the lower-left corner of your
workpiece.
Place the probe block face up, on the lower-left corner of
your workpiece.
{:else}
Place the probe block face down, with the bit above the recess.
Place the probe block face down, with the bit above the
recess.
{/if}
<p>The probing procedure will begin as soon as you click 'Next'.</p>
<p>
The probing procedure will begin as soon as you click
'Next'.
</p>
{:else if currentStep === "Probe"}
Probing in progress...
{:else if currentStep === "Done"}
@@ -327,7 +336,9 @@
Could not find the probe block during probing!
<p>
Make sure the tip of the bit is less than {metric ? "25mm" : "1 in"}
Make sure the tip of the bit is less than {metric
? "25mm"
: "1 in"}
above the probe block, and try again.
</p>
{:else}

View File

@@ -1,5 +1,10 @@
<script type="ts">
import Dialog, { Title, Content, Actions, InitialFocus } from "@smui/dialog";
import Dialog, {
Title,
Content,
Actions,
InitialFocus,
} from "@smui/dialog";
import Button, { Label } from "@smui/button";
import Radio from "@smui/radio";
import FormField from "@smui/form-field";

View File

@@ -1,5 +1,10 @@
<script lang="ts">
import Dialog, { Title, Content, Actions, InitialFocus } from "@smui/dialog";
import Dialog, {
Title,
Content,
Actions,
InitialFocus,
} from "@smui/dialog";
import TextField from "@smui/textfield";
import Button, { Label } from "@smui/button";
import { ControllerMethods } from "$lib/RegisterControllerMethods";
@@ -35,9 +40,10 @@
aria-labelledby="set-axis-position-dialog-title"
aria-describedby="set-axis-position-dialog-content"
>
<Title id="set-axis-position-dialog-title"
>Set {axis.toUpperCase()} Axis Position</Title
>
<Title id="set-axis-position-dialog-title">
Set {axis.toUpperCase()} Axis Position
</Title>
<Content id="set-axis-position-dialog-content">
<TextField
label="Position"

View File

@@ -1,5 +1,10 @@
<script lang="ts">
import Dialog, { Title, Content, Actions, InitialFocus } from "@smui/dialog";
import Dialog, {
Title,
Content,
Actions,
InitialFocus,
} from "@smui/dialog";
import Button, { Label } from "@smui/button";
import TextField from "@smui/textfield";
import CircularProgress from "@smui/circular-progress";
@@ -131,24 +136,27 @@
<Content id="set-time-dialog-content">
{#if loading}
<div style="display: flex; justify-content: center">
<CircularProgress style="height: 32px; width: 32px;" indeterminate />
<CircularProgress
style="height: 32px; width: 32px;"
indeterminate
/>
</div>
{:else}
{#if networkTimeSynchronized}
<p>
Because this controller is connected to the internet, the time is
managed automatically, and cannot be manually set.
Because this controller is connected to the internet, the
time is managed automatically, and cannot be manually set.
</p>
{:else}
<p>
Because this controller is not connected to the internet, you can
manually set the time.
Because this controller is not connected to the internet,
you can manually set the time.
</p>
<p>
Note: any time the controller is turned off, the time will need to be
reset. If you connect the controller to the internet, the time will be
managed automatically.
Note: any time the controller is turned off, the time will
need to be reset. If you connect the controller to the
internet, the time will be managed automatically.
</p>
<Label>Date & Time</Label>
@@ -156,7 +164,10 @@
bind:value
use={[
InitialFocus,
[virtualKeyboardChange, (newValue) => (value = newValue)],
[
virtualKeyboardChange,
(newValue) => (value = newValue),
],
]}
label="Time"
type="datetime-local"
@@ -166,8 +177,8 @@
{/if}
<p>
To display your local time correctly, the controller must know what
timezone it is in.
To display your local time correctly, the controller must know
what timezone it is in.
</p>
<div class="timezones-container" style="margin-top: 20px;">

View File

@@ -1,7 +1,7 @@
<script lang="ts">
import Dialog, { Title, Actions, InitialFocus } from "@smui/dialog";
import Button, { Label } from "@smui/button";
import * as Api from "$lib/api"
import * as Api from "$lib/api";
export let open;

View File

@@ -1,5 +1,10 @@
<script lang="ts">
import Dialog, { Title, Content, Actions, InitialFocus } from "@smui/dialog";
import Dialog, {
Title,
Content,
Actions,
InitialFocus,
} from "@smui/dialog";
import Button, { Label } from "@smui/button";
import LinearProgress from "@smui/linear-progress";

View File

@@ -1,5 +1,10 @@
<script lang="ts">
import Dialog, { Title, Content, Actions, InitialFocus } from "@smui/dialog";
import Dialog, {
Title,
Content,
Actions,
InitialFocus,
} from "@smui/dialog";
import Button, { Label } from "@smui/button";
import TextField from "@smui/textfield";
import Icon from "@smui/textfield/icon";
@@ -60,7 +65,10 @@
bind:value={password}
use={[
InitialFocus,
[virtualKeyboardChange, (newValue) => (password = newValue)],
[
virtualKeyboardChange,
(newValue) => (password = newValue),
],
]}
label="Password"
spellcheck="false"
@@ -72,7 +80,9 @@
slot="trailingIcon"
on:click={() => (showPassword = !showPassword)}
>
<Icon class={`fa ${showPassword ? "fa-eye-slash" : "fa-eye"}`} />
<Icon
class={`fa ${showPassword ? "fa-eye-slash" : "fa-eye"}`}
/>
</div>
<HelperText persistent slot="helper">
Wifi passwords must be 8 to 128 characters
@@ -82,7 +92,8 @@
<p>
<em>
Clicking {connectOrDisconnect} will reboot the controller to apply the changes.
Clicking {connectOrDisconnect} will reboot the controller to apply
the changes.
</em>
</p>
</Content>
@@ -95,7 +106,8 @@
<Button
defaultAction
on:click={onConfirm}
disabled={needPassword && (password.length < 8 || password.length > 128)}
disabled={needPassword &&
(password.length < 8 || password.length > 128)}
>
<Label>{connectOrDisconnect} & Reboot</Label>
</Button>

View File

@@ -31,15 +31,15 @@ const empty: NetworkInfo = {
ssid: "",
networks: []
}
}
};
export const networkInfo = writable<NetworkInfo>(empty);
export function processNetworkInfo(rawNetworkInfo: NetworkInfo) {
const now = Date.now();
const networksByName: Record<string, WifiNetwork> = {}
const networksByName: Record<string, WifiNetwork> = {};
for (let network of rawNetworkInfo.wifi.networks) {
for (const network of rawNetworkInfo.wifi.networks) {
if (network.Name) {
network.lastSeen = now;
network.active = rawNetworkInfo.wifi.ssid === network.Name;
@@ -53,7 +53,7 @@ export function processNetworkInfo(rawNetworkInfo: NetworkInfo) {
}
}
for (let network of Object.values(networksByName)) {
for (const network of Object.values(networksByName)) {
if (network.lastSeen - now > 30000) {
delete networksByName[network.Name];
}

View File

@@ -1,9 +1,3 @@
type NumberWithUnit = {
value: number,
metric: boolean,
toMetric: () => number;
}
function numberWithUnitToMetric() {
return this.metric ? this.value : this.value * 25.4;
}
@@ -38,12 +32,13 @@ function formatFraction(value: number) {
export const numberWithUnit = {
regex: /^\s*(?:(\d+)\s*\/\s*(\d+)|(\d*\.\d+)|(\d+(?:\.\d+)?))\s*("|in|inch|inches|mm|millimeters)\s*$/,
parse: function (str: string) {
// eslint-disable-next-line prefer-const
let [, numerator, denominator, decimal1, decimal2, unit]: any = str?.match(numberWithUnit.regex) ?? [];
numerator = Number.parseFloat(numerator)
denominator = Number.parseFloat(denominator)
decimal1 = Number.parseFloat(decimal1)
decimal2 = Number.parseFloat(decimal2)
numerator = Number.parseFloat(numerator);
denominator = Number.parseFloat(denominator);
decimal1 = Number.parseFloat(decimal1);
decimal2 = Number.parseFloat(decimal2);
const metric = (unit ?? "").includes("m");
@@ -81,10 +76,10 @@ export const numberWithUnit = {
return "";
case value.metric:
return `${value.value} mm`
return `${value.value} mm`;
default:
return `${formatFraction(value.value)} in`
return `${formatFraction(value.value)} in`;
}
}
}
};

View File

@@ -6,36 +6,36 @@ async function doFetch(method: HttpMethod, url: string, data: any, config: Reque
...config,
method,
cache: "no-cache",
body: (typeof data === 'object')
body: (typeof data === "object")
? JSON.stringify(data)
: undefined,
headers: (typeof data === 'object')
headers: (typeof data === "object")
? {
"Content-Type": 'application/json; charset=utf-8'
"Content-Type": "application/json; charset=utf-8"
}
: {}
});
return await response.json();
} catch (error) {
console.debug('API Error: ' + url + ': ' + error);
console.debug(`API Error: ${url}: ${error}`);
throw error;
}
}
export async function GET(url: string, config: RequestInit = {}) {
return doFetch('GET', url, undefined, config);
return doFetch("GET", url, undefined, config);
}
export async function PUT(url: string, data: any = undefined, config: RequestInit = {}) {
return doFetch('PUT', url, data, config);
return doFetch("PUT", url, data, config);
}
export async function POST(url: string, data: any = undefined, config: RequestInit = {}) {
return doFetch('POST', url, data, config);
return doFetch("POST", url, data, config);
}
export async function DELETE(url: string, config = {}) {
return doFetch('DELETE', url, undefined, config);
return doFetch("DELETE", url, undefined, config);
}

View File

@@ -1,12 +1,12 @@
import 'polyfill-object.fromentries';
import "polyfill-object.fromentries";
import matchAll from "string.prototype.matchall";
matchAll.shim();
import AdminNetworkView from '$components/AdminNetworkView.svelte';
import SettingsView from '$components/SettingsView.svelte';
import AdminNetworkView from "$components/AdminNetworkView.svelte";
import SettingsView from "$components/SettingsView.svelte";
import DialogHost, { showDialog } from "$dialogs/DialogHost.svelte";
import { handleConfigUpdate, setDisplayUnits } from '$lib/ConfigStore';
import { handleConfigUpdate, setDisplayUnits } from "$lib/ConfigStore";
import { handleControllerStateUpdate } from "$lib/ControllerState";
import { registerControllerMethods } from "$lib/RegisterControllerMethods";