--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/svghmi/widget_circularslider.ysl2 Wed Aug 05 15:16:03 2020 +0200
@@ -0,0 +1,159 @@
+// widget_circuralslider.ysl2
+
+template "widget[@type='CircularSlider']", mode="widget_class"
+ ||
+ class CircularSliderWidget extends Widget{
+ frequency = 5;
+ range = undefined;
+ circle = undefined;
+ handle_pos = undefined;
+ drag = false;
+ enTimer = false;
+
+ dispatch(value) {
+ if(!this.drag){
+ if(this.value_elt)
+ this.value_elt.textContent = String(value);
+
+ this.handle_position(value);
+ }
+ }
+
+ handle_position(value){
+ let [min,max,totalDistance] = this.range;
+ let length = Math.max(0,Math.min((totalDistance),(Number(value)-min)/(max-min)*(totalDistance)));
+ let tip = this.range_elt.getPointAtLength(length);
+ this.handle_elt.setAttribute('transform',"translate("+(tip.x-this.handle_pos.x)+","+(tip.y-this.handle_pos.y)+")");
+ }
+
+ on_release(evt) {
+ if(this.drag){
+ this.drag = false;
+ }
+ }
+
+ update_position(evt){
+ if(this.drag && this.enTimer){
+ var svg_dist = 0;
+
+ //calculate center of widget in html
+ // --TODO maybe it would be better to bind this part to window change size event ???
+ let [xdest,ydest,svgWidth,svgHeight] = page_desc[current_visible_page].bbox;
+ let [cX, cY,fiStart,fiEnd,minMax,x1,y1,width,height] = this.circle;
+ let htmlCirc = this.range_elt.getBoundingClientRect();
+ let cxHtml = ((htmlCirc.right-htmlCirc.left)/(width)*(cX-x1))+htmlCirc.left;
+ let cyHtml = ((htmlCirc.bottom-htmlCirc.top)/(height)*(cY-y1))+htmlCirc.top;
+
+
+ //get mouse coordinates
+ let mouseX = undefined;
+ let mouseY = undefined;
+ if (evt.type.startsWith("touch")){
+ mouseX = Math.ceil(evt.touches[0].clientX);
+ mouseY = Math.ceil(evt.touches[0].clientY);
+ }
+ else{
+ mouseX = evt.pageX;
+ mouseY = evt.pageY;
+ }
+
+ //calculate angle
+ let fi = Math.atan2(cyHtml-mouseY, mouseX-cxHtml);
+
+ // transform from 0 to 2PI
+ if (fi > 0){
+ fi = 2*Math.PI-fi;
+ }
+ else{
+ fi = -fi;
+ }
+
+ //offset it to 0
+ fi = fi - fiStart;
+ if (fi < 0){
+ fi = fi + 2*Math.PI;
+ }
+
+ //get handle distance from mouse position
+ if(fi<fiEnd){
+ svg_dist=(fi)/(fiEnd)*(this.range[1]-this.range[0]);
+ }
+ else if(fiEnd<fi && fi<fiEnd+minMax){
+ svg_dist = this.range[1];
+ }
+ else{
+ svg_dist = this.range[0];
+ }
+
+ //redraw handle --TODO is it fast enough if I just call change_hmi_value???
+ this.handle_position(svg_dist);
+ if(this.value_elt)
+ this.value_elt.textContent = String(Math.ceil(svg_dist));
+ change_hmi_value(this.indexes[0], "="+Math.ceil(svg_dist));
+
+ //reset timer
+ this.enTimer = false;
+ setTimeout("{hmi_widgets['"+this.element_id+"'].enTimer = true;}", 100);
+ }
+
+ }
+
+ on_select(evt){
+ this.drag = true;
+ this.enTimer = true;
+ this.update_position(evt);
+ }
+
+ init() {
+ //get min max
+ let min = this.min_elt ?
+ Number(this.min_elt.textContent) :
+ this.args.length >= 1 ? this.args[0] : 0;
+ let max = this.max_elt ?
+ Number(this.max_elt.textContent) :
+ this.args.length >= 2 ? this.args[1] : 100;
+
+ //fiStart ==> offset
+ let fiStart = Number(this.range_elt.getAttribute('sodipodi:start'));
+ let fiEnd = Number(this.range_elt.getAttribute('sodipodi:end'));
+ fiEnd = fiEnd - fiStart;
+
+ //fiEnd ==> size of angle
+ if (fiEnd < 0){
+ fiEnd = 2*Math.PI + fiEnd;
+ }
+
+ //min max barrier angle
+ let minMax = (2*Math.PI - fiEnd)/2;
+
+ //get parameters from svg
+ let cX = Number(this.range_elt.getAttribute('sodipodi:cx'));
+ let cY = Number(this.range_elt.getAttribute('sodipodi:cy'));
+ this.range_elt.style.strokeMiterlimit="0"; //eliminates some weird border around html object
+ this.range = [min, max,this.range_elt.getTotalLength()];
+ let cPos = this.range_elt.getBBox();
+ this.handle_pos = this.range_elt.getPointAtLength(0);
+ this.circle = [cX, cY,fiStart,fiEnd,minMax,cPos.x,cPos.y,cPos.width,cPos.height];
+
+ //init events
+ this.handle_elt.addEventListener("touchstart", hmi_widgets[this.element_id].on_select.bind(this));
+ this.handle_elt.addEventListener("mousedown", hmi_widgets[this.element_id].on_select.bind(this));
+ this.element.addEventListener("mousedown", hmi_widgets[this.element_id].on_select.bind(this));
+
+ window.addEventListener("touchmove", hmi_widgets[this.element_id].update_position.bind(this));
+ window.addEventListener("mousemove", hmi_widgets[this.element_id].update_position.bind(this));
+
+ window.addEventListener("mouseup", hmi_widgets[this.element_id].on_release.bind(this))
+ window.addEventListener("touchend", hmi_widgets[this.element_id].on_release.bind(this));
+ window.addEventListener("touchcancel", hmi_widgets[this.element_id].on_release.bind(this));
+
+ }
+ }
+ ||
+
+template "widget[@type='CircularSlider']", mode="widget_defs" {
+ param "hmi_element";
+ labels("handle range");
+ optional_labels("value min max");
+ |,
+}
\ No newline at end of file