legacy/outils/horloge/Horloge.js

import { j3pElement, j3pEnsureHtmlElement } from 'src/legacy/core/functions'
import { svgns } from 'src/legacy/core/functionsSvg'

/**
 * Ajoute une horloge en svg dans div (attention, il n’en faut qu’une dans le DOM car elle utilise des id mis en dur)
 * @param {string|HTMLElement} div
 * @param {number} echelle le scale du svg (base 100px, 2.5 => 250px)
 * @param {object} couleurs
 * @param {string} couleurs.cadran
 * @param {string} couleurs.chiffres code couleur des chiffres (attention, valeur hexa mais sans le # initial)
 * @param {string} couleurs.fond
 * @param {string} couleurs.fond_int
 * @param {string} couleurs.grande
 * @param {string} couleurs.petite
 * @param {number} taillechiffres Taille des chiffres en pixels
 */
class Horloge {
  /**
   * Le constructeur ne devrait pas être appelé, passer par la méthode statique create
   * @param echelle
   * @param couleurs
   * @param tailleChiffres
   */
  constructor ({ echelle = 1, couleurs = {}, tailleChiffres = 10 } = {}) {
    if (!Number.isFinite(echelle) || echelle <= 0) throw Error(`option echelle ${echelle} invalide`)
    /**
     * le scale qui sera mis sur le svg
     * @type {number}
     */
    this.echelle = echelle
    if (!Number.isInteger(tailleChiffres) || tailleChiffres < 5) throw Error(`option tailleChiffres ${tailleChiffres} invalide`)
    /**
     * Taille des chiffres en pixels
     * @type {number}
     */
    this.tailleChiffres = tailleChiffres
    const {
      cadran = '#fff',
      chiffres = '#000',
      fondInt = '#eee',
      fondExt = '#fff',
      petite = '#33f',
      grande = '#33f'
    } = couleurs
    /**
     * Les couleurs (idem css)
     * @type {{fondExt: string, fondInt: string, chiffres: string, cadran: string, grande: string, petite: string}}
     */
    this.couleurs = { cadran, chiffres, fondInt, fondExt, petite, grande }
  }

  /**
   * Change l’heure
   */
  change (heure, minute) {
    if (!Number.isInteger(heure) || heure < 0) throw Error(`heure ${heure} invalide`)
    if (!Number.isInteger(minute) || minute < 0 || minute > 59) throw Error(`minute ${minute} invalide`)
    const pa = this.svg.querySelector('.petiteAiguille')
    const ga = this.svg.querySelector('.grandeAiguille')
    // 360 / 60 = 6° par minute
    ga.setAttribute('transform', 'rotate(' + (6 * minute) + ',50,50)')
    // 360 / 12 = 30 donc 30° par heure
    pa.setAttribute('transform', 'rotate(' + (30 * (heure + minute / 60)) + ',50,50)')
  }

  /**
   * Les couleurs des éléments (format css, '#rrvvbb' ou 'red' ou 'rsl(…)' ou…)
   * @typedef CouleursHorloge
   * @property {string} [cadran=#fff] Couleur du cadran
   * @property {string} [chiffres=#000]
   * @property {string} [fondInt=#eee] Couleur de fond du cadran
   * @property {string} [fondExt=#fff] Couleur du fond du rectangle autour du cadran
   * @property {string} [petite=#33f]
   * @property {string} [grande=#33f]
   */

  /**
   * Crée une horloge dans le dom
   * @param {HTMLElement|string} container
   * @param {Object} options
   * @param {number} [options.echelle=1] une échelle de 1 donnera une horloge de 100 pixels de coté
   * @param {CouleursHorloge} [options.couleurs]
   * @param {number} [options.tailleChiffres=10] taille des chiffres en pixels
   * @return {Horloge}
   */
  static create (container, options) {
    if (typeof container === 'string') container = j3pElement(container)
    j3pEnsureHtmlElement(container)
    const horloge = new Horloge(options)
    const svg = document.createElementNS(svgns, 'svg')
    svg.setAttribute('width', 100 * horloge.echelle)
    svg.setAttribute('height', 100 * horloge.echelle)
    container.appendChild(svg)
    horloge.svg = svg
    const { cadran, chiffres, fondInt, fondExt, petite, grande } = horloge.couleurs
    svg.innerHTML = `<g transform="scale(${horloge.echelle}) translate(0,0)">
        <rect width="100" height="100" x="0" y="0" fill="${fondExt}"/>
        <circle cx="50" cy="50" r="48" stroke-width="2" fill-opacity="1.0"  fill="${fondInt}" stroke="black" />
        <text class="chiffre" x="44" y="16" >12</text>
        <text class="chiffre" x="68" y="22" >1</text>
        <text class="chiffre" x="77" y="34" >2</text>
        <text class="chiffre" x="83" y="53" >3</text>
        <text class="chiffre" x="78" y="73" >4</text>
        <text class="chiffre" x="66" y="83" >5</text> 
        <text class="chiffre" x="47" y="90" >6</text>
        <text class="chiffre" x="27" y="83" >7</text>
        <text class="chiffre" x="14" y="73" >8</text>
        <text class="chiffre" x="10"  y="52" >9</text>
        <text class="chiffre" x="14" y="34" >10</text>
        <text class="chiffre" x="26" y="22" >11</text>
        <symbol  id="cinqminutes">
          <line x1="50" y1="4" x2="50" y2="8"  stroke-width="2" stroke="${cadran}"/>
          <line x1="50" y1="4" x2="50" y2="6"  stroke-width="1" stroke="${cadran}" transform="rotate(6, 50,50)"/>
          <line x1="50" y1="4" x2="50" y2="6"  stroke-width="1" stroke="${cadran}" transform="rotate(12, 50,50)"/>
          <line x1="50" y1="4" x2="50" y2="6"  stroke-width="1" stroke="${cadran}" transform="rotate(18, 50,50)"/>
          <line x1="50" y1="4" x2="50" y2="6"  stroke-width="1" stroke="${cadran}" transform="rotate(24, 50,50)"/>
        </symbol>
        <symbol  id="quinzeminutes">
          <use xlink:href="#cinqminutes" />
          <use xlink:href="#cinqminutes" x="0" y="0" transform="rotate(30 , 50 , 50)" />
          <use xlink:href="#cinqminutes" x="0" y="0" transform="rotate(60 , 50 , 50)" />
        </symbol>
        <use xlink:href="#quinzeminutes" />
        <use xlink:href="#quinzeminutes" x="0" y="0" transform="rotate(90 , 50 , 50)" />
        <use xlink:href="#quinzeminutes" x="0" y="0" transform="rotate(180 , 50 , 50)" />
        <use xlink:href="#quinzeminutes" x="0" y="0" transform="rotate(270 , 50 , 50)" />
        <line class="petiteAiguille" x1="50" y1="53" x2="50" y2="27"  stroke-width="4"  stroke-linecap ="round" stroke="${petite}"/>
        <line class="grandeAiguille" x1="50" y1="53" x2="50" y2="14"  stroke-width="2"  stroke-linecap ="round" stroke="${grande}"/>
      </g>`
    for (const elt of svg.querySelectorAll('.chiffre')) {
      elt.style.fontSize = horloge.tailleChiffres + 'px'
      elt.style.fill = chiffres
    }
    return horloge
  }
}

export default Horloge