Customize sliders for DB2

A little bit of fun with sliders

[{"id":"1c0c26f3ab8a24c8","type":"ui-template","z":"e59576a114c1e493","group":"6f47b8907c5da63a","page":"","ui":"","name":"range","order":5,"width":"6","height":"1","head":"","format":"<template>\n    <v-range-slider class=\"range-slider\" v-model=\"value\" step=\"1\" thumb-label=\"true\" show-ticks=\"always\" :ticks=\"tickLabels\" :messages=\"advise\">\n        <template v-slot:append>\n            <v-chip v-model=\"value\">\n                Range: <span>{{rangeValue}}</span>\n            </v-chip>\n        </template>\n    </v-range-slider>\n</template>\n\n<script>\n    export default {\n        data() {\n           return {\n                min:0,\n                max:100,\n                value: [0, 100],\n                fromServer:false,\n                tickLabels: {\n                    0: '0',\n                    10: '10',\n                    20: '20',\n                    30: '30',\n                    40: '40',\n                    50: '50',\n                    60: '60',\n                    70: '70',\n                    80: '80',\n                    90: '90',\n                    100: '100',                \n                },\n                \n            }\n        },\n        watch: {           \n            value:function(){\n                if(this.fromServer == true){\n                    this.fromServer = false;\n                    return\n                }\n                this.send({payload:{min:this.value[0],max:this.value[1]}})\n            },\n            msg: function(){    \n                if(this.msg.payload !== undefined){\n                    this.fromServer = true;                      \n                    this.value = [this.msg.payload.min,this.msg.payload.max]\n                }\n            },\n        },\n        computed: {\n            rangeValue: function(){\n               return (this.value[1] - this.value[0]).toString() \n            },\n            advise:function(){\n                const r = this.value[1] - this.value[0]\n                if(this.value[0] == this.value[1] &&  this.value[1] == 0){\n                    return \"Please select range\"\n                }\n                if(r == 0){\n                    return \"No range\"\n                }\n                if(r < 10){\n                    return \"Too small range\"\n                }\n                if(r > 90){\n                    return \"Are you sure?\"\n                }\n                return \"\"\n            }\n        },\n    }\n</script>\n<style>\n    .range-slider {\n        color:rgb(var(--v-theme-primary));\n    }\n    .range-slider.v-input--horizontal {\n        grid-template-areas:\"a b messages\" \"prepend control append\";\n        grid-template-columns: max-content minmax(0, 1fr) max-content;\n        grid-template-rows: auto auto;\n    }\n    .range-slider .v-input__details{\n        min-heigth:20px;\n    }\n    .range-slider .v-slider-track__tick-label {   \n        font-size: .75rem;\n    }\n    .range-slider i{\n        color:currentColor;\n    }\n    .range-slider .v-slider-thumb__surface:before {\n        background-color:rgb(var(--v-theme-primary));\n    }\n    .range-slider .v-chip__content span {   \n        font-size: large;\n        font-weight: 600;       \n        min-width: 3.2ch;\n        text-align: end;\n    }\n    .range-slider .v-locale--is-ltr.v-slider.v-input--horizontal .v-slider-track__tick--last .v-slider-track__tick-label, .v-locale--is-ltr .v-slider.v-input--horizontal .v-slider-track__tick--last .v-slider-track__tick-label {\n        transform: translate(-50%); \n    }\n    .range-slider .v-slider-thumb__label {\n        background: rgba(var(--v-theme-primary), .6);\n        color: rgb(var(--v-theme-on-primary));\n    }\n    .range-slider .v-slider-thumb__label:before {\n        color: rgba(var(--v-theme-primary), .6);\n    }\n    .range-slider .v-messages{\n        text-align:center;\n    }\n</style>","storeOutMessages":true,"passthru":false,"resendOnRefresh":true,"templateScope":"local","className":"","x":370,"y":100,"wires":[["81b839ebcfea2eda"]]},{"id":"81b839ebcfea2eda","type":"debug","z":"e59576a114c1e493","name":"Range","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":510,"y":100,"wires":[]},{"id":"db354eee1821fe90","type":"inject","z":"e59576a114c1e493","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\"min\":50,\"max\":80}","payloadType":"json","x":190,"y":100,"wires":[["1c0c26f3ab8a24c8"]]},{"id":"7cca73e94c749a03","type":"ui-template","z":"e59576a114c1e493","group":"6f47b8907c5da63a","name":"mixer","order":6,"width":"6","height":"1","head":"","format":"<template>\n    <div class=\"mixer-wrapper\">\n        <div v-for=\"channel in mixer\" :key=\"channel.name\" class=\"mixer-channel\">           \n            <v-slider\n                v-model=\"channel.value\"\n                :label=\"channel.name\"\n                direction=\"vertical\"\n                step=\"0.5\"                \n                thumb-label=\"true\"\n                show-ticks=\"always\"\n                :ticks=\"tickLabels\"\n                :disabled=\"channel.disabled\"                                         \n                @end=\"onChange(channel)\"                               \n            >                    \n            <template v-slot:append v-model=\"channel.value\">\n                <v-chip>\n                    {{channel.value.toFixed(1)}}\n                </v-chip>\n            </template>                 \n            </v-slider>\n            \n             <v-btn v-model=\"channel.disabled\" icon @click=\"onMute(channel)\" elevation=\"1\">\n                <v-icon v-if=\"channel.disabled\">mdi-scent-off</v-icon>\n                <v-icon v-else>mdi-scent</v-icon>\n            </v-btn>\n        </div>        \n    </div>\n</template>\n\n<script>\n    export default {\n        data() {\n            // define variables available component-wide\n            // (in <template> and component functions)\n            return {               \n                mixer:[\n                    {name:\"Line 1\",value:0,lastValue:0,disabled:false},\n                    {name:\"Line 2\",value:0,lastValue:0,disabled:false},\n                    {name:\"Line 3\",value:0,lastValue:0,disabled:false},\n                    {name:\"Line 4\",value:0,lastValue:0,disabled:false},\n                    {name:\"Line 5\",value:0,lastValue:0,disabled:false},\n                    {name:\"Line 6\",value:0,lastValue:0,disabled:false}\n                ],\n                tickLabels: {\n                    0: '0',\n                    10: '10',\n                    20: '20',\n                    30: '30',\n                    40: '40',\n                    50: '50',\n                    60: '60',\n                    70: '70',\n                    80: '80',\n                    90: '90',\n                    100: '100',                \n                },\n                \n               \n            }\n        },\n        watch: {  \n            msg: function(){                \n                if(this.msg.payload != undefined) {                    \n                    this.mixer = this.msg.payload\n                }\n            }            \n        },\n        computed: {           \n        },\n        methods: {\n            onMute:function(channel){\n                if(!channel.disabled){\n                    channel.lastValue = channel.value\n                }\n                channel.disabled = !channel.disabled;\n                channel.value = channel.disabled ? 0 : channel.lastValue\n                this.onChange(channel)\n            },\n            onChange:function(c) {                       \n                this.send({payload:this.mixer,changed:c})\n           },\n           \n        },\n        mounted() {          \n        },\n        unmounted() {            \n        }\n    }\n</script>\n<style>\n    /* define any styles here - supports raw CSS */\n    .mixer-wrapper{\n        display:grid;        \n        grid-template-columns: repeat(auto-fit, 85px);\n        justify-content: space-evenly; \n        outline: 1px solid rgba(var(--v-theme-primary),0.4);\n        border-radius: .125rem;\n        padding: .25rem;  \n    }\n    .mixer-wrapper .mixer-channel {\n        display: flex;\n        flex-direction: column;\n        align-items: center;\n    }\n    .mixer-wrapper .v-slider.v-input--vertical>.v-input__control{\n        min-height:200px;\n    }\n    .mixer-wrapper .v-slider__label{\n        margin-inline:0;\n    }\n    .mixer-wrapper .v-chip__content{\n        justify-content:center;   \n        font-size: large;\n        font-weight: 600;       \n        min-width: 4.5ch;\n        text-align:center;\n        padding:0;        \n    }\n    .mixer-wrapper .v-slider.v-input--vertical {\n        color:rgb(var(--v-theme-primary));\n        margin-block-end: 0;\n    }\n   .mixer-wrapper .v-input__details{\n        display:none;\n   }\n    .mixer-wrapper .v-input__prepend{\n        justify-content:center;\n    }\n    .mixer-wrapper .v-slider.v-input--vertical .v-slider-track__tick{\n        width:20px;\n        height:1px;       \n        transform: translate(-50%,0);\n        background:rgba(var(--v-theme-primary),0.4);\n    }\n    .mixer-wrapper .v-slider.v-input--vertical .v-slider-track__tick .v-slider-track__tick-label {\n       \n        transform: translateY(-50%);\n        text-align: center;\n        width: 30px;\n        margin-inline-start: unset;\n        left: -30px;\n        font-size: x-small;\n    }\n    .mixer-wrapper .v-slider-thumb__label {\n        background: rgba(var(--v-theme-primary), .6);\n        color: rgb(var(--v-theme-on-primary));\n    }\n    .mixer-wrapper .v-slider-thumb__label:before {\n        color: rgba(var(--v-theme-primary), .6);\n    }\n    .mixer-wrapper .v-btn.v-btn--density-default{\n        min-width:unset;\n        min-height:unset;\n        width:35px;\n        aspect-ratio:1;\n        color: rgba(var(--v-theme-primary), .6);\n        background: rgb(var(--v-theme-on-primary));\n        \n    }\n   \n   \n</style>","storeOutMessages":true,"passthru":true,"resendOnRefresh":true,"templateScope":"local","className":"","x":370,"y":160,"wires":[["b0c6f0b9198e061c"]]},{"id":"b0c6f0b9198e061c","type":"debug","z":"e59576a114c1e493","name":"MIXER","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":520,"y":160,"wires":[]},{"id":"56fa38f41302946d","type":"comment","z":"e59576a114c1e493","name":"msg.payload for Mixer ","info":"msg.payload (an array) for Mixer should contain \nfull set of data. \n\nmsg.payload = [\n    {\"name\":\"Line 1\",\"value\":29,\"lastValue\":29,\"disabled\":false},\n    {\"name\":\"Line 2\",\"value\":72.5,\"lastValue\":28.5,\"disabled\":false},\n    {\"name\":\"Line 3\",\"value\":55,\"lastValue\":35,\"disabled\":false},\n    {\"name\":\"Line 4\",\"value\":67.5,\"lastValue\":33.5,\"disabled\":false},\n    {\"name\":\"Line 5\",\"value\":34.5,\"lastValue\":34.5,\"disabled\":false},\n    {\"name\":\"Line 6\",\"value\":51.5,\"lastValue\":51.5,\"disabled\":false}\n]\n","x":180,"y":160,"wires":[]},{"id":"6f47b8907c5da63a","type":"ui-group","name":"Sliders","page":"19eb6d108e9275e2","width":"6","height":"1","order":1,"showTitle":true,"className":"","visible":"true","disabled":"false"},{"id":"19eb6d108e9275e2","type":"ui-page","name":"Examples","ui":"ae3d4aeb3f977a90","path":"/examples","icon":"","layout":"grid","theme":"a965ccfef139317a","order":2,"className":"","visible":true,"disabled":"false"},{"id":"ae3d4aeb3f977a90","type":"ui-base","name":"Dashboard","path":"/dashboard","includeClientData":true,"acceptsClientConfig":["ui-notification","ui-control"],"showPathInSidebar":false,"navigationStyle":"icon","titleBarStyle":"default"},{"id":"a965ccfef139317a","type":"ui-theme","name":"Default","colors":{"surface":"#ffffff","primary":"#338109","bgPage":"#eeeeee","groupBg":"#ffffff","groupOutline":"#cccccc"},"sizes":{"pagePadding":"12px","groupGap":"12px","groupBorderRadius":"4px","widgetGap":"12px"}}]

5 Likes

and are they multitouch aware Mr hotNipi :wink:



very nice btw

No way. That will be another long journey with high hills...

2 Likes

Will you be doing a LCARS version :wink:
image

Oh Lord :flying_saucer:

Vuetify slider has pretty much all required parts in place so it's just using available properties and a bit of CSS to tweak. Whoever wants to take the challenge. I'll pass. Just as I have way more important challenges to deal with.

This is great stuff Endel, inspired me to create this PR: UI Slider - Add Thumb "always", ticks & vertical sliders by joepavitt · Pull Request #1014 · FlowFuse/node-red-dashboard · GitHub

1 Like