简体   繁体   中英

Color jumps from Blue to violette

I'm implementing a color screensaver. There is a colorrange and a slider.

The colors are in (HSB). There are 6 colors.

blue (230, S,B)
green (130, S,B)
yellow (55, S,B)
orange (40, S,B)
red (0(or 360), S,B)
violette (315, S,B)

the slider values are going from 0 to 14.9

blue 0 - 2.9 green
green 3 - 5.9 yellow
yellow 6 - 8.9 orange
orange 9 - 11.9 red
red 12 - 14.9 violette

if the slider values is used and the difference between the old slidervalue and the new slider value is under 2.9 the actual hue will change by substrating 0.5.

now if the difference is bigger then 2.9 there has to be a jump. This works fine until slider value is smaller then 12. At value 12 the color changes from 0 to 360 and my code doesn't work anymore.

// this works fine
if (lastSlide < 12) {
            // jump statement
            if (Math.abs(Math.round(top.fillColor.hue - value)) > 41){
                var fillColor = Math.round((Math.abs((value-top.fillColor.hue))/1.05) + Math.min(value, Math.round(top.fillColor.hue)));
                if (fillColor < 0) fillColor = adjustValue(fillColor);
                top.fillColor.hue = fillColor;
            }
            else if (Math.abs(Math.round(top.fillColor.hue - value)) < 41 && top.counter_dsg < 20){
                top.fillColor.hue-= 0.5; 
                top.counter_dsg+=0.5;
            }
            else if (Math.abs(Math.round(top.fillColor.hue - setValue())) < 41 && top.counter_dsg > 19){
                top.fillColor.hue+= 0.5; 
                top.counter_dsg+=0.5;
            }
            else top.fillColor.hue -= 0.5;
            if (top.counter_dsg > 39) top.counter_dsg = 0;
        }
// this not
else {
    // jump statement
    if (Math.abs(Math.round(top.fillColor.hue - value)) > 41){
        var fillColor = Math.round((Math.abs((value-top.fillColor.hue))/1.05) - Math.min(value, Math.round(top.fillColor.hue)));
        if (fillColor < 0) fillColor = adjustValue(fillColor);
        top.fillColor.hue = fillColor;
    }
    else if (Math.abs(Math.round(value - top.fillColor.hue)) < 41 && top.counter_dsg < 20){
        top.fillColor.hue-= 0.5;
        top.counter_dsg+=0.5;
    }
    else if (Math.abs(Math.round(value - top.fillColor.hue)) < 41 && top.counter_dsg > 19){
        top.fillColor.hue+= 0.5; 
        top.counter_dsg+=0.5;
    }
    else top.fillColor.hue -= 0.5;
    if (top.counter_dsg > 39) top.counter_dsg = 0;
}

EDIT:

Ok well, let's say there is a canvas on the screen and i want to change the color of the canvas by using a slider. If the slider isn't used, the actual color of the canvas is swining (+10hue, -10hue).

example

the color of the canvas is blue (230 hue, s, b), i'm not using the slider so the color of the canvas changes by adding 0,5 (counter counts: 20 times), after that 0,5 will be substrating from the color until the counter reached 40 and then the counter is set to 0. So the color is swining between (220 hue, s,b) and (240hue, s, b)

Now if i'm using the slider (slidersteps = 0.1) the color will change to the new value.

In the example I'm using the slider and the slider value is 2,9 then the color changes to green by substrating 0.5 hue. Steps looks like (230h,s,b),(229.5h,s,b),...,(130h,s,b). If (130h,s,b) is reached the color begans to swing.

Further if the new slider values is much bigger then the old, there have to be a faster change from the old color to the new.

example Slider value = 11.9, last slider value = 2,9, the difference between those is 9. So if the difference is bigger then 2.9 i wanted to go faster steps from green to red. So i decided to get the next value by using this formula (old value - new value) / 1.05 + Min[old value, new value] steps looks like (130h, s,b),(123h, s,b),...,(0h, s, b)

this works fine until the change from red to violet because the value of red is 0 and the one of the next is 360 until 325 violet. So i'm confused how to get the same steps like above with this valuechanges

EDIT2:

1.) yes its the actual hue
2.) my fault...it's always setValue() - i have declare it above in this ways value = setValue() to use it once time and didn't change it everywhere 
3.) value = setValue() -> the Hue calculated by the slider
4.) yes
5.) yes

I hope I correctly answer, but I'm not really sure to understand what you're trying to do. If I understand, you want to have some transitioning effect over a color change, right?

I propose a radically different approach, more "mathematical", fluent. Let's say you want to achieve the color transition within 1 second, regardless how big is the jump from old color to new color. You would just have to determinate a "transition vector", that would be the shortest possible: if the scale goes from 0 to 360, the vector is: (540 + new - old) % 360 - 180.

Why that? The "naive" vector is just (new-old). By adding 360 then modulo 360, we make sure we have a positive number. And by adding 180 (540=180+360) BEFORE modulo, then removing 180 AFTER modulo, we make sure we have a number in range [-180, 180] => which is what we want to get the shortest path.

For instance, with this formula:

  • if old=5, new=10 => vector is +5
  • if old=350, new=10 => vector is +20
  • if old=350, new=340 => vector is -10

Then once you've calculated that vector, you just have to apply it to your color value at each time frame, multiplied by the time factor. For instance:

var v = (540 + newColor - oldColor) % 360 - 180;
var currentColor = oldColor;
var delta = 200; // milliseconds
var timeElapsed = 0;
var timeFrame = 1000; // 1s
var hInt = setInterval(function() {
    if (timeElapsed >= timeFrame) {
       clearInterval(hInt);
       currentColor = newColor;
    } else {
       timeElapsed += delta;
       currentColor += v * delta / timeFrame;
    }
}, delta);

"currentColor" will give you the right color over time.

To get from one color to another on shortest path Joel 's answer is fine, I can't make it better. So I make another approach staying as close as possible to the code you have already since you say first part works fine.

In function setValue() the beforelast line is else c = 360 - m * 15; . Change it to:

else c = m * -15;

Now when the sliderValue goes from 12 to 15 the function returns a negative hue from 0 to -45. That way you remove the 'jump' from 0 to 315 and get continously decreasing values when sliderValue increases (and contrarywise). Since now value can be < 0 use adjustValue() each time you set a value to the canvas ( adjustValue() internally checks for < 0 so you need no extra check). Then all the code you posted could look like this:

var cur = top.fillColor.hue;
if (cur > 300) cur -= 360;
var dif = cur - setValue();
if (Math.abs(dif) > 41) cur -= Math.round(dif / 1.05);
else {
    cur += top.counter_dsg < 20 ? -0.5 : 0.5; 
    top.counter_dsg += 0.5
}
if (top.counter_dsg > 39) top.counter_dsg = 0;
top.fillColor.hue = adjustValue(cur);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM