我正在使用此color wheel picker,我正在尝试添加div
作为拖动器,而不是将其嵌入画布中。
我创建了一个外部div(一个wrapper
),并插入了一个div
(dragger),然后是画布。我将拖网div's position
设为absolute
。然后在redraw(e) function
中,我将left
和top
设置为以下内容:
dragger.style.left = currentX + 'px';
dragger.style.top = currentY + 'px';
这样可行,即拖拉机应该移动,但它位于错误的位置。
如何让拖动器与光标位于同一位置?
var b = document.body;
var c = document.getElementsByTagName('canvas')[0];
var a = c.getContext('2d');
var wrapper = document.getElementById('wrapper');
var dragger = document.createElement('div');
dragger.id = 'dragger';
wrapper.appendChild(dragger);
wrapper.insertBefore(dragger, c);
document.body.clientWidth; // fix bug in webkit: http://qfox.nl/weblog/218
(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 = 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];
dragger.style.left = currentX + 'px';
dragger.style.top = currentY + 'px';
// 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)
*/
})();
#wrapper {
width: 400px;
height: 400px;
position: relative;
}
#dragger {
background-color: orange;
width: 15px;
height: 15px;
border-radius: 50%;
position: relative;
}
<div id='wrapper'>
<canvas id="c"></canvas>
</div>
答案 0 :(得分:2)
通过操纵currentX和currentY坐标我非常接近。上述评论者接近解决方案;必须将~50%的高度和宽度添加到相对位置。我还建议在拖动器上使用 z-index 属性,如果您希望心脏在顶部以及它与色轮之间的拖动器。
具有适当偏移量的最终版本:Fiddle
如果拖动器的尺寸从15px减小到5px,则分别添加7和4px: https://jsfiddle.net/6n9zwahL/(固定金额)或https://jsfiddle.net/mak3Lace/(非固定,程序化解决方案)。
dragger.style.left = (currentX + radiusPlusOffset + (radiusPlusOffset/30)) + 'px';
dragger.style.top = (currentY + radiusPlusOffset+(radiusPlusOffset/40)) + 'px';
在我有时间编辑之前保留历史回复:
代码 - 这里是以像素为单位手动完成的,但是我通过查询浏览器的宽度来创建变量并将其设置为更准确的值:
dragger.style.left = currentX + 210 + 'px';
dragger.style.top = currentY +195 + 'px';
New Fiddle, with dragger exactly aligned to heart
新职位:
dragger.style.left = currentX + 204 + 'px';
dragger.style.top = currentY +199 + 'px';
添加了改进ux的指针:https://jsfiddle.net/4cLpvu2m/
进一步详细说明,使用心脏位置代码:
currentX + radiusPlusOffset - 4, currentY + radiusPlusOffset + 4
并查询浏览器以获取您的展示位置div的位置。然后简单地从x-dragger中减去x,从y-dragger中减去y以获得差异。将差异添加到dragger.style.left等等(碰巧这些数字是~204和199)。
Another fork with alerts indicating x/y position values
杰西卡的更新,删除+/- 4以对齐元素: https://jsfiddle.net/hf5k2ecg/
答案 1 :(得分:1)
在这里添加radiusPlusOffset:
dragger.style.left = currentX + radiusPlusOffset + 'px';
dragger.style.top = currentY + radiusPlusOffset + 'px';
https://jsfiddle.net/qsvmyh3z/1/
同时调整/减去高度&amp;拖动器的宽度指向正确的位置。