implementing double ended sliding window UI

102 Views Asked by At

I came across below sliding window SVG, which let's not only change the start and end range of the widow but also scroll through the selected range difference. the link to the same can be found in 2.

sliding window

What do we even call this, rage selector? or a sliding window? I couldn't even get the right terms to google this. Do we have any solution similar to this in Jquery?

Most of the range selectors let us only change the start and end range. but doesn't allow us to scroll through with that difference.

Please, kindly share pointers or resources around how to implement this.

Regards

2

There are 2 best solutions below

0
Twisty On

Looking at what is being done in your #2 link, they are using pure SVG to draw all the items and elements. The interaction is moving and manipulating the SVG itself.

There is nothing in jQuery UI that does this out of the box. You can customize jQuery UI Slider to offer a similar user interface. Consider the following. This is a very light weight example as a proof of concept.

$(function() {
  var handle = $("#custom-handle");
  $("#slider").slider({
    create: function() {
      var $self = $(this);
      $(".ui-slider-handle", this).css({
        height: ($self.height() - 4) + "px",
        width: "100px",
        background: "transparent",
        top: "1px",
        borderColor: "black",
        margin: 0
      }).resizable({
        classes: {
          "ui-resizable-e": "ui-icon ui-icon-grip-dotted-vertical",
          "ui-resizable-w": "ui-icon ui-icon-grip-dotted-vertical"
        },
        containment: $self,
        handles: "e, w"
      });
    },
    slide: function(event, ui) {

    }
  });
});
#custom-handle .ui-resizable-e,
#custom-handle .ui-resizable-w {
  top: 40px;
}
<link rel="stylesheet" href="//code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">
<script src="https://code.jquery.com/jquery-1.12.4.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>

<div id="slider" style="height: 100px;">
  <svg class="chart" width="100%">
  <polyline
     fill="none"
     stroke="#0074d9"
     stroke-width="2"
     points="
       1,100
       20,60
       40,80
       60,20
       80,30
       100,75
       120,60,
       140,33
       160,37
       180,40
       200,45
       220,20
       240,2
       260,10
       280,75
       300,60
       320,45
       340,30
       360,20
       380,10
       400,19
       420,12
       440,45
       460,50
       480,80"/>
</svg>
  <div id="custom-handle" class="ui-slider-handle"></div>
</div>

Here I make the slider larger and fill it with an SVG that represents the larger item. This could be an image too. I am using a Custom Handle, as suggested in the following Demo: https://jqueryui.com/slider/#custom-handle It is just a matter of styling it and adjusting the theme to work for you. I also made the handle resizable. This is has it's own level of Pros and Cons.

The last thing to do is identify how to handle overflow of the handle. It will move to the last position of the slider and the handle may move off the "viewport". You could add in some collision detection and prevent the slider from moving further. This has been discussed in a few other threads on this topic of Stack Overflow.

You might also consider things like: http://paperjs.org/

0
Darshan Puttaswamy On

Base on @Twisty's solution, the below solution using a jquery range slider. I am sure, we could have a cleaner solution in SVG itself. was just curious to know how one could implement this in without svg

$(function() {
  $("#slider-range-custom").slider({
    range: true,
    min: 0,
    max: 100,
    values: [0, 10],
    create: function() {
      var $self = $(this);
      $(".ui-slider-handle", this).css({
        height: ($self.height() - 4) + "px",
        width: "5px",
        top: "1px",
        borderColor: "black",
        margin: 0,
        cursor: 'e-resize',
      })
    },
  
    slide: function(event, ui) {

      var smin = $('#slider-range-custom').attr('min');
      var smax = $('#slider-range-custom').attr('max');


      var span = $('#slider-range-custom').find('span');
      var divRect = $('[class="ui-slider-range ui-corner-all ui-widget-header"]')

      if ((event.clientX >= divRect.offset().left + 10 && event.clientX <= divRect.offset().left + divRect.width() - 10)) {

        if (event.originalEvent) {
          event.preventDefault();

          var prevX = $('#slider-range-custom').attr('prevX') || 0;
          $('#slider-range-custom').attr('prevX', event.clientX);

          if (event.clientX < prevX) {
  
            $('#slider-range-custom').attr('direction', 'left');

          } else {
    
            $('#slider-range-custom').attr('direction', 'right');

          }

          return;

        } else {
          $('#slider-range-custom').attr('direction', 'none');
          return;
        }

      } else {

        $('#slider-range-custom').attr('direction', 'none');
        if (!($(span[0]).hasClass('ui-state-hover') || $(span[1]).hasClass('ui-state-hover'))) {
          event.preventDefault();
          return;
        }

      }


    },
    change: function(event, ui) {
      $('#slider-range-custom').attr('min', ui.values[0]);
      $('#slider-range-custom').attr('max', ui.values[1]);

      var direction = $('#slider-range-custom').attr('direction');

      if (direction == 'left') {
        if (event.originalEvent) {
          $(this).slider('values', [ui.values[0] - 5, ui.values[1] - 5])
        }
      } else if (direction == 'right') {
        if (event.originalEvent) {
          $(this).slider('values', [ui.values[0] + 5, ui.values[1] + 5])
        }
      } 


    },

  });

});
.ui-slider-range {
  background: transparent !important;
  ;
  cursor: move;
}
<link rel="stylesheet" href="https://code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">
<script src="https://code.jquery.com/jquery-1.12.4.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>

<div id="control-pannel" style="margin: 0 auto;width: 75%;">
  <div id="slider-range-custom" min="0" max="10" class="ui-slider-handle" style="height: 100px; background:transparent;
">
    <svg class="chart" width="100%">
  <polyline
     fill="none"
     stroke="#0074d9"
     stroke-width="2"
     points="
       1,100
       20,60
       40,80
       60,20
       80,30
       100,75
       120,60,
       140,33
       160,37
       180,40
       200,45
       220,20
       240,2
       260,10
       280,75
       300,60
       320,45
       340,30
       360,20
       380,10
       400,19
       420,12
       440,45
       460,50
       480,80"/>
</svg>

  </div>
</div>