// widget_meter.ysl2 widget_desc("Meter") { longdesc || Meter widget moves the end of "needle" labeled path along "range" labeled path, according to value of the single accepted variable. Needle is reduced to a single segment. If "min" a "max" labeled texts are provided, or if first and second argument are given, then they are used as respective minimum and maximum value. Otherwise, value is expected to be in between 0 and 100. || shortdesc > Moves "needle" along "range" arg name="min" count="optional" accepts="int,real" > minimum value arg name="max" count="optional" accepts="int,real" > maximum value path name="value" accepts="HMI_INT,HMI_REAL" > Value to display } widget_class("Meter"){ || frequency = 10; origin = undefined; range = undefined; dispatch(value) { this.display_val = value; this.request_animate(); } animate(){ if(this.value_elt) this.value_elt.textContent = String(this.display_val); let [min,max,totallength] = this.range; let length = Math.max(0,Math.min(totallength,(Number(this.display_val)-min)*totallength/(max-min))); let tip = this.range_elt.getPointAtLength(length); this.needle_elt.setAttribute('d', "M "+this.origin.x+","+this.origin.y+" "+tip.x+","+tip.y); } init() { let [min,max] = [[this.min_elt,0],[this.max_elt,100]].map(([elt,def],i)=>elt? Number(elt.textContent) : this.args.length >= i+1 ? this.args[i] : def); this.range = [min, max, this.range_elt.getTotalLength()] this.origin = this.needle_elt.getPointAtLength(0); } || } widget_defs("Meter") { labels("needle range"); optional_labels("min max"); }