UNPKG

@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
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;