Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 2 years ago.
Improve this question
This seems to be possible in the mobile version of interact.js while I am looking for a solution that works also in standard desktop browser.
I've found one solution on this Blog by bhch
Here is the code:
/*
* Some code borrowed from: https://codepen.io/taye/pen/wrrxKb
*/
interact('.rotation-handle')
.draggable({
onstart: function(event) {
var box = event.target.parentElement;
var rect = box.getBoundingClientRect();
// store the center as the element has css `transform-origin: center center`
box.setAttribute('data-center-x', rect.left + rect.width / 2);
box.setAttribute('data-center-y', rect.top + rect.height / 2);
// get the angle of the element when the drag starts
box.setAttribute('data-angle', getDragAngle(event));
},
onmove: function(event) {
var box = event.target.parentElement;
var pos = {
x: parseFloat(box.getAttribute('data-x')) || 0,
y: parseFloat(box.getAttribute('data-y')) || 0
};
var angle = getDragAngle(event);
// update transform style on dragmove
box.style.transform = 'translate(' + pos.x + 'px, ' + pos.y + 'px) rotate(' + angle + 'rad' + ')';
},
onend: function(event) {
var box = event.target.parentElement;
// save the angle on dragend
box.setAttribute('data-angle', getDragAngle(event));
},
})
function getDragAngle(event) {
var box = event.target.parentElement;
var startAngle = parseFloat(box.getAttribute('data-angle')) || 0;
var center = {
x: parseFloat(box.getAttribute('data-center-x')) || 0,
y: parseFloat(box.getAttribute('data-center-y')) || 0
};
var angle = Math.atan2(center.y - event.clientY,
center.x - event.clientX);
return angle - startAngle;
}
body {
font-family: sans-serif;
}
.box {
width: 150px;
height: 100px;
position: relative;
background-color: #4be091;
border-radius: 6px;
}
.rotation-handle {
padding: 3px 4px;
display: table;
position: absolute;
left: 50%;
right: 50%;
bottom: -35px;
background-color: #ff1661;
border-radius: 10rem;
line-height: 1;
text-align: center;
font-weight: bold;
color: #fff;
cursor: move;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/interact.js/1.2.9/interact.min.js"></script>
<p>
<strong>Rotate the box using the red handle.</strong>
</p>
<div class="box">
<div class="rotation-handle">↻</div>
</div>
Related
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 2 years ago.
Improve this question
I want to create a hand hour. The start position is 0 deg. If i click a button, the hand hour rotate to X deg with animation, and stay here, in X deg.Next time, I click the button, start a new rotation animation, and the hand hour rotate to X + Y deg from X deg, not the start 0 deg. How this operation is possible?
You could get the computed angle, increment it, and then update the CSS using JS.
const hand = document.querySelector('.hand'),
loop = document.querySelector('.loop'),
refreshRate = 60, tickAngle = 3;
let loopId = null;
const startStop = (e) => {
if (loopId) {
clearInterval(loopId); loopId = null;
} else {
loopId = setInterval(tick, 1000 / refreshRate);
}
loop.textContent = loopId ? 'Stop' : 'Start';
};
const tick = () => {
const degrees = (getCurrentAngle(hand) + tickAngle) % 360;
hand.style.transform = `rotate(${degrees}deg)`;
};
// Adapted from:
// https://css-tricks.com/get-value-of-css-rotation-through-javascript/
const getCurrentAngle = (el) => {
const st = window.getComputedStyle(el, null),
tr = st.getPropertyValue('-webkit-transform') ||
st.getPropertyValue('-moz-transform') ||
st.getPropertyValue('-ms-transform') ||
st.getPropertyValue('-o-transform') ||
st.getPropertyValue('transform'),
[a, b] = tr.match(/^matrix\((.+)\)$/)[1].split(/,\s*/g).map(Number);
return Math.round(Math.atan2(b, a) * (180 / Math.PI));
};
loop.addEventListener('click', startStop);
.face {
position: relative;
border: 0.25em solid black;
border-radius: 50%;
width: 8em;
height: 8em;
}
.hand {
position: absolute;
width: 0.25em;
height: 3.5em;
background: red;
left: 4em;
top: 4em;
transform-origin: 0.125em 0; /* x = width / 2 */
transform: rotate(180deg); /* Start at 0th hour */
}
<div class="face">
<div class="hand">
</div>
</div>
<div>
<button class="loop">Start</button>
</div>
I trying to create a map framework for some games and i have a problem with recalc position of marker. Look url to test, with wheel you can resize div with image but the dot red not come back to own position. Sorry but im new on this y trying to learn more about js and css. Thanks
$('.map-live').css('width', "928px");
$('.map-live').css('height', "928px");
$('.map-live').css('background-size', "100%");
$('.map-live').bind('mousewheel DOMMouseScroll', function(event) {
var divSize = $('.map-live').css('width');
console.log(divSize);
divSize = divSize.replace('px', '')
divSize = parseInt(divSize);
console.log("oldSize: " + divSize);
var delta_px = event.originalEvent.wheelDelta > 0 ? (divSize + (divSize * 0.15)) : (divSize - (divSize * 0.15));
console.log("NewSize: " + delta_px);
$(this).css('width', delta_px + "px");
$(this).css('height', delta_px + "px");
$(this).css('background-size', "100%");
UpdatePoints();
});
$(function() {
$("#map-live").draggable();
});
document.getElementById('map-live').addEventListener('click', printPosition)
function getPosition(e) {
var rect = e.target.getBoundingClientRect();
var x = e.clientX - rect.left;
var y = e.clientY - rect.top;
return {
x,
y
}
}
function printPosition(e) {
var position = getPosition(e);
console.log('X: ' + position.x + ' Y: ' + position.y);
var divX = parseInt($('.map-live').css('width').replace('px', ''));
var divY = parseInt($('.map-live').css('height').replace('px', ''));
var vhX = (position.x / divX) * 100;
var vhY = (position.y / divY) * 100;
console.log('vhX: ' + vhX + ' vhY: ' + vhY);
}
function UpdatePoints() {
$('.point').css('top', '2.477565353101834vh');
$('.point').css('left', '2.477565353101834vh');
$('.point').css('position', 'absolute');
}
body {
margin: 0;
overflow: hidden;
}
.map-live {
position: absolute;
left: 10px;
z-index: 9;
background-image: url(https://i.ibb.co/d2y5G1y/map.jpg);
width: 222px;
height: 222px;
transition: all 0.2s linear;
}
.point {
position: absolute;
left: 2.477565353101834vh;
top: 2.477565353101834vh;
width: 10px;
height: 10px;
background-color: red;
border-radius: 50%;
}
<script src="https://code.jquery.com/jquery-1.12.4.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
<div class="map-live ui-widget-content" id="map-live">
<div class="point"></div>
</div>
jsfiddle.net/f84mto52
Someone can correct me, but I believe your use of position: absolute is what is making the <div class="point"></div> stay in place.
Your UpdatePoints is setting always the same position in the div. With 'vh' you are calculating and absolute position proportional to viewport, no to parent container.
So, you are zooming the background image but the position (x, y) will be always be (x, y), positions are not zoomed. You need to recalculate which is the new position.
So you need to calculate new position.
function UpdatePoints(){
var divW = parseInt($('.map-live').css('width').replace('px',''));
var divH = parseInt($('.map-live').css('height').replace('px',''));
var topPosition = (2.477565353101834 / 928) * divH;
var leftPosition = (2.477565353101834 / 928) * divW;
$('.point').css('top', topPosition+'vh');
$('.point').css('left', leftPosition+'vh');
$('.point').css('position', 'absolute');
}
Also, instead using 'vh' I recommend to calculate the px position instead. I have added the already calculated delta_px parameter to UpdatePoints function:
<style>
.point {
position: absolute;
left: 22.99180647678502px;
top: 22.99180647678502px;
width: 10px;
height: 10px;
background-color: red;
border-radius: 50%;
}
</style>
<script>
function UpdatePoints(delta_px){
var position = (delta_px/100)*2.477565353101834;
$('.point').css('top', position+'px');
$('.point').css('left', position+'px');
$('.point').css('position', 'absolute');
}
</script>
Also, here we are calculating the top-left position of the .point element, not the position for the center. As it is a circle, it work fine, but if you use any other shape the position translation should be calculated from its center.
I recommend to do some research about how to translate elements. You can start here:
Calculating relative position of points when zoomed in and enlarged by a rectangle!
Zoom in on a point (using scale and translate)!
How do I effectively calculate zoom scale?!
I am trying to make an element follow the cursor with an added dead zone behaviour.
As long as the cursor moves within a radius of 100 pixels around the element, then the element should not move. Otherwise the element should follow behind the cursor when the 100 pixel radius is exceeded (in any direction). I don't want the orb to catch up with the cursor so it would prevent clicking on other elements, but rather stay on the edge of the dead zone.
In my example, the element is pushed away from the cursor, which is not what I want.
NOTE: I want a native JavaScript solution that doesn't use a library, like jQuery's stop().animate().
const $TheOrb = document.getElementById('TheOrb')
const deadzone = 100
document.addEventListener('mousemove', (event = {}) => {
const x = Math.abs(event.pageX - ($TheOrb.getBoundingClientRect().left + $TheOrb.clientWidth / 2))
const y = Math.abs(event.pageY - ($TheOrb.getBoundingClientRect().top + $TheOrb.clientHeight / 2))
if (x > deadzone || y > deadzone)
$TheOrb.style.transform = `translate(${
event.pageX - $TheOrb.clientWidth / 2 + deadzone // Don't work correctly with dead zone!
}px, ${
event.pageY - $TheOrb.clientHeight / 2 + deadzone // Don't work correctly with dead zone!
}px)`
})
#TheOrb {
position: absolute;
padding: 1em;
background-color: red;
font-size: 1.2em;
font-style: open-sans;
color: #fff;
border: 2px solid #000;
border-radius: 50%;
cursor: pointer;
transition: .1s;
}
<div id="TheOrb">Voff!</div>
New Version
I have made a new version, which uses transform: translate() instead of the left and right properties. It also ensures the orb stops at the deadzone distance when moving towards the cursor. I have also removed transition: 0.2s.
const $TheOrb = document.getElementById('TheOrb');
const deadzone = 100;
let orbX = 0;
let orbY = 0;
document.addEventListener('mousemove', e => {
const x = e.pageX - (orbX + $TheOrb.clientWidth / 2);
const y = e.pageY - (orbY + $TheOrb.clientHeight / 2);
if (x > deadzone) {
orbX = e.pageX - $TheOrb.clientWidth / 2 - deadzone;
} else if (Math.abs(x) > deadzone) {
orbX = e.pageX - $TheOrb.clientWidth / 2 + deadzone;
}
if (y > deadzone) {
orbY = e.pageY - $TheOrb.clientHeight / 2 - deadzone;
} else if (Math.abs(y) > deadzone) {
orbY = e.pageY - $TheOrb.clientHeight / 2 + deadzone;
}
$TheOrb.style.transform = `translate(${orbX}px, ${orbY}px)`;
});
#TheOrb {
position: absolute;
padding: 1em;
background-color: red;
font-size: 1.2em;
font-style: open-sans;
color: #fff;
border: 2px solid #000;
border-radius: 50%;
cursor: pointer;
}
<div id="TheOrb">Voff!</div>
Old Version
I have rewritten the JavaScript to use the CSS left and top properties instead of transform. I have also added transition: 0.2s; to the CSS, so that the orb follows the mouse smoothly.
const $TheOrb = document.getElementById('TheOrb');
const deadzone = 100;
document.addEventListener('mousemove', e => {
const x = Math.abs(e.pageX - (Number($TheOrb.style.left.replace('px', '')) + $TheOrb.clientWidth / 2));
const y = Math.abs(e.pageY - (Number($TheOrb.style.top.replace('px', '')) + $TheOrb.clientHeight / 2));
if (x > deadzone || y > deadzone) {
$TheOrb.style.left = e.pageX - $TheOrb.clientWidth / 2 + 'px';
$TheOrb.style.top = e.pageY - $TheOrb.clientHeight / 2 + 'px';
}
});
#TheOrb {
position: absolute;
padding: 1em;
background-color: red;
font-size: 1.2em;
font-style: open-sans;
color: #fff;
border: 2px solid #000;
border-radius: 50%;
cursor: pointer;
transition: 0.2s;
}
<div id="TheOrb">Voff!</div>
Note: I've asked this question again because I was not be able to edit my old question. (No idea if this was a SO bug or a bug with my beta safari.)
So I want to generate a joystick, as it is used in many games. The joystick stands out of a background and a movable billet. The billet may only be moved within the background.
Here you can find both images
let background = new Image()
let stick = new Image()
let enableMaxDistance = false
background.onload = function() {
$(this).css({
position: "absolute",
left: "2%",
bottom: "2%",
width: "30%"
}).appendTo(document.body)
}
stick.onload = function() {
$(this).css({
position: "absolute",
left: "2%",
bottom: "2%",
width: "30%"
}).appendTo(document.body)
let zeroPosition = $(this).offset()
$(this).draggable({
drag: function(e, ui) {
let distance = Math.sqrt(Math.pow(zeroPosition.top - $(this).offset().top, 2) + Math.pow(zeroPosition.left - $(this).offset().left, 2));
if (distance > 60 && enableMaxDistance) {
e.preventDefault();
}
},
scroll: false
})
}
background.src = "https://i.stack.imgur.com/5My6q.png"
stick.src = "https://i.stack.imgur.com/YEoJ4.png"
html, body {
overflow: hidden;
height: 100%;
}
input {
margin-top: 10%;
margin-left: 50%;
}
<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.min.js"></script>
<input onclick="enableMaxDistance = !enableMaxDistance " value="toggle maximum distance" type="button"/>
But while implementing this joystick some problems occurred:
My idea was to make the stick maneuverable by using jqueryUI and to calculate its distance to the origin with each drag event. If the distance is too large, the event will be stopped (not executed) using e.preventDefault();. --> If the distance in the frame, the stick is wearable.
The problem is that ...
The stick is no longer draggable after moving out the maximum distance.
The stick should be just be movable inside the bounds without canceling the event so that I have to grab the stick again and again if I'm touching the bounds (going out of the maximum distance).
How to implement a working joystick using jQuery + jQueryUI?
The issue with your logic is that as soon as the drag event is prevented the distance value will be over 60 due to the inherent delays in JS processing time. Therefore the logic in the next drag is immediately cancelled as the distance > 60 check is immediately hit. While it would be possible to fix this, a much better solution would be to not allow the value to ever be greater than the limit you set.
To achieve this I would not recommend using jQueryUI. You can do it quite easily using native methods which give you more direct control of the positioning without having to fight against any built in logic.
It's also slightly more performant, which is vital when dealing with game mechanics; especially when dealing with direct user input which needs to be as responsive as possible.
With that said, you can use modify the basic logic as laid out in Twisty's comment on this question. Then it simply becomes a question of changing the size of the relevant elements, which is a trivial task. Try this:
var $canvas = $('#background');
var $pointer = $('#stick');
var $window = $(window);
var settings = {
width: $canvas.prop('offsetWidth'),
height: $canvas.prop('offsetHeight'),
top: $canvas.prop('offsetTop'),
left: $canvas.prop('offsetLeft')
};
settings.center = [settings.left + settings.width / 2, settings.top + settings.height / 2];
settings.radius = settings.width / 2;
let mousedown = false;
$window.on('mouseup', function() { mousedown = false; });
$pointer.on('mousedown', function() { mousedown = true; });
$pointer.on('mouseup', function() { mousedown = false; });
$pointer.on('dragstart', function(e) { e.preventDefault(); });
$window.on('mousemove', function(e) {
if (!mousedown)
return;
var result = limit(e.clientX, e.clientY);
$pointer.css('left', result.x + 'px');
$pointer.css('top', result.y + 'px');
});
function limit(x, y) {
var dist = distance([x, y], settings.center);
if (dist <= settings.radius) {
return {
x: x,
y: y
};
} else {
x = x - settings.center[0];
y = y - settings.center[1];
var radians = Math.atan2(y, x)
return {
x: Math.cos(radians) * settings.radius + settings.center[0],
y: Math.sin(radians) * settings.radius + settings.center[1]
}
}
}
function distance(dot1, dot2) {
var x1 = dot1[0],
y1 = dot1[1],
x2 = dot2[0],
y2 = dot2[1];
return Math.sqrt(Math.pow(x1 - x2, 2) + Math.pow(y1 - y2, 2));
}
html,
body {
height: 100%;
}
#background {
background-image: url('https://i.stack.imgur.com/5My6q.png');
position: absolute;
height: 200px;
width: 200px;
top: 50%;
left: 50%;
margin: -100px 0 0 -100px;
border-radius: 200px;
border: dashed #ccc 1px;
}
#stick {
background: transparent url('https://i.stack.imgur.com/YEoJ4.png') 50% 50%;
position: absolute;
width: 100px;
height: 100px;
border-radius: 100px;
margin: -50px 0 0 -50px;
top: 50%;
left: 50%;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="background"></div>
<div id="stick"></div>
I was playing around with JavaScript/canvas and I want my objects color to depend on the distance to its center from current mouse position.This is my current function that gets color every mousemove event:
function getColorFromDistance(node1,node2){
var dist = getDist(node1,node2); //Getting distance;
var cl = (Math.round(255/dist*255)).toString(16); //this needs to be a propper formula
return "#" + cl + cl + cl; //converting to hex
}
Currently I get a blink effect when the distance gets 255.
I need a way to get the colors strength be depended on the distance, so that the further mouse is away from object the more its darken and when mouse is on the objects center its fully white.Well you get the idea.I just need the formula
The formula would be calculate the distance between the two points and get a percentage based on the maximum value (width of canvas/window)
//this would need to be recalulated on resize, but not doing it for demo
var targetElem = document.querySelector("div.x span");
box = targetElem.getBoundingClientRect(),
x = box.left + box.width/2,
y = box.top + box.height/2,
winBox = document.body.getBoundingClientRect(),
maxD = Math.sqrt(Math.pow(winBox.width/2, 2) + Math.pow(winBox.height/2, 2));
document.body.addEventListener("mousemove", function (evt) {
var diffX = Math.abs(evt.pageX-x),
diffY = Math.abs(evt.pageY-y),
distC = Math.sqrt(Math.pow(diffX, 2) + Math.pow(diffY, 2)),
strength = Math.ceil(255 - (distC/maxD*255)).toString(16),
color = "#" + strength + strength + strength;
targetElem.style.backgroundColor = color;
});
html, body { height: 100%; }
div.x { position: absolute; top: 50%; left:50%; }
span { display: inline-block; width: 20px; height: 20px; border-radius: 50%; border: 1px solid black; overflow: hidden; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<p>Test</p>
<div class="x"><span> </span></div>