js перемещение стрелки(угол) в полукруге на координату щелчка
Есть подобие спидометра, полукруг(1-1000 значения) со стрелкой. Она стоит в некотором положении (.png). При щелчке на полукруге того как бы спидометра стрелка должна встать в ту позицию и значение запоминается.
Как это нормально сделать?
Пытаюсь вычислить угол https://m.fxyz.ru/2/70/71/451/ https://www.cyberforum.ru/javascript/thread914317.html, чтоб перемещать с css rotate но и того не выходит.
const touchSupport = 'ontouchstart' in document.documentElement;
const slider = document.getElementsByClassName('visualizer')[0];
const handle = document.getElementsByClassName('visualizer__arrow')[0];
//const sliderInput = document.getElementsByClassName('slider__value')[0];
const sliderWidth = parseInt(getComputedStyle(slider).width, 10);
const sliderHeight = parseInt(getComputedStyle(slider).height, 10);
const sliderOffsetLeft = slider.getBoundingClientRect().left;
const sliderOffsetTop = slider.offsetTop;
let isMouseDown = false;
let mouseX;
let mouseY;
let handlePosition;
let sliderValue;
function getMouseX(ev) {
return sliderWidth / 2 - (ev.pageX - slider.offsetLeft);
}
function getMouseY(ev) {
return ev.pageY - slider.offsetTop;
}
function mouseToPointsComparer() {
//handle.style.transform = "rotate(" + Math.abs(260 + mouseX) + "deg)";
handle.style.transform = "rotate(" + Math.round(Math.cos(mouseY/(125 - mouseX)) * 180 / Math.PI) + "deg)";
console.log("+_+"+Math.round(Math.cos((mouseY/(125 - mouseX)) * 180 / Math.PI)))
//console.log( Math.sin(mouseY/(125 - mouseX)) * 180 / Math.PI );
//console.log(Math.atan2(mouseY, (125 - mouseX)) +"+++"+(mouseY/(125 - mouseX)) +"_"+Math.tan(mouseY/(125 - mouseX) ) );
//slider.setAttribute('data-value', sliderValue);
//sliderInput.value = sliderValue;
}
function moveHandle(ev) {
mouseX = getMouseX(ev);
mouseY = getMouseY(ev);
}
function cancelPageTouchmove(ev) {
ev.preventDefault();
}
['mousedown', 'touchstart'].forEach(item => {
slider.addEventListener(item, () => {
isMouseDown = true;
if (touchSupport) {
document.addEventListener('touchmove', cancelPageTouchmove, {passive: false});
}
else {
document.onselectstart = () => {return false;};
}
});
});
['mousemove', 'touchmove'].forEach(item => {
document.addEventListener(item, moveHandle, false);
});
['mouseup', 'touchend'].forEach(item => {
document.addEventListener(item, () => {
if (isMouseDown) {
isMouseDown = false;
if (touchSupport) {
document.removeEventListener('touchmove', cancelPageTouchmove, false);
}
else {
document.onselectstart = () => {return true;};
}
mouseToPointsComparer();
}
});
});
['click', 'mousedown', 'touchstart'].forEach(item => {
slider.addEventListener(item, ev => {
mouseX = getMouseX(ev);
mouseY = getMouseY(ev);
mouseToPointsComparer();
});
});
Ответы (1 шт):
Автор решения: Stranger in the Q
→ Ссылка
Как-то так:
var deg = Math.atan2(
mouseY,
mouseX
) + Math.PI;
+PI - это разворот на 180 градусов, необходим чтобы компенсировать то, что ось Y в математике направлен вверх, а на канве - вниз
const touchSupport = 'ontouchstart' in document.documentElement;
const slider = document.getElementsByClassName('visualizer')[0];
const handle = document.getElementsByClassName('visualizer__arrow')[0];
let ic = document.querySelector('.visualizer__innerCircle')
const sliderWidth = parseInt(getComputedStyle(slider).width, 10);
const sliderHeight = parseInt(getComputedStyle(slider).height, 10);
const sliderOffsetLeft = slider.getBoundingClientRect().left;
const sliderOffsetTop = slider.offsetTop;
let isMouseDown = false;
let mouseX;
let mouseY;
let handlePosition;
let sliderValue;
function getMouseX(ev) {
let r = ic.getBoundingClientRect();
return ev.clientX - r.x - r.width/2;
}
function getMouseY(ev) {
let r = ic.getBoundingClientRect();
return ev.clientY - r.y - r.height/2;
}
function mouseToPointsComparer() {
var deg = Math.atan2(
mouseY,
mouseX
) + Math.PI;
handle.style.transform = "rotate(" + deg + "rad)";
}
function moveHandle(ev) {
mouseX = getMouseX(ev);
mouseY = getMouseY(ev);
}
function cancelPageTouchmove(ev) {
ev.preventDefault();
}
['mousedown', 'touchstart'].forEach(item => {
slider.addEventListener(item, () => {
isMouseDown = true;
if (touchSupport) {
document.addEventListener('touchmove', cancelPageTouchmove, {
passive: false
});
} else {
document.onselectstart = () => {
return false;
};
}
});
});
['mousemove', 'touchmove'].forEach(item => {
document.addEventListener(item, moveHandle, false);
});
['mouseup', 'touchend'].forEach(item => {
document.addEventListener(item, () => {
if (isMouseDown) {
isMouseDown = false;
if (touchSupport) {
document.removeEventListener('touchmove', cancelPageTouchmove, false);
} else {
document.onselectstart = () => {
return true;
};
}
mouseToPointsComparer();
}
});
});
['click', 'mousedown', 'touchstart'].forEach(item => {
slider.addEventListener(item, ev => {
mouseX = getMouseX(ev);
mouseY = getMouseY(ev);
mouseToPointsComparer();
});
});
.visualizer__level {
-webkit-transform: scale(1.69, 1.7);
-moz-transform: scale(1.69, 1.7);
-ms-transform: scale(1.69, 1.7);
-o-transform: scale(1.69, 1.7);
transform: scale(1.69, 1.7);
position: relative;
top: 0;
left: 386px;
}
.visualizer__pie {
-webkit-transition: all 1s;
-o-transition: all 1s;
-moz-transition: all 1s;
transition: all 1s;
position: absolute;
width: 150px;
height: 150px;
-webkit-border-radius: 75px;
-moz-border-radius: 75px;
border-radius: 75px;
clip: rect(0px, 75px, 150px, 0px);
}
.visualizer__hold {
position: absolute;
width: 150px;
height: 150px;
-webkit-border-radius: 75px;
-moz-border-radius: 75px;
border-radius: 75px;
clip: rect(0px, 150px, 150px, 75px);
}
.visualizer__pieSlice1 {
-webkit-transform: rotate(-33deg);
-moz-transform: rotate(-33deg);
-ms-transform: rotate(-33deg);
-o-transform: rotate(-33deg);
transform: rotate(-33deg);
}
.visualizer__pieSlice1 .visualizer__pie {
background: #a3cd3b;
-webkit-transform: rotate(68deg);
-moz-transform: rotate(68deg);
-ms-transform: rotate(68deg);
-o-transform: rotate(68deg);
transform: rotate(68deg);
}
.visualizer__pieSlice2 {
-webkit-transform: rotate(39deg);
-moz-transform: rotate(39deg);
-ms-transform: rotate(39deg);
-o-transform: rotate(39deg);
transform: rotate(39deg);
}
.visualizer__pieSlice2 .visualizer__pie {
background-color: #fb93d7;
-webkit-transform: rotate(51deg);
-moz-transform: rotate(51deg);
-ms-transform: rotate(51deg);
-o-transform: rotate(51deg);
transform: rotate(51deg);
}
.visualizer__pieSlice3 {
-webkit-transform: rotate(270deg);
-moz-transform: rotate(270deg);
-ms-transform: rotate(270deg);
-o-transform: rotate(270deg);
transform: rotate(270deg);
}
.visualizer__pieSlice3 .visualizer__pie {
background-color: #33c815;
-webkit-transform: rotate(53deg);
-moz-transform: rotate(53deg);
-ms-transform: rotate(53deg);
-o-transform: rotate(53deg);
transform: rotate(53deg);
}
.visualizer__innerCircle {
position: absolute;
width: 85px;
height: 85px;
background-color: #fff;
-webkit-border-radius: 60px;
-moz-border-radius: 60px;
border-radius: 60px;
top: 32px;
left: 34px;
color: white;
}
.visualizer__arrow {
position: absolute;
bottom: 48px;
left: 283px;
width: 57px;
height: 39px;
border: 1px solid red;
border-left: 1px solid blue;
content: "";
background-image: url("../images/arrow.png");
-webkit-transform-origin: -webkit-calc(100% - 8px) -webkit-calc(100% - 8px);
-moz-transform-origin: -moz-calc(100% - 8px) -moz-calc(100% - 8px);
-ms-transform-origin: calc(100% - 8px) calc(100% - 8px);
-o-transform-origin: calc(100% - 8px) calc(100% - 8px);
transform-origin: 50% 50%;
-webkit-transition: all 0.5s;
-o-transition: all 0.5s;
-moz-transition: all 0.5s;
transition: all 0.5s;
}
<div class="js-level__visualizer visualizer">
<div class="visualizer__level">
<div class="visualizer__pieSlice1 visualizer__hold">
<div class="visualizer__pie"></div>
</div>
<div class="visualizer__pieSlice2 visualizer__hold">
<div class="visualizer__pie"></div>
</div>
<div class="visualizer__pieSlice3 visualizer__hold">
<div class="visualizer__pie"></div>
</div>
<div class="visualizer__innerCircle"></div>
</div>
<div class="visualizer__arrow"></div>
</div>