@navelpluisje/pcb-components
Version:
A library with native components. They are all pcb components, like a dip-switch, resitor etc.
176 lines (145 loc) • 5.68 kB
JavaScript
import htmlTemplate from './trimmer.html';
import style from './trimmer.css';
import { round } from '../helpers/round';
export const trimmer = () => (customElements.define('np-trimmer', class Rotary extends HTMLElement {
constructor() {
// Always call super first in constructor
super();
this.currentDocument = document.currentScript.ownerDocument;
// Get the template and substract the parts
// const template = document.getElementById('np-dip-switch').import;
const template = document.createElement('div');
template.innerHTML = htmlTemplate;
const templateContent = template.querySelector('.trimmer');
const styling = document.createElement('style');
styling.innerHTML = style;
// Create the shadowRoot and append the content
const shadowRoot = this.attachShadow({ mode: 'open' });
shadowRoot.appendChild(templateContent.cloneNode(true));
shadowRoot.appendChild(styling.cloneNode(true));
this.rotateKnob = this.handleMouseMove.bind(this);
// Create Events
this.changeEvent = new CustomEvent('change', {
bubbles: true,
cancelable: false,
});
}
connectedCallback() {
this.trimmer = this.shadowRoot.querySelector('.trimmer');
this.knob = this.shadowRoot.querySelector('.trimmer-knob');
this.valueField = this.shadowRoot.querySelector('.value');
this.body = document.body;
// Get the attributes of our web-component
this.min = parseFloat(this.getAttribute('min')) || 0;
this.max = parseFloat(this.getAttribute('max')) || 10;
this.step = parseFloat(this.getAttribute('step')) || 0.5;
this.label = this.getAttribute('label') || 'trimmer';
this.shadowRoot.querySelector('.trimmer-ring').dataset.label = this.label;
this.color = parseInt(this.getAttribute('color'), 10) || null;
this.saturation = parseInt(this.getAttribute('saturation'), 10) || null;
this.setValue(parseFloat(this.getAttribute('value')) || 0);
this.setEventBindings();
this.setColor();
this.setKnobValue();
}
setEventBindings() {
this.trimmer.addEventListener('mousedown', this.handleMouseDown.bind(this), false);
this.trimmer.addEventListener('click', this.handleKnobClick.bind(this));
this.trimmer.addEventListener('keyup', this.handleKeyClick.bind(this));
document.body.addEventListener('mouseup', this.handleMouseUp.bind(this), false);
}
handleKeyClick(event) {
switch (event.key) {
case 'ArrowUp':
this.setValue(this.value + this.step);
break;
case 'ArrowDown':
this.setValue(this.value - this.step);
break;
default:
}
}
handleMouseDown(event) {
this.click = true;
this.startY = event.screenY;
this.setKnobActive();
this.start = parseFloat(this.knob.style.transform.substring(7)) || 0;
this.body.addEventListener('mousemove', this.rotateKnob, false);
}
handleMouseMove(event) {
let next = ((event.screenY - this.startY) - this.start);
if (next > 140) { next = 140; }
if (next < -140) { next = -140; }
this.click = false;
this.knob.style.transform = `rotate(${-1 * next}deg)`;
this.setValue(this.getValueByCorner(-1 * next));
}
handleMouseUp() {
this.setKnobInActive();
this.body.removeEventListener('mousemove', this.rotateKnob, false);
}
handleKnobClick(event) {
let corner;
const width = this.trimmer.offsetWidth / 2;
const height = this.trimmer.offsetHeight / 2;
const clickX = event.pageX - this.trimmer.offsetLeft;
const clickY = event.pageY - this.trimmer.offsetTop;
const adjacent = Math.abs(width - clickX);
const opposite = Math.abs(height - clickY);
const hypotenuse = Math.sqrt((adjacent ** 2) + (opposite ** 2));
if (this.click) {
if (clickY > height) {
corner = 90 + ((360 / (Math.PI * 2)) * Math.acos(adjacent / hypotenuse));
} else {
corner = (360 / (Math.PI * 2)) * Math.asin(adjacent / hypotenuse);
}
if (corner > 140) { corner = 140; }
if (clickX < width) {
corner *= -1;
}
this.setValue(this.getValueByCorner(corner));
}
}
setKnobValue(corner) {
const newCorner = corner || ((280 / (this.max - this.min)) * (this.value - this.min)) - 140;
this.knob.style.transform = `rotate(${newCorner}deg)`;
}
getValueByCorner(corner) {
const calcCorner = corner || parseFloat(this.knob.style.transform.substring(7)) || 0;
return round(+this.min + (((calcCorner + 140) / 280) * (this.max - this.min)), this.step);
}
setValue(value) {
if (this.value === value) { return false; }
if (value > this.max) {
this.value = this.max;
} else if (value <= this.min) {
this.value = this.min;
} else {
this.value = value;
}
this.dispatchEvent(this.changeEvent);
this.setKnobValue();
this.valueField.textContent = this.value;
return true;
}
setKnobActive() {
this.knob.classList.add('active');
}
setKnobInActive() {
this.knob.classList.remove('active');
}
setColor() {
const html = document.querySelector('html');
if (this.color !== null) {
this.trimmer.style.setProperty('--switch-color', this.color);
} else if (getComputedStyle(html).getPropertyValue('--switch-color') === '') {
this.trimmer.style.setProperty('--switch-color', '0');
}
if (this.saturation !== null) {
this.trimmer.style.setProperty('--switch-saturation', `${this.saturation}%`);
} else if (getComputedStyle(html).getPropertyValue('--switch-saturation') === '') {
this.trimmer.style.setProperty('--switch-saturation', '50%');
}
}
}));
export default null;