1
0
Fork 0
mirror of https://github.com/iNavFlight/inav-configurator.git synced 2025-07-16 21:05:28 +03:00
inav-configurator/tabs/setup.js
Alberto García Hierro 0e01133fc9 Make tab loading async safe and add a small animation
Tab loading was relying on replacing the contents of '#content'
with the loading indicator, then replacing it with the loading tab
content and blocking rendering until the tab was ready by not
yielding. This is problematic for tabs that load some data
asynchronously, like PID and OSD.

Instead, put the loading indicator in front of everything else
and load new content inside '#content' next to the loading indicator
(but without showing it). Once the content and data are fully loaded
we fade out the loading indicator with a 0.4s long animation and
then we remove. This works for both synchronous and asynchonous
loading of tabs.
2020-01-21 18:19:06 +00:00

314 lines
12 KiB
JavaScript
Executable file

/*global $,chrome,FC,helper,mspHelper,MIXER_CONFIG,BF_CONFIG*/
'use strict';
TABS.setup = {
yaw_fix: 0.0
};
TABS.setup.initialize = function (callback) {
var self = this;
if (GUI.active_tab != 'setup') {
GUI.active_tab = 'setup';
googleAnalytics.sendAppView('Setup');
}
var loadChainer = new MSPChainerClass();
var loadChain = [
mspHelper.loadBfConfig,
mspHelper.queryFcStatus,
mspHelper.loadMixerConfig
];
loadChain.push(mspHelper.loadMiscV2);
loadChainer.setChain(loadChain);
loadChainer.setExitPoint(load_html);
loadChainer.execute();
function load_html() {
GUI.load("./tabs/setup.html", process_html);
}
function process_html() {
// translate to user-selected language
localize();
if (!FC.isMotorOutputEnabled()) {
GUI_control.prototype.log("<span style='color: red; font-weight: bolder'><strong>" + chrome.i18n.getMessage("logPwmOutputDisabled") + "</strong></span>");
}
// initialize 3D
self.initialize3D();
// set roll in interactive block
$('span.roll').text(chrome.i18n.getMessage('initialSetupAttitude', [0]));
// set pitch in interactive block
$('span.pitch').text(chrome.i18n.getMessage('initialSetupAttitude', [0]));
// set heading in interactive block
$('span.heading').text(chrome.i18n.getMessage('initialSetupAttitude', [0]));
// check if we have magnetometer
if (!bit_check(CONFIG.activeSensors, 2)) {
$('a.calibrateMag').addClass('disabled');
$('default_btn').addClass('disabled');
}
self.initializeInstruments();
$('a.resetSettings').click(function () {
if (confirm(chrome.i18n.getMessage('confirm_reset_settings'))) {
MSP.send_message(MSPCodes.MSP_RESET_CONF, false, false, function () {
GUI.log(chrome.i18n.getMessage('initialSetupSettingsRestored'));
GUI.tab_switch_cleanup(function () {
TABS.setup.initialize();
});
});
}
});
// display current yaw fix value (important during tab re-initialization)
$('div#interactive_block > a.reset').text(chrome.i18n.getMessage('initialSetupButtonResetZaxisValue', [self.yaw_fix]));
// reset yaw button hook
$('div#interactive_block > a.reset').click(function () {
self.yaw_fix = SENSOR_DATA.kinematics[2] * - 1.0;
$(this).text(chrome.i18n.getMessage('initialSetupButtonResetZaxisValue', [self.yaw_fix]));
console.log('YAW reset to 0 deg, fix: ' + self.yaw_fix + ' deg');
});
// cached elements
var bat_voltage_e = $('.bat-voltage'),
bat_percent_e = $('.bat-percent'),
bat_remaining_e = $('.bat-remain-cap'),
bat_cells_e = $('.bat-cells'),
bat_thresh_e = $('.bat-thresh'),
bat_full_e = $('.bat-full'),
bat_mah_drawn_e = $('.bat-mah-drawn'),
bat_wh_drawn_e = $('.bat-mwh-drawn'),
bat_current_draw_e = $('.bat-current-draw'),
bat_power_draw_e = $('.bat-power-draw'),
rssi_e = $('.rssi'),
gpsFix_e = $('.gpsFixType'),
gpsSats_e = $('.gpsSats'),
gpsLat_e = $('.gpsLat'),
gpsLon_e = $('.gpsLon'),
roll_e = $('dd.roll'),
pitch_e = $('dd.pitch'),
heading_e = $('dd.heading');
function get_slow_data() {
if (have_sensor(CONFIG.activeSensors, 'gps')) {
/*
* Enable balancer
*/
if (helper.mspQueue.shouldDrop()) {
return;
}
MSP.send_message(MSPCodes.MSP_RAW_GPS, false, false, function () {
var gpsFixType = chrome.i18n.getMessage('gpsFixNone');
if (GPS_DATA.fix >= 2)
gpsFixType = chrome.i18n.getMessage('gpsFix3D');
else if (GPS_DATA.fix >= 1)
gpsFixType = chrome.i18n.getMessage('gpsFix2D');
gpsFix_e.html(gpsFixType);
gpsSats_e.text(GPS_DATA.numSat);
gpsLat_e.text((GPS_DATA.lat / 10000000).toFixed(4) + ' deg');
gpsLon_e.text((GPS_DATA.lon / 10000000).toFixed(4) + ' deg');
});
}
}
function get_fast_data() {
/*
* Enable balancer
*/
if (helper.mspQueue.shouldDrop()) {
return;
}
MSP.send_message(MSPCodes.MSP_ATTITUDE, false, false, function () {
roll_e.text(chrome.i18n.getMessage('initialSetupAttitude', [SENSOR_DATA.kinematics[0]]));
pitch_e.text(chrome.i18n.getMessage('initialSetupAttitude', [SENSOR_DATA.kinematics[1]]));
heading_e.text(chrome.i18n.getMessage('initialSetupAttitude', [SENSOR_DATA.kinematics[2]]));
self.render3D();
self.updateInstruments();
});
}
helper.mspBalancedInterval.add('setup_data_pull_fast', 40, 1, get_fast_data);
helper.mspBalancedInterval.add('setup_data_pull_slow', 250, 1, get_slow_data);
helper.interval.add('gui_analog_update', function () {
bat_cells_e.text(chrome.i18n.getMessage('initialSetupBatteryDetectedCellsValue', [ANALOG.cell_count]));
bat_voltage_e.text(chrome.i18n.getMessage('initialSetupBatteryVoltageValue', [ANALOG.voltage]));
remaining_capacity_wh_decimals = ANALOG.battery_remaining_capacity.toString().length < 5 ? 3 : (7 - ANALOG.battery_remaining_capacity.toString().length);
remaining_capacity_value = MISC.battery_capacity_unit == 'mAh' ? ANALOG.battery_remaining_capacity : (ANALOG.battery_remaining_capacity / 1000).toFixed(remaining_capacity_wh_decimals < 0 ? 0 : remaining_capacity_wh_decimals);
remaining_capacity_unit = MISC.battery_capacity_unit == 'mAh' ? 'mAh' : 'Wh';
bat_remaining_e.text(chrome.i18n.getMessage('initialSetupBatteryRemainingCapacityValue', ((MISC.battery_capacity > 0) && ANALOG.battery_full_when_plugged_in) ? [remaining_capacity_value, remaining_capacity_unit] : ['NA', '']));
bat_percent_e.text(chrome.i18n.getMessage('initialSetupBatteryPercentageValue', [ANALOG.battery_percentage]));
bat_full_e.text(chrome.i18n.getMessage('initialSetupBatteryFullValue', [ANALOG.battery_full_when_plugged_in]));
bat_thresh_e.text(chrome.i18n.getMessage('initialSetupBatteryThresholdsValue', [ANALOG.use_capacity_thresholds]));
bat_mah_drawn_e.text(chrome.i18n.getMessage('initialSetupBatteryMahValue', [ANALOG.mAhdrawn]));
capacity_drawn_decimals = ANALOG.mWhdrawn.toString().length < 5 ? 3 : (7 - ANALOG.mWhdrawn.toString().length);
bat_wh_drawn_e.text(chrome.i18n.getMessage('initialSetup_Wh_drawnValue', [(ANALOG.mWhdrawn / 1000).toFixed(capacity_drawn_decimals < 0 ? 0 : capacity_drawn_decimals)]));
bat_current_draw_e.text(chrome.i18n.getMessage('initialSetupCurrentDrawValue', [ANALOG.amperage.toFixed(2)]));
bat_power_draw_e.text(chrome.i18n.getMessage('initialSetupPowerDrawValue', [ANALOG.power.toFixed(2)]));
rssi_e.text(chrome.i18n.getMessage('initialSetupRSSIValue', [((ANALOG.rssi / 1023) * 100).toFixed(0)]));
}, 100, true);
function updateArminFailure() {
var flagNames = FC.getArmingFlags();
for (var bit in flagNames) {
if (flagNames.hasOwnProperty(bit)) {
if (bit_check(CONFIG.armingFlags, bit)) {
$('#reason-' + flagNames[bit]).html(chrome.i18n.getMessage('armingCheckFail'));
}
else {
$('#reason-' + flagNames[bit]).html(chrome.i18n.getMessage('armingCheckPass'));
}
}
}
}
/*
* 1fps update rate will be fully enough
*/
helper.interval.add('updateArminFailure', updateArminFailure, 500, true);
GUI.content_ready(callback);
}
};
TABS.setup.initializeInstruments = function() {
var options = {size:90, showBox : false, img_directory: 'images/flightindicators/'};
var attitude = $.flightIndicator('#attitude', 'attitude', options);
var heading = $.flightIndicator('#heading', 'heading', options);
this.updateInstruments = function() {
attitude.setRoll(SENSOR_DATA.kinematics[0]);
attitude.setPitch(SENSOR_DATA.kinematics[1]);
heading.setHeading(SENSOR_DATA.kinematics[2]);
};
};
TABS.setup.initialize3D = function () {
var self = this,
loader,
canvas,
wrapper,
renderer,
camera,
scene,
light,
light2,
modelWrapper,
model,
model_file,
useWebGlRenderer = false;
canvas = $('.model-and-info #canvas');
wrapper = $('.model-and-info #canvas_wrapper');
// webgl capability detector
// it would seem the webgl "enabling" through advanced settings will be ignored in the future
// and webgl will be supported if gpu supports it by default (canary 40.0.2175.0), keep an eye on this one
var detector_canvas = document.createElement('canvas');
if (window.WebGLRenderingContext && (detector_canvas.getContext('webgl') || detector_canvas.getContext('experimental-webgl'))) {
renderer = new THREE.WebGLRenderer({canvas: canvas.get(0), alpha: true, antialias: true});
useWebGlRenderer = true;
} else {
renderer = new THREE.CanvasRenderer({canvas: canvas.get(0), alpha: true});
}
// initialize render size for current canvas size
renderer.setSize(wrapper.width()*2, wrapper.height()*2);
// modelWrapper adds an extra axis of rotation to avoid gimbal lock with the euler angles
modelWrapper = new THREE.Object3D();
// load the model including materials
if (useWebGlRenderer) {
if (MIXER_CONFIG.appliedMixerPreset === -1) {
model_file = 'custom';
GUI_control.prototype.log("<span style='color: red; font-weight: bolder'><strong>" + chrome.i18n.getMessage("mixerNotConfigured") + "</strong></span>");
} else {
model_file = helper.mixer.getById(MIXER_CONFIG.appliedMixerPreset).model;
}
} else {
model_file = 'fallback'
}
// Temporary workaround for 'custom' model until akfreak's custom model is merged.
if (model_file == 'custom') {
model_file = 'fallback';
}
// setup scene
scene = new THREE.Scene();
loader = new THREE.JSONLoader();
loader.load('./resources/models/' + model_file + '.json', function (geometry, materials) {
var modelMaterial = new THREE.MeshFaceMaterial(materials);
model = new THREE.Mesh(geometry, modelMaterial);
model.scale.set(15, 15, 15);
modelWrapper.add(model);
scene.add(modelWrapper);
});
// stationary camera
camera = new THREE.PerspectiveCamera(50, wrapper.width() / wrapper.height(), 1, 10000);
// some light
light = new THREE.AmbientLight(0x404040);
light2 = new THREE.DirectionalLight(new THREE.Color(1, 1, 1), 1.5);
light2.position.set(0, 1, 0);
// move camera away from the model
camera.position.z = 125;
// add camera, model, light to the foreground scene
scene.add(light);
scene.add(light2);
scene.add(camera);
scene.add(modelWrapper);
this.render3D = function () {
if (!model) {
return;
}
// compute the changes
model.rotation.x = (SENSOR_DATA.kinematics[1] * -1.0) * 0.017453292519943295;
modelWrapper.rotation.y = ((SENSOR_DATA.kinematics[2] * -1.0) - self.yaw_fix) * 0.017453292519943295;
model.rotation.z = (SENSOR_DATA.kinematics[0] * -1.0) * 0.017453292519943295;
// draw
renderer.render(scene, camera);
};
// handle canvas resize
this.resize3D = function () {
renderer.setSize(wrapper.width()*2, wrapper.height()*2);
camera.aspect = wrapper.width() / wrapper.height();
camera.updateProjectionMatrix();
self.render3D();
};
$(window).on('resize', this.resize3D);
};
TABS.setup.cleanup = function (callback) {
$(window).off('resize', this.resize3D);
if (callback) callback();
};