2019-06-29 12:54:32 +02:00
|
|
|
/*
|
|
|
|
* μlogger
|
|
|
|
*
|
|
|
|
* Copyright(C) 2019 Bartek Fabiszewski (www.fabiszewski.net)
|
|
|
|
*
|
|
|
|
* This is free software; you can redistribute it and/or modify it under
|
|
|
|
* the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation; either version 3 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program 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
|
|
|
|
* General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
2019-05-15 11:32:36 +02:00
|
|
|
import { config, lang } from './constants.js';
|
|
|
|
import uEvent from './event.js';
|
|
|
|
import uUtils from './utils.js';
|
|
|
|
|
|
|
|
/* global Chartist */
|
|
|
|
|
|
|
|
document.addEventListener('DOMContentLoaded', () => {
|
|
|
|
Chart.onDomLoaded();
|
|
|
|
});
|
|
|
|
|
|
|
|
export default class Chart {
|
|
|
|
/**
|
|
|
|
* @param {uBinder} binder
|
|
|
|
*/
|
|
|
|
constructor(binder) {
|
2019-06-29 12:54:32 +02:00
|
|
|
binder.addEventListener(uEvent.MARKER_OVER, this);
|
|
|
|
binder.addEventListener(uEvent.MARKER_SELECT, this);
|
2019-05-15 11:32:36 +02:00
|
|
|
binder.addEventListener(uEvent.TRACK_READY, this);
|
2019-06-29 12:54:32 +02:00
|
|
|
binder.addEventListener(uEvent.UI_READY, this);
|
2019-05-15 11:32:36 +02:00
|
|
|
this._binder = binder;
|
|
|
|
this._targetEl = null;
|
2019-06-29 12:54:32 +02:00
|
|
|
this._points = null;
|
2019-05-15 11:32:36 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @return {Array<{x: number, y: number}>}
|
|
|
|
*/
|
|
|
|
get data() {
|
|
|
|
return this._data;
|
|
|
|
}
|
|
|
|
|
|
|
|
render() {
|
|
|
|
if (!this._targetEl) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
const chart = new Chartist.Line(this._targetEl, {
|
|
|
|
series: [ this.data ]
|
|
|
|
}, {
|
|
|
|
lineSmooth: true,
|
|
|
|
showArea: true,
|
|
|
|
axisX: {
|
|
|
|
type: Chartist.AutoScaleAxis,
|
|
|
|
onlyInteger: true,
|
|
|
|
showLabel: false
|
|
|
|
},
|
|
|
|
plugins: [
|
|
|
|
Chartist.plugins.ctAxisTitle({
|
|
|
|
axisY: {
|
|
|
|
axisTitle: `${lang.strings['altitude']} (${config.unit_m})`,
|
|
|
|
axisClass: 'ct-axis-title',
|
|
|
|
offset: {
|
|
|
|
x: 0,
|
|
|
|
y: 20
|
|
|
|
},
|
|
|
|
textAnchor: 'middle',
|
|
|
|
flipTitle: true
|
|
|
|
}
|
|
|
|
})
|
|
|
|
]
|
|
|
|
});
|
|
|
|
|
|
|
|
chart.on('created', () => {
|
2019-06-29 12:54:32 +02:00
|
|
|
this._points = document.querySelectorAll('.ct-chart-line .ct-point');
|
|
|
|
const len = this._points.length;
|
|
|
|
for (let i = 0; i < len; i++) {
|
2019-05-15 11:32:36 +02:00
|
|
|
((id) => {
|
2019-06-29 12:54:32 +02:00
|
|
|
this._points[id].addEventListener('click', () => {
|
|
|
|
this._binder.dispatchEvent(uEvent.CHART_CLICKED, id);
|
2019-05-15 11:32:36 +02:00
|
|
|
});
|
|
|
|
})(i);
|
|
|
|
}
|
2019-06-29 12:54:32 +02:00
|
|
|
this._binder.dispatchEvent(uEvent.CHART_READY, len);
|
2019-05-15 11:32:36 +02:00
|
|
|
});
|
|
|
|
|
|
|
|
// need to update chart first time the container becomes visible
|
2019-06-29 12:54:32 +02:00
|
|
|
if (!this.isVisible()) {
|
2019-05-15 11:32:36 +02:00
|
|
|
const observer = new MutationObserver(() => {
|
2019-06-29 12:54:32 +02:00
|
|
|
if (this.isVisible()) {
|
2019-05-15 11:32:36 +02:00
|
|
|
// eslint-disable-next-line no-underscore-dangle
|
|
|
|
this._targetEl.__chartist__.update();
|
|
|
|
observer.disconnect();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
observer.observe(this._targetEl.parentNode, { attributes: true });
|
|
|
|
}
|
2019-06-29 12:54:32 +02:00
|
|
|
}
|
2019-05-15 11:32:36 +02:00
|
|
|
|
2019-06-29 12:54:32 +02:00
|
|
|
isVisible() {
|
|
|
|
return this._targetEl && this._targetEl.parentNode && this._targetEl.parentNode.style.display === 'block';
|
2019-05-15 11:32:36 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static onDomLoaded() {
|
|
|
|
uUtils.addScript('js/lib/chartist.min.js', 'chartist_js', () => {
|
|
|
|
uUtils.addScript('js/lib/chartist-plugin-axistitle.min.js', 'chartist_axistitle_js');
|
|
|
|
});
|
|
|
|
uUtils.addCss('css/chartist.min.css', 'chartist_css');
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param {uEvent} event
|
|
|
|
* @param {*=} args
|
|
|
|
*/
|
|
|
|
handleEvent(event, args) {
|
|
|
|
if (event.type === uEvent.TRACK_READY) {
|
|
|
|
/** @type {uTrack} */
|
|
|
|
const track = args;
|
|
|
|
this._data = track.plotData;
|
|
|
|
this.render()
|
|
|
|
} else if (event.type === uEvent.UI_READY) {
|
|
|
|
/** @type {uUI} */
|
|
|
|
const ui = args;
|
|
|
|
this._targetEl = ui.chart;
|
2019-06-29 12:54:32 +02:00
|
|
|
} else if (event.type === uEvent.MARKER_OVER) {
|
|
|
|
/** @type {number} */
|
|
|
|
const pointId = args;
|
|
|
|
if (pointId) {
|
|
|
|
this.pointOver(pointId);
|
|
|
|
} else {
|
|
|
|
this.pointOut();
|
|
|
|
}
|
|
|
|
} else if (event.type === uEvent.MARKER_SELECT) {
|
|
|
|
/** @type {number} */
|
|
|
|
const pointId = args;
|
|
|
|
if (pointId) {
|
|
|
|
this.pointSelect(pointId);
|
|
|
|
} else {
|
|
|
|
this.pointUnselect();
|
|
|
|
}
|
2019-05-15 11:32:36 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-06-29 12:54:32 +02:00
|
|
|
pointOver(pointId) {
|
|
|
|
if (this.isVisible()) {
|
|
|
|
const point = this._points[pointId];
|
|
|
|
point.classList.add('ct-point-hilight');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pointOut() {
|
|
|
|
this._targetEl.querySelectorAll('.ct-point-hilight').forEach((el) => el.classList.remove('ct-point-hilight'));
|
|
|
|
}
|
|
|
|
|
|
|
|
pointSelect(pointId) {
|
|
|
|
if (this.isVisible()) {
|
|
|
|
const point = this._points[pointId];
|
|
|
|
point.classList.add('ct-point-selected');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pointUnselect() {
|
|
|
|
this._targetEl.querySelectorAll('.ct-point-selected').forEach((el) => el.classList.remove('ct-point-selected'));
|
|
|
|
}
|
2019-05-15 11:32:36 +02:00
|
|
|
}
|