stevereich / hueristics

jQuery plugin for color cycling...
https://stevereich.github.io/hueristics/
1 stars 1 forks source link

A simple way to 'stop' hueristics once it's been called on an element? #1

Open bkuz114 opened 2 years ago

bkuz114 commented 2 years ago

Hello. Really enjoy this plugin, thanks for creating it. Sorry if this is not the appropriate place to ask this - My question: is there a way to 'stop' hueristics on an element once it's been initialized?

for example:

$('body').hueristics(); // start the hueristics plugin on the body

Is there a simple way to stop it afterwards, if you want to stop the color changing on the background, something such as:

$("body").stopHueristics();

I didn't notice anything in the code such as this, but wasn't sure if there was already a simple way to accomplish this. I tried removing the style attr from the element, but hueristic's styling remains. (for example $("body").removeAttr("style"); seems to have no effect, and in-line style remains). Even if you go into developer tools and attempt to unselect the in-line background-color style that hueristics is adding, it keeps adding itself back. Any thoughts?

bkuz114 commented 2 years ago

After looking more deeply at the code, it seems removing in-line style on the element has no effect, because the moveTo function continually calls itself. Seems it would require some exit criteria for hueristics to stop. (Just wanted to provide more info.)

bkuz114 commented 2 years ago

I was able to find a solution to this request, and wanted to share what I did. The code change was minimal, just a few lines. Anyway, not sure if this is useful, but wanted to share just in case, and since I didn't expect anyone to do the work for me. Please note I am not well versed with javascript, so this might be a poor approach. Thank you again for this plugin, I really like it.

Overview:

In the code below, the only changes to the plugin are:

  1. introduction of variable stopHueristicsFlag and function stopHueristics() (stopHueristics() just sets the value of stopHueristicsFlag to true)
  2. adds checks within the existing functions moveTo() and doHue() to check if stopHueristicsFlag is true. If it is, it removes the inline styling for the property that's been set on the element hueristics() was called on, and returns (thus terminating the function. Additionally, the check in doHue() also calls clearInterval() on the setInterval() that's being called there, as otherwise the setInterval() functions will keep going). Note - The reason I found it necessary to remove the inline style from within the plugin: if you call stopHueristics() from outside the plugin and want to remove the inline style that was set, or want to try to set a new css value for the property the plugin is modifying, you would need some way to know when the heuristics function had actually stopped, else any removal of inline style, or any new style you set, will just get overwritten as the plugin is in the process of stopping (before it hits one of those checks). It seemed stopHueristics() would need to return a promise or something to achieve this, that would only resolve once the hueristics() functions had actually terminated, so that you could set new style values only once the promise had resolved, but I could not figure out how to get this to work. That is why I'm removing the inline style properties from within the plugin itself.)

Using these modifications, here's an example of how the plugin could then be used:

$("body").hueristics();
// do stuff
$("body").stopHueristics();

Modified version of the plugin:

var stopHueristicsFlag = false;

(function($) {  
    $.fn.stopHueristics = function(options){
        stopHueristicsFlag = true;
    }
})(jQuery);

(function($) {  
    $.fn.hueristics = function(options){
        stopHueristicsFlag = false;
        var settings = $.extend({
            property: 'background-color',
            startColor: '',
            hue: 0,
            saturation: 100,
            lightness: 50,
            alpha: 1,
            moveVal: 'hue',
            maxVal: 360,
            minVal: 0,
            speed: 70,
            step: 1,
            reverse:false
        }, options ),
        config = {
            'dir' : (settings.reverse) ? 'd' : 'u',
            'el' : $(this),
            'speed' : ((101-settings.speed) * 15) / 10
        },
        getHSLA = function(color){
            var rgb2hsl = function(r, g, b, a){
                r /= 255, g /= 255, b /= 255, a = a | 1;
                var max = Math.max(r, g, b), min = Math.min(r, g, b),
                h, s, l = (max + min) / 2;
                if (max == min) { h = s = 0; } 
                else {
                    var d = max - min;
                    s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
                    switch (max){
                        case r: h = (g - b) / d + (g < b ? 6 : 0); break;
                        case g: h = (b - r) / d + 2; break;
                        case b: h = (r - g) / d + 4; break;
                    }
                    h /= 6;
                }
                return [(h*360+0.5)|0, ((s*100+0.5)|0), ((l*100+0.5)|0), a];
            },
            hex2hsla = function(hex){
                var a,r,g,b;
                if(hex.length==4 || hex.length==8){
                    a = (hex.length==4) ? parseInt(hex.substring(0,1).repeat(2), 16) : parseInt(hex.substring(0,2), 16);
                    a = parseFloat((a/255).toFixed(2));
                    r = (hex.length==4) ? parseInt(hex.substring(1,2).repeat(2), 16) : parseInt(hex.substring(2,4), 16);
                    g = (hex.length==4) ? parseInt(hex.substring(2,3).repeat(2), 16) : parseInt(hex.substring(4,6), 16);
                    b = (hex.length==4) ? parseInt(hex.substring(3,4).repeat(2), 16) : parseInt(hex.substring(6,8), 16);
                }
                else{
                    a = 1;
                    r = (hex.length==3) ? parseInt(hex.substring(0,1).repeat(2), 16) : parseInt(hex.substring(0,2), 16);
                    g = (hex.length==3) ? parseInt(hex.substring(1,2).repeat(2), 16) : parseInt(hex.substring(2,4), 16);
                    b = (hex.length==3) ? parseInt(hex.substring(2,3).repeat(2), 16) : parseInt(hex.substring(4,6), 16);
                }
                return rgb2hsl(r,g,b,a);
            },
            rgbaHex = new RegExp(/(rgba?|hsla?)\s*\(\s*([1-2]?[0-9]{0,2}|[1-3]?[0-6]{0,2}|[1]?[0-9]{0,2}%?)\s*,\s*([1-2]?[0-9]+|[1]?[0-9]*\.?[0-9]*%?)\s*,\s*([1-2]?[0-9]+|[1]?[0-9]*\.?[0-9]*%?)\s*,?\s*([0-1]?\.?[0-9]*|[1]?[0-9]*\.?[0-9]*%?)\s*\)/,'i'),
            hexReg = new RegExp(/#?([a-f0-9]{8}|[a-f0-9]{6}|[a-f0-9]{4}|[a-f0-9]{3})/,'i'),
            isRGBAMatch = rgbaHex.test(color),
            isHEXMatch = hexReg.test(color);
            if(isRGBAMatch){
                switch(color.match(rgbaHex)[1]){
                    case "rgb":
                    case "rgba":
                        return rgb2hsl(color.match(rgbaHex)[2], color.match(rgbaHex)[3], color.match(rgbaHex)[4], color.match(rgbaHex)[5]);
                    case "hsl":
                    case "hsla":
                        return [color.match(rgbaHex)[2], color.match(rgbaHex)[3], color.match(rgbaHex)[4], (typeof color.match(rgbaHex)[5] === 'undefined' | color.match(rgbaHex)[5]==null | !color.match(rgbaHex)[5].length) ? 1 : color.match(rgbaHex)[5]];
                }
            }
            if (isHEXMatch) {
                if(hexReg.test(color)){
                    return hex2hsla(color.match(hexReg)[1]);
                }
            }
            return [0,0,0,0];   
        },
        startVals = getHSLA(config.el.css(settings.property)),
        firstVals = (settings.startColor.length) ? getHSLA(settings.startColor) : [parseInt(settings.hue),parseInt(settings.saturation),parseInt(settings.lightness),parseInt(settings.alpha)],
        init = function(){
            moveTo(startVals,firstVals,doHue);
        },
        times = 0,
        moveTo = function(startColor,endColor,callback){
            if (stopHueristicsFlag) {
                config.el.css(settings.property, "");
                return;
            }
            var pos = 'up', neg = 'd',
                hueDirection = (startColor[0] < endColor[0]) ? pos : neg,
                satDirection = (startColor[1] < endColor[1]) ? pos : neg,
                lightDirection = (startColor[2] < endColor[2]) ? pos : neg,
                alphaDirection = (startColor[3] < endColor[3]) ? pos : neg,
                hueStep = Math.abs(startColor[0] - endColor[0]),
                satStep = Math.abs(startColor[1] - endColor[1]),
                lightStep = Math.abs(startColor[2] - endColor[2]),
                alphaStep = Math.abs(startColor[3] - endColor[3]),
                eachStep = Math.max(hueStep,satStep,lightStep,alphaStep)/settings.step;

            if(startColor[0]!=endColor[0] || startColor[1]!=endColor[1] || startColor[2]!=endColor[2] || startColor[3]!=endColor[3]){
                setTimeout(function(){
                    var h = (h != endColor[0]) ? (hueDirection == 'd') ? ((startColor[0] - (hueStep/eachStep)) < endColor[0]) ? endColor[0] : startColor[0] - (hueStep/eachStep) : ((startColor[0] + 1) > endColor[0]) ? endColor[0] : startColor[0] + (hueStep/eachStep) : endColor[0],
                    s = (s != endColor[1]) ? (satDirection == 'd') ? ((startColor[1] - (satStep/eachStep)) < endColor[1]) ? endColor[1] : startColor[1] - (satStep/eachStep) : ((startColor[1] + 1) > endColor[1]) ? endColor[1] : startColor[1] + (satStep/eachStep) : endColor[1],
                    l = (l != endColor[2]) ? (lightDirection == 'd') ? ((startColor[2] - (lightStep/eachStep)) < endColor[2]) ? endColor[2] : startColor[2] - (lightStep/eachStep) : ((startColor[2] + 1) > endColor[2]) ? endColor[2] : startColor[2] + (lightStep/eachStep) : endColor[2],
                    a = (a != endColor[3]) ? (alphaDirection == 'd') ? ((startColor[3] - (alphaStep/eachStep)) < endColor[3]) ? endColor[3] : startColor[3] - (alphaStep/eachStep) : ((startColor[3] + 1) > endColor[3]) ? endColor[3] : startColor[3] + (alphaStep/eachStep) : endColor[3];
                    config.el.css(settings.property,'hsla('+h+','+s+'%,'+l+'%,'+a+')');
                    moveTo([h,s,l,a],endColor);
                },config.speed)
            }
            else{
                doHue();
            }
        },
        doHue = function(){
                        var refreshIntervalId = setInterval(function(){
                            if (stopHueristicsFlag) {
                                config.el.css(settings.property, "");
                                clearInterval(refreshIntervalId);
                                return;
                            }
                settings[settings['moveVal']] = (config.dir=='u') ? settings[settings['moveVal']]-=settings.step : settings[settings['moveVal']]+=settings.step;
                config.el.css(settings.property,'hsla('+settings.hue+','+settings.saturation+'%,'+settings.lightness+'%,'+settings.alpha+')');
            },config.speed)
        };

        init();
    }
})(jQuery);

Anyway, not sure if this is of use in any way. Maybe if someone else wants to achieve the same ability to stop the plugin, they can use this code above, or fiddle around with it to their liking. Thank you again.