Round Slider with multicolor background fixed

1.2k Views Asked by At

I'm trying to create a round slider with the librery roundSlider.js, which has a background in the path that is multicolour. I have tried using a linear-gradient but the result is not good, because when I start moving the slider with the hadler, the background colors start to move and some disappear.

This is the code that I have:

  $(document).ready(function () {

    $("#shape").roundSlider({
    radius: 80,
    width: 8,
    min: 0,
    max: 100,
    handleSize: "+16",
    circleShape: "pie",
    handleShape: "dot",
    sliderType: "min-range",
    startAngle: 315,
    value: 24,
    disabled: false
});
        });
 .rs-range-color {
  background: linear-gradient(to right, yellow 20%, blue 20%, blue 40%, red 40%, red 60%, green 60%, green 80%, brown 80%, brown 100%);
 }

 .rs-path-color {
   /*background-color: #C2E9F7;*/
  background: linear-gradient(to right, yellow 20%, blue 20%, blue 40%, red 40%, red 60%, green 60%, green 80%, brown 80%, brown 100%);
   background-repeat: no-repeat;
   background-size: cover;
   background-position: center;
   background-attachment: fixed;
 }

 .rs-handle {
   background-color: #C2E9F7;
   padding: 7px;
   border: 2px solid #C2E9F7;
 }

 .rs-handle.rs-focus {
   border-color: #33B5E5;
 }

 .rs-handle:after {
   border-color: #33B5E5;
   background-color: #33B5E5;
 }

 .rs-border {
   border-color: transparent;
 }

 .rs-tooltip-text {
   font-family: Roboto, sans-serif;
   font-size: 20px;
   border-radius: 7px;
   transition: background 0.02s ease-in-out;
   color: #33B5E5;
 }

 .rs-tooltip-text:before {
   position: absolute;
   left: -10px;
   top: -18px;
   content: 'DISCOUNT';
   font-size: 12px;
 }

 .rs-tooltip-text:after {
   position: absolute;
   left: 10px;
   top: 48px;
   content: '';
   font-size: 12px;
 }


.container{
  position: absolute;
  z-index: 2;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  font-family: Roboto, sans-serif;
  padding: 20px;
  border: 1px solid;
}

/* Solution for inner circle with shadow */
#shape:after {
  content: " ";
  display: block;
  height: calc(100% - 40px); /* here 40 is the gap between the outer and inner circle */
  width: calc(100% - 40px);
  position: absolute;
  top: 20px;  /* divide the gap value by 2 */
  left: 20px;
  z-index: 9; /* tooltip z-index is 10, so we put less than that value */
  border-radius: 1000px;
  box-shadow: 0 0 10px -2px;
}

/* Solution for bottom triangle out issue */
#shape .rs-overlay {
    height: calc(50% + 5px);
    width: calc(50% + 5px);
    top: -5px;
    left: -5px;
    border-radius: 1000px 0 0 0;
}
<!DOCTYPE html>
<html>
<head>
    <title>RoundSlider - A sample testing</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/roundslider.min.css" rel="stylesheet" />
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/roundslider.min.js"></script>
</head>
<body style="padding: 10px 0 0 20px; font-family: monospace;">

        <div class="container">
            <div class="control">
                <div id="shape"></div>
            </div>
        </div>
    
</body>
<html>

When you run the code above, you can see the background color of the path moves as I move the handler, that's the problem. I would like the background to stay fixed. In other words, I would like the background path as a gradient with 3 or more colors and that this background covered 100% of the slider. I don't want the colors moving or be removed to make way for others.

2

There are 2 best solutions below

3
On BEST ANSWER

In roundSlider the svgMode was available where the slider was constructed by SVG elements. So using that you can apply the SVG gradient to the range and path element. Also here these elements are single element, so you won't get this problem.

Here I have updated the demo based on your scenario, check below:

https://jsfiddle.net/soundar24/6se2tmp9/

In this demo I didn't set the pathColor because if both rangeColor and path color are same then you won't find any difference.

Also, since this is the default SVG gradient only, so based on your requirement you can modify this SVG linear gradient.

EDIT 1:

Based on your comments, then you need to use the conic gradient. In SVG there is no explicit option for conic gradient, but still you can find the ways to achieve that.

  1. Alternatively I have used the CSS conic gradient to achieve that. Check the below demo:

    https://jsfiddle.net/soundar24/6se2tmp9/2/

  2. Also I have done a workaround to create SVG range segments on the roundSlider path. This is also similar to your requirement. Check the below demo:

    https://jsfiddle.net/soundar24/8pgo9ce7/

1
On

        $(document).ready(function () {
            $.fn.roundSlider.prototype._invertRange = true;

            // this is core functionality to generate the numbers
            $.fn.roundSlider.prototype.defaults.create = function () {
                var o = this.options, tickInterval = 20;

                for (var i = o.min; i <= o.max; i += tickInterval) {
                    var angle = this._valueToAngle(i);
                    var numberTag = this._addSeperator(angle, "rs-custom");
                    var number = numberTag.children();
                    number.clone().css({
                        "width": o.width + this._border(),
                        "margin-top": this._border(true) / -2
                    });
                    number.removeClass().addClass("rs-number").html(i).rsRotate(-angle);
                }

            }
            
            // ####### ---------- Workaround for custom range segments ---------- ####### //
            var fn1 = $.fn.roundSlider.prototype._setProperties;
            $.fn.roundSlider.prototype._setProperties = function () {
                fn1.apply(this);
                var o = this.options, r = o.radius, r1 = r - (o.width / 2) - o.borderWidth;
                var svgElement = this.svgContainer.children();

                for (var i = 0; i < o.ranges.length; i++) {
                    var obj = o.ranges[i];
                    var startPoint = this._valueToAngle(obj.start),
                        endPoint = this._valueToAngle(obj.end);

                    var path = this.$createSVG("path");
                    var d = this.$drawPath(r, r1, startPoint, endPoint);
                    var attr = {
                        "d": d, "stroke-width": o.width,
                        "stroke": obj.bgcolor, "fill": "transparent"
                    };
                    this.$setAttribute(path, attr);
                    svgElement.append(path);
                }
            }
            // ####### ---------- ---------- ####### //

            $("#handle1").roundSlider({

                svgMode: true,
                pathColor: "transparent",
                rangeColor: "transparent",
                sliderType: "min-range",
                editableTooltip: false,
                radius: 105,
                width: 16,
                value: 75,
                handleShape: "square",
                handleSize: 0,
                circleShape: "pie",
                startAngle: 315,
                min: 0,
                max: 100,
                step: 5,
                disabled: false,

                ranges: [
                    { start: 0, end: 20, bgcolor: "#D91907"},
                    { start: 20, end: 40, bgcolor: "#F58B00" },
                    { start: 40, end: 60, bgcolor: "#FFBB00" },
                    { start: 60, end: 80, bgcolor: "#6FA600" },
                    { start: 80, end: 100, bgcolor: "#009619" }
                ]
            });
        });
   
        body{
            padding:50px;
            }
        .rs-bg-color {
            background-color: #fff;
        }
        .rs-block.rs-outer.rs-border.rs-split .rs-path.rs-transition:first-child {
            background: #ff4434 !important;
        }

        .rs-block.rs-outer.rs-border.rs-split .rs-path.rs-transition:nth-child(2) {
            background: #ff9000 !important;
        }

        .rs-block.rs-outer.rs-border.rs-split .rs-path.rs-transition:nth-child(4) {
            background: #00b71c !important;
            z-index: 2 !important;
        }
        #handle1 .rs-handle {
            background-color: transparent;
            border: 8px solid transparent;
            border-right-color: black;
            margin: -6px 0px 0px 14px !important;
            border-width: 6px 104px 6px 4px;
        }

        #handle1 .rs-handle:before {
            display: block;
            content: " ";
            position: absolute;
            height: 22px;
            width: 22px;
            background: black;
            right: -11px;
            bottom: -11px;
            border-radius: 100px;
        }

        #handle1 .rs-tooltip {
            top: 75%;
            font-size: 12px;
        }

        #handle1 .rs-tooltip div {
            text-align: center;
            background: orange;
            color: white;
            border-radius: 4px;
            padding: 1px 5px 1px;

        }

        #handle1 .rs-range-color {
            background-color: #DB5959;
        }

        #handle1 .rs-path-color {
            background-color: #F0C5C5;
        }

        span.rs-number {
            position: absolute;
            top: -8px;
            left: -25px;
            font-size: 15px;
            color: #000;
        }
<!DOCTYPE html>
<html lang="en">

<head>
    <title>Fuel</title>
    <script src="https://code.jquery.com/jquery-3.2.1.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/roundslider.min.js"></script>
    <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/roundslider.min.css" rel="stylesheet" />
    <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet">
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js"></script>
    

</head>

<body>
    <div id="handle1"></div>
</body>

</html>