const template = document.createElement('template');
template.innerHTML = `
`;
class HorizontalSituationIndicator extends HTMLElement {
static get observedAttributes() {
return [
'debug',
'fix-north',
'heading',
'heading-select',
'nav1-label',
'nav1-course',
'nav1-deviation',
'nav1-bearing',
'nav1-to',
'nav2-label',
'nav2-course',
'nav2-deviation',
'nav2-bearing',
'nav2-to'
];
}
constructor() {
super();
let shadowRoot = this.attachShadow({ mode: 'open' });
shadowRoot.appendChild(document.importNode(template.content, true));
const degreeAttributes = [
'heading',
'heading-select',
'nav1-course',
'nav1-bearing',
'nav2-course',
'nav2-bearing'
];
this._elements = {
'top': shadowRoot.getElementById('top')
};
this._svg = {
centerX: 67.733/2,
centerY: 67.733/2
};
/* eslint-disable wc/no-constructor-attributes */
this.constructor.observedAttributes.forEach((attrName) => {
const matches = this._getStructuredAttributeName(attrName);
Object.defineProperty(this, attrName, {
get() {
if (!this.hasAttribute(attrName)) {
return null;
}
return (matches[2] !== 'label') ? Number(this.getAttribute(attrName)) : this.getAttribute(attrName);
},
set(attrValue) {
if (attrValue !== null && attrValue !== undefined) {
attrValue = Number(attrValue);
if (degreeAttributes.indexOf(attrName) > -1) {
attrValue = this._limitDeg(attrValue);
}
this.setAttribute(attrName, attrValue);
if (matches[2] === 'course' || matches[2] === 'bearing') {
this._calculateDeviation(matches[1]);
}
}
else {
this.removeAttribute(attrName);
}
this._log('warn', 'Set', attrName, attrValue);
}
});
const element = shadowRoot.getElementById(attrName);
if (element) {
this._log('Registering DOM element for ' + attrName, element);
this._elements[attrName] = element;
this._elements[attrName].setAttribute('display', 'none');
}
});
}
attributeChangedCallback(attrName, oldValue, newValue) {
this._log('Manipulate stuff via attributeChangedCallback', attrName, newValue);
const matches = this._getStructuredAttributeName(attrName);
if (attrName === 'fix-north') {
this._log('Switching mode');
this._rotateSvgElement(this._elements['top'], 0);
this._rotateSvgElement(this._elements['heading'], 0);
this.heading = this.heading;
}
const el = this._elements[attrName];
if (!el) {
return;
}
if (oldValue === null) {
el.removeAttribute('display');
}
if (newValue === null) {
el.setAttribute('display', 'none');
return;
}
let rotate = null;
switch (matches[2]) {
case 'label':
el.querySelector('tspan').textContent = this[attrName];
break;
case 'deviation':
let translate = this[attrName];
if (translate < -90) { translate += 180; translate *= -1; }
else if (translate > +90) { translate -= 180; translate *= -1; }
translate = Math.max(-10, Math.min(10, translate));
el.setAttribute('transform','translate(' + (translate * -1.45) + ' 0)');
translate = Math.abs(translate);
if (this[matches[1] + '-bearing'] !== null) {
if (translate < 10) {
this._elements[matches[1] + '-bearing'].setAttribute('opacity', translate / 10);
} else {
this._elements[matches[1] + '-bearing'].removeAttribute('opacity');
}
}
break;
case 'to':
rotate = this[attrName] > 0 ? 0 : 180;
break;
case 'heading':
if (this['fix-north']) {
this._rotateSvgElement(this._elements['top'], this[attrName]);
} else {
rotate = -this[attrName];
}
break;
default:
rotate = this[attrName];
break;
}
if (rotate !== null) {
this._rotateSvgElement(el, rotate);
}
this._setTitle(el, attrName.replace(/-/g, ' ').toUpperCase() + ': ' + this[attrName]+ '°');
}
connectedCallback() {
['nav1', 'nav2'].forEach((source) => {
this._calculateDeviation(source);
});
}
disconnectedCallback() {
}
_setTitle(el, title) {
const elTitle = el.querySelector('title');
if (elTitle) {
elTitle.textContent = title;
}
}
_getStructuredAttributeName(attrName) {
return attrName.match(/^(nav\d)-(\S+)/) || [attrName, '', attrName];
}
_calculateDeviation(source) {
if (this[source + '-course'] === null || this[source + '-bearing'] === null) {
return;
}
const deviation = this._limitDeg(this[source + '-course'] - this[source + '-bearing'], -180, 180)
this[source + '-deviation'] = deviation;
this[source + '-to'] = (deviation >= -90 && deviation <= 90) ? 1 : -1;
this._log('Setting derived values', {
deviation: this[source + '-deviation'],
to: this[source + '-to']
});
}
_degToRad(deg) {
return deg * (Math.PI / 180);
}
_limitDeg(deg, min = 0, max = 360) {
while (deg >= max) {
deg -= 360;
}
while (deg < min) {
deg += 360;
}
return deg;
}
_rotateSvgElement(element, degrees) {
element.setAttribute('transform','rotate(' + [degrees, this._svg.centerX, this._svg.centerY].join(' ') + ')');
}
_log(...theArgs) {
let method = 'log';
if (theArgs[0] === 'warn' || theArgs[0] === 'error') {
method = theArgs.shift();
}
if (this.debug) {
console[method](...theArgs);
}
}
};
customElements.define('horizontal-situation-indicator', HorizontalSituationIndicator);