• Jump To … +
    app.js Chronograph.js Crown.js DateIndicator.js DayIndicator.js DayNightIndicator.js Dial.js EquationOfTime.js Foudroyante.js MinuteRepeater.js MonthIndicator.js MoonPhase.js PowerReserve.js WeekIndicator.js YearIndicator.js
  • Chronograph.js

  • ¶

    Chronograph Class @params settings: object @params parentWatch: Watch instance

    The chronograph complication requires a buttons and hands object the buttons object contains the start and reset buttons which control the hands The hands are designed and used to indicate tenth seconds, seconds, and minutes for timing events. Flyback and Split-Second (rattrapante) functionality is supported for timing laps.

    MONO-PUSHER Pusher 1: Click to start Pusher 1: Click to pause Pusher 1: Click to reset

    DUAL-PUSHER Standard Pusher 1: Starts the time Pusher 1: Pauses all hands Pusher 2: Resets all hands

    Flyback Pusher 1: Starts the time Pusher 2: Resets all hands then continues

    Rattrapante Pusher 1: Starts the time Pusher 2: Stops the lap hand Pusher 2: Resets lap hand to current second hand Pusher 1: Stops all hands Pusher 2: Resets all hands

    TRI-PUSHER Pusher 1: Starts the time Pusher 2: Pauses the lap hand Pusher 2: Resets the lap hand back to constant second hand Pusher 3: Stops all hands Pusher 1: Resets all hands to original position

    class Chronograph {
        constructor(settings, parentWatch) {
            this.errorChecking(settings);
    
            this.buttons = {
                primary: document.getElementById(settings.buttons.primary),
                secondary: document.getElementById(settings.buttons.secondary) || null,
                tertiary: document.getElementById(settings.buttons.tertiary) || null
            };
    
            this.hands = {
                tenth: document.getElementById(settings.hands.tenth) || null,
                second: document.getElementById(settings.hands.second),
                minute: document.getElementById(settings.hands.minute),
                hour: document.getElementById(settings.hands.hour) || null,
                lap: document.getElementById(settings.hands.lap) || null,
            };
    
            this.flyback = settings.flyback || false;
            this.rattrapante = settings.rattrapante || false;
    
            this.monopusher = false;
            this.dualpusher = false;
            this.tripusher = false;
    
            this.interval;
            this.counter = 1;
            this.isRunning = false;
            this.isPaused = false;
            this.lapActive = false;
            this.parent = parentWatch;
    
            if (!this.parent.testing) this.init();
        }
    
        errorChecking(settings) {
            if (!settings.buttons || !settings.hands) throw new ReferenceError("The Chronograph requires a settings object containing both the buttons and hands.");
            if (!settings.hands.second || !settings.hands.minute) throw new ReferenceError("The Chronograph requires at least a second and minute hands.");
            if (!settings.buttons.secondary && !settings.buttons.tertiary && settings.rattrapante) throw new ReferenceError("A monopusher chronograph cannot support rattrapante functionality.");
            if (!settings.buttons.secondary && !settings.buttons.tertiary && settings.flyback) throw new ReferenceError("A monopusher chronograph cannot support flyuback functionality.");
            if (settings.rattrapante && !settings.hands.lap) throw new ReferenceError("A rattrapante Chronograph requires a 'lap' hand.");
        }
    
        checkForChronographType() {
            if (this.buttons.primary && !this.buttons.secondary && !this.buttons.tertiary) {
                this.monopusher = true;
            } else if (this.buttons.primary && this.buttons.secondary && !this.buttons.tertiary) {
                this.dualpusher = true;
            } else if (this.buttons.primary && this.buttons.secondary && this.buttons.tertiary) {
                this.tripusher = true;
                this.rattrapante = true;
            } else {
                throw "The Chronograph class expects the buttons to be added sequentially beginning with primary, secondary, and, lastly, tertiary.";
            }
        }
    
        bindEvents() {
            this.buttons.primary.addEventListener('click', () => {
                this.toggleActiveState(this.buttons.primary);
    
                if (this.monopusher) {
                    if (!this.isRunning && !this.isPaused) {
                        this.isRunning = true;
                        this.startInterval();
                    } else if (this.isRunning && !this.isPaused) {
                        this.isRunning = false;
                        this.isPaused = true;
                        this.clearInterval();
                    } else if (!this.isRunning && this.isPaused) {
                        this.isPaused = false;
                        this.resetHands();
                    }
    
                } else if (this.dualpusher) {
                    this.isRunning = !this.isRunning;
    
                    if (this.isRunning) {
                        this.startInterval();
                    } else {
                        this.clearInterval();
                    }
    
                } else if (this.tripusher) {
                    if (!this.isRunning && !this.isPaused) {
                        this.isRunning = true;
                        this.startInterval();
                    } else if (!this.isRunning && this.isPaused) {
                        this.isRunning = false;
                        this.isPaused = false;
                        this.counter = 1;
                        this.clearInterval();
                        this.resetHands();
                    }
                }
            });
    
            this.buttons.primary.addEventListener('transitionend', () => {
                if (this.buttons.primary.classList.contains('active')) this.toggleActiveState(this.buttons.primary);
            });
    
            if (this.buttons.secondary) {
                this.buttons.secondary.addEventListener('click', () => {
                    this.toggleActiveState(this.buttons.secondary);
    
                    if (this.dualpusher) {
                        this.resetHands();
                        this.counter = 1;
    
                        if ((!this.rattrapante && !this.flyback) || !this.isRunning) {
                            this.clearInterval();
                            this.isRunning = false;
                        }
                    } else if (this.tripusher) {
                        if (this.isRunning) {
                            this.resetHands();
                        }
                    }
                });
    
                this.buttons.secondary.addEventListener('transitionend', () => {
                    if (this.buttons.secondary.classList.contains('active')) this.toggleActiveState(this.buttons.secondary);
                });
            }
    
            if (this.buttons.tertiary) {
                this.buttons.tertiary.addEventListener('click', () => {
                    this.toggleActiveState(this.buttons.tertiary);
                    this.isRunning = !this.isRunning;
    
                    if (this.isRunning) {
                        this.startInterval();
                        this.isPaused = false;
                    } else {
                        this.clearInterval();
                        this.isRunning = false;
                        this.isPaused = true;
                    }
                });
    
                this.buttons.tertiary.addEventListener('transitionend', () => {
                    if (this.buttons.tertiary.classList.contains('active')) this.toggleActiveState(this.buttons.tertiary);
                });
            }
        }
    
        clearInterval() {
            clearInterval(this.interval);
            this.interval = null;
        }
    
        startInterval() {
            this.interval = setInterval(() => {
                this.rotateHands();
                this.counter++;
            }, 100);
        }
    
        resetHands() {
            if (this.rattrapante && this.isRunning) {
                if (!this.flyback) {
                    this.lapActive = !this.lapActive;
                    if (!this.lapActive) {
                        this.hands.lap.style.transform = `rotate(${this.parent.getCurrentRotateValue(this.hands.second)}deg)`;
                    }
                } else {
                    this.lapActive = true;
                    this.hands.lap.style.transform = `rotate(${this.parent.getCurrentRotateValue(this.hands.second)}deg)`;
                    this.hands.second.style.transform = 'rotate(0deg)';
                    if (this.hands.tenth) this.hands.tenth.style.transform = 'rotate(0deg)';
                }
            } else {
                Object.keys(this.hands).map(hand => {
                    if (this.hands[hand]) this.hands[hand].style.transform = 'rotate(0deg)';
                });
                this.lapActive = false;
            }
        }
    
        rotateHands() {
            let tenthValue = this.hands.tenth ? this.parent.getCurrentRotateValue(this.hands.tenth) : 0;
            let secondValue = this.parent.getCurrentRotateValue(this.hands.second);
            let minuteValue = this.parent.getCurrentRotateValue(this.hands.minute);
            let hourValue = this.hands.hour ? this.parent.getCurrentRotateValue(this.hands.hour) : 0;
    
            if (this.hands.tenth) this.hands.tenth.style.transform = `rotate(${tenthValue + 0.6}deg)`;
    
            if (this.counter % 10 === 0) {
                this.hands.second.style.transform = `rotate(${secondValue + 6}deg)`;
                if (!this.lapActive && this.hands.lap) this.hands.lap.style.transform = `rotate(${secondValue + 6}deg)`;
            }
    
            if (this.counter % 600 === 0) {
                this.hands.minute.style.transform = `rotate(${minuteValue + 6}deg)`;
                if (this.hands.hour) this.hands.hour.style.transform = `rotate(${hourValue + 0.5}deg)`;
                this.counter = 0;
            }
        }
    
        toggleActiveState(btn) {
            btn.classList.toggle('active');
        }
    
        init() {
            this.checkForChronographType();
            this.bindEvents();
    
            Object.keys(this.buttons).map(btn => {
                if (this.buttons[btn]) {
                    this.buttons[btn].style.cursor = 'pointer';
                }
            });
        }
    }
    
    module.exports = Chronograph;