Как ограничить движение в области круга - PullRequest
4 голосов
/ 15 декабря 2011

Это может быть скорее вопрос, связанный с геометрией, но я пытаюсь ограничить контроллер в пределах области круга.Я знаю, что должен коснуться методов Math.sin () и Math.cos (), но мои попытки до сих пор были бесплодными.

enter image description here

Вот jsfiddle: До сих пор я был в состоянии ограничить его невидимым квадратом.http://jsfiddle.net/maGVK/

Ответы [ 4 ]

6 голосов
/ 16 декабря 2011

Так что я наконец смог завершить это с небольшой помощью каждого.

var pointerEl = document.getElementById("pointer");
var canvasEl = document.getElementById("canvas");
var canvas = {
    width: canvasEl.offsetWidth,
    height: canvasEl.offsetHeight,
    top: canvasEl.offsetTop,
    left: canvasEl.offsetLeft
};
canvas.center = [canvas.left + canvas.width / 2, canvas.top + canvas.height / 2];
canvas.radius = canvas.width / 2;


window.onmousemove = function(e) {
    var result = limit(e.x, e.y);
        pointer.style.left = result.x + "px";
        pointer.style.top = result.y + "px";
}

function limit(x, y) {
    var dist = distance([x, y], canvas.center);
    if (dist <= canvas.radius) {
        return {x: x, y: y};
    } 
    else {
        x = x - canvas.center[0];
        y = y - canvas.center[1];
        var radians = Math.atan2(y, x)
           return {
               x: Math.cos(radians) * canvas.radius + canvas.center[0],
               y: Math.sin(radians) * canvas.radius + canvas.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));
}

Результат вы можете увидеть здесь:

http://jsfiddle.net/7Asn6/

1 голос
/ 15 декабря 2011

Эта арифметика тривиальна, пока вы нормализуете каждую точку данных (предполагаемое положение), что я пытался сделать в приведенной ниже функции:

function locatePoint(canvas_size, next_position) {
    // canvas_size & next_position are both 2-element arrays
    // (w, h) & (x, y)
    dist = function(x, y) {
        return Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2));
    };
    x = next_position[0];
    y = next_position[1];
    rescaledX = x/(canvas_size[0]/2);
    rescaledY = y/(canvas_size[1]/2);
    if (distance(x, y) <= 1) {
    // the base case; position is w/in the circle
    } 
    else {
    // position is outside the circle, so perhaps
    // do something like random select a new position, then
    // call this function again (recursively) passing in 
    // that new position
    }   
}

поэтому на простой диаграмме ниже я только что вписал единичную окружность (r = 1) в квадрат, стороны которого - r * 2. Ваши размеры холста не должны быть квадратными. Чтобы еще больше упростить вычисление, вам нужно только рассмотреть один из четырех квадрантов - скажем, верхний правый квадрант. Причина в том, что евклидова формула расстояния возводит в квадрат каждое значение координаты, поэтому отрицательные значения становятся положительными.

Другими словами, самый простой способ - представить круг, вписанный в ваш холст, центр которого также является центром вашего холста (поэтому (0, 0) - это центр , а не верхний левый ручной угол); затем холст и круг сжимаются до тех пор, пока у круга не будет радиус = 1. Надеюсь, я уловил это в приведенной выше функции.

enter image description here

1 голос
/ 15 декабря 2011
var pointerEl = document.getElementById("pointer");
var canvasEl = document.getElementById("canvas");
var canvas = {
    width: canvasEl.offsetWidth,
    height: canvasEl.offsetHeight,
    top: canvasEl.offsetTop,
    left: canvasEl.offsetLeft
};
canvas.center = [canvas.left + canvas.width / 2, canvas.top + canvas.height / 2];
canvas.radius = canvas.width / 2;


window.onmousemove = function(e) {
    var result = limit(e.x, e.y);
    if (!result.limit) {
        pointer.style.left = result.x + "px";
        pointer.style.top = result.y + "px";
    }
}

function limit(x, y) {
    var dist = distance([x, y], canvas.center);
    if (dist <= canvas.radius) {
        return {x: x, y: y};
    } else {
        return {limit: true};
    }
}

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));
}  

это могло бы сделать работу, хотя движение не плавное .... это потребует большего знания геометрии ...
скрипка: http://jsfiddle.net/cRxMa/

0 голосов
/ 29 июля 2012

Привет и спасибо, что поделились своим решением.

Ваш jsfiddle очень помогает мне ограничить движение ручки поворота.

Вот мое решение с использованием jQuery:

function getBall(xVal, yVal, dxVal, dyVal, rVal, colorVal) {
  var ball = {
    x: xVal,
    lastX: xVal,
    y: yVal,
    lastY: yVal,
    dx: dxVal,
    dy: dyVal,
    r: rVal,
    color: colorVal,
    normX: 0,
    normY: 0
  };

  return ball;
}

var canvas = document.getElementById("myCanvas");
var xLabel = document.getElementById("x");
var yLabel = document.getElementById("y");
var dxLabel = document.getElementById("dx");
var dyLabel = document.getElementById("dy");

var ctx = canvas.getContext("2d");

var containerR = 200;
canvas.width = containerR * 2;
canvas.height = containerR * 2;
canvas.style["border-radius"] = containerR + "px";

var balls = [
  getBall(containerR, containerR * 2 - 30, 2, -2, 20, "#0095DD"),
  getBall(containerR, containerR * 2 - 50, 3, -3, 30, "#DD9500"),
  getBall(containerR, containerR * 2 - 60, -3, 4, 10, "#00DD95"),
  getBall(containerR, containerR * 2 / 5, -1.5, 3, 40, "#DD0095")
];

function draw() {
  ctx.clearRect(0, 0, canvas.width, canvas.height);

  for (var i = 0; i < balls.length; i++) {
    var curBall = balls[i];
    ctx.beginPath();
    ctx.arc(curBall.x, curBall.y, curBall.r, 0, Math.PI * 2);
    ctx.fillStyle = curBall.color;
    ctx.fill();
    ctx.closePath();
    curBall.lastX = curBall.x;
    curBall.lastY = curBall.y;
    curBall.x += curBall.dx;
    curBall.y += curBall.dy;
    var dx = curBall.x - containerR;
    var dy = curBall.y - containerR;
    var distanceFromCenter = Math.sqrt(dx * dx + dy * dy);

    if (distanceFromCenter >= containerR - curBall.r) {
      var normalMagnitude = distanceFromCenter;
      var normalX = dx / normalMagnitude;
      var normalY = dy / normalMagnitude;
      var tangentX = -normalY;
      var tangentY = normalX;
      var normalSpeed = -(normalX * curBall.dx + normalY * curBall.dy);
      var tangentSpeed = tangentX * curBall.dx + tangentY * curBall.dy;
      curBall.dx = normalSpeed * normalX + tangentSpeed * tangentX;
      curBall.dy = normalSpeed * normalY + tangentSpeed * tangentY;
    }

    xLabel.innerText = "x: " + curBall.x;
    yLabel.innerText = "y: " + curBall.y;
    dxLabel.innerText = "dx: " + curBall.dx;
    dyLabel.innerText = "dy: " + curBall.dy;
  }
  requestAnimationFrame(draw);
}

draw();
canvas { background: #eee; }
<div id="x"></div>
<div id="y"></div>
<div id="dx"></div>
<div id="dy"></div>
<canvas id="myCanvas"></canvas>

Надеюсь, это кому-нибудь поможет.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...