svghmi/widget_scrollbar.ysl2
author Edouard Tisserant
Fri, 19 Feb 2021 14:56:14 +0100
branchsvghmi
changeset 3159 1d7c3d13a4df
parent 3151 8e5d383a58cb
child 3178 21cb76012c78
permissions -rw-r--r--
SVGHMI: Add icons
// widget_scrollbar.ysl2

template "widget[@type='ScrollBar']", mode="widget_class"{
    ||
    class ScrollBarWidget extends Widget{
        frequency = 10;
        position = undefined;
        range = undefined;
        size = undefined;
        mincursize = 0.1;

        dispatch(value,oldval, index) {
            switch(index) {
                case 0:
                    this.position = value;
                    break;
                case 1:
                    this.range = Math.max(1,value);
                    break;
                case 2:
                    this.size = value;
                    break;
            }

            this.request_animate();
        }

        get_ratios() {
            let range = this.range;
            let size = Math.max(this.range * this.mincursize, Math.min(this.size, range));
            let maxh = this.range_elt.height.baseVal.value;
            let pixels = maxh;
            let units = range;
            return [size, maxh, range, pixels, units];
        }

        animate(){
            if(this.position == undefined || this.range == undefined || this.size == undefined)
                return;
            let [size, maxh, range, pixels, units] = this.get_ratios();

            let new_y = this.range_elt.y.baseVal.value + Math.round(Math.min(this.position,range-size) * pixels / units);
            let new_height = Math.round(maxh * size/range);

            this.cursor_elt.y.baseVal.value = new_y;
            this.cursor_elt.height.baseVal.value = new_height;
        }

        init_mandatory() {
            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(0, this.position);
        }

        on_page_click(is_up){
            this.apply_position(is_up ? this.position-this.size
                                      : this.position+this.size);
        }

        on_cursor_down(e){
            // get scrollbar -> root transform
            let ctm = this.range_elt.getCTM();
            // relative motion -> discard translation
            ctm.e = 0;
            ctm.f = 0;
            // 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;
        }

        drop(e) {
            svg_root.removeEventListener("pointerup", this.bound_drop, true);
            svg_root.removeEventListener("pointermove", this.bound_drag, true);
        }

        drag(e) {
            let [size, maxh, range, pixels, units] = this.get_ratios();
            if(pixels == 0) return;
            let point = new DOMPoint(e.movementX, e.movementY);
            let movement = point.matrixTransform(this.invctm).y;
            this.dragpos += movement * units / pixels;
            this.apply_position(this.dragpos);
        }
    }
    ||
}

template "widget[@type='ScrollBar']", mode="widget_defs" {
    param "hmi_element";
    labels("cursor range");

    const "pagebuttons" optional_labels("pageup pagedown");
    const "have_pagebuttons","string-length($pagebuttons)>0";
    value "$pagebuttons";

    |     init: function() {
    |         this.init_mandatory();

    if "$have_pagebuttons" {
    |         this.pageup_elt.onclick = () => this.on_page_click(true);
    |         this.pagedown_elt.onclick = () => this.on_page_click(false);
    }
    |     },
}