Files
mixly3/common/modules/mixly-modules/common/statusbar-serial-chart.js
2024-07-19 21:53:55 +08:00

267 lines
6.9 KiB
JavaScript

goog.loadJs('common', () => {
goog.require('path');
goog.require('$.ui');
goog.require('$.flot');
goog.require('$.select2');
goog.require('Mixly.Env');
goog.require('Mixly.Msg');
goog.require('Mixly.PageBase');
goog.require('Mixly.Regression');
goog.require('Mixly.HTMLTemplate');
goog.require('Mixly.Config');
goog.provide('Mixly.StatusBarSerialChart');
const {
Env,
Msg,
PageBase,
Regression,
HTMLTemplate,
Config
} = Mixly;
const { USER, SELECTED_BOARD } = Config;
class StatusBarSerialChart extends PageBase {
static {
HTMLTemplate.add(
'html/statusbar/statusbar-serial-chart.html',
new HTMLTemplate(goog.get(path.join(Env.templatePath, 'html/statusbar/statusbar-serial-chart.html')))
);
}
#data_ = [];
#totalPoints_ = SELECTED_BOARD?.serial?.pointNum ?? 100;
#yMax_ = SELECTED_BOARD?.serial?.yMax ?? 100;
#yMin_ = SELECTED_BOARD?.serial?.yMin ?? 0;
#needUpdate_ = false;
#regression_ = new Regression();
#plot_ = null;
#opened_ = false;
#started_ = false;
#$pointNum_ = null;
#$yMax_ = null;
#$yMin_ = null;
#isOpened_ = false;
constructor() {
super();
const template = HTMLTemplate.get('html/statusbar/statusbar-serial-chart.html');
const $template = $(template.render({
pointsNum: Msg.Lang['statusbar.serial.chart.pointsNum'],
yMin: Msg.Lang['statusbar.serial.chart.yMin'],
yMax: Msg.Lang['statusbar.serial.chart.yMax']
}));
this.setContent($template);
this.#$pointNum_ = $template.find('select');
this.#$pointNum_.select2({
width: '100%',
minimumResultsForSearch: 50,
dropdownCssClass: 'mixly-scrollbar'
});
this.#$pointNum_.val(this.#totalPoints_).trigger('change');
this.#$yMax_ = $template.find('.y-max');
this.#$yMax_.val(this.#yMax_);
this.#$yMin_ = $template.find('.y-min');
this.#$yMin_.val(this.#yMin_);
const axisFontColor = USER.theme === 'light' ? '#000' : '#c2c3c2';
this.#plot_ = $.plot($template.find('.figure'), this.getValue(), {
series: {
shadowSize: 1
},
colors: ['#777'],
yaxis: {
min: this.#yMin_,
max: this.#yMax_,
show: true,
font: {
fill: axisFontColor
}
},
xaxis: {
show: true,
font: {
fill: axisFontColor
},
mode: 'time',
timezone: 'browser',
twelveHourClock: true,
timeBase: 'milliseconds',
minTickSize: [1, 'second'],
min: Date.now(),
max: Date.now() + 1000 * 10,
}
});
this.#addEventsListener_();
}
#addEventsListener_() {
this.#$pointNum_.on('select2:select', (event) => {
const { data } = event.params;
this.#totalPoints_ = data.id;
this.setValue([]);
});
this.#$yMax_.change(() => {
const yMax = parseInt(this.#$yMax_.val());
if (isNaN(yMax) || yMax <= this.#yMin_) {
this.#$yMax_.val(this.#yMax_);
} else {
this.#yMax_ = yMax;
let { yaxis } = this.#plot_.getAxes();
yaxis.options.max = yMax;
}
});
this.#$yMin_.change(() => {
const yMin = parseInt(this.#$yMin_.val());
if (isNaN(yMin) || yMin >= this.#yMax_) {
this.#$yMin_.val(this.#yMin_);
} else {
this.#yMin_ = yMin;
let { yaxis } = this.#plot_.getAxes();
yaxis.options.min = yMin;
}
});
}
init() {
super.init();
this.hideCloseBtn();
this.resize();
}
resize() {
this.#plot_.getSurface().clearCache();
super.resize();
this.#plot_.resize();
this.#plot_.setupGrid(false);
this.#plot_.draw();
}
stop() {
this.setValue([]);
this.#opened_ = false;
this.#started_ = false;
}
start() {
this.#opened_ = true;
if (this.#started_) {
return;
}
this.#started_ = true;
this.update();
}
update() {
if (!this.#started_) {
return;
}
if (!this.isActive()) {
this.#started_ = false;
return;
}
if (!this.#needUpdate_) {
setTimeout(() => this.update(), 50);
return;
}
this.#plot_.setData(this.getValue());
this.#plot_.getSurface().clearCache();
this.#plot_.setupGrid(false);
this.#plot_.draw();
this.setRange(this.#plot_);
this.#needUpdate_ = false;
window.requestAnimationFrame(() => this.update());
}
getValue() {
return [{
data: this.#data_,
lines: {
show: true,
fill: false,
fillColor: '#007acc'
}
}];
}
addValue(data) {
if (!this.#started_) {
return;
}
if (this.#data_.length
&& data[0] === this.#data_[this.#data_.length - 1][0]) {
return;
}
while (this.#data_.length > this.#totalPoints_) {
this.#data_.shift();
}
this.#data_.push([Date.now(), data]);
this.#needUpdate_ = true;
}
setValue(data) {
if (!this.#started_) {
return;
}
this.#data_ = data;
this.#needUpdate_ = true;
}
setRange() {
let { xaxis } = this.#plot_.getAxes();
let { data = [] } = this.#plot_.getData()[0] ?? {};
if (!data.length) {
return;
}
if (data.length >= this.#totalPoints_) {
xaxis.options.min = data[0][0];
xaxis.options.max = data[this.#totalPoints_ - 1][0];
return;
}
let x = [], y = [];
for (let i in data) {
x.push((i - 0) + 1);
y.push(data[i][0] - data[0][0]);
}
this.#regression_.fit(x, y);
let xMax = this.#regression_.predict([this.#totalPoints_])[0] + data[0][0];
let xMin = data[0][0];
xaxis.options.min = xMin;
xaxis.options.max = xMax;
}
setStatus(isOpened) {
this.#isOpened_ = isOpened;
}
isOpened() {
return this.#isOpened_;
}
onMounted() {
super.onMounted();
if (this.#opened_) {
this.start();
}
}
onUnmounted() {
this.setValue([]);
super.onUnmounted();
}
dispose() {
this.#plot_.shutdown();
this.#$pointNum_.select2('destroy');
super.dispose();
}
}
Mixly.StatusBarSerialChart = StatusBarSerialChart;
});