我有一个色轮选择器(我从this library中获取了大量代码)。我试图让色轮光标不会超出界限。我不希望它通过灰色边框。
我可以做到显而易见并制作父PrintWriter
:div
,但这只会隐藏光标,它不会使它不能超越边界。
我认为要编辑的相关变量是以下之一(在overflow:hidden
函数中,从第39行开始):
hsvMove
如何让光标不越过边界?
var r = currentTargetHeight / 2,
x = e.pageX - startPoint.left - r,
y = e.pageY - startPoint.top - r
(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;
}
答案 0 :(得分:3)
<强>问题:强>
让我们首先概述算法,因此我们都清楚我们要做的事情:每次鼠标移动/点击,计算鼠标位置相对所代表的H
和S
值到彩色光盘(HSV彩色系统)。定期将磁盘光标准确渲染到与H
和S
值对应的位置。
我们需要注意以下几点:
我们用来计算颜色值的实际半径(特别是S
)是彩色圆盘的半径减去光标的半径,因为我们想要阻止光标离开彩色磁盘的边界。在这种情况下,我们有175px
- 6.5px
,即168.5px
。
渲染光标时,我们设置其左上角位置。我们需要通过半径来偏移位置,以便我们的“手指指针”很好地出现在光标的中间。
<强>解决方案:强>
基于上述理解,解决方案很简单。
您的代码存在问题,因为您使用的是整个光盘半径(175px
),而没有考虑光盘光标的半径(6.5px
)。
您应该在代码中修复/考虑的一些事项:
您的currentTargetHeight
是包装器(350px
)的高度,然后将其减半以派生r
。这看起来对我不对。你根本不应该关心包装器的尺寸。从代码中删除此变量。我们需要关注的值应为colorDiskRadius
和colorDiskCursorRadius
。
您的colorDiscCursor
设置为position: absolute
,但其偏移父级不是包装器,因为包装器不是定位元素。因此,我们为colorDiscCursor
设置的左上角位置可能完全不可预测,具体取决于其实际父级在实际页面上的位置。要解决此问题,请将包装器设置为position: relative
。
我注意到您没有设置box-sizing
(默认为content-box
),这就是为什么您的光标实际上13px
宽,尽管有width: 9px
;同样适合身高。我个人喜欢使用box-sizing: border-box
,因此当我必须进行像素精确计算时,我只需要查看CSS中的实际width
和height
属性,而无需参考到padding
和border
。
次要问题:您有时在代码中使用disc
,有时使用disk
。为了理智,尝试将其标准化。
<强> TL; DR 强>
这是实施1,2和4的小提琴:https://jsfiddle.net/hrnn9w9k/4/
我没有包括3,因为它可能不是您的偏好,但我强烈推荐它。