Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Border Radius Prevent Clickable

I'm using this color wheel, and I want to make it that when you click outside the canvas, when you click the border radius, nothing should happen.

I have to prevent 2 things from happening:

  • I have to prevent the cursor from becoming a pointer.
  • I have to prevent the color and the dragger to not move and change.
    Or I could just not call redraw().

Here's what I tried doing: In the redraw() function, at the if statement of d > radiusSquared (line 97), I consoled a random string to know when the if statement gets called, so I can insert the prevention's there.

The problem with doing that, is if you start dragging the dragger in the canvas, then drag out of the canvas, it still consoles the string. (I hope this is clear. If you have a better way of expressing my point, please edit the question.)

How can I prevent changes from happening if the cursor is out of the border radius of the canvas, whether the dragging started within the canvas, or out of the canvas?

JSFiddle

var b = document.body;
var c = document.createElement('canvas');
var a = c.getContext('2d');
var wrapper = document.getElementById('wrapper');
document.body.clientWidth; // fix bug in webkit: http://qfox.nl/weblog/218

var colorWheelDiv = document.createElement('div');
var dragger = document.createElement('div');
dragger.id = 'dragger';

var otherDiv = document.createElement('div');
colorWheelDiv.appendChild(c);
colorWheelDiv.appendChild(dragger);
colorWheelDiv.style.position = 'relative';

wrapper.appendChild(otherDiv);
wrapper.appendChild(colorWheelDiv);

(function() {

  // 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 = 0,
    diameter = width - circleOffset * 2,
    radius = diameter / 2,
    radiusPlusOffset = radius + circleOffset,
    radiusSquared = radius * radius,
    two55 = 255,
    currentY = oneHundred,
    currentX = -currentY,
    wheelPixel = 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;
  dragger.onmousedown = 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).offset().left - radiusPlusOffset || currentX;
    currentY = e.pageY - $(c).offset().top - 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) {
      console.log('outside');
      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);*/

    dragger.style.left = (~~currentX + radiusPlusOffset) + 'px';
    dragger.style.top = (~~currentY + radiusPlusOffset) + 'px';

  }

  // 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)
  */

})();
#wrapper {
  position: relative;
  width: 400px;
  height: 400px;
  cursor: pointer;
}
#dragger {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  display: block;
  position: absolute;
  border: 2px solid black;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<div id='wrapper'>
</div>
like image 368
Jessica Avatar asked Jul 20 '26 02:07

Jessica


1 Answers

To prevent the colour and dragger from changing:

if (d > radiusSquared) {
  currentX = radius * math.cos(theta);
  currentY = radius * math.sin(theta);
  theta = atan2(currentY, currentX);
  d = currentX * currentX + currentY * currentY;
}else{
  label.textContent = b.style.background = hsvToRgb(
    (theta + PI) / PI2,
    sqrt(d) / radius,
    input.value / oneHundred 
  )[3];
  a.putImageData(imageData, 0, 0);
  dragger.style.left = (~~currentX + radiusPlusOffset) + 'px';
  dragger.style.top = (~~currentY + radiusPlusOffset) + 'px';
}

JSFiddle

As for the pointer, one option is to catch mouseover events on the canvas, and manually set the pointer according to position.

like image 94
GAntoine Avatar answered Jul 22 '26 16:07

GAntoine



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!