Skip to content

Instantly share code, notes, and snippets.

@eurocat2k
Last active June 12, 2023 21:45
Show Gist options
  • Save eurocat2k/8c0ce08ca26a6ba458258bc482533405 to your computer and use it in GitHub Desktop.
Save eurocat2k/8c0ce08ca26a6ba458258bc482533405 to your computer and use it in GitHub Desktop.
VSCROLL SELECTION MENU
$(function(){
console.log(`ready....`);
$vscroll = $('.vscroll_container');
$vscroll.vScrolled({
visible: 7 // number of visible list items in the scrolled menu
});
$(document).on('onVSelect', {selected: 0}, function (ev, fl) { ev.data.selected = fl; console.log(`FL${fl} [${$vscroll.selected()}]`, ev) });
});
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>VSCROLL</title>
<link rel="shortcut icon" href="#" type="image/x-icon">
<link rel="stylesheet" href="css/style.css">
</head>
<body>
<div class="wrapper">
<!-- FIELD CONTAINS STATIC AND VSCROLLED SELECTION WINDOWS -->
<div class="cfl_value_container">
<div class="cfl_static_value">000</div>
<div class="vscroll_container">
<div class="vscroll_strip">
<div class="vscroll_item">400</div>
<div class="vscroll_item">395</div>
<div class="vscroll_item">390</div>
<div class="vscroll_item">385</div>
<div class="vscroll_item">380</div>
<div class="vscroll_item">375</div>
<div class="vscroll_item">370</div>
<div class="vscroll_item">365</div>
<div class="vscroll_item">360</div>
<div class="vscroll_item">355</div>
<div class="vscroll_item">350</div>
<div class="vscroll_item">345</div>
<div class="vscroll_item">340</div>
<div class="vscroll_item">335</div>
<div class="vscroll_item">330</div>
<div class="vscroll_item vs_selected">325</div>
<div class="vscroll_item">320</div>
<div class="vscroll_item">315</div>
<div class="vscroll_item">310</div>
<div class="vscroll_item">305</div>
<div class="vscroll_item">300</div>
<div class="vscroll_item">295</div>
<div class="vscroll_item">290</div>
</div>
</div>
</div>
<!-- END -->
</div>
</body>
<script defer src="js/jquery.min.js"></script>
<script defer src="js/jquery-ui.min.js"></script>
<script defer src="js/vscroll-cfl.min.js"></script>
<script defer src="js/app.min.js"></script>
</html>
/*
* html5resetcss
*/
html,body,div,span,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,abbr,address,cite,code,del,dfn,em,img,ins,kbd,q,samp,small,strong,sub,sup,var,b,i,dl,dt,dd,ol,ul,li,fieldset,form,label,legend,table,caption,tbody,tfoot,thead,tr,th,td,article,aside,canvas,details,figcaption,figure,footer,header,hgroup,menu,nav,section,summary,time,mark,audio,video{margin:0;padding:0;border:0;outline:0;font-size:100%;vertical-align:baseline;background:transparent}
body{line-height:1}
article,aside,details,figcaption,figure,footer,header,hgroup,menu,nav,section{display:block}
nav ul{list-style:none}
blockquote,q{quotes:none}
blockquote:before,blockquote:after,q:before,q:after{content:none}
a{margin:0;padding:0;font-size:100%;vertical-align:baseline;background:transparent}
ins{background-color:#ff9;color:#000;text-decoration:none}
mark{background-color:#ff9;color:#000;font-style:italic;font-weight:bold}
del{text-decoration:line-through}
abbr[title],dfn[title]{border-bottom:1px dotted;cursor:help}
table{border-collapse:collapse;border-spacing:0}
hr{display:block;height:1px;border:0;border-top:1px solid #ccc;margin:1em 0;padding:0}
input,select{vertical-align:middle}
/* end */
:root {
--vscrollVisible: 7; /* default visible for vscrolled list */
--vscrollWidth: "40px"; /* default width of vscrolled window list and static value container */
--vscrollHeight: "16px"; /* default height of vscrolled window static value container and list item */
--vscrollFontSize: "14px"; /* default font size of vscrolled window items */
--vscrollFontWeight: 500; /* default font weight of vscrolled window text items */
}
body {
min-height: 100vh;
min-width: 100vw;
overflow: hidden;
font-size: 16px;
font-weight: 400;
font-family: Arial, Helvetica, sans-serif;
}
.wrapper {
position: absolute;
top: 0;
left: 0;
bottom: 0;
right: 0;
display: flex;
align-items: center;
justify-content: center;
}
/* active element with static and vertical scrollable selection window */
.cfl_value_container {
width: var(--vscrollWidth);
height: var(--vscrollHeight);
background-color: #ccc;
display: flex;
align-items: center;
justify-content: center;
cursor: default;
}
.cfl_static_value {
flex: 1;
width: var(--vscrollWidth);
display: flex;
align-items: center;
justify-content: center;
height: var(--vscrollHeight);
}
.vscroll_container {
position: absolute;
width: var(--vscrollWidth);
height: calc(var(--vscrollVisible) * 17px);
background-color: rgba(0,0,0,.21);
overflow: hidden;
}
.vscroll_container::-webkit-scrollbar {display:none;}
.vscroll_container::-moz-scrollbar {display:none;}
.vscroll_container::-o-scrollbar {display:none;}
.vscroll_container::-google-ms-scrollbar {display:none;}
.vscroll_container::-khtml-scrollbar {display:none;}
.vscroll_strip {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
row-gap: 1px;
}
.vscroll_item {
background-color: rgba(10, 20, 40, .13);
}
.vscroll_item:first-child {
margin-top: 1px;
}
.vscroll_item:last-child {
margin-bottom: 1px;
}
.vscroll_item.vs_selected {
background-color: rgba(51, 114, 241, 0.63);
color: white;
}
.vscroll_item.vs_selected:hover {
background-color: rgba(64, 238, 73, 0.63);
color: white;
}
.vscroll_item:hover {
background-color: rgba(241, 209, 51, 0.63);
color: rgb(0, 0, 0);
}
/* end */
(function (factory) {
if (typeof define === 'function' && define.amd) {
// AMD. Register as an anonymous module.
define(['jquery'], factory);
} else if (typeof module === 'object' && module.exports) {
// Node/CommonJS
module.exports = function( root, jQuery ) {
if ( jQuery === undefined ) {
// require('jQuery') returns a factory that requires window to
// build a jQuery instance, we normalize how we use modules
// that require this pattern but the window provided is a noop
// if it's defined (how jquery works)
if ( typeof window !== 'undefined' ) {
jQuery = require('jquery');
}
else {
jQuery = require('jquery')(root);
}
}
factory(jQuery);
return jQuery;
};
} else {
// Browser globals
factory(jQuery);
}
}(function ($) {
$.fn.vScrolled = function (params) {
//
let self = this;
let main_container = $('.cfl_value_container');
let static_value = $('.cfl_static_value');
let selected = $(".vs_selected");
let listElems = $(".vscroll_strip").children();
// handle context menu event on vscroll DOM elements
$(main_container).on('contextmenu', function(ev) {
ev.preventDefault();
$(self).hide();
$(static_value).show();
return false;
});
// data
let options = {
animate: false,
visible: 5,
min: 290,
max: 400,
step: 5
};
let tmp;
$.extend(options, params);
// make corrections of options
tmp = parseInt(options.visible);
options.visible = tmp;
// - if visible < 5
if (options.visible < 5) {
options.visible = 5;
}
tmp = parseInt(options.step);
options.step = tmp;
// make corrections:
// - if step is 5 or 10
if (options.step >= 10) {
options.step = 10;
} else if (options.step < 10) {
options.step = 5;
}
// - if max-min / step < visible, extend list toward max to reach the minimum criteria of visible items
tmp = Math.min(parseInt(options.min), parseInt(options.max));
options.max = Math.max(parseInt(options.min), parseInt(options.max));
options.min = tmp;
if (((options.max - options.min) / options.step) < options.visible) {
if (options.visible === 10) {
options.step = 5;
if (((options.max - options.min) / options.step) < options.visible) {
console.log(`Too few elements in the list after reducing step value to ${options.step}: visible = ${options.visible}, number of elements = ${(options.max - options.min) / options.step}`);
}
}
}
// private methods
function focus() {
let scrollTo = $(".vs_selected");
let container = $(".vscroll_container");
let centerPos = $(container).height() / 2 - $(".vscroll_strip").children(1).height() / 2;
var position = scrollTo.offset().top - container.offset().top + container.scrollTop();
if (options.animate) {
self.animate({
scrollTop: position - centerPos
},500);
} else {
self.scrollTop(position - centerPos);
}
}
function init() {
$(static_value).click((e,o) => {
$vscroll.show();
});
focus();
// interfaces
self.show = _show;
self.hide = _hide;
self.selected = _selected;
// Set new selected
function _setSelected(v) {
$(listElems).each((e, o) => {
let txt = $(o).text();
if (txt === v) {
$(o).addClass('vs_selected');
} else {
$(o).removeClass('vs_selected');
}
})
}
//
let tmp = 0, mousewheelevt = (/Firefox/i.test(navigator.userAgent)) ? "DOMMouseScroll" : "mousewheel";
let container = $(".vscroll_container");
let centerPos = $(container).height() / 2 - $(".vscroll_strip").children(1).height() / 2;
$(listElems).each((e, o) => {
let v = $(o).text();
$(o).click((evt) => {
_setSelected(v);
$('.cfl_static_value').text(v);
$(document).trigger('onVSelect', [v]);
self.hide();
});
});
let divT = selected;
let min = $(listElems).last().text(), max = $(listElems).first().text();
$(container).bind(mousewheelevt, function(e){
var evt = window.event || e;
evt = evt.originalEvent ? evt.originalEvent : evt;
var delta = evt.detail ? evt.detail*(-40) : evt.wheelDelta;
let level = $(divT).text();
if(delta<0){
if (level > min) {
divT = $(divT).next();
let scrollTo = $(divT);
var position = scrollTo.offset().top - container.offset().top + container.scrollTop();
if (options.animate) {
self.animate({
scrollTop: position - centerPos
}, 5);
} else {
self.scrollTop(position - centerPos);
}
}
// end new way
} else if(delta>0){
if (level < max) {
divT = $(divT).prev();
let scrollTo = $(divT);
var position = scrollTo.offset().top - container.offset().top + container.scrollTop();
self.animate({
scrollTop: position - centerPos
},5);
}
}
return false;
});
self.hide();
}
// public methods
function _show() {
$(".cfl_static_value").hide();
$(self).show();
focus();
}
function _hide() {
$(self).hide();
$(".cfl_static_value").show();
}
function _selected(v) {
if (typeof v !== 'undefined' && Number.isInteger(v)) {
$(".cfl_static_value").text(v);
return parseInt(v);
} else {
let _v = $(".vs_selected").text();
return parseInt(_v);
}
}
//
init();
return self;
};
}));
@eurocat2k
Copy link
Author

VSCROLLED MENU jQuery plugin

For Altitude selection menu in the track label

As you can see the scripts are minified and you need to have jquery and jquery-ui available before use this plugin.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment