I'm looking at this example (jsfiddle). It's almost what I need, but I need the user to "grab" the roulette with the mouse, then spin it, like you would do with a real one with your hand.
Like, you click and hold on the wheel, it "sticks" to your mouse, then you move your mouse to left or right, and release the button, and the wheel starts to spin until it stops.
Another question is, even if the user is doing that, can I choose a predetermined order to the wheel stops?
This is the jsFiddle:
$(function(){
var overWheel = false;
var mouseDown = false;
var lastMousePos = 0;
$('.wheel').on('mouseover', function(){
overWheel = true;
}).on('mouseout', function(){
overWheel = false;
});
$(document).on('mousedown', function(e){
if(overWheel){
lastMousePos = e.offsetY;
mouseDown = true;
}
}).on('mouseup', function(){
mouseDown = false;
});
$(document).on('mousemove', function(e){
if(overWheel && mouseDown){
handleWheel(e);
}
});
function handleWheel(e) {
var yPos = e.offsetY;
var direction = 0;
var deg = getRotationDegrees($('.wheel'));
if(yPos < lastMousePos){ // mouse is going up, move against the clock
console.log(yPos);
direction = -2;
} else { //mouse is going down, move with the clock
direction = 2;
}
$('.wheel').css({'-webkit-transform': 'rotate(' + (deg + (direction)) + 'deg)'});
}
function getRotationDegrees(obj){
var matrix = obj.css("-webkit-transform");
if(matrix !== 'none') {
var values = matrix.split('(')[1].split(')')[0].split(',');
var a = values[0];
var b = values[1];
var angle = Math.round(Math.atan2(b, a) * (180/Math.PI));
} else { var angle = 0; }
return angle;
}
});
I've managed to work.
I Used the jQuery Rotate library.
Thanks!
Related
I'm trying to create some "flick" like functionality. Instead of just dragging an item across the screen, I'd like to drag and throw/release it to a location. Any idea how to accomplish this?
Sorry I don't have any code snippets here...but I just don't know where to even start.
Thanks!
--moe
You can use the mousedown, mousemove and mouseup event handlers to get the mouse events with the cursor positions at which they happened. You'd need to store the current cursor position (startCursorPos) and the element position (startElementPos) at mousedown. At each mousemove event, you can calculate the difference between the current cursor position and startCursorPos, and add the result to startElementPos, and use the result as new element position. This will implement a basic drag-and-drop behaviour.
To get the flinging, you need to also record the current time at mousedown and mouseup. Combined with the positions, you'll be able to calculate the movement speed, and use this at mouseup to continue the movement for some time (e.g. using setInterval).
var foo=document.getElementById("foo");
var isMoving, startCursorPos, startElementPos, startTime, newPos;
function Point(x,y) {
this.x=x; this.y=y;
}
Point.fromElement=function(el) {
return new Point(parseInt(el.style.left), parseInt(el.style.top));
}
Point.sum = function(a,b) {
return new Point(a.x+b.x, a.y+b.y);
}
Point.difference = function(a,b) {
return new Point(a.x-b.x, a.y-b.y);
}
Point.prototype.multiply = function(factor) {
return new Point(this.x*factor, this.y*factor);
}
Point.prototype.distance = function() {
return Math.sqrt(this.x*this.x + this.y*this.y);
}
Point.prototype.toString = function() {
return this.x + "x" + this.y;
}
Point.prototype.moveElement = function(el) {
el.style.left = this.x + "px"; el.style.top = this.y + "px";
}
foo.addEventListener("mousedown", function(e) {
startCursorPos = new Point(e.pageX, e.pageY);
startElementPos = Point.fromElement(foo);
startTime = +new Date();
isMoving=true;
},false);
window.addEventListener("mousemove", function(e) {
if (isMoving) {
var cursorpos = new Point(e.pageX, e.pageY);
newPos = Point.sum(startElementPos, Point.difference(cursorpos, startCursorPos));
//console.log(startElementPos, cursorpos, newPos);
newPos.moveElement(foo);
}
},false);
window.addEventListener("mouseup", function(e) {
if (isMoving) {
isMoving=false;
var cursorpos = new Point(e.pageX, e.pageY);
var interval = +new Date() - startTime;
var movement = Point.difference(cursorpos, startCursorPos).multiply(1/interval);
var speed = movement.distance();
console.log(interval, speed, ""+movement);
moveOn(newPos, movement, speed);
}
},false);
function moveOn(startPos, movement, speed) {
startPos = Point.sum(startPos, movement.multiply(speed*200))
startPos.moveElement(foo);
if (speed > 10)
setTimeout(function() {
moveOn(startPos, movement, speed/2);
}, 100);
}
#foo { position:absolute; width:50px;height:50px; background:magenta; }
<div id="foo" style="top:50px; left:50px;"></div>
When the content goes outside the div, we use scrollbars to see it. How can I scroll the div content by grabbing and dragging its background? I've searched the solution but did not find what I need. Here is my fiddle:
https://jsfiddle.net/vaxobasilidze/xhn49e1j/
Drag any item to the right div and move it outside the container to the right or bottom. scrollbars appear to help you to scroll. Here is an example of what I want to achieve. See the first diagram on the link and drag it:
https://jsplumbtoolkit.com/
Any tips on how to do this?
You should just need to detect when the mouse is down and then when the mouse is moving afterwards you can store the previous mouse coordinates and reference the current coordinates. Finally you can scroll the div in question by an amount based on the difference in drag since the last mousemove call.
var mouseDown = false;
var prevCoords = { x: 0, y: 0 };
$("#mainDiv").mousedown(function() {
mouseDown = true;
}).mousemove(function(e) {
var currentScrollX = $('#mainDiv').scrollLeft();
var currentScrollY = $('#mainDiv').scrollTop();
if(mouseDown) {
$('#mainDiv').scrollLeft(currentScrollX + prevCoords.x - (e.clientX + currentScrollX))
$('#mainDiv').scrollTop(currentScrollY + prevCoords.y - e.clientY)
};
prevCoords.x = e.clientX + currentScrollX;
prevCoords.y = e.clientY;
}).mouseup(function() {
mouseDown = false;
});
https://jsfiddle.net/6rx30muh/
EDIT: Fixed bug with wiggling tables when dragging:
var mouseDown = false;
var prevCoords = { x: 0, y: 0 };
$("#mainDiv").mousedown(function() {
mouseDown = true;
}).mousemove(function(e) {
var currentScrollX = $('#mainDiv').scrollLeft();
var currentScrollY = $('#mainDiv').scrollTop();
if(mouseDown) {
$('#mainDiv').scrollLeft(currentScrollX + prevCoords.x - e.clientX)
$('#mainDiv').scrollTop(currentScrollY + prevCoords.y - e.clientY)
};
prevCoords.x = e.clientX;
prevCoords.y = e.clientY;
}).mouseup(function() {
mouseDown = false;
});
Check for mousemove between mousedown and mouseup on the body element is a good place to start.
element = $('body');
element.addEventListener("mousedown", function(){
flag = 0;
}, false);
element.addEventListener("mousemove", function(){
flag = 1;
}, false);
element.addEventListener("mouseup", function(){
if(flag === 0){
console.log("click");
}
else if(flag === 1){
console.log("drag");
}
}, false);
What I mean is that the user presses a mouse button at point xy on an HTML canvas and while the mouse button is pressed the rectangle can be resized according to the movement of the cursor with point xy fixed. Like how highlighting works.
This is what I've got so far but it doesn't seem to be working:
canvas.addEventListener('mousedown', function(e){
var rectx = e.clientX;
var recty = e.clientY;
canvas.onmousemove = function(e){
var df = e.clientX;
var fg = e.clientY;
};
context.rect(rectx, recty, df-rectx, fg-recty);
context.stroke();
}, false);
Assuming there are no transforms (scale, translate) on your canvas context.
Basic steps for having a resizable rectangle are as follows:
Create a mousedown listener that sets a flag indicating the use is holding down the mouse button, as well as sets the "anchor," or initial coordinates.
Create a mouseup listener that unsets the flag.
Create a mousemove listener that, if the flag indicates the mouse is down, redraws the canvas with the rectangle's size changed according to mouse coordinates.
An important note is that client coordinates in the event object are relative to the page, not to your canvas element. You will frequently need to convert clientX and clientY into canvas coordinates:
var getCanvasCoords = function (clientX, clientY) {
var rect = canvas.getBoundingClientRect();
return {
x: clientX - rect.left,
y: clientY - rect.top
};
};
The first two steps look something like this:
var anchorX;
var anchorY;
var mouseDown = false;
canvas.addEventListener('mousedown', function (event) {
var coords = getCanvasCoords(event.clientX, event.clientY);
anchorX = coords.x;
anchorY = coords.y;
mouseDown = true;
});
canvas.addEventListener('mouseup', function (event) {
mouseDown = false;
});
And the mousemove handler:
canvas.addEventListener('mousemove', function (event) {
var coords = getCanvasCoords(event.clientX, event.clientY);
var width = coords.x - anchorX;
var height = coords.y - anchorY;
// clear canvas for redrawing
context.clearRect(0, 0, canvas.width, canvas.height);
context.fillRect(anchorX, anchorY, width, height);
});
Don't Render from mouse events!
The given answer is correct but it is not the best way to do this.
The are two reasons. First the mousemove event can fire up to 600+ times a second but the display only refreshes 60 times a second. Rendering from the input event is many time just a waste of CPU time as the results will be overwritten by the next mouse event before it is ever had a chance to be displayed.
The second reason is that dedicating an event listener to a single task makes it hard to add more functionality. You end up adding more and more code to the mousemove event to handle all the types of input, most of which can be ignored because of the high update speed of the mouse.
Mouse listeners
Mouse event listeners do the minimum possible. They just record the mouse state and no more. Also all mouse events return the mouse position. You should not ignore the mouse position for events like mouse down and up
The following function creates a mouse object for a element. The mouse object has the x,y position relative to the to left of the element, and the current button states for 3 buttons it is left to right button1, button2, button3.
Also when the mouse leaves the element and then releases the mouse button the mouse for the element will not see the mouseup event and not know the mouse button is up. To prevent the mouse buttons from getting stuck you turn off the buttons when the mouse leaves the element.
The best mouse listener is to the whole page as it can track mouse events that happen even when the mouse is outside the window/tab (if the window/tab has focus), but that is a little to complex for this answer.
Function to create a mouse for an element
function createMouse(element){
var mouse = {
x : 0,
y : 0,
button1 : false,
button2 : false,
button3 : false,
over : false,
};
function mouseEvent(event){
var bounds = element.getBoundingClientRect();
mouse.x = event.pageX - bounds.left - scrollX;
mouse.y = event.pageY - bounds.top - scrollY;
if(event.type === "mousedown"){
mouse["button"+event.which] = true;
} else if(event.type === "mouseup"){
mouse["button"+event.which] = false;
} else if(event.type === "mouseover"){
mouse.over = true;
} else if(event.type === "mouseout"){
mouse.over = false;
mouse.button1 = false; // turn of buttons to prevent them locking
mouse.button2 = false;
mouse.button3 = false;
}
event.preventDefault(); // stops default mouse behaviour.
}
var events = "mousemove,mousedown,mouseup,mouseout,mouseover".split(',');
events.forEach(eventType => element.addEventListener(eventType,mouseEvent));
mouse.remove = function(){
events.forEach(eventType => element.removeEventListener(eventType, mouseEvent));
}
return mouse;
}
Using the mouse
It is now just a matter of creating a mouse for the element
var canMouse = createMouse(canvas);
And then in your main render loop do the dragging.
var drag = {
x : 0,
y : 0,
x1 : 0,
y1 : 0,
dragging : false,
top : 0,
left : 0,
width : 0,
height : 0,
}
function mainLoop(){
if(canMouse.button1){ // is button down
if(!drag.dragging){ // is dragging
drag.x = canMouse.x;
drag.y = canMouse.y;
drag.dragging = true;
}
drag.x1 = canMouse.x;
drag.y1 = canMouse.y;
drag.top = Math.min(drag.y, drag.y1);
drag.left = Math.min(drag.x, drag.x1);
drag.width = Math.abs(drag.x - drag.x1);
drag.height = Math.abs(drag.y - drag.y1);
}else{
if(drag.dragging){
drag.dragging = false;
}
}
}
Putting it all together
function createMouse(element){
var mouse = {
x : 0,
y : 0,
button1 : false,
button2 : false,
button3 : false,
over : false,
};
function mouseEvent(event){
var bounds = element.getBoundingClientRect();
// NOTE getting the border should not be done like this as
// it will not work in all cases.
var border = Number(element.style.border.split("px")[0])
mouse.x = event.pageX - bounds.left - scrollX - border;
mouse.y = event.pageY - bounds.top - scrollY - border;
if(event.type === "mousedown"){
mouse["button"+event.which] = true;
} else if(event.type === "mouseup"){
mouse["button"+event.which] = false;
} else if(event.type === "mouseover"){
mouse.over = true;
} else if(event.type === "mouseout"){
mouse.over = false;
mouse.button1 = false; // turn of buttons to prevent them locking
mouse.button2 = false;
mouse.button3 = false;
}
event.preventDefault(); // stops default mouse behaviour.
}
var events = "mousemove,mousedown,mouseup,mouseout,mouseover".split(',');
events.forEach(eventType => element.addEventListener(eventType,mouseEvent));
mouse.remove = function(){
events.forEach(eventType => element.removeEventListener(eventType, mouseEvent));
}
return mouse;
}
var drag = {
x : 0,
y : 0,
x1 : 0,
y1 : 0,
dragging : false,
top : 0,
left : 0,
width : 0,
height : 0,
}
var ctx = canvas.getContext("2d");
ctx.strokeStyle = "black";
ctx.lineWidth = 1;
var mouse = createMouse(canvas);
function update(){
ctx.clearRect(0,0,canvas.width,canvas.height);
if(mouse.button1){ // is button down
if(!drag.dragging){ // is dragging
drag.x = mouse.x;
drag.y = mouse.y;
drag.dragging = true;
}
drag.x1 = mouse.x;
drag.y1 = mouse.y;
drag.top = Math.min(drag.y, drag.y1);
drag.left = Math.min(drag.x, drag.x1);
drag.width = Math.abs(drag.x - drag.x1);
drag.height = Math.abs(drag.y - drag.y1);
}else{
if(drag.dragging){
drag.dragging = false;
}
}
if(drag.dragging){
ctx.strokeRect(drag.left, drag.top, drag.width, drag.height);
}
requestAnimationFrame(update);
}
requestAnimationFrame(update);
canvas {
border : 1px solid black;
}
Click drag to draw rectangle.<br>
<canvas id="canvas" width= "512" height = "256"></canvas>
getMouseXY = function(e) {
tempX = e.pageX
tempY = e.pageY
if (tempX < 0){tempX = 0}
if (tempY < 0){tempY = 0}
document.getElementById("circle1").style.top = (tempY - 25) + "px";
document.getElementById("circle1").style.left = (tempX - 25) + "px";
return true
}
document.onmousemove = getMouseXY;
trackCircle = function() {
document.getElementById("circle1").style.top = "10px";
document.getElementById("circle1").style.left = "10px";
}
document.getElementById("circle1").addEventListener("click", trackCircle);
<div id="circle1" style="width:50px;height:50px;background-color:orange;border-radius:50px;position:absolute;"></div>
The idea is the circle tracks your mouse wherever it goes, until you click, then it goes back to its resting spot. The problem is, when I move the mouse again it undoes the resting position, and returns to tracking the document.onmousemove The plan is for it to only resume tracking, once in rest, after you re-hover "circle1" ... and then resumes tracking with document.onmousemove
I know I could call something like this instead of document.onmousemove:
document.getElementById("circle1").addEventListener('mousemove', getMouseXY);
But the "is the mouse hovering over this specific element?" event is to imprecise and you end up losing your tracking a lot when you move the mouse around quickly.
Seems like I need to build some kind of state machine where its either trackingON or trackingOFF. Where trackingOFF is triggered by clicking the circle and trackingON is triggered by hovering the circle (but then the actual tracking uses document.onmousemove
You need a flag to specify that "I have clicked, stop tracking my mouse" to be set when you click and a check to say "I have moved my mouse over the circle, resume tracking me"
Here is the updated fiddle: http://jsfiddle.net/ub9v9p0j/8/
and the actual code:
var stopTracking = false;
getMouseXY = function(e) {
tempX = e.pageX
tempY = e.pageY
var circle = document.querySelector('#circle1');
var r = circle.offsetWidth / 2;
if (tempX < 0){tempX = 0}
if (tempY < 0){tempY = 0}
if (stopTracking) {
if (Math.pow(tempX - circle.offsetLeft - r, 2) + Math.pow(tempY - circle.offsetTop - r, 2) < r * r) {
stopTracking = false;
} else {
return;
}
}
document.getElementById("circle1").style.top = (tempY - 25) + "px";
document.getElementById("circle1").style.left = (tempX - 25) + "px";
return true
}
document.onmousemove = getMouseXY;
trackCircle = function() {
document.getElementById("circle1").style.top = "10px";
document.getElementById("circle1").style.left = "10px";
stopTracking = true;
}
document.getElementById("circle1").addEventListener("click", trackCircle);
seems like I cannot find a solution for this. Please Help me out.
What I want to do is to have a simple volume slider.
SO, as you can see the orange part is my volume slider.
This is my jQuery:
var mouseDown = false;
$("#volSlider").mousedown(function() { mouseDown = true; });
$("#volSlider").mouseup(function() { mouseDown = false; });
$("#volSlider").mouseleave(function() { mouseDown = false; });
$("#controlVolume").mousemove(function(e)
{
if (mouseDown == true)
{
var caretFromTop = $("#volCaret").position().top;
var areaHeight = $("#volSlider").height();
var volume = (caretFromTop / areaHeight) * 100;
volume = Math.round(volume);
$("#volCaret").css("bottom", volume);
$("#volText").text(volume);
if (volume <= 100 && volume >= 0)
{
//To be added.
}
}
});
EDIT: For those who want to see my HTML:
<div id="controlVolume">
<div id="volSlider">
<div id="volCaret"></div>
</div>
<div id="volText"></div>
</div>
When i try to drag the caret to the top, it just goes to "1" and not further. Anything I am missing? Thanks in advance.
What you actually want to do is track the Y vertex of the mouse, not the height of the caret (well, technically yes - the height of the caret that changes between the mouse moves). You're currently tracking the position of the volume bar, which doesn't change.
As such your code should be something like this:
var mousePos = 0;
var mouseDown = false;
var height = 0;
$("#volSlider").mousedown(function(e) { mouseDown = true; mousePos = e.pageY; height = $("#volCaret").height(); });
$("#volSlider").mouseup(function() { mouseDown = false; mousePos = 0 });
$("#volSlider").mouseleave(function() { mouseDown = false; mousePos = 0 });
$("#controlVolume").mousemove(function(e)
{
if (mouseDown == true)
{
var areaHeight = $("#volSlider").height();
var caretHeight = height + (e.pageY - mousePos);
$("#volCaret").height(caretHeight );
var volume = caretHeight / areaHeight * 100;
console.log(volume);
}
});
It would be great if you'd put your code on jsfiddle, as probably there's something I've not thought of and this code fails horribly.