Create new CircularSlider widget which extand class widget svghmi
authorusveticic
Wed, 05 Aug 2020 15:16:03 +0200
branchsvghmi
changeset 3013 0ea6b4f435de
parent 3012 65471f50b421
child 3014 1a3fd83d9136
Create new CircularSlider widget which extand class widget
svghmi/widget_circularslider.ysl2
--- /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