svghmi/widget_xygraph.ysl2
changeset 3505 a27b5862e363
parent 3490 4f252e8d6759
child 3509 b5ca17732b1e
equal deleted inserted replaced
3504:9d895a103019 3505:a27b5862e363
    20 
    20 
    21     shortdesc > Cartesian trend graph showing values of given variables over time
    21     shortdesc > Cartesian trend graph showing values of given variables over time
    22 
    22 
    23     path name="value" count="1+" accepts="HMI_INT,HMI_REAL" > value
    23     path name="value" count="1+" accepts="HMI_INT,HMI_REAL" > value
    24 
    24 
    25     arg name="size" accepts="int" > buffer size
    25     arg name="xrange" accepts="int,time" > X axis range expressed either in samples or duration.
    26     arg name="xformat" count="optional" accepts="string" > format string for X label
    26     arg name="xformat" count="optional" accepts="string" > format string for X label
    27     arg name="yformat" count="optional" accepts="string" > format string for Y label
    27     arg name="yformat" count="optional" accepts="string" > format string for Y label
    28     arg name="ymin" count="optional" accepts="int,real" > minimum value foe Y axis
       
    29     arg name="ymax" count="optional" accepts="int,real" > maximum value for Y axis
       
    30 }
    28 }
    31 
    29 
    32 widget_class("XYGraph") {
    30 widget_class("XYGraph") {
    33     ||
    31     ||
    34         frequency = 1;
    32         frequency = 1;
    35         init() {
    33         init() {
    36             [this.x_size,
    34             let x_duration_s;
       
    35             [x_duration_s,
    37              this.x_format, this.y_format] = this.args;
    36              this.x_format, this.y_format] = this.args;
       
    37 
       
    38             let timeunit = x_duration_s.slice(-1);
       
    39             let factor = {
       
    40                 "s":1,
       
    41                 "m":60,
       
    42                 "h":3600,
       
    43                 "d":86400}[timeunit];
       
    44             if(factor == undefined){
       
    45                 this.max_data_length = Number(x_duration_s);
       
    46                 this.x_duration = undefined;
       
    47             }else{
       
    48                 let duration = factor*Number(x_duration_s.slice(0,-1));
       
    49                 this.max_data_length = undefined;
       
    50                 this.x_duration = duration*1000;
       
    51             }
       
    52 
    38 
    53 
    39             // Min and Max given with paths are meant to describe visible range,
    54             // Min and Max given with paths are meant to describe visible range,
    40             // not to clip data.
    55             // not to clip data.
    41             this.clip = false;
    56             this.clip = false;
    42 
    57 
    95             for(let curve of this.curves){
   110             for(let curve of this.curves){
    96                 curve.setAttribute("clip-path", "url(#" + clipPath.id + ")");
   111                 curve.setAttribute("clip-path", "url(#" + clipPath.id + ")");
    97             }
   112             }
    98 
   113 
    99             this.curves_data = this.curves.map(_unused => []);
   114             this.curves_data = this.curves.map(_unused => []);
   100             this.max_data_length = this.args[0];
       
   101         }
   115         }
   102 
   116 
   103         dispatch(value,oldval, index) {
   117         dispatch(value,oldval, index) {
   104             // TODO: get PLC time instead of browser time
   118             // TODO: get PLC time instead of browser time
   105             let time = Date.now();
   119             let time = Date.now();
   112             let data_length = this.curves_data[index].length;
   126             let data_length = this.curves_data[index].length;
   113             let ymin_damaged = false;
   127             let ymin_damaged = false;
   114             let ymax_damaged = false;
   128             let ymax_damaged = false;
   115             let overflow;
   129             let overflow;
   116 
   130 
   117             if(data_length > this.max_data_length){
   131             if(this.max_data_length == undefined){
   118                 // remove first item
   132                 let peremption = time - this.x_duration;
   119                 [this.xmin, overflow] = this.curves_data[index].shift();
   133                 let oldest = this.curves_data[index][0][0]
   120                 data_length = data_length - 1;
   134                 this.xmin = peremption;
       
   135                 if(oldest < peremption){
       
   136                     // remove first item
       
   137                     overflow = this.curves_data[index].shift()[1];
       
   138                     data_length = data_length - 1;
       
   139                 }
   121             } else {
   140             } else {
   122                 if(this.xmin == undefined){
   141                 if(data_length > this.max_data_length){
   123                     this.xmin = time;
   142                     // remove first item
       
   143                     [this.xmin, overflow] = this.curves_data[index].shift();
       
   144                     data_length = data_length - 1;
       
   145                 } else {
       
   146                     if(this.xmin == undefined){
       
   147                         this.xmin = time;
       
   148                     }
   124                 }
   149                 }
   125             }
   150             }
   126 
   151 
   127             this.xmax = time;
   152             this.xmax = time;
   128             let Xrange = this.xmax - this.xmin;
   153             let Xrange = this.xmax - this.xmin;
   139                     this.ymin = value;
   164                     this.ymin = value;
   140                 }
   165                 }
   141             }
   166             }
   142             let Yrange = this.ymax - this.ymin;
   167             let Yrange = this.ymax - this.ymin;
   143 
   168 
       
   169             // apply margin by moving min and max to enlarge range
   144             let [xMargin,yMargin] = zip(this.Margins, [Xrange, Yrange]).map(([m,l]) => m*l);
   170             let [xMargin,yMargin] = zip(this.Margins, [Xrange, Yrange]).map(([m,l]) => m*l);
   145             [[this.dxmin, this.dxmax],[this.dymin,this.dymax]] =
   171             [[this.dxmin, this.dxmax],[this.dymin,this.dymax]] =
   146                 [[this.xmin-xMargin, this.xmax+xMargin],
   172                 [[this.xmin-xMargin, this.xmax+xMargin],
   147                  [this.ymin-yMargin, this.ymax+yMargin]];
   173                  [this.ymin-yMargin, this.ymax+yMargin]];
   148             Xrange += 2*xMargin;
   174             Xrange += 2*xMargin;
   161                         let xv = vectorscale(xvect, (x - this.dxmin) / Xrange);
   187                         let xv = vectorscale(xvect, (x - this.dxmin) / Xrange);
   162                         let yv = vectorscale(yvect, (y - this.dymin) / Yrange);
   188                         let yv = vectorscale(yvect, (y - this.dymin) / Yrange);
   163                         let px = base_point.x + xv.x + yv.x;
   189                         let px = base_point.x + xv.x + yv.x;
   164                         let py = base_point.y + xv.y + yv.y;
   190                         let py = base_point.y + xv.y + yv.y;
   165                         if(!this.fixed_y_range){
   191                         if(!this.fixed_y_range){
       
   192                             // update min and max from curve data if needed
   166                             if(ymin_damaged && y < this.ymin) this.ymin = y;
   193                             if(ymin_damaged && y < this.ymin) this.ymin = y;
   167                             if(ymax_damaged && y > this.ymax) this.ymax = y;
   194                             if(ymax_damaged && y > this.ymax) this.ymax = y;
   168                         }
   195                         }
   169 
   196 
   170                         return " " + px + "," + py;
   197                         return " " + px + "," + py;