2157 lines
108 KiB
QML
2157 lines
108 KiB
QML
//========================================================================================================================================================================
|
|
// CIRCUIT.QML
|
|
// Ce fichier traite l'affichage des détails d'un circuit. La page affiche notamment :
|
|
// - la commande actuelle du circuit (et permet la commande, y compris en variateur s'il est configuré pour),
|
|
// - la consommation actuelle du circuit,
|
|
// - la liste des derniers événements,
|
|
// - les éventuelles infos d'état ou d'alarme (commande manuelle, défaut, etc...).
|
|
// - la courbe de consommation
|
|
// La page est appelée depuis la page HOME, en cliquant sur la zone d'information du circuit.
|
|
//========================================================================================================================================================================
|
|
|
|
import QtQuick 2.12
|
|
import QtQuick.Controls 2.12
|
|
import QtQuick.Layouts 1.12
|
|
import QtCharts 2.3
|
|
|
|
import qt.koriolan.shipheart 1.0
|
|
import"fonctions.js" as Fonctions
|
|
import"fonctions_date_heure.js" as Fonctions_date_heure
|
|
|
|
|
|
Shipheart_page {
|
|
id: page_circuit
|
|
|
|
|
|
// Mis en forme :
|
|
readonly property double pourcentage_largeur_colonne_gauche_haut: 0.5
|
|
readonly property double pourcentage_largeur_colonne_centre_haut: 0.07 // 80/1280 pour se rapprocher du bouton de slider (80)
|
|
readonly property double pourcentage_largeur_graphique: 0.85
|
|
readonly property int espace_colonnes_principales: 10
|
|
readonly property int espace_colonnes_secondaires: 10
|
|
readonly property int largeur_bouton_slider: 80
|
|
|
|
readonly property double pourcentage_hauteur_ligne_haut: 0.15
|
|
readonly property double pourcentage_hauteur_ligne_milieu: (1 - pourcentage_hauteur_ligne_haut - pourcentage_hauteur_ligne_graphique)
|
|
readonly property double pourcentage_hauteur_ligne_graphique: 0.45
|
|
readonly property double hauteur_utile: (shipheart_hauteur_page - shipheart_hauteur_bandeau_haut - shipheart_hauteur_bandeau_bas - (4 * espace_lignes_principales))
|
|
readonly property int espace_lignes_principales: 20
|
|
readonly property int espace_lignes_secondaires: 10
|
|
|
|
readonly property int nombre_widgets_par_ligne: 4
|
|
readonly property int largeur_bouton_suite: 15
|
|
|
|
readonly property int nombre_lignes_historique_visibles: 8
|
|
readonly property int nombre_lignes_historique_par_page: 30
|
|
|
|
readonly property int nb_boutons_periode: 4
|
|
|
|
readonly property int periode_init_raffraichissement_parametres: 20 // En ms ATtention : The Timer type is synchronized with the animation timer. Since the animation timer is usually set to 60fps, the resolution of Timer will be at best 16ms.
|
|
readonly property int periode_raffraichissement_parametres: 1000 // En ms
|
|
readonly property int periode_init_raffraichissement_graphiques: 20 // En ms
|
|
readonly property int periode_raffraichissement_graphiques: (15 * 1000) // en ms
|
|
|
|
// Affichage :
|
|
property int periode_analyse: 0
|
|
|
|
property string source_picto_alerte: ""
|
|
property string texte_alerte : "---"
|
|
|
|
property string date_premiere_entree_historique: "" // Contient une chaine (format BDD) représentant la date/heure de l'entrée historique la plus ancienne. Permet de recharger de plus anciennes lors d'un MORE...
|
|
property string date_derniere_entree_historique: "" // Contient une chaine (format BDD) représentant la date/heure de l'entrée historique la plus récente. Permet de ne recharger que les nouvelles...
|
|
property bool flag_journal_full: false // est positionné à vrai quand il n'y a plus d'enregistrements supplémentaires disponibles pour ce filtre
|
|
|
|
property bool courbe_flag_vide: false // Flag indiquant s'il y a des données à afficher ou pas
|
|
property int courbe_nombre_principal_graduations_axe_x: 13
|
|
property int courbe_nombre_zoom_1_graduations_axe_x: 8
|
|
property int courbe_nombre_graduations_axe_y: 5
|
|
property string courbe_format_principal_axe_x: "HH:mm" // exemple : "yyyy-MM-dd HH:mm:ss"
|
|
property string courbe_format_zoom_1_axe_x: "HH:mm" // exemple : "yyyy-MM-dd HH:mm:ss"
|
|
|
|
property bool flag_zoom_en_cours: false
|
|
property real zoomx_en_cours: 1
|
|
|
|
property date xMin_date
|
|
property date xMax_date
|
|
property real yMin_valeur: 0
|
|
property real yMax_valeur: 1
|
|
property int precision_affichage_axe_y_courbe: 1
|
|
property string symbole_unite: "--"
|
|
|
|
property int etat_systeme: 0 // Le '0' permet d'éviter l'affichage du message d'erreur pendant un très court instant au démarrage
|
|
|
|
// Données :
|
|
property bool flag_init: true // Permet de bloquer certains affichage tant que l'init n'est pas terminée
|
|
|
|
property int id_circuit: 0
|
|
property int id_variable: -1
|
|
property string nom: "---"
|
|
property string nom_batterie: "---"
|
|
property int type_module: shipheart_type_module_inconnu
|
|
property int no_circuit: 0
|
|
property double plancher_intensite;
|
|
property int precision_tension: 0
|
|
property int precision_intensite: 0
|
|
property int mode_commande: 0 // 0=On-Off, 1=On-Off soft, 2=Variable soft et 3=Cadencé
|
|
property int etat_commande_carte: 0 // 0=Ok, 1=Undervoltage, 2=Test
|
|
property int mode_test: 0
|
|
property int etat: 0
|
|
property int mode_cdes_auto: -1
|
|
|
|
property int consigne: 0
|
|
property int consigne_id_variable: 0
|
|
property string consigne_unite_variable: ""
|
|
property string tension: ""
|
|
property int tension_etat: 0
|
|
property int tension_id_variable: 0
|
|
property string tension_unite_variable: ""
|
|
property string intensite: ""
|
|
property string intensite_seuil_haut: ""
|
|
property int intensite_etat: 0
|
|
property int intensite_id_variable: 0
|
|
property string intensite_unite_variable: ""
|
|
property string frequence: ""
|
|
property int frequence_etat: 0
|
|
property int frequence_id_variable: 0
|
|
property string frequence_unite_variable: ""
|
|
property string puissance: ""
|
|
property int puissance_etat: 0
|
|
property int puissance_id_variable: 0
|
|
property string puissance_unite_variable: ""
|
|
property string energie: "--"
|
|
property int energie_etat: 0
|
|
property int energie_id_variable: 0
|
|
property string energie_unite_variable: ""
|
|
|
|
|
|
// Modèles :
|
|
// Note : les modèles chargés dans 'main.qml' n'ont pas à être rechargés dans les pages suivantes
|
|
|
|
|
|
//===========================================================
|
|
// Timer periode raffraichissement parametres du circuit :
|
|
//===========================================================
|
|
Timer {
|
|
id: timer_raffraichissement_parametres
|
|
interval: periode_init_raffraichissement_parametres
|
|
triggeredOnStart: false
|
|
running: true
|
|
repeat: true
|
|
onTriggered: {
|
|
if (interval === periode_init_raffraichissement_parametres) // Premier passage, 1ms après le premier chargement
|
|
{
|
|
interval = periode_raffraichissement_parametres;
|
|
busy_indicator.running = true;
|
|
init_page();
|
|
}
|
|
else
|
|
{
|
|
mise_a_jour_valeurs_instantanees();
|
|
}
|
|
}
|
|
}
|
|
//===========================================================
|
|
// Timer periode raffraichissement graphiques :
|
|
//===========================================================
|
|
Timer {
|
|
id: timer_raffraichissement_graphiques
|
|
interval: periode_raffraichissement_graphiques
|
|
triggeredOnStart: false
|
|
running: true
|
|
repeat: true
|
|
onTriggered: {
|
|
if (interval === periode_init_raffraichissement_graphiques) interval = periode_raffraichissement_graphiques;
|
|
|
|
if (!flag_init) // La gestion du premier calcul des courbes est géré directement par 'init()' car le séquençage des 2 timers au démarrage n'est pas garanti !!
|
|
{
|
|
if (!flag_zoom_en_cours) // On ne met pas à jour les courbes si on est en train de zoomer
|
|
{
|
|
if (id_variable !== -1) // Cas du port USB arrière par exemple
|
|
{
|
|
mise_a_jour_courbes();
|
|
mise_a_jour_valeur_energie(); // On utilise ce timer "lent" pour mettre à jour cette valeur qui évolue peu
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// Titre de la page :
|
|
Shipheart_titre_1 {titre:nom; hauteur: shipheart_hauteur_bandeau_haut}
|
|
|
|
|
|
//===========================================================
|
|
// Ecran haut - gauche : Commande du circuit
|
|
//===========================================================
|
|
Rectangle {
|
|
id: zone_affichage_haut_gauche
|
|
x: largeur_bouton_suite + (espace_colonnes_secondaires / 2) // Alignement avec les widgets
|
|
y: shipheart_hauteur_bandeau_haut + espace_lignes_principales
|
|
width: (shipheart_largeur_page * pourcentage_largeur_colonne_gauche_haut) // Part de la zone de gauche
|
|
- largeur_bouton_suite - (espace_colonnes_secondaires / 2) // Espace à gauche pour s'aligner avec les widgets
|
|
- (espace_colonnes_principales / 2) // 1/2 de l'espace entre cette zone et la zone centrale (à droite donc)
|
|
height: hauteur_utile * pourcentage_hauteur_ligne_haut
|
|
color: "transparent"
|
|
visible: (etat_systeme === 0) && ((type_module !== shipheart_type_module_shipbase) || (no_circuit !== 0))
|
|
|
|
//-----------------------------------------
|
|
// Cas d'un circuit en commande TOR :
|
|
//-----------------------------------------
|
|
// Bouton OFF :
|
|
Rectangle {
|
|
id: zone_consigne_off
|
|
x: 0
|
|
width: (parent.width / 2) - (espace_colonnes_secondaires / 2);
|
|
height: parent.height
|
|
// color: (consigne === 0) ? couleur_rouge_transparent : shipheart_couleur_fond_bouton
|
|
color: (consigne === 0) ? shipheart_couleur_fond_bouton_actif : shipheart_couleur_fond_bouton // SDIR #207
|
|
radius: shipheart_rayon_bouton
|
|
visible: (etat_commande_carte === shipheart_etat_commande_module_ok) &&
|
|
(mode_commande !== shipheart_mode_commande_circuit_soft_variable)
|
|
|
|
Text {
|
|
id: consigne_off
|
|
text: qsTr("Off")
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
anchors.verticalCenterOffset: 0
|
|
anchors.horizontalCenter: parent.horizontalCenter
|
|
font.pixelSize: 24
|
|
font.weight: (consigne === 0) ? Font.Bold : Font.Normal // SDIR #207
|
|
color: (consigne === 0) ? couleur_blanc_casse : couleur_gris_pale // SDIR #207
|
|
}
|
|
|
|
MouseArea { // Zone d'interaction. On est obligé de la mettre dans la grille pour que Rectangle et MouseArea soient frères ou parent/enfant ET qu'on n'occupe qu'un espace dans la grille.
|
|
id: mouse_area_consigne_off
|
|
anchors.fill: parent
|
|
onClicked: {
|
|
shipheart_clic();
|
|
changement_consigne(0, -1); // La Old_consigne n'est pas affecté par une commande OFF
|
|
}
|
|
}
|
|
}
|
|
|
|
//-------------------
|
|
// Bouton ON :
|
|
Rectangle {
|
|
id: zone_consigne_on
|
|
x: (parent.width / 2) + (espace_colonnes_secondaires / 2);
|
|
width: (parent.width / 2) - (espace_colonnes_secondaires / 2);
|
|
height: parent.height
|
|
color: (consigne !== 0) ? couleur_vert_transparent : shipheart_couleur_fond_bouton
|
|
radius: shipheart_rayon_bouton
|
|
visible: (etat_commande_carte === shipheart_etat_commande_module_ok) &&
|
|
(mode_commande !== shipheart_mode_commande_circuit_soft_variable)
|
|
|
|
Text {
|
|
id: consigne_on
|
|
text: qsTr("On")
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
anchors.verticalCenterOffset: 0
|
|
anchors.horizontalCenter: parent.horizontalCenter
|
|
font.pixelSize: 24
|
|
font.weight: (consigne !== 0) ? Font.Bold : Font.Normal // SDIR #207
|
|
color: (consigne !== 0) ? couleur_green_yellow : couleur_gris_pale
|
|
}
|
|
|
|
MouseArea { // Zone d'interaction. On est obligé de la mettre dans la grille pour que Rectangle et MouseArea soient frères ou parent/enfant ET qu'on n'occupe qu'un espace dans la grille.
|
|
id: mouse_area_consigne_on
|
|
anchors.fill: parent
|
|
onClicked: {
|
|
shipheart_clic();
|
|
changement_consigne(100, -1); // La Old_consigne n'est pas affecté par une commande ON
|
|
}
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------
|
|
// Cas d'un circuit en commande variable :
|
|
//-----------------------------------------
|
|
Slider {
|
|
id: slider_consigne
|
|
|
|
width: parent.width
|
|
height: parent.height
|
|
padding: 0
|
|
anchors {
|
|
horizontalCenter: parent.horizontalCenter
|
|
}
|
|
visible: (etat_commande_carte === shipheart_etat_commande_module_ok) &&
|
|
(mode_commande === shipheart_mode_commande_circuit_soft_variable)
|
|
from: 0
|
|
value: consigne
|
|
to: 100
|
|
stepSize:1 // Permet de n'avoir que des valeurs en %, sans décimales (il est probable que cela accélère le traitement mais pas vérifié...)
|
|
|
|
background: Rectangle {
|
|
x: parent.leftPadding
|
|
y: 0
|
|
width: parent.width
|
|
height: parent.height
|
|
radius: shipheart_rayon_bouton
|
|
color: shipheart_couleur_fond_bouton
|
|
|
|
Rectangle {
|
|
id: slider_consigne_bande_active
|
|
width: slider_consigne.visualPosition * parent.width
|
|
height: parent.height
|
|
color: couleur_vert_transparent
|
|
radius: shipheart_rayon_bouton
|
|
Behavior on width {
|
|
NumberAnimation {
|
|
properties:"width"
|
|
duration: 350
|
|
easing.type: Easing.OutQuad
|
|
}
|
|
}
|
|
|
|
|
|
Text { // Affichage de la valeur dans la barre lorsque le circuit est ON :
|
|
text: qsTr("On\n%1%").arg(slider_consigne.value.toFixed(0))
|
|
anchors.fill: parent // Permet que le texte occupe tout l'espace du parent (et que le centrage vertical qui suit fonctionne...)
|
|
verticalAlignment: Text.AlignVCenter
|
|
horizontalAlignment: Text.AlignHCenter
|
|
font.pixelSize: 18
|
|
font.weight: Font.Bold
|
|
color: couleur_green_yellow
|
|
visible: (slider_consigne.value === 0) ? false : true
|
|
}
|
|
}
|
|
}
|
|
|
|
handle: Rectangle {
|
|
x: parent.leftPadding + (parent.visualPosition * (parent.availableWidth - width))
|
|
y: (parent.availableHeight / 2) - (height / 2)
|
|
implicitWidth: largeur_bouton_slider // Le bouton n'étant pas visible la plupart du temps, cette taille n'est pas critique
|
|
implicitHeight: parent.height
|
|
radius: shipheart_rayon_bouton
|
|
color: (slider_consigne_bande_active.width === 0) ?
|
|
// couleur_rouge_transparent :
|
|
shipheart_couleur_fond_bouton_actif : // SDIR #207
|
|
"transparent"
|
|
border.color: "transparent"
|
|
|
|
Text { // Affichage de la valeur dans le bouton lorsque le circuit est OFF :
|
|
text: qsTr("Off")
|
|
anchors.fill: parent // Permet que le texte occupe tout l'espace du parent (et que le centrage vertical qui suit fonctionne...)
|
|
verticalAlignment: Text.AlignVCenter
|
|
horizontalAlignment: Text.AlignHCenter
|
|
font.pixelSize: 18
|
|
font.weight: Font.Bold
|
|
color: couleur_blanc_casse // SDIR #207
|
|
visible: (slider_consigne_bande_active.width === 0)
|
|
}
|
|
|
|
}
|
|
onMoved: {
|
|
shipheart_clic();
|
|
if (!timer_time_out_consigne.running)
|
|
{
|
|
timer_time_out_consigne.running = true
|
|
changement_consigne(slider_consigne.value, slider_consigne.value);
|
|
}
|
|
}
|
|
Timer { // Timer qui permet de brider les envoi de mise à jour dans la BDD
|
|
id: timer_time_out_consigne
|
|
interval: 250
|
|
triggeredOnStart: false
|
|
running: false
|
|
repeat: false
|
|
onTriggered: { // Permet d'être sûr que la dernière position est bien enregistrée dans la BDD, même si l'arrêt s'est produit pendant que le timer tournait
|
|
changement_consigne(slider_consigne.value, slider_consigne.value);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//-------------------------------------------------------------
|
|
// Cas d'un circuit sur une carte en Undervoltage
|
|
//-------------------------------------------------------------
|
|
Rectangle {
|
|
id: zone_info_etat_circuit_undervoltage
|
|
anchors.fill: parent
|
|
color: "transparent"
|
|
radius: shipheart_rayon_bouton
|
|
border.color: couleur_rouge
|
|
border.width: 3
|
|
visible: (etat_commande_carte === shipheart_etat_commande_module_undervoltage) ? true : false
|
|
|
|
Text {
|
|
text: qsTr("Off")
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
anchors.horizontalCenter: parent.horizontalCenter
|
|
font.pixelSize: 24
|
|
color: couleur_rouge
|
|
}
|
|
}
|
|
|
|
//-------------------------------------------------------------
|
|
// Cas d'un circuit sur une carte en mode Test
|
|
//-------------------------------------------------------------
|
|
Rectangle {
|
|
id: zone_info_etat_circuit_test
|
|
anchors.fill: parent
|
|
color: "transparent"
|
|
radius: shipheart_rayon_bouton
|
|
border.color: (mode_test === 0) ? couleur_rouge : couleur_vert
|
|
border.width: 3
|
|
visible: (etat_commande_carte === shipheart_etat_commande_module_test) ? true : false
|
|
|
|
Text {
|
|
text: (mode_test === 0) ? qsTr("Off") : qsTr("On")
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
anchors.horizontalCenter: parent.horizontalCenter
|
|
font.pixelSize: 24
|
|
color: (mode_test === 0) ? couleur_rouge : couleur_green_yellow
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//-------------------------------------------------------
|
|
// Ecran haut - centre : Commandes Auto
|
|
//-------------------------------------------------------
|
|
Rectangle {
|
|
id: zone_affichage_haut_centre
|
|
x: zone_affichage_haut_gauche.x + zone_affichage_haut_gauche.width + espace_colonnes_principales // Alignement avec les widgets
|
|
y: shipheart_hauteur_bandeau_haut + espace_lignes_principales
|
|
width: (shipheart_largeur_page * pourcentage_largeur_colonne_centre_haut) - (espace_colonnes_principales)
|
|
height: hauteur_utile * pourcentage_hauteur_ligne_haut;
|
|
color: shipheart_couleur_fond_bouton
|
|
// border.width: (etat !== 0) ? 3 : 0
|
|
// border.color: (etat !== 0) ? couleur_rouge : "transparent"
|
|
radius: shipheart_rayon_bouton
|
|
visible: (etat_systeme === 0) && (mode_cdes_auto !== -1)
|
|
|
|
Text {
|
|
text: "Auto" // Attention : Non traduit...
|
|
anchors.fill: parent // Permet que le texte occupe tout l'espace du parent (et que le centrage vertical qui suit fonctionne...)
|
|
verticalAlignment: Text.AlignVCenter
|
|
horizontalAlignment: Text.AlignHCenter
|
|
font.pixelSize: 18
|
|
font.weight: Font.Bold
|
|
color : (mode_cdes_auto === 0) ? couleur_gris_moyen : couleur_green_yellow
|
|
opacity: 1//0.8
|
|
}
|
|
MouseArea {
|
|
id: mouse_area_cdes_auto
|
|
anchors.fill: parent
|
|
pressAndHoldInterval: shipheart_mouse_press_and_hold_interval_long
|
|
onPressed: {
|
|
shipheart_clic();
|
|
}
|
|
onPressAndHold: {
|
|
shipheart_clic();
|
|
toggle_cdes_auto();
|
|
timer_raffraichissement_parametres.restart(); // Permet de réarmer le timer (qui ne doit PAS être 'triggeredOnStart' !) afin de reporter la prochaine mise à jour à une période entière de timer. Cela évite qu'un raffraichissement arrive trop tôt, avant que la nouvelle consigne ne soit prise en compte => On>Off>On ou Off>On>Off...
|
|
}
|
|
onClicked: {
|
|
maj_liste_events();
|
|
boite_information.open();
|
|
}
|
|
}
|
|
|
|
// Halo autour du bouton pendant l'appui :
|
|
Rectangle {
|
|
anchors {
|
|
verticalCenter: parent.verticalCenter
|
|
horizontalCenter: parent.horizontalCenter
|
|
}
|
|
width: Math.max(parent.width, parent.height) + 100
|
|
height: width
|
|
radius: width / 2
|
|
color: (mode_cdes_auto === 0) ? couleur_gris_moyen : couleur_green_yellow
|
|
opacity: 0.2
|
|
visible: mouse_area_cdes_auto.pressed
|
|
}
|
|
}
|
|
|
|
|
|
|
|
//-------------------------------------------------------
|
|
// Ecran haut - droite : Messages d'alerte
|
|
//-------------------------------------------------------
|
|
Rectangle {
|
|
id: zone_affichage_haut_droite
|
|
x: zone_affichage_haut_centre.x + zone_affichage_haut_centre.width + espace_colonnes_principales
|
|
y: shipheart_hauteur_bandeau_haut + espace_lignes_principales
|
|
width: (shipheart_largeur_page * (1 - pourcentage_largeur_colonne_gauche_haut - pourcentage_largeur_colonne_centre_haut))
|
|
- (espace_colonnes_principales / 2) // 1/2 de l'espace entre cette zone et la zone centrale (à gauche donc)
|
|
- largeur_bouton_suite - (espace_colonnes_secondaires / 2) // Espace à gauche pour s'aligner avec les widgets
|
|
height: hauteur_utile * pourcentage_hauteur_ligne_haut;
|
|
color: "transparent"
|
|
border.width: 3
|
|
border.color: couleur_rouge
|
|
radius: shipheart_rayon_bouton
|
|
visible: (etat_systeme === 0) && (texte_alerte !== "")
|
|
|
|
Image {
|
|
id: picto_alerte
|
|
source: source_picto_alerte
|
|
sourceSize.height: 30;
|
|
anchors {
|
|
left: parent.left
|
|
leftMargin: 20
|
|
verticalCenter: parent.verticalCenter
|
|
}
|
|
// visible: (texte_alerte !== "")
|
|
}
|
|
Text { // Affiche parfaitement 1, 2 ou 3 lignes de texte. A partir de 4 et 5, ça mort sur le contour du rectangle mais c'est encore lisible.
|
|
id: etat_circuit
|
|
width: parent.width - picto_alerte.width - picto_alerte.anchors.leftMargin - anchors.leftMargin;
|
|
wrapMode: Text.Wrap
|
|
horizontalAlignment: Text.AlignHCenter
|
|
leftPadding: 10 // Dégage le pictogramme sur la gauche
|
|
rightPadding: 10 // Evite de se caler sur le bord droit du rectangle
|
|
text: texte_alerte;
|
|
anchors {
|
|
left: picto_alerte.right
|
|
verticalCenter: parent.verticalCenter
|
|
}
|
|
font.pixelSize: 16
|
|
color: couleur_blanc_casse
|
|
// visible: (texte_alerte !== "")
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//-------------------------------------------------------
|
|
// Ecran milieu : Widgets
|
|
//-------------------------------------------------------
|
|
Rectangle {
|
|
id: zone_affichage_milieu
|
|
x: 0
|
|
y: shipheart_hauteur_bandeau_haut + zone_affichage_haut_gauche.height + (2 * espace_lignes_principales);
|
|
width: shipheart_largeur_page
|
|
height: hauteur_utile * pourcentage_hauteur_ligne_milieu;
|
|
color: "transparent"
|
|
visible: (etat_systeme === 0)
|
|
|
|
|
|
|
|
//--------------------
|
|
// Grille principale:
|
|
GridView {
|
|
id : grille_donnees_principale
|
|
|
|
property int index_base_en_cours: 0 // Utilsé pour stocker l'index du premier widget affiché à gauche
|
|
|
|
highlightRangeMode: GridView.StrictlyEnforceRange // Nécessaire pour que 'index_base_en_cours' soit mis à jour. Au passage, autorise de faire défiler les widgets jusqu'à ne garder que le dernier visible (pas génant et même plutôt sympa...)
|
|
width: parent.width - (2 * largeur_bouton_suite)
|
|
height: parent.height
|
|
cellWidth: width / nombre_widgets_par_ligne
|
|
cellHeight: height
|
|
flow: GridView.FlowTopToBottom // Items are laid out from top to bottom, and the view scrolls horizontally
|
|
snapMode: GridView.SnapToRow // L'arret de l'affichage se fera sur une rangée entière
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
anchors.horizontalCenter: parent.horizontalCenter
|
|
clip: true // Nécessaire pour que les Delegates s'arretent à l'intérieur de la GridView
|
|
model: ListModel { }
|
|
|
|
onMovementEnded: {
|
|
index_base_en_cours = currentIndex; // Capte la valeur de currentIndex aà la fin du mouvement (la valeur vaut alors l'index du widget le plus à gauche). Si on ne le capte pas, la valeur de CurrentIndex repasse à 0 après l'arrêt du flicker (pourquoi...???)
|
|
}
|
|
|
|
delegate: Rectangle { // Permet d'occuper toute la cellule de la grille
|
|
width: grille_donnees_principale.cellWidth
|
|
height: grille_donnees_principale.cellHeight
|
|
color: "transparent"
|
|
|
|
Rectangle { // Permet d'avoir un bouton plus petit que la cellule de la grille et de le centrer sur la cellule (=> espace entre boutons)
|
|
width: parent.width - espace_colonnes_secondaires;
|
|
height: parent.height - espace_lignes_secondaires;
|
|
color: (id_variable === model.id_var) ? shipheart_couleur_fond_bouton_actif : shipheart_couleur_fond_bouton
|
|
radius: shipheart_rayon_bouton
|
|
anchors {
|
|
verticalCenter: parent.verticalCenter
|
|
horizontalCenter: parent.horizontalCenter
|
|
}
|
|
|
|
//-----------------------------------
|
|
// Titre :
|
|
Text {
|
|
id: titre
|
|
text: model.titre
|
|
padding: 10
|
|
font.pixelSize: 18
|
|
color: couleur_blanc_casse
|
|
}
|
|
|
|
//-----------------------------------
|
|
// Valeur courante :
|
|
Text {
|
|
id: valeur
|
|
text: model.valeur
|
|
anchors {
|
|
verticalCenter: parent.verticalCenter
|
|
verticalCenterOffset: 10 // Permet de 'rencentre' du fait de l'affichage du nom de la batterie et que le titre du widget est plus gros que l'alerte basse ou haute
|
|
horizontalCenter: parent.horizontalCenter
|
|
horizontalCenterOffset: -20 // Permet de garder l'ensemble 'valeur + unité) centré sans utiliser un conteneur spécial
|
|
}
|
|
font.family: "Montserrat"
|
|
font.pixelSize: 60
|
|
font.weight: Font.Black
|
|
color: (model.etat <= 0) ?
|
|
( ((model.type_couleur !== 0) && (model.valeur < 0)) ?
|
|
couleur_orange :
|
|
couleur_blanc_casse ) :
|
|
couleur_rouge
|
|
}
|
|
Text {
|
|
id: unite
|
|
text: model.unite
|
|
anchors {
|
|
baseline: valeur.baseline
|
|
left: valeur.right
|
|
}
|
|
leftPadding: 20
|
|
font.pixelSize: 20
|
|
// color: (model.etat === 0) ? couleur_blanc_casse : couleur_rouge
|
|
color: couleur_blanc_casse
|
|
}
|
|
|
|
//-----------------------------------
|
|
// Nom de batterie :
|
|
Image {
|
|
id: batterie_icone
|
|
source: (id_variable === model.id_var) ? "/images/batterie.png" : "/images/batterie_sombre.png"
|
|
sourceSize.width: 20
|
|
anchors {
|
|
top: parent.top
|
|
topMargin: 50
|
|
left: parent.left
|
|
leftMargin: 10
|
|
}
|
|
visible: (id_var === tension_id_variable) && (nom_batterie !== "")
|
|
}
|
|
Text {
|
|
id: batterie_nom
|
|
text: nom_batterie
|
|
anchors {
|
|
verticalCenter: batterie_icone.verticalCenter
|
|
left: batterie_icone.right
|
|
leftMargin: 5
|
|
}
|
|
font.pixelSize: 10
|
|
color: (id_variable === model.id_var) ? couleur_blanc_casse : couleur_gris_moyen
|
|
visible: batterie_icone.visible
|
|
}
|
|
|
|
//-----------------------------------
|
|
// Zone de clic principale :
|
|
MouseArea{
|
|
anchors.fill : parent
|
|
onClicked: {
|
|
shipheart_clic();
|
|
raz_zoom(); // Au-delà de la fonctionnalité, c'est obligatoire sinon, le raffraichissement des la courbe est bloqué au niveau du timer
|
|
if (id_variable === model.id_var) // Toggle pour revenir à la consigne si aucun widget n'est sélectionné
|
|
{
|
|
if ((type_module !== shipheart_type_module_shipbase) || (no_circuit !== 0)) // Le circuit ShipHeart est le seul à ne pas avoir de consigne...
|
|
{
|
|
id_variable = consigne_id_variable;
|
|
symbole_unite = consigne_unite_variable;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
id_variable = model.id_var;
|
|
symbole_unite = model.unite;
|
|
}
|
|
busy_indicator.running = true;
|
|
timer_raffraichissement_graphiques.interval = periode_init_raffraichissement_graphiques; // Cela permet de lancer le "busy_indicator' avant de faire la mise à jour de la courbe
|
|
}
|
|
}
|
|
|
|
//-----------------------------------
|
|
// Alarmes :
|
|
Rectangle {
|
|
id: zone_alarmes
|
|
width: parent.width
|
|
height: 50
|
|
color: shipheart_couleur_fond_bouton
|
|
radius: shipheart_rayon_bouton
|
|
anchors {
|
|
left: parent.left
|
|
bottom: parent.bottom
|
|
}
|
|
visible: model.etat >= 0
|
|
|
|
Image {
|
|
source: (model.etat === 0) ? "/images/cloche_sombre.png" : "/images/cloche_rouge.png"
|
|
sourceSize.height: 20
|
|
anchors {
|
|
verticalCenter: zone_alarmes.verticalCenter
|
|
horizontalCenter: zone_alarmes.horizontalCenter
|
|
}
|
|
}
|
|
|
|
//-----------------------------------
|
|
// Zone de clics dédiée aux alarmes :
|
|
MouseArea{
|
|
anchors.fill: zone_alarmes
|
|
|
|
onClicked: {
|
|
shipheart_clic();
|
|
boite_dialogue_liste_alarmes.id_variable = model.id_var;
|
|
boite_dialogue_liste_alarmes.titre_widget = model.titre;
|
|
boite_dialogue_liste_alarmes.unite = model.unite;
|
|
boite_dialogue_liste_alarmes.open();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} // Fin de Gridview
|
|
|
|
// Flèche de suite gauche :
|
|
Image {
|
|
anchors.verticalCenter: grille_donnees_principale.verticalCenter
|
|
anchors.right: grille_donnees_principale.left
|
|
source: "/images/fleche_suite_gauche_sombre.png"
|
|
width: largeur_bouton_suite
|
|
height: grille_donnees_principale.height - espace_lignes_secondaires
|
|
opacity: 0.5
|
|
visible: (!grille_donnees_principale.moving) && // Permet de ne pas afficher la flèche pendant le mouvement (surtout génant à cause du lag généré par la fin du mouvement qui est assez lent).
|
|
(grille_donnees_principale.index_base_en_cours > 0)
|
|
}
|
|
|
|
// Flèche de suite droite :
|
|
Image {
|
|
anchors.verticalCenter: grille_donnees_principale.verticalCenter
|
|
anchors.left: grille_donnees_principale.right
|
|
source: "/images/fleche_suite_droite_sombre.png"
|
|
width: largeur_bouton_suite
|
|
height: grille_donnees_principale.height - espace_lignes_secondaires
|
|
opacity: 0.5
|
|
visible: (!grille_donnees_principale.moving) && // Permet de ne pas afficher la flèche pendant le mouvement (surtout génant à cause du lag généré par la fin du mouvement qui est assez lent).
|
|
((grille_donnees_principale.count - grille_donnees_principale.index_base_en_cours) > (nombre_widgets_par_ligne * (grille_donnees_principale.height / grille_donnees_principale.cellHeight))) // le calcul 'height/cellheight' donne le nombre de lignes de widget (généralement, 1 ou 2)
|
|
}
|
|
|
|
} // Fin des Widgets
|
|
|
|
|
|
|
|
//-------------------------------------------------------
|
|
// Ecran bas :
|
|
//-------------------------------------------------------
|
|
Rectangle {
|
|
id: zone_affichage_bas
|
|
x: 0
|
|
y: shipheart_hauteur_bandeau_haut + zone_affichage_haut_gauche.height + zone_affichage_milieu.height + (3 * espace_lignes_principales);
|
|
width: shipheart_largeur_page;
|
|
height: hauteur_utile * pourcentage_hauteur_ligne_graphique;
|
|
color: "transparent"
|
|
visible: (etat_systeme === 0) && (id_variable !== -1)
|
|
|
|
|
|
|
|
//===================================
|
|
// Consommation d'énergie
|
|
Rectangle {
|
|
id: zone_affichage_energie
|
|
x: 0
|
|
y: 0
|
|
width: (parent.width * pourcentage_largeur_graphique) - espace_colonnes_secondaires;
|
|
height: parent.height
|
|
color: "transparent"
|
|
visible: (id_variable === 0)
|
|
|
|
|
|
GridView {
|
|
id : grille_energie
|
|
width: parent.width
|
|
height: parent.height
|
|
cellWidth: parent.width / grille_energie.model.count
|
|
cellHeight: parent.height
|
|
flow: GridView.FlowTopToBottom // Items are laid out from top to bottom, and the view scrolls horizontally
|
|
snapMode: GridView.SnapToRow // L'arret de l'affichage se fera sur une rangée entière
|
|
clip: true // Nécessaire pour que les Delegates s'arretent à l'intérieur de la GridView
|
|
model: ListModel { }
|
|
|
|
delegate: Rectangle { // Permet d'occuper toute la cellule de la grille
|
|
id: bouton_consommateur
|
|
width: grille_energie.cellWidth
|
|
height: grille_energie.cellHeight
|
|
color: "transparent"
|
|
visible: !busy_indicator.running
|
|
|
|
// Valeur d'énergie (yc unité) :
|
|
Text {
|
|
id: valeur_energie
|
|
text: (model.valeur !== 0) ? model.valeur.toFixed(model.precision) : "--"
|
|
anchors {
|
|
top: parent.top
|
|
horizontalCenter: parent.horizontalCenter
|
|
}
|
|
font.weight: (model.hauteur === 1) ? Font.Bold : Font.Normal
|
|
font.pixelSize: 13
|
|
color: (model.hauteur === 1) ?
|
|
(!flag_periode_en_cours ? couleur_orange : couleur_jaune_post_it) :
|
|
((model.valeur !== 0) ? couleur_blanc_casse : couleur_gris_moyen)
|
|
}
|
|
Text {
|
|
id: unite_energie
|
|
text: model.unite
|
|
anchors {
|
|
top: valeur_energie.bottom
|
|
horizontalCenter: parent.horizontalCenter
|
|
}
|
|
font.pixelSize: 10
|
|
color: (model.valeur !== 0) ? couleur_blanc_casse : couleur_gris_moyen
|
|
}
|
|
// Bargraph :
|
|
Rectangle {
|
|
width: model.largeur
|
|
color: !flag_periode_en_cours ? couleur_orange : couleur_jaune_post_it
|
|
radius: shipheart_rayon_bouton
|
|
anchors {
|
|
bottom: parent.bottom
|
|
bottomMargin: 20
|
|
horizontalCenter: parent.horizontalCenter
|
|
}
|
|
PropertyAnimation on height {
|
|
to: (bouton_consommateur.height - 70) * model.hauteur; // Le '-60' permet de laisser la place à l'énergie et au pourcentage
|
|
duration: 500;
|
|
}
|
|
}
|
|
// Date de début principale :
|
|
Text {
|
|
text: model.debut_principal
|
|
anchors {
|
|
bottom: parent.bottom
|
|
horizontalCenter: parent.horizontalCenter
|
|
}
|
|
font.pixelSize: 12
|
|
font.weight: Font.Bold
|
|
color: couleur_blanc_casse
|
|
}
|
|
// Date de début secondaire :
|
|
Text {
|
|
text: model.debut_secondaire
|
|
anchors {
|
|
bottom: parent.bottom
|
|
horizontalCenter: parent.horizontalCenter
|
|
}
|
|
font.pixelSize: 10
|
|
color: couleur_blanc_casse
|
|
}
|
|
}
|
|
}
|
|
|
|
Label {
|
|
anchors.fill: parent
|
|
horizontalAlignment: Qt.AlignHCenter
|
|
verticalAlignment: Qt.AlignVCenter
|
|
visible: (grille_energie.model.count === 0) &&
|
|
(!busy_indicator.running) // Tant que le sablier tourne, on n'affiche pas le texte (car il risque d'y avoir des données ensuite...)
|
|
text: qsTr("Aucune consommation d'énergie sur cette période...")
|
|
color: couleur_gris_moyen
|
|
font.pixelSize: 15
|
|
font.bold: true
|
|
wrapMode: Label.Wrap
|
|
}
|
|
}
|
|
|
|
//========================
|
|
// Graphique :
|
|
ChartView {
|
|
id: graphique
|
|
antialiasing: true
|
|
anchors {
|
|
top: parent.top;
|
|
left:parent.left;
|
|
bottom:parent.bottom;
|
|
margins: -15 // Un peu compliqué mais permet, avec la ligne suivante, ...
|
|
}
|
|
margins { right: 0; bottom: 0; left: 5; top: 0 } // ... d'annuler les marges.
|
|
width: parent.width * pourcentage_largeur_graphique;
|
|
backgroundColor: "transparent"
|
|
// animationDuration: 10000
|
|
// animationOptions: ChartView.SeriesAnimations
|
|
legend {visible: false }
|
|
visible: (id_variable !== 0)
|
|
|
|
DateTimeAxis {
|
|
id: axisX
|
|
format: (zoomx_en_cours > 0.5) ? courbe_format_principal_axe_x : courbe_format_zoom_1_axe_x
|
|
min: xMin_date
|
|
max: xMax_date
|
|
tickCount: (zoomx_en_cours > 0.5) ? courbe_nombre_principal_graduations_axe_x : courbe_nombre_zoom_1_graduations_axe_x
|
|
//labelsColor: (!flag_zoom_en_cours) ? couleur_blanc_casse : couleur_green_yellow
|
|
labelsColor: couleur_blanc_casse
|
|
labelsFont: Qt.font({pointSize: 10})
|
|
color: couleur_gris_moyen
|
|
shadesColor: courbes_couleur_shades_fond
|
|
shadesVisible: true
|
|
gridVisible: false
|
|
// gridLineColor: "green"
|
|
}
|
|
ValueAxis {
|
|
id: axisY1
|
|
min: yMin_valeur
|
|
max: yMax_valeur
|
|
tickCount: courbe_nombre_graduations_axe_y
|
|
labelFormat: "%." + precision_affichage_axe_y_courbe + "f"
|
|
// labelsColor: (!flag_zoom_en_cours) ? couleur_blanc_casse : couleur_green_yellow
|
|
labelsColor: couleur_blanc_casse
|
|
labelsFont:Qt.font({pointSize: 10})
|
|
color: couleur_gris_moyen
|
|
// shadesColor: courbes_couleur_shades_fond
|
|
shadesVisible: false
|
|
gridVisible: true
|
|
gridLineColor: couleur_gris_tres_fonce
|
|
titleText: "<font color='" + couleur_blanc_casse + "'>" + symbole_unite + "</font>"
|
|
titleFont {
|
|
pointSize: 20
|
|
bold: true
|
|
}
|
|
}
|
|
LineSeries { // Utilisé si on veut renforcer la courbe mais sans avoir tout le tour de l'area renfocée (qui se fait dans AreaSeries pour le coup)
|
|
id: courbe_principale
|
|
name: "Courbe principale"
|
|
axisX: axisX
|
|
axisY: axisY1
|
|
capStyle: Qt.RoundCap
|
|
style: Qt.SolidLine
|
|
width: courbes_epaisseur_bordure
|
|
color: shipheart_couleur_bordure_courbes
|
|
}
|
|
Text {
|
|
id: texte_courbe_vide
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
anchors.horizontalCenter: parent.horizontalCenter
|
|
text: qsTr("Aucune donnée n'est disponible pour cette période")
|
|
font.pixelSize: 20
|
|
font.weight: Font.Bold
|
|
color: "red"
|
|
visible: courbe_flag_vide ? true : false;
|
|
}
|
|
|
|
//---------------------------------
|
|
// Rectangle de sélection de zoom :
|
|
Rectangle {
|
|
id: rectangle_zoom
|
|
x: pinch_area.zoom_x
|
|
y: pinch_area.zoom_y
|
|
width: pinch_area.zoom_w
|
|
height: pinch_area.zoom_h
|
|
radius: shipheart_rayon_zoom
|
|
|
|
color: couleur_bleu_koriolan_tres_transparent
|
|
}
|
|
|
|
//---------------------------------
|
|
// Zone de pinch :
|
|
PinchArea{
|
|
id: pinch_area
|
|
|
|
// Propriété de la eone de zoom pendant toute la phase de sélection :
|
|
property real zoom_x: 0
|
|
property real zoom_y: 0
|
|
property real zoom_w: 0
|
|
property real zoom_h: 0
|
|
|
|
anchors.fill: parent // Calé sur 'graphique'.
|
|
// Attention : la zone de traçage à l'intérieur de 'graphique' est 'graphique.plotArea'.
|
|
// Toutes les coordonnées sont données dans 'graphique' mais on limite à l'usage les coordonnées intérieures à 'graphique.plotArea'.
|
|
|
|
//-----------------------------------------------
|
|
// Mis à jour en cours de déplacement du pinch :
|
|
onPinchUpdated: {
|
|
|
|
if ((pinch.point1.x !== pinch.point2.x) || // Il arrive, en fin de pinch, que les 2 points renvoyés soient les mêmes...
|
|
(pinch.point1.y !== pinch.point2.y)) // ... Il faut éviter de les traiter sous peine de ramener W et H à 0.
|
|
{
|
|
// Récupération des données en s'affranchissant de la position des 2 points :
|
|
zoom_x = Math.min(pinch.point1.x, pinch.point2.x)
|
|
zoom_y = Math.min(pinch.point1.y, pinch.point2.y)
|
|
zoom_w = Math.abs(pinch.point1.x - pinch.point2.x)
|
|
zoom_h = Math.abs(pinch.point1.y - pinch.point2.y)
|
|
|
|
// Limitation de 'x' et 'w' à la largeur de la zone de traçage :
|
|
if (zoom_x < graphique.plotArea.x) zoom_x = graphique.plotArea.x;
|
|
if (zoom_x > (graphique.plotArea.x + graphique.plotArea.width)) zoom_x = graphique.plotArea.x + graphique.plotArea.width
|
|
if ((zoom_x + zoom_w) > (graphique.plotArea.x + graphique.plotArea.width)) zoom_w = (graphique.plotArea.x + graphique.plotArea.width) - zoom_x;
|
|
|
|
// Limitation de 'y' et 'h' à la hauteur de la zone de traçage :
|
|
if (zoom_y < graphique.plotArea.y) zoom_y = graphique.plotArea.y;
|
|
if (zoom_y > (graphique.plotArea.y + graphique.plotArea.height)) zoom_y = graphique.plotArea.y + graphique.plotArea.height
|
|
if ((zoom_y + zoom_h) > (graphique.plotArea.y + graphique.plotArea.height)) zoom_h = (graphique.plotArea.y + graphique.plotArea.height) - zoom_y;
|
|
}
|
|
}
|
|
|
|
//-------------------------
|
|
// Valeur de fin du pinch :
|
|
onPinchFinished: {
|
|
// Préparation du zoom sur le rectangle sélectionné :
|
|
var r = Qt.rect(zoom_x, zoom_y, zoom_w, zoom_h);
|
|
graphique.zoomIn(r);
|
|
flag_zoom_en_cours = true;
|
|
|
|
zoomx_en_cours *= (zoom_w / graphique.plotArea.width);
|
|
|
|
// Effacement du rectangle :
|
|
zoom_x = 0
|
|
zoom_y = 0
|
|
zoom_w = 0
|
|
zoom_h = 0
|
|
}
|
|
|
|
// Déplacement de la courbe :
|
|
MouseArea{
|
|
anchors.fill: parent
|
|
drag.target: dragTarget
|
|
drag.axis: Drag.XAndYAxis
|
|
onClicked: {
|
|
shipheart_clic();
|
|
if (!flag_zoom_en_cours) // Si le zoom est en cours, il ne faut PAS lancer le raffraichissement...!
|
|
{
|
|
busy_indicator.running = true;
|
|
timer_raffraichissement_graphiques.interval = periode_init_raffraichissement_graphiques; // Cela permet de lancer le "busy_indicator' avant de faire la mise à jour de la courbe
|
|
}
|
|
}
|
|
onPressAndHold: {
|
|
raz_zoom();
|
|
}
|
|
}
|
|
Item {
|
|
id: dragTarget
|
|
property real oldX : x // Permet de mémoriser la dernière position d'arrivée
|
|
property real oldY : y
|
|
|
|
property real cumulX : 0 // Permet de revenir à un déclage nul lorsque nécessaire
|
|
property real cumulY : 0
|
|
|
|
onXChanged: {
|
|
graphique.scrollLeft( x - oldX );
|
|
cumulX -= (x - oldX); // Le signe '-' permettra ensuite de revenir à le position de départ
|
|
oldX = x;
|
|
}
|
|
|
|
onYChanged: {
|
|
graphique.scrollUp( y - oldY );
|
|
cumulY -= (y - oldY); // Le signe '-' permettra ensuite de revenir à le position de départ
|
|
oldY = y;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//========================
|
|
// Busy Indicator :
|
|
Shipheart_busy_indicator {
|
|
id: busy_indicator
|
|
}
|
|
|
|
//========================
|
|
// Boutons de pếriode :
|
|
ColumnLayout {
|
|
spacing: 10
|
|
anchors {
|
|
top: parent.top;
|
|
right:parent.right;
|
|
rightMargin: 5;
|
|
bottom:parent.bottom;
|
|
}
|
|
width: (parent.width * (1 - pourcentage_largeur_graphique)) - anchors.rightMargin;
|
|
|
|
ListModel {
|
|
id: modele_periodes_graphique
|
|
}
|
|
|
|
Repeater {
|
|
model: modele_periodes_graphique
|
|
|
|
Rectangle {
|
|
color: "transparent"
|
|
Layout.preferredWidth: parent.width;
|
|
Layout.preferredHeight: (parent.height / nb_boutons_periode) - parent.spacing;
|
|
|
|
Text {
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
anchors.horizontalCenter: parent.horizontalCenter
|
|
text: model.libelle
|
|
font.pixelSize: 18
|
|
font.weight: (model.index === periode_analyse) ? Font.Bold : Font.Normal
|
|
color: couleur_blanc_casse
|
|
}
|
|
MouseArea { // Zone d'interaction. On est obligé de la mettre dans la grille pour que Rectangle et MouseArea soient frères ou parent/enfant ET qu'on n'occupe qu'un espace dans la grille.
|
|
anchors.fill: parent
|
|
onClicked: {
|
|
shipheart_clic();
|
|
raz_zoom(); // Au-delà de la fonctionnalité, c'est obligatoire sinon, le raffraichissement des la courbe est bloqué au niveau du timer
|
|
periode_analyse = model.index;
|
|
busy_indicator.running = true;
|
|
mise_a_jour_valeur_energie(); // Permet que la mise à jour du widget soit quasi instantanée après l'appui.
|
|
timer_raffraichissement_graphiques.interval = periode_init_raffraichissement_graphiques; // Cela permet de lancer le "busy_indicator' avant de faire la mise à jour de la courbe
|
|
}
|
|
}
|
|
// Fond du bouton :
|
|
Rectangle { // Permet d'avoir un fond et de pouvoir régler son opacité sans changer celle des textes au-dessus
|
|
width: parent.width
|
|
height: parent.height
|
|
color: (model.index === periode_analyse) ? (flag_zoom_en_cours ? couleur_green_yellow_transparent : shipheart_couleur_fond_bouton_actif) : shipheart_couleur_fond_bouton;
|
|
opacity: 0.5
|
|
radius: shipheart_rayon_bouton
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//-------------------------------------------------------
|
|
// Message d'erreur si circuit Absent
|
|
// (le module sur lequel le circuit est configuré n'est pas physiquement présent)
|
|
//-------------------------------------------------------
|
|
Rectangle {
|
|
id: zone_message_absence
|
|
x: 0
|
|
y: shipheart_hauteur_bandeau_haut + espace_lignes_principales
|
|
width: shipheart_largeur_page
|
|
height: shipheart_hauteur_page - shipheart_hauteur_bandeau_haut - shipheart_hauteur_bandeau_bas - espace_lignes_principales
|
|
color: "transparent"
|
|
visible: (etat_systeme !== 0)
|
|
|
|
Rectangle { // Rectangle entouré de rouge
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
anchors.verticalCenterOffset: -50
|
|
anchors.horizontalCenter: parent.horizontalCenter
|
|
width: parent.width
|
|
height: parent.height / 2
|
|
radius: shipheart_rayon_bouton
|
|
border.width: 3
|
|
border.color: couleur_rouge
|
|
color: couleur_rouge_transparent//"transparent"
|
|
|
|
Image { // Pictogramme DANGER
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
anchors.verticalCenterOffset: -100
|
|
anchors.horizontalCenter: parent.horizontalCenter
|
|
source: "/images/ak14.png"
|
|
sourceSize.height: 70;
|
|
}
|
|
|
|
Text { // Texte d'info
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
anchors.verticalCenterOffset: 50
|
|
anchors.horizontalCenter: parent.horizontalCenter
|
|
width: parent.width
|
|
height : parent.height / 2
|
|
horizontalAlignment: Qt.AlignCenter
|
|
verticalAlignment: Qt.AlignVCenter
|
|
padding: 50
|
|
text: shipheart_defaut_config_k_bus ?
|
|
qsTr("Le module assurant le pilotage de ce circuit n'est pas accessible !<br /><br />Si des ajouts/suppression/déplacements de modules ont eu lieu récemment, mettez à jour la configuration correspondant dans le menu [Réseau ShipHeart] de [Paramètres Avancés].<br /><br />Dans le cas où aucune modification n'a été effectuée récemment, vérifier les connexions de tous les modules.") :
|
|
qsTr("Ce circuit est configuré comme <i>Non Affecté</i> et n'est donc pas accessible !<br /><br />Pour accéder à nouveau à ce circuit, merci de l'affecter à un circuit disponible dans le menu [Circuits] de [Paramètres Avancés].")
|
|
color: couleur_blanc_casse
|
|
font.pixelSize: 18
|
|
wrapMode: Label.Wrap
|
|
}
|
|
}
|
|
}
|
|
|
|
//-------------------------------------------------------
|
|
// Bandeau bas :
|
|
//-------------------------------------------------------
|
|
Row {
|
|
x: 0
|
|
y: shipheart_hauteur_page - shipheart_hauteur_bandeau_bas;
|
|
width: shipheart_largeur_page;
|
|
height: shipheart_hauteur_bandeau_bas;
|
|
spacing: 5
|
|
padding: 5
|
|
|
|
//.................................................
|
|
// Bouton retour
|
|
//.................................................
|
|
Rectangle {
|
|
id: bandeau_bas_zone_retour
|
|
width: parent.width - (2 * parent.padding)
|
|
height: shipheart_hauteur_bandeau_bas - parent.topPadding - parent.bottomPadding;
|
|
radius: 5
|
|
color: shipheart_couleur_fond_bouton
|
|
|
|
Image {
|
|
source: "/images/icone_retour.png"
|
|
sourceSize.height: 30
|
|
anchors {
|
|
verticalCenter: parent.verticalCenter
|
|
horizontalCenter: parent.horizontalCenter
|
|
}
|
|
}
|
|
|
|
MouseArea { // Zone d'interaction. On est obligé de la mettre dans la grille pour que Rectangle et MouseArea soient frères ou parent/enfant ET qu'on n'occupe qu'un espace dans la grille.
|
|
id: mouse_area_bandeau_bas_zone_retour
|
|
anchors.fill: parent
|
|
onClicked: {
|
|
shipheart_clic();
|
|
stackView.pop()
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//-------------------------------------------------------
|
|
// Boite d'information sur les events déclenchannt la commande du circuit :
|
|
//-------------------------------------------------------
|
|
Shipheart_boite_dialogue {
|
|
id: boite_information
|
|
imageTitreSource: "/images/event.png"
|
|
alignementMessage: Text.AlignLeft
|
|
}
|
|
|
|
//-------------------------------------------------------
|
|
// Boite d'affichage de la liste des alarmes :
|
|
//-------------------------------------------------------
|
|
Shipheart_boite_dialogue_liste_alarmes {
|
|
id: boite_dialogue_liste_alarmes
|
|
|
|
titre: nom
|
|
type_source: shipheart_source_mesure_circuit
|
|
id_source: id_circuit
|
|
}
|
|
|
|
//===========================================================
|
|
// Economiseur : Doit être placé en fin de page pour fonctionner
|
|
//===========================================================
|
|
MouseArea {
|
|
anchors.fill: parent
|
|
preventStealing: true // Permet que cela fonctionne même si un élément flickable (notamment) soit derrière et "vole" le click
|
|
enabled: flag_economiseur_actif
|
|
onClicked: {
|
|
mise_en_veille(0);
|
|
}
|
|
}
|
|
|
|
|
|
//=============================================================================================================
|
|
// Init de la page
|
|
//=============================================================================================================
|
|
function init_page()
|
|
{
|
|
var res, req;
|
|
var nb;
|
|
var i;
|
|
|
|
|
|
//====================================================================
|
|
// Init du nom des périodes du graphique :
|
|
modele_periodes_graphique.append({ "libelle": Fonctions_date_heure.nom_periode_analyse(0), "actif": true });
|
|
modele_periodes_graphique.append({ "libelle": Fonctions_date_heure.nom_periode_analyse(1), "actif": true });
|
|
modele_periodes_graphique.append({ "libelle": Fonctions_date_heure.nom_periode_analyse(2), "actif": true });
|
|
modele_periodes_graphique.append({ "libelle": Fonctions_date_heure.nom_periode_analyse(3), "actif": true });
|
|
|
|
//====================================================================
|
|
// Lecture des infos générales concernant le circuit :
|
|
req = 'SELECT Nom, Adresse_module, intensite_seuil_haut, No_circuit FROM TB_Circuits WHERE Cle_primaire=' + id_circuit + ' ';
|
|
//console.log("Requête = [" + req + "]");
|
|
res = bdd.requete_unique(req);
|
|
nom = res[0];
|
|
var adresse_module = Number(res[1]);
|
|
intensite_seuil_haut = Number(res[2]);
|
|
no_circuit = Number(res[3]);
|
|
|
|
if (adresse_module >= 0) // Permet de ne pas effectuer les traitements (qui ne pourront de toutes façons pas se faire !) si le circuit est dévalidé...
|
|
{
|
|
req = 'SELECT Type FROM TB_Modules_config WHERE Adresse_k_bus=' + adresse_module + ' ';
|
|
//console.log("Requête = [" + req + "]");
|
|
res = bdd.requete_unique(req);
|
|
type_module = res[0];
|
|
|
|
//====================================================================
|
|
// Recherche de la batterie alimentant le circuit :
|
|
if (type_module !== shipheart_type_module_shippower4AC)
|
|
{
|
|
req = 'SELECT batt.Nom AS Nom_batterie from TB_Circuits AS circ, TB_Modules_config AS module, TB_Batteries as batt WHERE circ.Cle_primaire=' + id_circuit + ' AND circ.Adresse_module=module.Adresse_k_bus AND module.ID_Batterie=batt.Cle_primaire';
|
|
//console.log("Requête = [ " + req + "; ]");
|
|
// res = bdd.requete_unique(req); // SDIR #262 : Début
|
|
nb = bdd.requete(req);
|
|
if (nb > 0)
|
|
{
|
|
res = bdd.lecture_ligne();
|
|
nom_batterie = res[0];
|
|
}
|
|
else nom_batterie = qsTr("Non défini"); // SDIR #262 : Fin
|
|
}
|
|
else nom_batterie = "";
|
|
|
|
|
|
//====================================================================
|
|
// Recherche des ID_Variable circuit :
|
|
req = ' SELECT Code, Cle_primaire, Unite FROM TB_Variables WHERE Code LIKE "%Circ_%" ';
|
|
nb = bdd.requete(req);
|
|
for (i = 0; i < nb; i ++)
|
|
{
|
|
res = bdd.lecture_ligne();
|
|
if (!res.isEmpty)
|
|
{
|
|
switch(res[0])
|
|
{
|
|
case shipheart_circuit_consigne:
|
|
consigne_id_variable = Number(res[1]);
|
|
consigne_unite_variable = res[2];
|
|
break;
|
|
case shipheart_circuit_tension:
|
|
if (type_module !== shipheart_type_module_shippower4AC)
|
|
{
|
|
tension_id_variable = Number(res[1]);
|
|
tension_unite_variable = res[2];
|
|
}
|
|
break;
|
|
case shipheart_circuit_courant:
|
|
intensite_id_variable = Number(res[1]);
|
|
intensite_unite_variable = res[2];
|
|
break;
|
|
case shipheart_circuit_frequence:
|
|
frequence_id_variable = Number(res[1]);
|
|
frequence_unite_variable = res[2];
|
|
break;
|
|
case shipheart_circuit_puissance:
|
|
puissance_id_variable = Number(res[1]);
|
|
puissance_unite_variable = res[2];
|
|
break;
|
|
case shipheart_circuit_energie:
|
|
energie_id_variable = Number(res[1]);
|
|
energie_unite_variable = res[2];
|
|
break;
|
|
case shipheart_circuit_tension_secteur:
|
|
if (type_module === shipheart_type_module_shippower4AC)
|
|
{
|
|
tension_id_variable = Number(res[1]);
|
|
tension_unite_variable = res[2];
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
else break; // Ne devrait pas arriver....
|
|
}
|
|
|
|
|
|
switch(type_module)
|
|
{
|
|
case shipheart_type_module_shipbase:
|
|
plancher_intensite = shipheart_plancher_intensite_circuit_shipbase;
|
|
precision_tension = 2;
|
|
precision_intensite = 2;
|
|
break;
|
|
case shipheart_type_module_shippower812:
|
|
case shipheart_type_module_shippower8DC:
|
|
plancher_intensite = shipheart_plancher_intensite_circuit_sp8xx;
|
|
precision_tension = 2;
|
|
precision_intensite = 2;
|
|
break;
|
|
case shipheart_type_module_shippower4AC:
|
|
plancher_intensite = shipheart_plancher_intensite_circuit_sp4ac;
|
|
precision_tension = 0;
|
|
precision_intensite = 1;
|
|
break;
|
|
default:
|
|
plancher_intensite = 0;
|
|
precision_tension = 0;
|
|
precision_intensite = 0;
|
|
}
|
|
|
|
// Choix de la variable par défaut :
|
|
if ((type_module === shipheart_type_module_shipbase) && (no_circuit === 0)) // Circuit ShipHeart (le seul à ne pas avoir de consigne...)
|
|
{
|
|
id_variable = intensite_id_variable;
|
|
symbole_unite = intensite_unite_variable;
|
|
}
|
|
else // Tous les autres circuits
|
|
{
|
|
id_variable = consigne_id_variable;
|
|
symbole_unite = consigne_unite_variable;
|
|
}
|
|
|
|
// Première mise à jour :
|
|
if (id_variable !== -1) // Cas du port USB arrière par exemple qui n'a aucuns mesures (mais qui doit apparaitre pour sa consigne...)
|
|
{
|
|
mise_a_jour_valeur_energie();
|
|
mise_a_jour_valeurs_instantanees();
|
|
mise_a_jour_courbes();
|
|
}
|
|
}
|
|
|
|
// Libération du flag :
|
|
flag_init = false;
|
|
}
|
|
|
|
|
|
|
|
//=============================================================================================================
|
|
// Mise à jour de la valeur instantanée
|
|
//=============================================================================================================
|
|
function mise_a_jour_valeurs_instantanees()
|
|
{
|
|
var req, res;
|
|
var nb;
|
|
var i;
|
|
var adresse_module;
|
|
var tens, intens, puiss;
|
|
var nb_events;
|
|
|
|
//console.time('mise_a_jour_valeurs_instantanées')
|
|
|
|
// Requete :
|
|
req = 'SELECT ';
|
|
req += 'Adresse_module, ';
|
|
req += 'Etat_systeme, ';
|
|
req += 'Tension, ';
|
|
req += 'Intensite, ';
|
|
req += 'Frequence, ';
|
|
req += 'Intensite_seuil_haut, ';
|
|
req += 'Consigne, ';
|
|
req += 'Etat, ';
|
|
req += 'Etat_commande_carte, ';
|
|
req += 'Mode_commande, '
|
|
req += 'Mode_test, ';
|
|
req += ' (SELECT COUNT(*) FROM TB_Events WHERE Validite=1 AND (Action_circuits LIKE CONCAT(TB_Circuits.Cle_primaire,"/%") OR Action_circuits LIKE CONCAT("%;", TB_Circuits.Cle_primaire,"/%") ) ) AS nb_events, ';
|
|
req += ' Validation_cdes_events ';
|
|
req += 'FROM TB_Circuits WHERE Cle_primaire="' + id_circuit + '" ';
|
|
//console.log("Requête = [ " + req + "; ]");
|
|
res = bdd.requete_unique(req);
|
|
|
|
// Récupération des données :
|
|
i = 0;
|
|
adresse_module = Number(res[i++]);
|
|
etat_systeme = Number(res[i++]);
|
|
tens = Number(res[i++]);
|
|
tension = tens.toFixed(precision_tension);
|
|
intens = Number(res[i++]);
|
|
intensite = intens.toFixed(precision_intensite);
|
|
frequence = Number(res[i++]).toFixed(2);
|
|
intensite_seuil_haut = Number(res[i++]).toFixed(0);
|
|
consigne = Number(res[i++]);
|
|
etat = Number(res[i++]);
|
|
etat_commande_carte = Number(res[i++]);
|
|
mode_commande = Number(res[i++]);
|
|
mode_test = Number(res[i++]);
|
|
nb_events = Number(res[i++]); // Nb d'event Valides (mais pas forcément Visibilite) ayant une Action sur ce circuit.
|
|
mode_cdes_auto = Number(res[i++]); // Flag de validation de commande depuis les évènements.
|
|
if (nb_events === 0) mode_cdes_auto = -1; // Si aucun event Valide ne pointe sur ce circuit, on n'afffiche même pas le bouton
|
|
puiss = tens * intens;
|
|
puissance_unite_variable = "W"; // Par défaut
|
|
if (puiss < 100) puissance = puiss.toFixed(1);
|
|
else if (puiss < 1000) puissance = puiss.toFixed(0);
|
|
else
|
|
{
|
|
puiss /= 1000;
|
|
puissance_unite_variable = "kW"
|
|
if (puiss < 10) puissance = puiss.toFixed(1);
|
|
else puissance = puiss.toFixed(0);
|
|
}
|
|
|
|
|
|
|
|
// Recherche des éventuelles alarmes provenant des évènements :
|
|
var consigne_etat = -1;
|
|
var tension_etat = -1;
|
|
var intensite_etat = -1;
|
|
var frequence_etat = -1;
|
|
var puissance_etat = -1;
|
|
var energie_etat = -1;
|
|
|
|
req = 'SELECT ID_Variable, Etat_test ';
|
|
req += ' FROM TB_Events ';
|
|
req += ' WHERE Validite=1 ';
|
|
req += ' AND Alarme_source>0 ';
|
|
req += ' AND Type_source=' + shipheart_source_mesure_circuit + ' ';
|
|
req += ' AND ID_Source=' + id_circuit + ' ';
|
|
//console.log("Requête = [ " + req + "; ]");
|
|
nb = bdd.requete(req);
|
|
for (i = 0; i < nb; i ++)
|
|
{
|
|
res = bdd.lecture_ligne();
|
|
if (!res.isEmpty)
|
|
{
|
|
switch(Number(res[0]))
|
|
{
|
|
case consigne_id_variable:
|
|
if (consigne_etat < Number(res[1])) consigne_etat = Number(res[1]);
|
|
break;
|
|
case tension_id_variable:
|
|
if (tension_etat < Number(res[1])) tension_etat = Number(res[1]);
|
|
break;
|
|
case intensite_id_variable:
|
|
if (intensite_etat < Number(res[1])) intensite_etat = Number(res[1]);
|
|
break;
|
|
case frequence_id_variable:
|
|
if (frequence_etat < Number(res[1])) frequence_etat = Number(res[1]);
|
|
break;
|
|
case puissance_id_variable:
|
|
if (puissance_etat < Number(res[1])) puissance_etat = Number(res[1]);
|
|
break;
|
|
case energie_id_variable:
|
|
if (energie_etat < Number(res[1])) energie_etat = Number(res[1]);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// Mise à jour du modèle de la grille principale :
|
|
grille_donnees_principale.model.clear();
|
|
|
|
|
|
if ((type_module !== shipheart_type_module_shipbase) || // Pour tous les modules autres que ShipBase...
|
|
(no_circuit === 0) || // ou, sur ShipBase, uniquement les circuit 'ShipHeart' ...
|
|
(no_circuit === 1) ) // ... ou "ShipHeart-USB"
|
|
{
|
|
grille_donnees_principale.model.append({
|
|
"titre": Fonctions.nom_variable("Circ_courant"),
|
|
"id_var":intensite_id_variable,
|
|
"valeur": intensite,
|
|
"unite": intensite_unite_variable,
|
|
"etat": intensite_etat,
|
|
"type_couleur": 0 })
|
|
grille_donnees_principale.model.append({
|
|
"titre": Fonctions.nom_variable("Circ_tension"),
|
|
"id_var":tension_id_variable,
|
|
"valeur": tension,
|
|
"unite": tension_unite_variable,
|
|
"etat": tension_etat,
|
|
"type_couleur": 0 })
|
|
}
|
|
|
|
if (type_module === shipheart_type_module_shippower4AC)
|
|
{
|
|
grille_donnees_principale.model.append({
|
|
"titre": Fonctions.nom_variable("Circ_frequence"),
|
|
"id_var":frequence_id_variable,
|
|
"valeur": frequence,
|
|
"unite": frequence_unite_variable,
|
|
"etat": frequence_etat,
|
|
"type_couleur": 0 })
|
|
}
|
|
|
|
if ((type_module !== shipheart_type_module_shipbase) || // Pour tous les modules autres que ShipBase...
|
|
(no_circuit === 0) || // ou, sur ShipBase, uniquement les circuit 'ShipHeart' ...
|
|
(no_circuit === 1) ) // ... ou "ShipHeart-USB"
|
|
{
|
|
grille_donnees_principale.model.append({
|
|
"titre": Fonctions.nom_variable("Circ_puissance"),
|
|
"id_var":puissance_id_variable,
|
|
"valeur": puissance,
|
|
"unite": puissance_unite_variable,
|
|
"etat": puissance_etat,
|
|
"type_couleur": 0 })
|
|
grille_donnees_principale.model.append({
|
|
"titre": Fonctions.nom_variable("Circ_energie"),
|
|
"id_var":0,
|
|
"valeur": energie,
|
|
"unite": energie_unite_variable,
|
|
"etat": energie_etat,
|
|
"type_couleur": 0 })
|
|
}
|
|
|
|
|
|
|
|
|
|
// Définition du message d'alerte et du picto associé en fonction de l'état de la carte et du circuit :
|
|
if (etat_commande_carte === shipheart_etat_commande_module_undervoltage)
|
|
{
|
|
texte_alerte = qsTr("Le module pilotant ce circuit n'est pas alimentée correctement.\n Vérifier l'alimentation correspondante.")
|
|
source_picto_alerte = "/images/ak14.png"
|
|
}
|
|
else if (etat_commande_carte === shipheart_etat_commande_module_test)
|
|
{
|
|
texte_alerte = qsTr("Le module pilotant ce circuit est en mode MANUEL.\n Repositionnez le module en mode AUTO pour commander à nouveau ce circuit normalement.")
|
|
// Définir un message spécifique à chaque carte ? Ajout d'une photo ?
|
|
|
|
source_picto_alerte = "/images/ak5.png"
|
|
}
|
|
else
|
|
{
|
|
if (type_module === shipheart_type_module_shipbase) // Cas particulier de ShipBase :
|
|
{
|
|
if (no_circuit === 1)
|
|
{
|
|
switch(etat)
|
|
{
|
|
case 0 : texte_alerte = ""; break;
|
|
case 1: texte_alerte = qsTr("Le port USB du bas est en défaut."); break;
|
|
case 2: texte_alerte = qsTr("Le port USB du milieu est en défaut."); break;
|
|
case 3: texte_alerte = qsTr("Les 2 ports USB du milieu et du bas sont en défaut."); break;
|
|
case 4: texte_alerte = qsTr("Le port USB du haut est en défaut."); break;
|
|
case 5: texte_alerte = qsTr("Les 2 ports USB du haut et du bas sont en défaut."); break;
|
|
case 6: texte_alerte = qsTr("Les 2 ports USB du haut et du milieu sont en défaut."); break;
|
|
case 6: texte_alerte = qsTr("Les 3 ports USB du haut, du milieu et du bas sont en défaut."); break;
|
|
default : texte_alerte = qsTr("Etat inconnu...")
|
|
}
|
|
}
|
|
else if (no_circuit === 2)
|
|
{
|
|
switch(etat)
|
|
{
|
|
case 0 : texte_alerte = ""; break;
|
|
case 1: texte_alerte = qsTr("Le port USB est en défaut."); break;
|
|
default : texte_alerte = qsTr("Etat inconnu...")
|
|
}
|
|
}
|
|
else texte_alerte = "";
|
|
}
|
|
else // Cas général :
|
|
{
|
|
switch(etat)
|
|
{
|
|
case shipheart_etat_circuit_ok: texte_alerte = ""; break;
|
|
case shipheart_etat_circuit_limitation: texte_alerte = qsTr("L'alimentation du circuit a été coupée \n car sa limite de courant (%1 A)\n a été dépassée.").arg(intensite_seuil_haut); break;
|
|
case shipheart_etat_circuit_protection: texte_alerte = qsTr("L'alimentation du circuit a été coupée \n car les circuits de protection interne ont détecté une anomalie."); break;
|
|
case shipheart_etat_circuit_disjonte: texte_alerte = qsTr("L'alimentation du circuit a été coupée \n car le seuil de disjonction du circuit a été dépassé."); break;
|
|
case shipheart_etat_circuit_cc_batterie: texte_alerte = qsTr("Le circuit est en court-circuit avec le + batterie."); break;
|
|
case shipheart_etat_circuit_deleste:
|
|
req = 'SELECT Courant_maxi, Courant_maxi_tempo FROM TB_Modules_config WHERE Adresse_k_bus=' + adresse_module + ' ';
|
|
res = bdd.requete_unique(req);
|
|
|
|
texte_alerte = qsTr("L'alimentation du circuit a été coupée<br />car la consommation totale du module a dépassé %1 A pendant plus de %2 secondes (limite du module)").arg(Number(res[0])).arg(Number(res[1]));
|
|
break;
|
|
case shipheart_etat_circuit_undervoltage: texte_alerte = qsTr("La tension du circuit est anormalement basse."); break;
|
|
case shipheart_etat_circuit_inversion_phase_neutre: texte_alerte = qsTr("La phase et le neutre sont inversés sur ce circuit."); break;
|
|
case shipheart_etat_circuit_absence_terre: texte_alerte = qsTr("DANGER : Le neutre n'est pas référencé à la terre sur ce circuit (\"absence de terre\")."); break; // SDIR #283
|
|
case shipheart_etat_circuit_absence_masse: texte_alerte = qsTr("La masse est absente du connecteur d'alimentation du module"); break;
|
|
default : texte_alerte = qsTr("Etat inconnu...")
|
|
}
|
|
}
|
|
|
|
source_picto_alerte = "/images/ak14.png"
|
|
}
|
|
|
|
//console.timeEnd('mise_a_jour_valeurs_instantanées')
|
|
}
|
|
|
|
//=============================================================================================================
|
|
// Mise à jour de la valuer de consigne
|
|
//=============================================================================================================
|
|
function maj_liste_events()
|
|
{
|
|
var req, res;
|
|
var nb;
|
|
var i;
|
|
|
|
req = " SELECT Type_source, '' AS nom_source, TB_Events.Nom AS nom_event";
|
|
req += " FROM TB_Events";
|
|
req += " WHERE Validite=1 ";
|
|
req += " AND Type_source=0 ";
|
|
req += " AND (Action_circuits LIKE '" + id_circuit + "/%' OR Action_circuits LIKE '%;" + id_circuit + "/%') ";
|
|
req += " UNION";
|
|
req += " SELECT Type_source, tb_source.Nom AS nom_source, TB_Events.Nom AS nom_event";
|
|
req += " FROM TB_Events";
|
|
req += " INNER JOIN TB_Circuits AS tb_source ON TB_Events.ID_Source=tb_source.Cle_primaire";
|
|
req += " WHERE TB_Events.Validite=1 ";
|
|
req += " AND Type_source=1 ";
|
|
req += " AND (Action_circuits LIKE '" + id_circuit + "/%' OR Action_circuits LIKE '%;" + id_circuit + "/%') ";
|
|
req += " UNION";
|
|
req += " SELECT Type_source, tb_source.Nom AS nom_source, TB_Events.Nom AS nom_event";
|
|
req += " FROM TB_Events";
|
|
req += " INNER JOIN TB_Capteurs AS tb_source ON TB_Events.ID_Source=tb_source.Cle_primaire";
|
|
req += " WHERE TB_Events.Validite=1 ";
|
|
req += " AND Type_source=2 ";
|
|
req += " AND (Action_circuits LIKE '" + id_circuit + "/%' OR Action_circuits LIKE '%;" + id_circuit + "/%') ";
|
|
req += " UNION";
|
|
req += " SELECT Type_source, tb_source.Nom AS nom_source, TB_Events.Nom AS nom_event";
|
|
req += " FROM TB_Events";
|
|
req += " INNER JOIN TB_Reservoirs AS tb_source ON TB_Events.ID_Source=tb_source.Cle_primaire";
|
|
req += " WHERE TB_Events.Validite=1 ";
|
|
req += " AND Type_source=3 ";
|
|
req += " AND (Action_circuits LIKE '" + id_circuit + "/%' OR Action_circuits LIKE '%;" + id_circuit + "/%') ";
|
|
req += " UNION";
|
|
req += " SELECT Type_source, tb_source.Nom AS nom_source, TB_Events.Nom AS nom_event";
|
|
req += " FROM TB_Events";
|
|
req += " INNER JOIN TB_Batteries AS tb_source ON TB_Events.ID_Source=tb_source.Cle_primaire";
|
|
req += " WHERE TB_Events.Validite=1 ";
|
|
req += " AND Type_source=4 ";
|
|
req += " AND (Action_circuits LIKE '" + id_circuit + "/%' OR Action_circuits LIKE '%;" + id_circuit + "/%') ";
|
|
req += " ORDER BY Type_source, nom_source, nom_event ";
|
|
//console.log("Requête = [ " + req + "; ]");
|
|
nb = bdd.requete(req);
|
|
|
|
// Renseignement de la partie fixe du message :
|
|
if (nb !== 0) boite_information.message = qsTr("Evènements actuellement actifs qui sont susceptibles de commander ce circuit :");
|
|
// else boite_information.message = qsTr("Aucun évènement actuellement actif n'est sont susceptibles de commander ce circuit.");
|
|
// Ne devrait pas arriver...
|
|
|
|
// Ajout de chaque évènement trouvé :
|
|
boite_information.message += "<ul>";
|
|
for (i = 0; i < nb; i ++)
|
|
{
|
|
res = bdd.lecture_ligne();
|
|
if (!res.isEmpty)
|
|
{
|
|
boite_information.message += "<li><b>" + res[2] + "</b>" + (Number(res[0]) !==0 ? (" [" + res[1] + "]") : "") + "</li>";
|
|
}
|
|
else break; // Ne devrait pas arriver....
|
|
}
|
|
boite_information.message += "</ul>";
|
|
}
|
|
|
|
|
|
//=============================================================================================================
|
|
// Mise à jour de la valuer de consigne
|
|
//=============================================================================================================
|
|
function changement_consigne(new_consigne, old_consigne)
|
|
{
|
|
var req;
|
|
|
|
if (new_consigne !== consigne) // Ce cas apparait souvent en fin de mouvement de slider ; il est alors inutile de recharger la même demande vers la BDD puis l'appli...
|
|
{
|
|
req = "UPDATE TB_Circuits SET New_consigne=" + new_consigne + " ";
|
|
if (old_consigne !== -1) req += ", Old_consigne=" + old_consigne + " ";
|
|
req += " WHERE Cle_primaire='" + id_circuit + "'";
|
|
//console.log("Requête = [" + req + "]");
|
|
|
|
bdd.requete_unique(req);
|
|
synchro_bdd(shipheart_type_synchro_data);
|
|
|
|
consigne = new_consigne; // Permet la prise en compte immédiate par toute la page
|
|
timer_raffraichissement_parametres.restart(); // Permet de réarmer le timer (qui ne doit PAS être 'triggeredOnStart' !) afin de reporter la prochaine mise à jour à une période entière de timer. Cela évite qu'un raffraichissement arrive trop tôt, avant que la nouvelle consigne ne soit prise en compte => On>Off>On ou Off>On>Off...
|
|
}
|
|
}
|
|
|
|
|
|
//=============================================================================================================
|
|
// Mise à jour de la valeur instantanée
|
|
//=============================================================================================================
|
|
function toggle_cdes_auto()
|
|
{
|
|
var req;
|
|
|
|
if (mode_cdes_auto > -1) // Si la valeur est -1, c'est qu'aucun Event valide ne pointe sur ce circuit et on ne devrait pas arriver là...
|
|
{
|
|
if (mode_cdes_auto === 0) mode_cdes_auto = 1;
|
|
else mode_cdes_auto = 0;
|
|
|
|
bdd.requete_unique("UPDATE TB_Circuits SET Validation_cdes_events=" + mode_cdes_auto + " WHERE Cle_primaire='" + id_circuit + "'")
|
|
}
|
|
}
|
|
|
|
//=============================================================================================================
|
|
// Mise à jour de la valeur globale de l'énergie consommée sur la période en cours
|
|
//=============================================================================================================
|
|
function mise_a_jour_valeur_energie()
|
|
{
|
|
var req, res;
|
|
var i;
|
|
var date_debut, date_fin;
|
|
var type_mesure;
|
|
var total;
|
|
|
|
|
|
//console.time('calcul_valeur_energie')
|
|
|
|
// Dates et durée :
|
|
date_fin = new Date(); // En UTC
|
|
date_debut = Fonctions_date_heure.date_add_secondes(date_fin, -(Fonctions_date_heure.duree_periode_analyse(periode_analyse))); // En UTC
|
|
//console.log("Date de début initiale UTC = " + date_debut + " et date de fin UTC = " + date_fin)
|
|
|
|
// Ajustements à l'intervalle fini d'analyse :
|
|
var debut_fin = Fonctions_date_heure.ajustement_periode_analyse(periode_analyse, date_debut, date_fin, shipheart_fuseau_horaire, shipheart_heure_ete);
|
|
switch(periode_analyse)
|
|
{
|
|
default:
|
|
case 0: // 1 heure
|
|
type_mesure=3;
|
|
break;
|
|
case 1: // 24 heures
|
|
case 2: // 7 jours
|
|
case 3: // 30 jours
|
|
type_mesure=2;
|
|
break;
|
|
}
|
|
|
|
// Requete :
|
|
req = ' SELECT';
|
|
req += ' SUM(Valeur)';
|
|
req += ' FROM TB_Mesures_circuits';
|
|
req += ' WHERE ID=' + id_circuit + ' AND';
|
|
req += ' ID_Variable=' + energie_id_variable + ' AND';
|
|
req += ' Type=' + type_mesure + ' AND';
|
|
req += ' Date>="' + Fonctions_date_heure.chaine_date_heure_bdd(debut_fin.debut) + '" AND';
|
|
req += ' Date<="' + Fonctions_date_heure.chaine_date_heure_bdd(debut_fin.fin) + '"';
|
|
// req += ' ORDER BY Date '; // Pas utile pour faire la somme au final...
|
|
//console.log("Requête = [" + req + "]");
|
|
res = bdd.requete_unique(req);
|
|
total = Number(res[0]);
|
|
|
|
// Mise en forme du résultat :
|
|
energie_unite_variable = "Wh"; // Par défaut
|
|
if (total < 100) energie = total.toFixed(1);
|
|
else if (total < 1000) energie = total.toFixed(0);
|
|
else
|
|
{
|
|
total /= 1000;
|
|
energie_unite_variable = "kWh"
|
|
if (total < 10) energie = total.toFixed(1);
|
|
else energie = total.toFixed(0);
|
|
}
|
|
|
|
// Mise à jour immédiate du modele (sinon, il faudra attendre mise_a_jour_valeurs_instantanées()) :
|
|
for (i = 0; i < grille_donnees_principale.model.count; i ++)
|
|
{
|
|
if (grille_donnees_principale.model.get(i).id_var === 0)
|
|
{
|
|
grille_donnees_principale.model.setProperty(i, "valeur", energie);
|
|
grille_donnees_principale.model.setProperty(i, "unite", energie_unite_variable);
|
|
}
|
|
}
|
|
|
|
//console.timeEnd('calcul_valeur_energie')
|
|
}
|
|
|
|
|
|
//=============================================================================================================
|
|
// Consommation d'énergie du circuit entre dates
|
|
// Attention : cette fonction marche à tous les coups puisqu'elle va chercher les mesures de puissance du circuit et
|
|
// recalcule complètement l'énergie correspondante. Mais elle a un coût d'environ 200-250ms par appel !!
|
|
// Par comparaison, calculer TOUTES les barres d'énergie sur 30 jours en se basant sur les mresures de type 2
|
|
// coûte 30ms environ... Le calcul de la dernière barre "en cours" côute donc 10 fois plus que toutes les autres
|
|
// réunies...!
|
|
//=============================================================================================================
|
|
function conso_energie_intervalle(date_debut, date_fin)
|
|
{
|
|
var req, res;
|
|
var nb;
|
|
var chaine_date_debut = Fonctions_date_heure.chaine_date_heure_bdd(date_debut);
|
|
var chaine_date_fin = Fonctions_date_heure.chaine_date_heure_bdd(date_fin);
|
|
|
|
|
|
//console.time('maj_energie')
|
|
|
|
req = 'SELECT (SUM(Duree * Puissance) / 3600) AS Energie '; // 3600 secondes. NB : la division a intérêt à être faite sur la somme (et non la somme des divisions...)
|
|
req += ' FROM ( ';
|
|
req += ' SELECT ';
|
|
req += ' IFNULL'; // Return the specified value IF the expression is NULL, otherwise return the expression ie on convertit les valeurs NULL en 0.
|
|
req += ' (mesures.Valeur, 0) as Puissance, '; // Contrairement aux calculs usuels d'intégrale, la forme de stockage des mesures ne nécessite de connaitre que la valeur du point de début d'intervalle.
|
|
req += ' ( UNIX_TIMESTAMP(';
|
|
req += ' COALESCE('; // Returns the first non-null value in a list
|
|
req += ' LEAST(LEAD(mesures.Date) OVER (ORDER BY mesures.Date), "' + chaine_date_fin + '"),'; // "Plus petit" entre [date de la prochaine mesure] et [date de fin] ou NULL si l'un au moins est NULL (cas du dernier point de l'intervalle avec aucun point au-delà).
|
|
req += ' LEAD(mesures.Date) OVER (ORDER BY mesures.Date),'; // Date de la prochaine mesure (qui peut être NULL si on est sur le dernier point et qu'aucun point ultérieur n'existe)
|
|
req += ' "' + chaine_date_fin + '")) '; // Date de fin qui est forcément non NULL...
|
|
req += ' - ';
|
|
req += ' UNIX_TIMESTAMP(';
|
|
req += ' GREATEST(mesures.Date, "' + chaine_date_debut + '"))'; // "Plus grand" entre [date de mesure] et [date de début]. NB : contrairement à la fin de la période, aucune de ces deux valeurs ne peut être nulle...
|
|
req += ' ) as Duree'; // en secondes, entre le point en cours (ou la date de début si on est sur le point "ajouté") et le point suivant (ou la date de fin si on est sur le dernier point de l'intervalle)
|
|
req += ' FROM (';
|
|
req += ' (SELECT Date, Valeur FROM TB_Mesures_circuits WHERE ID_Variable=' + puissance_id_variable + ' AND Date>="' + chaine_date_debut + '" AND Date<="' + chaine_date_fin + '" AND ID=' + id_circuit + ') '; // Tous les points dans l'intervalle (y compris ceux avec la valeur NULL)
|
|
req += ' UNION ';
|
|
req += ' (SELECT Date, Valeur FROM TB_Mesures_circuits WHERE ID_Variable=' + puissance_id_variable + ' AND Date<="' + chaine_date_debut + '" AND ID=' + id_circuit + ' ORDER BY Date DESC LIMIT 1) ';
|
|
req += ' ) AS mesures ';
|
|
req += ' ) AS valeurs ';
|
|
//console.log("Requête = [" + req + "]");
|
|
res = bdd.requete_unique(req);
|
|
|
|
//console.timeEnd('maj_energie')
|
|
|
|
return(Number(res[0]));
|
|
}
|
|
|
|
|
|
|
|
//=============================================================================================================
|
|
// Mise à jour des données des courbes
|
|
//=============================================================================================================
|
|
function mise_a_jour_courbes()
|
|
{
|
|
var req, res;
|
|
var nb;
|
|
var i;
|
|
var courbe_principale_duree;
|
|
var date_debut, date_fin;
|
|
var date_debut_intervalle, date_fin_intervalle;
|
|
var date_debut_intervalle_locale;
|
|
var mini_maxi;
|
|
var type_mesure;
|
|
var valeur;
|
|
var precision;
|
|
var unite;
|
|
var max;
|
|
var largeur_bargraph;
|
|
var texte_debut_principal;
|
|
var texte_debut_secondaire;
|
|
var regroupement;
|
|
|
|
|
|
console.time('mise_a_jour_courbes')
|
|
|
|
//=======================================================
|
|
// Elements communs à tous les type de graphique :
|
|
|
|
// Dates et durée :
|
|
courbe_principale_duree = Fonctions_date_heure.duree_periode_analyse(periode_analyse); // En secondes
|
|
date_fin = new Date(); // En UTC
|
|
date_debut = Fonctions_date_heure.date_add_secondes(date_fin, -(courbe_principale_duree)); // En UTC
|
|
//console.log("Date de début initiale UTC = " + date_debut + " et date de fin UTC = " + date_fin)
|
|
|
|
|
|
//=======================================================
|
|
// Barres d'énergie :
|
|
if (id_variable === 0)
|
|
{
|
|
max = 0;
|
|
|
|
grille_energie.model.clear();
|
|
|
|
// Ajustements à l'intervalle fini d'analyse :
|
|
var debut_fin = Fonctions_date_heure.ajustement_periode_analyse(periode_analyse, date_debut, date_fin, shipheart_fuseau_horaire, shipheart_heure_ete);
|
|
|
|
switch(periode_analyse)
|
|
{
|
|
default:
|
|
case 0: // 1 heure
|
|
type_mesure=3;
|
|
courbe_nombre_principal_graduations_axe_x = 13;
|
|
largeur_bargraph = 40;
|
|
regroupement = "";
|
|
break;
|
|
|
|
case 1: // 24 heures
|
|
type_mesure=2;
|
|
courbe_nombre_principal_graduations_axe_x = 25;
|
|
largeur_bargraph = 35;
|
|
regroupement = "";
|
|
break;
|
|
|
|
case 2: // 7 jours
|
|
type_mesure=2;
|
|
courbe_nombre_principal_graduations_axe_x = 29;
|
|
largeur_bargraph = 30;
|
|
regroupement = "(6*60*60)";
|
|
break;
|
|
|
|
case 3: // 30 jours
|
|
type_mesure=2;
|
|
courbe_nombre_principal_graduations_axe_x = 31;
|
|
largeur_bargraph = 28;
|
|
regroupement = "(24*60*60)";
|
|
break;
|
|
}
|
|
|
|
// Recherche des data dans la BDD :
|
|
req = ' SELECT';
|
|
if (regroupement === "") req += ' Valeur,';
|
|
else req += ' SUM(Valeur),'; // Somme des valeurs uniquement si un regroupement est nécessaire (sinon, on obtient une seule valeur !)
|
|
if (regroupement === "") req += ' Date';
|
|
else req += ' MAX(Date)'; // Max des dates du groupe est obligatoire en cas de regoupement, sous peine de résultats aléatoires !
|
|
req += ' FROM TB_Mesures_circuits';
|
|
req += ' WHERE ID=' + id_circuit + ' AND';
|
|
req += ' ID_Variable=' + energie_id_variable + ' AND';
|
|
req += ' Type=' + type_mesure + ' AND';
|
|
req += ' Date>="' + Fonctions_date_heure.chaine_date_heure_bdd(debut_fin.debut) + '" AND';
|
|
req += ' Date<="' + Fonctions_date_heure.chaine_date_heure_bdd(debut_fin.fin) + '"';
|
|
if (regroupement !== "") req += ' GROUP BY (UNIX_TIMESTAMP(Date) - UNIX_TIMESTAMP("' + Fonctions_date_heure.chaine_date_heure_bdd(debut_fin.debut) + '")) DIV ' + regroupement + ' ';
|
|
req += ' ORDER BY Date ';
|
|
//console.log("Requête = [" + req + "]");
|
|
nb = bdd.requete(req);
|
|
for (i = 0; i < nb; i ++)
|
|
{
|
|
res = bdd.lecture_ligne();
|
|
if (!res.isEmpty)
|
|
{
|
|
// Récupération des données de l'intervalle :
|
|
valeur = Number(res[0]);
|
|
date_fin_intervalle = Fonctions_date_heure.chaine_bdd_date_heure(res[1]);
|
|
date_debut_intervalle = Fonctions_date_heure.date_add_secondes(date_fin_intervalle, -((courbe_principale_duree / (courbe_nombre_principal_graduations_axe_x - 1)) - 1) );
|
|
|
|
// Calcul du 'max' (en Wh) :
|
|
if (max < valeur) max = valeur;
|
|
|
|
// Ajout de l'intervale au modèle :
|
|
grille_energie.model.append({"debut_intervalle": date_debut_intervalle, "debut_principal": "", "debut_secondaire": "", "valeur": valeur, "precision": 0, "unite": "", "hauteur": 0.0, "largeur": largeur_bargraph, "flag_periode_en_cours": false });
|
|
}
|
|
else break; // Ne devrait pas arriver....
|
|
}
|
|
|
|
//-------------------------------------------------------------------------
|
|
// Calcul de l'échantillon "période en cours" (qui se termine MAINTENANT) :
|
|
// NOTA : la ligne suivnte représente environ 200-250ms, soit 90% du temps total de traitement...!
|
|
valeur = conso_energie_intervalle(debut_fin.fin, date_fin);
|
|
//console.log("DERNIER INTERVALLE : Début intervalle UTC = " + debut_fin.fin + " et fin d'intervalle UTC = " + date_fin);
|
|
|
|
// Calcul du 'max' (en Wh) avec le dernier intervalle :
|
|
if (max < valeur) max = valeur;
|
|
|
|
// Ajout du dernier intervalle au modèle :
|
|
grille_energie.model.append({"debut_intervalle": debut_fin.fin, "debut_principal": "", "debut_secondaire": "", "valeur": valeur, "precision": 0, "unite": "", "hauteur": 0.0, "largeur": largeur_bargraph, "flag_periode_en_cours": true });
|
|
|
|
|
|
//---------------------------------------------------
|
|
// Mise à jour des autres informations du circuit :
|
|
// NB : on est obligé de faire cette mise à jour en deuxième passe car on doit d'abord avoir le MAX calculé lors de la précédente...
|
|
if (max > 0)
|
|
{
|
|
for(i = 0; i < grille_energie.model.count; i++)
|
|
{
|
|
// Récupéartion de la valeur brute de l'échantillon :
|
|
valeur = grille_energie.model.get(i).valeur;
|
|
|
|
// Calcul de la hauteur de la barre :
|
|
// NB : à faire avant ajustement de la valeur en kWh !!
|
|
grille_energie.model.setProperty(i, "hauteur", (valeur / max));
|
|
|
|
// Calcul de l'unité et de la précision d'affichage en fonction de la valeur :
|
|
unite = "Wh"; // Par défaut
|
|
if (valeur < 100) precision = 1;
|
|
else if (valeur < 1000) precision = 0;
|
|
else
|
|
{
|
|
valeur /= 1000;
|
|
grille_energie.model.setProperty(i, "valeur", valeur); // Dans ce cas, il faut mettre à jour la valeur dans le modèle...
|
|
unite = "kWh"
|
|
if (valeur < 10) precision = 1;
|
|
else precision = 0;
|
|
}
|
|
grille_energie.model.setProperty(i, "precision", precision);
|
|
grille_energie.model.setProperty(i, "unite", unite);
|
|
|
|
// Calcul des dates de début principales et secondaires de l'échantillon avec le format associé :
|
|
date_debut_intervalle = grille_energie.model.get(i).debut_intervalle;
|
|
date_debut_intervalle_locale = Fonctions_date_heure.date_courante(date_debut_intervalle, shipheart_fuseau_horaire, shipheart_heure_ete);
|
|
|
|
// Détermination des légendes de temps :
|
|
switch(periode_analyse)
|
|
{
|
|
default:
|
|
case 0: // 1 heure
|
|
texte_debut_principal = Qt.formatDateTime(date_debut_intervalle_locale, "HH:mm");
|
|
texte_debut_secondaire = "";
|
|
break;
|
|
|
|
case 1: // 24 heures
|
|
if (Math.trunc(date_debut_intervalle_locale.getHours() % 6) === 0)
|
|
{
|
|
texte_debut_principal = Qt.formatDateTime(date_debut_intervalle_locale, "HH:mm");
|
|
texte_debut_secondaire = "";
|
|
}
|
|
else
|
|
{
|
|
texte_debut_principal = "";
|
|
texte_debut_secondaire = Qt.formatDateTime(date_debut_intervalle_locale, "HH:mm");
|
|
}
|
|
break;
|
|
|
|
case 2: // 7 jours
|
|
if (date_debut_intervalle_locale.getHours() === 0)
|
|
{
|
|
texte_debut_principal = Qt.formatDateTime(date_debut_intervalle_locale, "dd/MM");
|
|
texte_debut_secondaire = "";
|
|
}
|
|
else
|
|
{
|
|
texte_debut_principal = "";
|
|
texte_debut_secondaire = Qt.formatDateTime(date_debut_intervalle_locale, "HH:mm");
|
|
}
|
|
break;
|
|
|
|
case 3: // 30 jours
|
|
texte_debut_principal = Qt.formatDateTime(date_debut_intervalle_locale, "dd");
|
|
texte_debut_secondaire = "";
|
|
break;
|
|
}
|
|
grille_energie.model.setProperty(i, "debut_principal", texte_debut_principal);
|
|
grille_energie.model.setProperty(i, "debut_secondaire", texte_debut_secondaire);
|
|
}
|
|
}
|
|
else grille_energie.model.clear(); // Si le MAX vaut 0Wh, on peut supprimer toutes les entrées car elles sont toutes nulles...
|
|
|
|
}
|
|
|
|
//=======================================================
|
|
// Courbes des variables (autre qu'énergie) :
|
|
else
|
|
{
|
|
// Paramètres de la courbe dépendant de la période d'analyse :
|
|
switch(periode_analyse)
|
|
{
|
|
default:
|
|
case 0: // 1 heure
|
|
courbe_nombre_principal_graduations_axe_x = 7 // Nombre de bandes verticales + 1
|
|
courbe_nombre_zoom_1_graduations_axe_x = 7 // Utilisé lorsque le taux de zoom passe en-dessous de 0.5
|
|
courbe_format_principal_axe_x = "HH:mm" // exemple : "yyyy-MM-dd HH:mm:ss"
|
|
courbe_format_zoom_1_axe_x = "HH:mm" // Utilisé lorsque le taux de zoom passe en-dessous de 0.5
|
|
break;
|
|
|
|
case 1: // 24 heures
|
|
courbe_nombre_principal_graduations_axe_x = 13 // Nombre de bandes verticales + 1
|
|
courbe_nombre_zoom_1_graduations_axe_x = 13 // Utilisé lorsque le taux de zoom passe en-dessous de 0.5
|
|
courbe_format_principal_axe_x = "HH:mm" // exemple : "yyyy-MM-dd HH:mm:ss"
|
|
courbe_format_zoom_1_axe_x = "HH:mm" // Utilisé lorsque le taux de zoom passe en-dessous de 0.5
|
|
break;
|
|
|
|
case 2: // 7 jours
|
|
courbe_nombre_principal_graduations_axe_x = 8 // Nombre de bandes verticales + 1
|
|
courbe_nombre_zoom_1_graduations_axe_x = 8 // Utilisé lorsque le taux de zoom passe en-dessous de 0.5
|
|
courbe_format_principal_axe_x = "dd/MM HH:mm" // exemple : "yyyy-MM-dd HH:mm:ss"
|
|
courbe_format_zoom_1_axe_x = "HH:mm" // Utilisé lorsque le taux de zoom passe en-dessous de 0.5
|
|
break;
|
|
|
|
case 3: // 30 jours
|
|
courbe_nombre_principal_graduations_axe_x = 31 // Nombre de bandes verticales + 1
|
|
courbe_nombre_zoom_1_graduations_axe_x = 13 // Utilisé lorsque le taux de zoom passe en-dessous de 0.5
|
|
courbe_format_principal_axe_x = "dd" // exemple : "yyyy-MM-dd HH:mm:ss"
|
|
courbe_format_zoom_1_axe_x = "HH:mm" // Utilisé lorsque le taux de zoom passe en-dessous de 0.5
|
|
break;
|
|
}
|
|
|
|
// Mise à jour des données de la courbe principale :
|
|
res = tbmesuresModel.maj_data(graphique.series("Courbe principale"), "TB_Mesures_circuits", id_circuit, id_variable, date_debut, date_fin, 1, 1, (shipheart_fuseau_horaire + shipheart_heure_ete), 0, 0);
|
|
|
|
//-----------------------------------------------------------------------------------------------------
|
|
// Cas où aucune donnée n'est disponible sur la période :
|
|
if (Number(res[0]) === 0)
|
|
{
|
|
courbe_flag_vide = true; // Permet d'afficher le texte "Aucune donnée disponible..." sur la zone graphique
|
|
}
|
|
//-----------------------------------------------------------------------------------------------------
|
|
// Cas où des données sont disponibles sur la période (cas normal donc...) :
|
|
else
|
|
{
|
|
courbe_flag_vide = false;
|
|
|
|
//console.log("Min val=" + Number(res[6]) + " et mini=" + yMin_valeur + " - Max val=" + Number(res[8]) + " et maxi=" + yMax_valeur);
|
|
xMin_date = new Date(Number(res[1])); // Nécessaire pour la Min de l'axe X (NB : les dates retournées par 'maj_data' sont en heure locale)
|
|
xMax_date = new Date(Number(res[3])); // Nécessaire pour la Max de l'axe X (NB : les dates retournées par 'maj_data' sont en heure locale)
|
|
mini_maxi = Fonctions.ajustement_mini_maxi(Number(res[6]), Number(res[8]), courbe_nombre_graduations_axe_y);
|
|
yMin_valeur = mini_maxi.mini // Nécessaire pour le Min de l'axe Y
|
|
yMax_valeur = mini_maxi.maxi // Nécessaire pour le Max de l'axe Y
|
|
precision_affichage_axe_y_courbe = Fonctions.precision_affichage_mini_maxi(Number(res[6]), Number(res[8]), courbe_nombre_graduations_axe_y);
|
|
|
|
|
|
}
|
|
}
|
|
|
|
console.timeEnd('mise_a_jour_courbes')
|
|
|
|
// Arrêt du sablier :
|
|
busy_indicator.running = false; // Arrêt du tourniquet s'il est en marche
|
|
}
|
|
|
|
|
|
|
|
//=============================================================================================================
|
|
// RAZ du zoom
|
|
//=============================================================================================================
|
|
function raz_zoom()
|
|
{
|
|
|
|
graphique.zoomReset(); // RAZ du zoom proprement dit
|
|
graphique.scrollLeft(dragTarget.cumulX); // RAZ du déplacement horizontal par annulation du cumul
|
|
graphique.scrollUp(dragTarget.cumulY); // RAZ du déplacement vertical par annulation du cumul
|
|
|
|
dragTarget.cumulX = 0; // RAZ du cumul après retour à la position d'origine
|
|
dragTarget.cumulY = 0;
|
|
|
|
flag_zoom_en_cours = false;
|
|
zoomx_en_cours = 1;
|
|
}
|
|
|
|
|
|
}
|
|
|