How to Add Linear-Gradient Color to Slider

How to add linear-gradient color to Slider?

linear-gradient creates an image not a color. So you need to use it in CSS that specifies an image (e.g. background-image).

Below is an example of a Slider using a gradient.

import React from "react";
import { makeStyles, withStyles } from "@material-ui/core/styles";
import Slider from "@material-ui/core/Slider";

const useStyles = makeStyles({
root: {
width: 200
}
});

const CustomSlider = withStyles({
rail: {
backgroundImage: "linear-gradient(.25turn, #f00, #00f)"
},
track: {
backgroundImage: "linear-gradient(.25turn, #f00, #00f)"
}
})(Slider);

export default function ContinuousSlider() {
const classes = useStyles();
const [value, setValue] = React.useState(30);

const handleChange = (event, newValue) => {
setValue(newValue);
};

return (
<div className={classes.root}>
<CustomSlider
value={value}
onChange={handleChange}
aria-labelledby="continuous-slider"
/>
</div>
);
}

Edit Gradient Slider

Change color gradient of input slider using js?

In this case I would consider CSS variables to simplify the code. The idea is to change the color variable using JS and the code will be reduced.

Then you can adjust the gradient color by using the variable in the needed place and using only CSS:

var red_slider = document.getElementById("red_slider");var green_slider = document.getElementById("green_slider");var blue_slider = document.getElementById("blue_slider");
var red_output = document.getElementById("red_value");var green_output = document.getElementById("green_value");var blue_output = document.getElementById("blue_value");

red_slider.oninput = function() { red_output.innerHTML = this.value; document.documentElement.style.setProperty('--red-color', this.value);
}green_slider.oninput = function() { green_output.innerHTML = this.value; document.documentElement.style.setProperty('--green-color', this.value);
}blue_slider.oninput = function() { blue_output.innerHTML = this.value; document.documentElement.style.setProperty('--blue-color', this.value);}
:root { --red-color:127; --blue-color:127; --green-color:127;}
.slider { display: inline; -webkit-appearance: none; height: 15px; border-radius: 5px; background: #d3d3d3; outline: none; -webkit-transition: .2s; transition: opacity .2s; width: 80%; margin-left: 5%;}
.slider::-webkit-slider-thumb { -webkit-appearance: none; appearance: none; width: 25px; height: 25px; border-radius: 50%; background: #4CAF50; cursor: pointer;}
.slider::-moz-range-thumb { width: 25px; height: 25px; border-radius: 50%; background: #4CAF50; cursor: pointer;}
#rgb_value_container { /*margin: 16px auto;*/ text-align: center; font-weight: bold; font-size: 20px;}
#red_slider { background: linear-gradient(to right, rgb(0, 0, 0), rgb(255, var(--green-color), var(--blue-color)));}
#green_slider { background: linear-gradient(to right, rgb(0, 0, 0), rgb(var(--red-color), 255, var(--blue-color)));}
#blue_slider { background: linear-gradient(to right, rgb(0, 0, 0), rgb(var(--red-color), var(--green-color), 255));}
#color_box { width: 250px; height: 250px; margin: 30px auto; background-color: rgb(var(--red-color), var(--green-color), var(--blue-color));}
<div id="color_box"></div>

<input type="range" min="0" max="255" value="127" class="slider" id="red_slider"><p>Red: <span id="red_value">127</span></p>
<input type="range" min="0" max="255" value="127" class="slider" id="green_slider"><p>Green: <span id="green_value">127</span></p>
<input type="range" min="0" max="255" value="127" class="slider" id="blue_slider"><p>Blue: <span id="blue_value">127</span></p>

How to add a gradient in a Slider?

I solved this by using react-native-linear-gradient inside react-native-multi-slider's code.

First use the slider anywhere.

import MultiSlider from '@ptomasroos/react-native-multi-slider'

<MultiSlider
min={100}
max={100000}
/>

Then navigate to MultiSlider.js file in the library, and look for const body inside render method.
Then replace this:

<View
style={[
styles.track,
this.props.trackStyle,
trackOneStyle,
{ width: trackOneLength },
]}
/>

With this:

<LinearGradient
style={[
styles.track,
this.props.trackStyle,
trackOneStyle,
{ width: trackOneLength },
]}
colors={['white','chocolate']}
start={{ x: 0, y: 0 }}
end={{ x: 1, y: 0 }}
/>

Result

Add Gradient to color slider

I'm sorry if I didn't understand you right.

First of all you have two variables lInput. I think the second one (for LAB) has to be llInput (considering your naming technique).

Then you have to add setGradient() functions. For V in HSV, for instance that should be setGradient(vInput, [hsv(hhInput.value, ssInput.value, 0), hsv(hhInput.value, ssInput.value, 100)]);. Obviously you have only two function calls here (check yourself this block), they are for 'H' and 'S'.

Also, you have a typo here too, change hsl(300, ssInput.value, vInput.value) to hsv(300, ssInput.value, vInput.value) in the setGradient() for HSV.

For lab it's exactly the same process, if we speak about just gradients, but you have to change the setGradient() algorithm for this one, because css doesn't support LAB.

I hope this answer will help you :)

How can I make a linear gradient follow the thumb of a range slider in html

The problem is you're binding your function directly to the oninput handler, which does not get triggered just by changing the input's value programmatically.

You can solve it just by declaring your function outside the oninput, and then assign your function to it later and calling it inside your timeupdate listener. It doesn't really matter if you declare your function before or after assigning it to oninput as long as you're using the function keyword to declare it, since it gets hoisted.

Working snippet

I also uploaded the following snippet in JSFiddle in which you'll be able to see it more clearly.

var video = document.querySelector(".video");var juice = document.querySelector(".red-juice");var btn = document.getElementById("play-pause");
function togglePlayPause() { if (video.paused) { btn.className = 'pause'; video.play(); } else { btn.className = 'play'; video.pause(); }}
btn.onclick = function(params) { //video.fastSeek(570); // 9:30 // video.currentTime = 570; //test togglePlayPause();}
video.addEventListener('timeupdate', function() {
if (video.ended) { btn.className = "play"; // At the end of the movie, reset the position to the start and pause the playback. video.currentTime = 0; togglePlayPause(); }});
function slidingProgress() { // this.value will not work here, since it points to the global window obj // so I'm using juice.value instead // See: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this#Function_context juice.style.background = 'linear-gradient(to right, red ' + juice.value * 100 / juice.max + '%, rgba(0, 0, 0, 0.4) ' + juice.value + '%, rgba(0, 0, 0, 0.4) 100%)'}
video.addEventListener('timeupdate', () => { juice.value = video.currentTime / video.duration * juice.max slidingProgress() // Call your function here to update .red-juice})
juice.addEventListener('change', () => { video.currentTime = video.duration * juice.value / juice.max})
// And finally assign it to juice.oninputjuice.oninput = slidingProgress;
// you're not specifying any events to listen to here, so it wouldn't work// juice.addEventListener(slidingProgress);
.container {  display: flex;  background-color: #000000;  justify-content: center;  align-items: center;  height: 100vh;}
.video { width: 100%;}
.c-video { width: 100%; max-width: 800px; position: relative; overflow: hidden;}
.c-video:hover .title { transform: translateY(0);}
.c-video:hover .controls { transform: translateY(0);}
.c-video:hover .buttons { top: 50%; left: 50%; transform: translate(240%, -50%);}
.title { display: flex; position: absolute; top: 0; height: 120px; width: 100%; flex-wrap: wrap; background-image: linear-gradient(rgba(0, 0, 0, 0.9), rgba(0, 0, 0, 0.01)); transform: translateY(-100%); transition: all .2s;}
.controls { display: flex; position: absolute; bottom: 0; height: 70px; width: 100%; flex-wrap: wrap; background-image: linear-gradient(rgba(0, 0, 0, 0.01), rgba(0, 0, 0, 0.9)); transform: translateY(100%); transition: all .2s;}
.buttons { position: absolute; top: 50%; left: 50%; transform: translate(-999%, -50%);}
.buttons button { background: none; height: 45px; border: none; outline: 0; cursor: pointer; transform: translate(-300%, 0px);}
.buttons button:before { content: "\f144"; font-family: "Font Awesome 5 Free"; display: inline-block; font-size: 300%; color: #ffff; -webkit-font-smoothing: antialiased;}
.buttons button.play:before { content: "\f144"; font-family: 'Font Awesome 5 Free';}
.buttons button.pause:before { content: "\f28b"; font-family: 'Font Awesome 5 Free';}

/* Progress bar container */
.red-bar { height: 2px; margin-top: 15px; margin-bottom: -15px; background-color: rgba(0, 0, 0, 0.4); margin-left: 10px; margin-right: 10px; width: 100%;}

/* This represents the progress bar */
.red-juice { position: relative; width: 100%; height: 2px; /* thumbHeight + (2 x thumbBorderWidth)*/ background-image: linear-gradient(to right, red 1%, rgba(0, 0, 0, 0.4) 1%); -webkit-appearance: none; /*remove the line*/ outline: none; top: -12px; margin-left: 1px; margin-right: 100px;}
.red-juice::-webkit-slider-runnable-track { -webkit-appearance: none; height: 20px;}
.red-juice::-webkit-slider-thumb { -webkit-appearance: none; background: red; /*thumbColor*/ width: 15px; /* thumbHeight + (2 x thumbBorderWidth)*/ height: 15px; /* thumbHeight + (2 x thumbBorderWidth)*/ border-radius: 100%; margin-top: 1px; /* -[thumbHeight + (2 x thumbBorderWidth) - trackHeight]/2*/ cursor: pointer; border: 0px solid #fff; /*border-width should be equal to thumbBorderWidth if you want same border width across all browsers and border-color should match the background*/ transition: 0.3s;}
<!DOCTYPE html><html lang="en">
<head>
<meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Netflix video player</title>
<link rel="stylesheet" href="https://cdnjs.cloudlflare.com/ajax/libs/meyer-reset/2.0/reset.min.css"> <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.7.2/css/all.css" integrity="sha384-fnmOCqbTlWIlj8LyTjo7mOUStjsKC4pOpQbqyi7RrhN7udi9RwhKkMHpvLbHG9Sr" crossorigin="anonymous"> <link rel="stylesheet" href="style.css">

</head>
<body> <div class="container"> <div class="c-video"> <video class="video" src="https://www.w3schools.com/html/mov_bbb.mp4"></video> <div class="controls"> <div class="red-bar"> <!-- inputs are self-closing tags. You don't need a closing tag for it! Self-closing tags are single tagged elements - you only need to add a slash before '>', like so: <input /> --> <input class="red-juice" type="range" min="1" max="100" step="1" value="1" />
</div>
</div> <div class="buttons"> <button id="play-pause"></button> </div> <div class="title"></div> </div> </div> <script src="script.js"></script>
</body>
</html>

How to make a custom slider with color gradient?

I am working on something quite similar for one of my projects. I hope this can help you. (!!! It's a work in progress !!!)

It's a generic 1D Selector for a given value

This selector is totally agnostic of the meaning of the [value] that must be normalized on a {0, 1} range.
The Selector is configured with a [pointerColor], background [gradientColors] and [withChecker], whether or not we should display checkers. The pointer's border is white by default but if [highContrastPointer] is used, it becomes black on light backgrounds.
[onSelect] is called when the User selects a new value.

Here is a sample demo with a Color Hue Selector and another one quite similar to your design:

Sample Image

In the following full source code, you will find the Demo App, the Generic1dSelector (and its CustomPainter) as well as three helpers:

  1. isDark, as an extension on Color, to determine if a Color is dark or light
  2. showCursorOnHover, as an extension on Widgets, to display a pointer cursor on a Widget
  3. paintCheckers to paint a checkers background if the gradient used by the selector is semi-transparent

Let me know what you think and how to further improve it!

Full source code

import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter_hooks/flutter_hooks.dart';

void main() {
runApp(
MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Flutter Demo',
home: HomePage(),
),
);
}

class HomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
padding: EdgeInsets.all(16.0),
alignment: Alignment.center,
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
SelectorOne(),
const SizedBox(height: 16.0),
SelectorTwo(),
],
),
),
);
}
}

class SelectorOne extends HookWidget {
@override
Widget build(BuildContext context) {
final _valueOne = useState<double>(.2);
final _colorsOne = [Color(0xff5bc5f6), Color(0xff5a3738)];
return SizedBox(
width: 200,
height: 30,
child: Generic1DSelector(
direction: Axis.horizontal,
value: _valueOne.value,
pointerColor: Color.fromARGB(
(_colorsOne[0].alpha +
_valueOne.value *
(_colorsOne[1].alpha - _colorsOne[0].alpha))
.round(),
(_colorsOne[0].red +
_valueOne.value *
(_colorsOne[1].red - _colorsOne[0].red))
.round(),
(_colorsOne[0].green +
_valueOne.value *
(_colorsOne[1].green - _colorsOne[0].green))
.round(),
(_colorsOne[0].blue +
_valueOne.value *
(_colorsOne[1].blue - _colorsOne[0].blue))
.round(),
),
gradientColors: _colorsOne,
onSelect: (value) => _valueOne.value = value,
),
);
}
}

class SelectorTwo extends HookWidget {
@override
Widget build(BuildContext context) {
final _valueTwo = useState<double>(.6);
return SizedBox(
width: 200,
height: 30,
child: Generic1DSelector(
direction: Axis.horizontal,
value: _valueTwo.value,
pointerColor:
HSVColor.fromAHSV(1, 360 * _valueTwo.value, 1, 1).toColor(),
gradientColors: List<Color>.generate(
11,
(i) => HSVColor.fromAHSV(1, i * 36.0, 1, 1).toColor(),
),
onSelect: (value) => _valueTwo.value = value,
),
);
}
}

/// 1D Selector for a given value
///
/// This selector is totally agnostic of the meaning of the [value] that must be
/// normalized on a {0, 1} range.
/// The Selector is configured with a [pointerColor], background [gradientColors]
/// and [withChecker], whether or not we should display checkers. The pointer's
/// border is `white` by default but if [highContrastPointer] is used, it becomes
/// `black` on light backgrounds.
///
/// [onSelect] is called when the User select a new value.
class Generic1DSelector extends StatelessWidget {
final double value;
final Axis direction;
final Color pointerColor;
final bool highContrastPointer;
final List<Color> gradientColors;
final bool withCheckers;

final ValueChanged<double> onSelect;

const Generic1DSelector({
Key key,
@required this.value,
this.direction = Axis.vertical,
this.pointerColor = Colors.transparent,
this.highContrastPointer = false,
this.gradientColors = const [Colors.white, Colors.black],
this.withCheckers = false,
this.onSelect,
}) : super(key: key);

void _update(
BuildContext context,
PointerEvent event,
Size size,
) {
if (event.down) {
final value = direction == Axis.vertical
? event.localPosition.dy / size.height
: event.localPosition.dx / size.width;
if (value >= 0 && value <= 1) onSelect(value);
}
}

@override
Widget build(BuildContext context) {
return LayoutBuilder(builder: (context, constraints) {
final size = constraints.biggest;
return Listener(
onPointerDown: (event) => _update(context, event, size),
onPointerMove: (event) => _update(context, event, size),
child: CustomPaint(
painter: _Painter(
value: value,
direction: direction,
gradientColors: gradientColors,
withCheckers: withCheckers,
pointerColor: pointerColor,
highContrastPointer: highContrastPointer,
),
),
);
}).showCursorOnHover();
}
}

class _Painter extends CustomPainter {
final double value;
final Axis direction;
final Color pointerColor;
final bool highContrastPointer;
final bool withCheckers;
final List<Color> gradientColors;

_Painter({
this.value,
this.direction,
this.pointerColor,
this.highContrastPointer,
this.withCheckers,
this.gradientColors,
});

void paintBackground(Canvas canvas, Size size) {
if (withCheckers) {
(direction == Axis.vertical)
? paintcheckers(canvas, size, nbCols: 2)
: paintcheckers(canvas, size, nbRows: 2);
}
final rect = Rect.fromLTWH(0, 0, size.width, size.height);
final rrect =
RRect.fromRectAndRadius(rect, Radius.circular(size.shortestSide / 4));
final LinearGradient gradient = LinearGradient(
colors: gradientColors,
begin: direction == Axis.vertical
? Alignment.topCenter
: Alignment.centerLeft,
end: direction == Axis.vertical
? Alignment.bottomCenter
: Alignment.centerRight,
);
final paint = Paint()..shader = gradient.createShader(rect);
canvas.drawRRect(rrect, paint);
}

void paintPointer(Canvas canvas, Size size) {
final double x =
direction == Axis.vertical ? size.width / 2 : value * size.width;
final double y =
direction == Axis.vertical ? value * size.height : size.height / 2;
final Offset c = Offset(x, y);
final double w = direction == Axis.vertical ? size.width : size.height;
final RRect rrect = RRect.fromRectAndRadius(
Rect.fromCenter(center: c, width: w, height: w),
Radius.circular(w / 4));
final Color pointerBorderColor = highContrastPointer
? pointerColor.isDark()
? Colors.white
: Colors.black
: Colors.grey;
canvas.drawRRect(
rrect,
Paint()
..color = pointerColor
..style = PaintingStyle.fill);
canvas.drawRRect(
rrect,
Paint()
..color = pointerBorderColor
..strokeWidth = w / 8
..style = PaintingStyle.stroke);
}

@override
void paint(Canvas canvas, Size size) {
paintBackground(canvas, size);
paintPointer(canvas, size);
}

@override
bool shouldRepaint(covariant CustomPainter oldDelegate) => false;
}

extension HoverExtensions on Widget {
/// Changes cursor on Hover to [cursor] (default is `SystemMouseCursors.click`).
Widget showCursorOnHover({
SystemMouseCursor cursor = SystemMouseCursors.click,
}) {
return MouseRegion(cursor: cursor, child: this);
}
}

extension ColorX on Color {
/// Determines if the color is dark based on a [luminance] (default is `0.179`).
bool isDark({double luminance = 0.179}) => computeLuminance() < luminance;
}

/// Paints a checker in the [canvas] of [size].
///
/// User may define either the [nbRows] and/or the [nbCols], or the [checkerSize]
/// (default is `kCheckerSize`). The checkers will be display in [darkColor] and
/// [lightCOlor] (default are `kCheckerDarkColor` and `kCheckerLightColor`).
void paintcheckers(
Canvas canvas,
Size size, {
int nbRows,
int nbCols,
double checkerSize = 10,
Color darkColor = const Color(0xff777777),
Color lightColor = const Color(0xffaaaaaa),
}) {
nbRows ??= (nbCols == null)
? size.height ~/ checkerSize
: size.height ~/ (size.width / nbCols);
nbCols ??= size.width ~/ (size.height / nbRows);
final checkerWidth = size.width / nbCols;
final checkerHeight = size.height / nbRows;
final darkPaint = Paint()..color = darkColor;
final lightPaint = Paint()..color = lightColor;
for (var i = 0; i < nbCols; i++) {
for (var j = 0; j < nbRows; j++) {
canvas.drawRect(
Rect.fromLTWH(
i * checkerWidth,
j * checkerHeight,
checkerWidth,
checkerHeight,
),
(i + j) % 2 == 0 ? darkPaint : lightPaint,
);
}
}
}


Related Topics



Leave a reply



Submit