widget_desc("ScrollBar") {
ScrollBar - svg:rect based scrollbar
path name="value" accepts="HMI_INT" > value
path name="range" accepts="HMI_INT" > range
path name="visible" accepts="HMI_INT" > visible
widget_class("ScrollBar") {
dispatch(value,oldval, index) {
this.range = Math.max(1,value);
let size = Math.max(range * this.mincursize, Math.min(this.size, range));
let maxh = this.range_elt.height.baseVal.value;
return [size, maxh, range, pixels];
if(this.position == undefined || this.range == undefined || this.size == undefined)
let [size, maxh, range, pixels] = this.get_ratios();
let new_y = this.range_elt.y.baseVal.value + Math.round(Math.min(this.position,range-size) * pixels / range);
let new_height = Math.round(maxh * size/range);
this.cursor_elt.y.baseVal.value = new_y;
this.cursor_elt.height.baseVal.value = new_height;
this.cursor_elt.onpointerdown = () => this.on_cursor_down();
this.bound_drag = this.drag.bind(this);
this.bound_drop = this.drop.bind(this);
apply_position(position){
this.position = Math.round(Math.max(Math.min(position, this.range - this.size), 0));
this.apply_hmi_value(1, this.position);
this.apply_position(is_up ? this.position-this.size
: this.position+this.size);
// get scrollbar -> root transform
let ctm = this.range_elt.getCTM();
// relative motion -> discard translation
// root -> scrollbar transform
this.invctm = ctm.inverse();
svg_root.addEventListener("pointerup", this.bound_drop, true);
svg_root.addEventListener("pointermove", this.bound_drag, true);
this.dragpos = this.position;
svg_root.removeEventListener("pointerup", this.bound_drop, true);
svg_root.removeEventListener("pointermove", this.bound_drag, true);
let [size, maxh, range, pixels] = this.get_ratios();
let point = new DOMPoint(e.movementX, e.movementY);
let movement = point.matrixTransform(this.invctm).y;
this.dragpos += movement * range / pixels;
this.apply_position(this.dragpos);
widget_defs("ScrollBar") {
const "pagebuttons" optional_labels("pageup pagedown");
const "have_pagebuttons","string-length($pagebuttons)>0";
| this.pageup_elt.onclick = () => this.on_page_click(true);
| this.pagedown_elt.onclick = () => this.on_page_click(false);