grudus-timepicker
Version:
Material design time picker in pure Javascript without any dependencies
149 lines (123 loc) • 5.39 kB
JavaScript
import MinutesFace from "./minutesFace";
import HoursFace from "./hoursFace";
import Utils from "../meta/utils";
import Config, {css, DOM} from "../meta/config";
import ClockFaceCreator from "./clockFaceCreator";
export default class ClockFace {
constructor(options, initialTime, onTimeUpdate) {
this.options = options;
this.time = initialTime;
this.onTimeUpdate = onTimeUpdate;
this.isMouseDown = false;
this.clockItems = [];
this.innerClockItems = [];
this.outerClockItems = [];
this.size = {};
this.middle = {};
this.initViews();
this.initTimeFaces(initialTime);
this.createFace();
this.hoursFace.items.radius = this.itemsRadius;
this.currentFace = this.hoursFace;
this.changeDisplayed(this.currentFace.displayed);
}
initViews() {
this.clockElem = document.getElementById(DOM.clockId);
this.innerClockElem = document.getElementById(DOM.innerId);
this.handOfAClock = document.getElementById(DOM.handId);
this.clockElem.onmousedown = () => this.isMouseDown = true;
this.clockElem.onmouseup = () => {this.isMouseDown = false;
this.toggleToMinutes();
};
this.handOfAClock.onmouseup = (e) => e.stopPropagation();
this.handOfAClock.onmousemove = (e) => e.stopPropagation();
this.handOfAClock.onclick = (e) => e.stopPropagation();
this.clockElem.onmousemove = (e) => this.selectTime(e, false, this.clockElem);
this.clockElem.onclick = (e) => this.selectTime(e, true, this.clockElem);
this.innerClockElem.onmousemove = (e) => this.selectTime(e, false, this.innerClockElem);
this.innerClockElem.onclick = (e) => this.selectTime(e, true, this.innerClockElem);
}
initTimeFaces(initialTime) {
this.minutesFace = new MinutesFace({
options: this.options,
clockItems: this.clockItems,
outerClockItems: this.outerClockItems
}, initialTime.minutes, (minutes, angle) => this.updateMinutes(minutes, angle));
this.hoursFace = new HoursFace({
options: this.options,
innerClockItems: this.innerClockItems,
clockItems: this.clockItems,
innerClockElem: this.innerClockElem
}, initialTime.hours, (hours, angle, radius) => this.updateHours(hours, angle, radius));
}
onStart() {
this.currentFace.onEnter();
}
createFace() {
const clockFaceCreator = new ClockFaceCreator(this.clockElem, this.innerClockElem);
clockFaceCreator.create(this.clockItems, this.innerClockItems, this.outerClockItems, this.hoursFace);
clockFaceCreator.calculateSize(this.clockItems, this.innerClockItems, this.outerClockItems);
this.size = clockFaceCreator.size;
this.middle = clockFaceCreator.middle;
this.itemsRadius = clockFaceCreator.itemsRadius;
}
selectTime(event, isMouseDown, elem) {
if (!(isMouseDown || this.isMouseDown))
return;
const mouse = Utils.findMousePosition(event, this.clockElem);
const x = mouse.x - this.middle.x;
const y = this.middle.y - mouse.y;
let angle = 90 - Utils.toDegrees(Math.atan(y / x));
if (x < 0) angle += 180;
this.currentFace.selectTime(angle, elem);
event.stopPropagation();
}
changeDisplayed(array) {
for (let i = 0; i < this.clockItems.length; i++)
this.clockItems[i].innerText = array[i];
}
onEachClockElement(fun) {
[].forEach.call(this.clockItems, c => fun(c));
}
updateMinutes(minutes, angle) {
this.time.minutes = minutes;
this.calculateHandOfTheClock(angle, this.itemsRadius);
this.onTimeUpdate(this.time, Config.FaceType.MINUTES);
}
updateHours(hours, angle, radius) {
this.time.hours = hours;
this.calculateHandOfTheClock(angle, radius);
this.onTimeUpdate(this.time, Config.FaceType.HOURS);
}
calculateHandOfTheClock(angle, size = this.itemsRadius) {
this.handOfAClock.style.transform = `rotate(${angle - 90}deg)`;
this.handOfAClock.style.width = size + "px";
}
toggleToHours() {
this.minutesFace.onLeave();
this.toggleTime(this.hoursFace);
}
toggleToMinutes() {
this.hoursFace.onLeave();
this.toggleTime(this.minutesFace);
}
toggleTime(face) {
if (this.currentFace !== face) {
this.onEachClockElement(c => c.classList.add(css.fadeOut));
this.handOfAClock.classList.add(css.fadeOut);
Promise.delay(() => {
this.onEachClockElement(c => c.classList.remove(css.fadeOut));
this.handOfAClock.classList.remove(css.fadeOut);
this.changeDisplayed(face.displayed);
this.currentFace = face;
this.onEachClockElement(c => this.removeSelected(c));
face.onEnter();
}, 300);
}
}
removeSelected(c) {
c.classList.remove(css.selected);
c.style.background = "transparent";
c.style.color = this.options.clockItemColor;
}
}