繁体   English   中英

将div定位在光标位置

[英]Position div at cursor location

我正在使用这个色轮 ,我想添加一个div作为拖动器。 我能够实现它。 问题是,当我在色轮上方添加内容时。 拖动器使色轮上方物体的高度偏移

例如,如果我在色轮上方添加一个高度为50px的div,则拖动器将与光标一起移动,但它将位于光标位置上方50px 我希望它位于光标的确切位置。

必须更改的相关代码是:

currentX = e.pageX - $(c).offset().left - radiusPlusOffset || currentX;
currentY = e.pageY - $(c).offset().top - radiusPlusOffset || currentY;

显而易见的“解决方案”将是减去色轮上方的div高度。 这样做的问题是,它不是动态的。 我必须为每个div添加高度。 我以为offset()应该可以计算出来。

如何动态地将拖动器div置于光标的确切位置? 我更喜欢使用裸露的JavaScript,而不是JQuery。

的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'); var text = document.createTextNode('Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec quam felis, ultricies nec, pellentesque eu, pretium quis, sem. Nulla consequat massa quis enim. Donec pede justo, fringilla vel, aliquet nec, vulputate eget, arcu. In enim justo, rhoncus ut, '); colorWheelDiv.appendChild(c); otherDiv.appendChild(text); colorWheelDiv.appendChild(dragger); 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; ba = b.appendChild; var width = c.width = c.height = 400, label = ba(doc.c("p")), input = ba(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; 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) { 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) */ })(); 
 canvas { 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> 

您需要将包含画布和拖动器的div的位置更改为relative。 则顶部偏移将是正确的。 左偏移量在计算中也是错误的,应为:e.pageX-$(colorWheelDiv).offset()。left

更新小提琴

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');
var text = document.createTextNode('Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec quam felis, ultricies nec, pellentesque eu, pretium quis, sem. Nulla consequat massa quis enim. Donec pede justo, fringilla vel, aliquet nec, vulputate eget, arcu. In enim justo, rhoncus ut, ');
colorWheelDiv.appendChild(c);
otherDiv.appendChild(text);
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;
  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) {
      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 = (e.pageX - $(colorWheelDiv).offset().left) + '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)
  */

})();

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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