// widget_circuralslider.ysl2
template "widget[@type='CircularSlider']", mode="widget_class"
class CircularSliderWidget extends Widget{
this.value_elt.textContent = String(value);
this.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)+")");
if(this.drag && this.enTimer){
//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;
if (evt.type.startsWith("touch")){
mouseX = Math.ceil(evt.touches[0].clientX);
mouseY = Math.ceil(evt.touches[0].clientY);
let fi = Math.atan2(cyHtml-mouseY, mouseX-cxHtml);
// transform from 0 to 2PI
//get handle distance from mouse position
svg_dist=(fi)/(fiEnd)*(this.range[1]-this.range[0]);
else if(fiEnd<fi && fi<fiEnd+minMax){
svg_dist = this.range[1];
svg_dist = this.range[0];
//redraw handle --TODO is it fast enough if I just call change_hmi_value???
this.handle_position(svg_dist);
this.value_elt.textContent = String(Math.ceil(svg_dist));
change_hmi_value(this.indexes[0], "="+Math.ceil(svg_dist));
setTimeout("{hmi_widgets['"+this.element_id+"'].enTimer = true;}", 100);
this.update_position(evt);
Number(this.min_elt.textContent) :
this.args.length >= 1 ? this.args[0] : 0;
Number(this.max_elt.textContent) :
this.args.length >= 2 ? this.args[1] : 100;
let fiStart = Number(this.range_elt.getAttribute('sodipodi:start'));
let fiEnd = Number(this.range_elt.getAttribute('sodipodi:end'));
//fiEnd ==> size of angle
fiEnd = 2*Math.PI + fiEnd;
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];
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" {
optional_labels("value min max");