使光标停留在边界内

霍雷

我有一个色轮选择器(我从该库中获取了大量代码)。我正在尝试使色轮光标不超出范围。我不希望它通过灰色边框。

我可以做明显的,使家长divoverflow:hidden,但这只是隐藏光标,就不会让它不去通过边界。

我认为要编辑的相关变量是以下内容之一(在hsvMove函数中,从第39行开始):

var r = currentTargetHeight / 2,
x = e.pageX - startPoint.left - r,
y = e.pageY - startPoint.top - r

如何使光标不越过边界?

JSFiddle

(function(window) {
  "use strict"

  // Some common use variables
  var myColor = new Colors(),
    startPoint,
    currentTarget,
    currentTargetHeight = 0,
    PI = Math.PI,
    PI2 = PI * 2;


  /* ---------------------------------- */
  /* ---- HSV-circle color picker ----- */
  /* ---------------------------------- */
  var colorDiskWrapper = document.getElementById('colorDiskWrapper'),
    colorDiskCursor = document.getElementById('colorDiskCursor'),
    colorDisk = document.getElementById('colorDisk');

  var colorDiscRadius = colorDisk.offsetHeight / 2;

  // Create Event Functions
  var hsvDown = function(e) { // mouseDown callback
      var target = e.target || e.srcElement;

      if (e.preventDefault) e.preventDefault();
      if (target === colorDiskCursor || target === colorDisk) {
        currentTarget = target.parentNode;
      } else
        return;

      startPoint = getOrigin(currentTarget);
      currentTargetHeight = currentTarget.offsetHeight;

      addEvent(window, 'mousemove', hsvMove);
      hsvMove(e);
      startRender();
    },
    hsvMove = function(e) { // mouseMove callback
      var r = currentTargetHeight / 2,
        x = e.pageX - startPoint.left - r,
        y = e.pageY - startPoint.top - r,
        h = 360 - ((Math.atan2(y, x) * 180 / PI) + (y < 0 ? 360 : 0)),
        s = (Math.sqrt((x * x) + (y * y)) / r) * 100;
      myColor.setColor({
        h: h,
        s: s
      }, 'hsv');
    },
    renderHSVPicker = function(color) { // used in renderCallback of 'new ColorPicker'
      var x = Math.cos(PI2 - color.hsv.h * PI2),
        y = Math.sin(PI2 - color.hsv.h * PI2),
        r = color.hsv.s * colorDiscRadius;

      // Position the Cursor
      colorDiskCursor.style.left = (x * r + colorDiscRadius) + 'px';
      colorDiskCursor.style.top = (y * r + colorDiscRadius) + 'px';
    };

  addEvent(colorDiskWrapper, 'mousedown', hsvDown); // event delegation
  addEvent(window, 'mouseup', function() {
    removeEvent(window, 'mousemove', hsvMove);
    stopRender();
  });


  var doRender = function(color) {
      renderHSVPicker(color);
    },
    renderTimer,
    startRender = function(oneTime) {
      if (oneTime) { // only Colors is instanciated
        doRender(myColor.colors);
      } else {
        renderTimer = window.setInterval(
          function() {
            doRender(myColor.colors);
            // http://stackoverflow.com/questions/2940054/
          }, 13); // 1000 / 60); // ~16.666 -> 60Hz or 60fps
      }
    },
    stopRender = function() {
      window.clearInterval(renderTimer);
    };



  /*
  Function Helpers
  */

  function getOrigin(elm) {
    var box = (elm.getBoundingClientRect) ? elm.getBoundingClientRect() : {
        top: 0,
        left: 0
      },
      doc = elm && elm.ownerDocument,
      body = doc.body,
      win = doc.defaultView || doc.parentWindow || window,
      docElem = doc.documentElement || body.parentNode,
      clientTop = docElem.clientTop || body.clientTop || 0, // border on html or body or both
      clientLeft = docElem.clientLeft || body.clientLeft || 0;

    return {
      left: box.left + (win.pageXOffset || docElem.scrollLeft) - clientLeft,
      top: box.top + (win.pageYOffset || docElem.scrollTop) - clientTop
    };
  }


  function addEvent(obj, type, func) {
    addEvent.cache = addEvent.cache || {
      _get: function(obj, type, func, checkOnly) {
        var cache = addEvent.cache[type] || [];

        for (var n = cache.length; n--;) {
          if (obj === cache[n].obj && '' + func === '' + cache[n].func) {
            func = cache[n].func;
            if (!checkOnly) {
              cache[n] = cache[n].obj = cache[n].func = null;
              cache.splice(n, 1);
            }
            return func;
          }
        }
      },
      _set: function(obj, type, func) {
        var cache = addEvent.cache[type] = addEvent.cache[type] || [];

        if (addEvent.cache._get(obj, type, func, true)) {
          return true;
        } else {
          cache.push({
            func: func,
            obj: obj
          });
        }
      }
    };

    if (!func.name && addEvent.cache._set(obj, type, func) || typeof func !== 'function') {
      return;
    }

    if (obj.addEventListener) obj.addEventListener(type, func, false);
    else obj.attachEvent('on' + type, func);
  }

  function removeEvent(obj, type, func) {
    if (typeof func !== 'function') return;
    if (!func.name) {
      func = addEvent.cache._get(obj, type, func) || func;
    }

    if (obj.removeEventListener) obj.removeEventListener(type, func, false);
    else obj.detachEvent('on' + type, func);
  }
})(window);
#colorDisk {
  background-image: url("http://i.imgur.com/tX5NbWs.png");
  width: 350px;
  height: 350px;
  background-repeat: no-repeat;
  cursor: pointer;
}
#colorDiskCursor {
  position: absolute;
  border: 2px solid black;
  border-radius: 50%;
  width: 9px;
  height: 9px;
  cursor: pointer;
}
<div id="colorDiskWrapper">
  <div id="colorDisk"></div>
  <div id="colorDiskCursor"></div>
</div>
<script src="https://rawgit.com/PitPik/colorPicker/master/colors.js"></script>

问题:

让我们从概述算法开始,这样我们就知道我们要做什么:每次移动/单击鼠标,计算鼠标相对于(HSV彩色系统的)色盘的位置所表示HS值。定期在H与和S对应的位置上准确呈现磁盘光标

我们需要注意以下几点:

  1. 我们应该用来计算颜色值的实际半径(S特别是)是色盘的半径减去光标的半径,因为我们要防止光标离开色盘的边界。在这种情况下,我们有175px- 6.5px,即168.5px

  2. 渲染光标时,我们将其设置为左上角。我们需要将位置偏移其半径,以使“手指指针”很好地出现在光标的中间。

解:

基于以上理解,解决方案很简单。

由于使用的是彩色磁盘的整个半径(175px),而没有考虑磁盘光标的半径),因此代码存在问题6.5px

您还应该在代码中修复/考虑的几件事:

  1. currentTargetHeight是包装纸(350px的高度,然后将其减半以得出r这对我来说似乎是错误的。您完全不必担心包装器的尺寸。从代码中删除此变量。我们需要关注的价值应该是colorDiskRadiuscolorDiskCursorRadius

  2. colorDiscCursor的设置为position: absolute,但是它的偏移父级不是包装器,因为包装器不是定位的元素。因此,我们为其设置的左上角位置colorDiscCursor可能完全不可预测,这取决于其实际父级在实际页面上的位置。要解决此问题,请将wrapper设置为position: relative

  3. 我注意到您没有设置box-sizing(默认为content-box),这就是为什么13px尽管有width: 9px;光标实际上仍然宽的原因同样的高度。我个人喜欢使用它,box-sizing: border-box这样当我必须进行像素精确的计算时,我只需要查看CSS中的realwidthheight属性,而不必同时参考paddingand border

  4. 次要问题:您disc有时disk在代码中使用为了理智起见,请尝试对此进行标准化。

TL; DR

这是实现1、2和4的小提琴:https : //jsfiddle.net/hrnn9w9k/4/

我没有包括3,因为它可能不是您的首选,但我强烈建议您使用。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章