1 // widget_circuralslider.ysl2 |
|
2 |
|
3 widget_desc("CircularSlider") { |
|
4 longdesc |
|
5 || |
|
6 CircularSlider - DEPRECATED, to be replaced by PathSlider |
|
7 This widget moves "handle" labeled group along "range" labeled |
|
8 arc, according to value of the single accepted variable. |
|
9 |
|
10 If "min" a "max" labeled texts are provided, or if first and second |
|
11 argument are given, then they are used as respective minimum and maximum |
|
12 value. Otherwise, value is expected to be in between 0 and 100. |
|
13 |
|
14 If "value" labeled text is found, then its content is replaced by value. |
|
15 During drag, "setpoint" labeled group is moved to position defined by user |
|
16 while "handle" reflects current value from variable. |
|
17 || |
|
18 |
|
19 shortdesc > CircularSlider - DEPRECATED |
|
20 |
|
21 arg name="min" count="optional" accepts="int,real" > minimum value |
|
22 |
|
23 arg name="min" count="optional" accepts="int,real" > maximum value |
|
24 |
|
25 // TODO: add printf-like format |
|
26 |
|
27 path name="value" accepts="HMI_INT,HMI_REAL" > Value to display |
|
28 |
|
29 } |
|
30 |
|
31 widget_class("CircularSlider") |
|
32 || |
|
33 frequency = 5; |
|
34 range = undefined; |
|
35 circle = undefined; |
|
36 handle_pos = undefined; |
|
37 curr_value = 0; |
|
38 drag = false; |
|
39 enTimer = false; |
|
40 last_drag = false; |
|
41 |
|
42 dispatch(value) { |
|
43 let [min,max,start,totallength] = this.range; |
|
44 //save current value inside widget |
|
45 this.curr_value = value; |
|
46 |
|
47 //check if in range |
|
48 if (this.curr_value > max){ |
|
49 this.curr_value = max; |
|
50 this.apply_hmi_value(0, this.curr_value); |
|
51 } |
|
52 else if (this.curr_value < min){ |
|
53 this.curr_value = min; |
|
54 this.apply_hmi_value(0, this.curr_value); |
|
55 } |
|
56 |
|
57 if(this.value_elt) |
|
58 this.value_elt.textContent = String(value); |
|
59 |
|
60 //don't update if draging and setpoint ghost doesn't exist |
|
61 if(!this.drag || (this.setpoint_elt != undefined)){ |
|
62 this.update_DOM(value, this.handle_elt); |
|
63 } |
|
64 } |
|
65 |
|
66 update_DOM(value, elt){ |
|
67 let [min,max,totalDistance] = this.range; |
|
68 let length = Math.max(0,Math.min((totalDistance),(Number(value)-min)/(max-min)*(totalDistance))); |
|
69 let tip = this.range_elt.getPointAtLength(length); |
|
70 elt.setAttribute('transform',"translate("+(tip.x-this.handle_pos.x)+","+(tip.y-this.handle_pos.y)+")"); |
|
71 |
|
72 // show or hide ghost if exists |
|
73 if(this.setpoint_elt != undefined){ |
|
74 if(this.last_drag!= this.drag){ |
|
75 if(this.drag){ |
|
76 this.setpoint_elt.setAttribute("style", this.setpoint_style); |
|
77 }else{ |
|
78 this.setpoint_elt.setAttribute("style", "display:none"); |
|
79 } |
|
80 this.last_drag = this.drag; |
|
81 } |
|
82 } |
|
83 } |
|
84 |
|
85 on_release(evt) { |
|
86 //unbind events |
|
87 window.removeEventListener("touchmove", this.on_bound_drag, true); |
|
88 window.removeEventListener("mousemove", this.on_bound_drag, true); |
|
89 |
|
90 window.removeEventListener("mouseup", this.bound_on_release, true) |
|
91 window.removeEventListener("touchend", this.bound_on_release, true); |
|
92 window.removeEventListener("touchcancel", this.bound_on_release, true); |
|
93 |
|
94 //reset drag flag |
|
95 if(this.drag){ |
|
96 this.drag = false; |
|
97 } |
|
98 |
|
99 // get final position |
|
100 this.update_position(evt); |
|
101 } |
|
102 |
|
103 on_drag(evt){ |
|
104 //ignore drag event for X amount of time and if not selected |
|
105 if(this.enTimer && this.drag){ |
|
106 this.update_position(evt); |
|
107 |
|
108 //reset timer |
|
109 this.enTimer = false; |
|
110 setTimeout("{hmi_widgets['"+this.element_id+"'].enTimer = true;}", 100); |
|
111 } |
|
112 } |
|
113 |
|
114 update_position(evt){ |
|
115 if(this.drag && this.enTimer){ |
|
116 var svg_dist = 0; |
|
117 |
|
118 //calculate center of widget in html |
|
119 // --TODO maybe it would be better to bind this part to window change size event ??? |
|
120 let [xdest,ydest,svgWidth,svgHeight] = page_desc[current_visible_page].bbox; |
|
121 let [cX, cY,fiStart,fiEnd,minMax,x1,y1,width,height] = this.circle; |
|
122 let htmlCirc = this.range_elt.getBoundingClientRect(); |
|
123 let cxHtml = ((htmlCirc.right-htmlCirc.left)/(width)*(cX-x1))+htmlCirc.left; |
|
124 let cyHtml = ((htmlCirc.bottom-htmlCirc.top)/(height)*(cY-y1))+htmlCirc.top; |
|
125 |
|
126 |
|
127 //get mouse coordinates |
|
128 let mouseX = undefined; |
|
129 let mouseY = undefined; |
|
130 if (evt.type.startsWith("touch")){ |
|
131 mouseX = Math.ceil(evt.touches[0].clientX); |
|
132 mouseY = Math.ceil(evt.touches[0].clientY); |
|
133 } |
|
134 else{ |
|
135 mouseX = evt.pageX; |
|
136 mouseY = evt.pageY; |
|
137 } |
|
138 |
|
139 //calculate angle |
|
140 let fi = Math.atan2(cyHtml-mouseY, mouseX-cxHtml); |
|
141 |
|
142 // transform from 0 to 2PI |
|
143 if (fi > 0){ |
|
144 fi = 2*Math.PI-fi; |
|
145 } |
|
146 else{ |
|
147 fi = -fi; |
|
148 } |
|
149 |
|
150 //offset it to 0 |
|
151 fi = fi - fiStart; |
|
152 if (fi < 0){ |
|
153 fi = fi + 2*Math.PI; |
|
154 } |
|
155 |
|
156 //get handle distance from mouse position |
|
157 if(fi<fiEnd){ |
|
158 this.curr_value=(fi)/(fiEnd)*(this.range[1]-this.range[0]); |
|
159 } |
|
160 else if(fiEnd<fi && fi<fiEnd+minMax){ |
|
161 this.curr_value = this.range[1]; |
|
162 } |
|
163 else{ |
|
164 this.curr_value = this.range[0]; |
|
165 } |
|
166 |
|
167 //apply value to hmi |
|
168 this.apply_hmi_value(0, Math.ceil(this.curr_value)); |
|
169 |
|
170 //redraw handle |
|
171 this.request_animate(); |
|
172 |
|
173 } |
|
174 |
|
175 } |
|
176 |
|
177 animate(){ |
|
178 // redraw handle on screen refresh |
|
179 // check if setpoint(ghost) handle exsist otherwise update main handle |
|
180 if(this.setpoint_elt != undefined){ |
|
181 this.update_DOM(this.curr_value, this.setpoint_elt); |
|
182 } |
|
183 else{ |
|
184 this.update_DOM(this.curr_value, this.handle_elt); |
|
185 } |
|
186 } |
|
187 |
|
188 on_select(evt){ |
|
189 //enable drag flag and timer |
|
190 this.drag = true; |
|
191 this.enTimer = true; |
|
192 |
|
193 //bind events |
|
194 window.addEventListener("touchmove", this.on_bound_drag, true); |
|
195 window.addEventListener("mousemove", this.on_bound_drag, true); |
|
196 |
|
197 window.addEventListener("mouseup", this.bound_on_release, true); |
|
198 window.addEventListener("touchend", this.bound_on_release, true); |
|
199 window.addEventListener("touchcancel", this.bound_on_release, true); |
|
200 |
|
201 //update postion on mouse press |
|
202 this.update_position(evt); |
|
203 |
|
204 //prevent next events |
|
205 evt.stopPropagation(); |
|
206 } |
|
207 |
|
208 init() { |
|
209 //get min max |
|
210 let min = this.min_elt ? |
|
211 Number(this.min_elt.textContent) : |
|
212 this.args.length >= 1 ? this.args[0] : 0; |
|
213 let max = this.max_elt ? |
|
214 Number(this.max_elt.textContent) : |
|
215 this.args.length >= 2 ? this.args[1] : 100; |
|
216 |
|
217 //fiStart ==> offset |
|
218 let fiStart = Number(this.range_elt.getAttribute('sodipodi:start')); |
|
219 let fiEnd = Number(this.range_elt.getAttribute('sodipodi:end')); |
|
220 fiEnd = fiEnd - fiStart; |
|
221 |
|
222 //fiEnd ==> size of angle |
|
223 if (fiEnd < 0){ |
|
224 fiEnd = 2*Math.PI + fiEnd; |
|
225 } |
|
226 |
|
227 //min max barrier angle |
|
228 let minMax = (2*Math.PI - fiEnd)/2; |
|
229 |
|
230 //get parameters from svg |
|
231 let cX = Number(this.range_elt.getAttribute('sodipodi:cx')); |
|
232 let cY = Number(this.range_elt.getAttribute('sodipodi:cy')); |
|
233 this.range_elt.style.strokeMiterlimit="0"; //eliminates some weird border around html object |
|
234 this.range = [min, max,this.range_elt.getTotalLength()]; |
|
235 let cPos = this.range_elt.getBBox(); |
|
236 this.handle_pos = this.range_elt.getPointAtLength(0); |
|
237 this.circle = [cX, cY,fiStart,fiEnd,minMax,cPos.x,cPos.y,cPos.width,cPos.height]; |
|
238 |
|
239 //bind functions |
|
240 this.bound_on_select = this.on_select.bind(this); |
|
241 this.bound_on_release = this.on_release.bind(this); |
|
242 this.on_bound_drag = this.on_drag.bind(this); |
|
243 |
|
244 this.handle_elt.addEventListener("mousedown", this.bound_on_select); |
|
245 this.element.addEventListener("mousedown", this.bound_on_select); |
|
246 this.element.addEventListener("touchstart", this.bound_on_select); |
|
247 //touch recognised as page drag without next command |
|
248 document.body.addEventListener("touchstart", function(e){}, false); |
|
249 |
|
250 //save ghost style |
|
251 //save ghost style |
|
252 if(this.setpoint_elt != undefined){ |
|
253 this.setpoint_style = this.setpoint_elt.getAttribute("style"); |
|
254 this.setpoint_elt.setAttribute("style", "display:none"); |
|
255 } |
|
256 |
|
257 } |
|
258 || |
|
259 |
|
260 widget_defs("CircularSlider") { |
|
261 labels("handle range"); |
|
262 optional_labels("value min max setpoint"); |
|
263 |, |
|
264 } |
|