以编程方式更改值

时间:2015-12-16 20:31:11

标签: javascript math colors trigonometry color-wheel

我正在使用this color wheel,我想以编程方式更改色轮的颜色。所以如果我有一个颜色值(rgb,hsv等)我想将色轮改成那个特定的颜色?

例如,如果我有rgb(255, 255, 80),如何更改色轮以显示?

JSFiddle

相关代码:

自定义代码:

function changeColor() {
    var redColor = 255;
    var greenColor = 255;
    var blueColor = 80;

    //currentX =
    //currentY =
    redraw(0);

    // The following line is redundent if I'm calling 'redraw`, but it's there just to show what I mean.
    label.textContent = b.style.background = 'rgb(' + redColor + ', ' + greenColor + ', ' + blueColor + ')';
}
来自redraw() function

实际代码

function redraw(e) {

    // Only process an actual change if it is triggered by the mousemove or mousedown event.
    // Otherwise e.pageX will be undefined, which will cause the result to be NaN, so it will fallback to the current value
    currentX = e.pageX - c.offsetLeft - radiusPlusOffset || currentX;
    currentY = e.pageY - c.offsetTop - radiusPlusOffset || currentY;

    // Scope these locally so the compiler will minify the names.  Will manually remove the 'var' keyword in the minified version.
    var theta = atan2(currentY, currentX),
        d = currentX * currentX + currentY * currentY;

    // If the x/y is not in the circle, find angle between center and mouse point:
    //   Draw a line at that angle from center with the distance of radius
    //   Use that point on the circumference as the draggable location
    if (d > radiusSquared) {
        currentX = radius * math.cos(theta);
        currentY = radius * math.sin(theta);
        theta = atan2(currentY, currentX);
        d = currentX * currentX + currentY * currentY;
    }

    label.textContent = b.style.background = hsvToRgb(
        (theta + PI) / PI2, // Current hue (how many degrees along the circle)
        sqrt(d) / radius, // Current saturation (how close to the middle)
        input.value / oneHundred // Current value (input type="range" slider value)
    )[3];

    // Reset to color wheel and draw a spot on the current location. 
    a.putImageData(imageData, 0, 0);

    // Draw the current spot.
    a.stroke();
    a.font = "1em arial";
    a.fillText("♥", currentX+radiusPlusOffset-4,currentY+radiusPlusOffset+4);

}

(function() {

  document.getElementById('button').onclick = changeColor;

  function changeColor() {
    var redColor = 255;
    var greenColor = 255;
    var blueColor = 80;

    //currentX =
    //currentY =
    redraw(0);

    // The following line is redundent if I'm calling 'redraw`, but it's there just to show what I mean.
    label.textContent = b.style.background = 'rgb(' + redColor + ', ' + greenColor + ', ' + blueColor + ')';
  }

  // Declare constants and variables to help with minification
  // Some of these are inlined (with comments to the side with the actual equation)
  var doc = document;
  doc.c = doc.createElement;
  b.a = b.appendChild;

  var width = c.width = c.height = 400,
    label = b.a(doc.c("p")),
    input = b.a(doc.c("input")),
    imageData = a.createImageData(width, width),
    pixels = imageData.data,
    oneHundred = input.value = input.max = 100,
    circleOffset = 10,
    diameter = 380, //width-circleOffset*2,
    radius = 190, //diameter / 2,
    radiusPlusOffset = 200, //radius + circleOffset
    radiusSquared = radius * radius,
    two55 = 255,
    currentY = oneHundred,
    currentX = -currentY,
    wheelPixel = 16040; // circleOffset*4*width+circleOffset*4;

  // Math helpers
  var math = Math,
    PI = math.PI,
    PI2 = PI * 2,
    sqrt = math.sqrt,
    atan2 = math.atan2;

  // Setup DOM properties
  b.style.textAlign = "center";
  label.style.font = "2em courier";
  input.type = "range";

  // Load color wheel data into memory.
  for (y = input.min = 0; y < width; y++) {
    for (x = 0; x < width; x++) {
      var rx = x - radius,
        ry = y - radius,
        d = rx * rx + ry * ry,
        rgb = hsvToRgb(
          (atan2(ry, rx) + PI) / PI2, // Hue
          sqrt(d) / radius, // Saturation
          1 // Value
        );

      // Print current color, but hide if outside the area of the circle
      pixels[wheelPixel++] = rgb[0];
      pixels[wheelPixel++] = rgb[1];
      pixels[wheelPixel++] = rgb[2];
      pixels[wheelPixel++] = d > radiusSquared ? 0 : two55;
    }
  }

  // Bind Event Handlers
  input.onchange = redraw;
  c.onmousedown = doc.onmouseup = function(e) {
    // Unbind mousemove if this is a mouseup event, or bind mousemove if this a mousedown event
    doc.onmousemove = /p/.test(e.type) ? 0 : (redraw(e), redraw);
  }

  // Handle manual calls + mousemove event handler + input change event handler all in one place.
  function redraw(e) {

    // Only process an actual change if it is triggered by the mousemove or mousedown event.
    // Otherwise e.pageX will be undefined, which will cause the result to be NaN, so it will fallback to the current value
    currentX = e.pageX - c.offsetLeft - radiusPlusOffset || currentX;
    currentY = e.pageY - c.offsetTop - radiusPlusOffset || currentY;

    // Scope these locally so the compiler will minify the names.  Will manually remove the 'var' keyword in the minified version.
    var theta = atan2(currentY, currentX),
      d = currentX * currentX + currentY * currentY;

    // If the x/y is not in the circle, find angle between center and mouse point:
    //   Draw a line at that angle from center with the distance of radius
    //   Use that point on the circumference as the draggable location
    if (d > radiusSquared) {
      currentX = radius * math.cos(theta);
      currentY = radius * math.sin(theta);
      theta = atan2(currentY, currentX);
      d = currentX * currentX + currentY * currentY;
    }

    label.textContent = b.style.background = hsvToRgb(
      (theta + PI) / PI2, // Current hue (how many degrees along the circle)
      sqrt(d) / radius, // Current saturation (how close to the middle)
      input.value / oneHundred // Current value (input type="range" slider value)
    )[3];

    // Reset to color wheel and draw a spot on the current location. 
    a.putImageData(imageData, 0, 0);

    // Draw the current spot.
    // I have tried a rectangle, circle, and heart shape.
    /*
    // Rectangle:
    a.fillStyle = '#000';
    a.fillRect(currentX+radiusPlusOffset,currentY+radiusPlusOffset, 6, 6);
    */
    /*
    // Circle:
    a.beginPath();  
    a.strokeStyle = '#000';
    a.arc(~~currentX+radiusPlusOffset,~~currentY+radiusPlusOffset, 4, 0, PI2);
    a.stroke();
    */

    // Heart:
    a.font = "1em arial";
    a.fillText("♥", currentX + radiusPlusOffset - 4, currentY + radiusPlusOffset + 4);

  }

  // Created a shorter version of the HSV to RGB conversion function in TinyColor
  // https://github.com/bgrins/TinyColor/blob/master/tinycolor.js
  function hsvToRgb(h, s, v) {
    h *= 6;
    var i = ~~h,
      f = h - i,
      p = v * (1 - s),
      q = v * (1 - f * s),
      t = v * (1 - (1 - f) * s),
      mod = i % 6,
      r = [v, q, p, p, t, v][mod] * two55,
      g = [t, v, v, q, p, p][mod] * two55,
      b = [p, p, t, v, v, q][mod] * two55;

    return [r, g, b, "rgb(" + ~~r + "," + ~~g + "," + ~~b + ")"];
  }

  // Kick everything off
  redraw(0);

  /*
  // Just an idea I had to kick everything off with some changing colors…
  // Probably no way to squeeze this into 1k, but it could probably be a lot smaller than this:
  currentX = currentY = 1;
  var interval = setInterval(function() {
      currentX--;
      currentY*=1.05;
      redraw(0)
  }, 7);
    
  setTimeout(function() {
      clearInterval(interval)
  }, 700)
  */

})();
<button id="button">Click Me To Change Color</button>
<br />

<canvas id="c"></canvas>
<script>
  var b = document.body;
  var c = document.getElementsByTagName('canvas')[0];
  var a = c.getContext('2d');
  document.body.clientWidth; // fix bug in webkit: http://qfox.nl/weblog/218
</script>

2 个答案:

答案 0 :(得分:0)

色轮仅使用var mx = cx - s * radius * Math.cos(2 * Math.PI * h); var my = cy - s * radius * Math.sin(2 * Math.PI * h); 值1,因此假设您可以使用现有库从RGB等转换回HSV,您需要做的就是提取H和S并转换它们回到像素坐标。

在此车轮上,从负X轴顺时针测量色调,&#34; S&#34;中心是0,外面是1,所以:

cx, cy

其中[(]?\d{3}[)]?[(\s)?.-]\d{3}[\s.-]\d{4} 是色轮的中心。

答案 1 :(得分:0)

这是一个取自TinyColor的函数(已在此色轮源中引用)并添加到某些代码中,以将HSV转换回x,y和滑块值。

// Created a modified version of the HSV to RGB conversion function in TinyColor
// https://github.com/bgrins/TinyColor/blob/master/tinycolor.js
function rgbToHsv(r, g, b) {

  r = r / two55;
  g = g / two55;
  b = b / two55;

  var max = math.max(r, g, b), min = math.min(r, g, b);
  var h, s, v = max;

  var d = max - min;
  s = max === 0 ? 0 : d / max;

  if(max == min) {
    h = 0; // achromatic
  }
  else {
    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: h, s: s, v: v };
}

// This function converts the RGB to HSV and uses the HSV to set the 
// currentX, currentY, and input.value (saturation) values.
function update(r,g,b){
  var hsv = rgbToHsv(r,g,b);

  var newD = math.round(math.pow(radius * hsv.s, 2));
  var newTheta = (hsv.h * PI2) - PI;

  currentX = math.round(math.sqrt(newD) * math.cos(newTheta));
  currentY = math.round(math.sqrt(newD) * math.sin(newTheta));

  input.value = hsv.v * 100;

  redraw(0);
}

update(158,255,151);

除非您更改..函数中的~~ NOT按位运算符以消除掉小数的舍入问题,否则最终显示的RGB值与传入的值略有不同。

这是整个修改过的库的要点。 https://gist.github.com/tonypatton/bf4e13cabf03fc4a1777