26.03.2018, 21:24
|
Интересующийся
|
|
Регистрация: 26.03.2018
Сообщений: 25
|
|
Drag and Drop, пересечение полигонов
Здравствуйте, учу js, на данный момент изучаю работу с DOM. Реализовываю Drag and Drop с полигонами, при пересечении полигонов, необходимо чтобы пересекаемые полигоны становились красными, не могу понять в почему работает только с с первым объектом из массива, может подскажет кто??
window.onload = function () {
var canvas = document.getElementById('lienzo');
if (canvas && canvas.getContext) {
var ctx = canvas.getContext('2d');
if (ctx) {
width = canvas.width = window.innerWidth - 5;
height = canvas.height = window.innerHeight - 5;
var isDragging = false;
var delta = new Object();
function drawPoligon(poligon) {
ctx.beginPath();
ctx.moveTo(poligon.points[0].x, poligon.points[0].y);
for (var i = 1; i < poligon.points.length; i++) {
ctx.lineTo(poligon.points[i].x, poligon.points[i].y);
}
ctx.closePath();
ctx.fill();
}
function updatePoligon(star) {
for (var i = 0; i < star.points.length; i++) {
star.points[i].x = star.x + star.offset[i].x;
star.points[i].y = star.y + star.offset[i].y;
}
}
function updatePoligons() {
for (var i = 0; i < list.length; i++) {
updatePoligon(list[i]);
}
}
function drawPoligons() {
for (var i = 0; i < list.length; i++) {
drawPoligon(list[i]);
}
}
var list = [
{
'x': 50,
'y': 100,
'color': '#3F51B5',
'points': [
{ 'x': 0, 'y': 0 },
{ 'x': 0, 'y': 0 },
{ 'x': 0, 'y': 0 },
{ 'x': 0, 'y': 0 },
],
'offset': [
{ 'x': 50, 'y': 0 },
{ 'x': 5, 'y': -48 },
{ 'x': -40, 'y': 0 },
{ 'x': 5, 'y': 48 },
],
'bool': false
},
{
'x': 50,
'y': 200,
'color': '#3F51B5',
'points': [
{ 'x': 0, 'y': 0 },
{ 'x': 0, 'y': 0 },
{ 'x': 0, 'y': 0 },
{ 'x': 0, 'y': 0 },
{ 'x': 0, 'y': 0 },
{ 'x': 0, 'y': 0 },
],
'offset': [
{ 'x': 25, 'y': -48 },
{ 'x': -15, 'y': -48 },
{ 'x': -40, 'y': 0 },
{ 'x': -15, 'y': 48 },
{ 'x': 25, 'y': 48 },
{ 'x': 50, 'y': 0 },
],
'bool': false
},
{
'x': 50,
'y': 300,
'color': '#3F51B5',
'points': [
{ 'x': 0, 'y': 0 },
{ 'x': 0, 'y': 0 },
{ 'x': 0, 'y': 0 },
{ 'x': 0, 'y': 0 },
{ 'x': 0, 'y': 0 },
{ 'x': 0, 'y': 0 },
{ 'x': 0, 'y': 0 },
{ 'x': 0, 'y': 0 },
{ 'x': 0, 'y': 0 },
{ 'x': 0, 'y': 0 }
],
'offset': [
{ 'x': 50, 'y': 0 },
{ 'x': 20, 'y': 14 },
{ 'x': 15, 'y': 48 },
{ 'x': -8, 'y': 24 },
{ 'x': -40, 'y': 29 },
{ 'x': -25, 'y': 0 },
{ 'x': -40, 'y': -29 },
{ 'x': -8, 'y': -24 },
{ 'x': 15, 'y': -48 },
{ 'x': 20, 'y': -14 }
],
'bool': false
}
];
updatePoligons()
drawPoligons();
function oMousePos(canvas, evt) {
var rect = canvas.getBoundingClientRect();
return {
x: parseInt(evt.clientX - rect.left),
y: parseInt(evt.clientY - rect.top)
};
}
function checkStarCollision(starA, starB) {
for (var i = 0; i < starA.points.length; i++) {
var p0 = starA.points[i],
p1 = starA.points[(i + 1) % starA.points.length];
for (var j = 0; j < starB.points.length; j++) {
var p2 = starB.points[j],
p3 = starB.points[(j + 1) % starB.points.length];
if (segmentIntersect(p0, p1, p2, p3)) {
return true;
}
}
}
return false;
}
function segmentIntersect(p0, p1, p2, p3) {
var A1 = p1.y - p0.y,
B1 = p0.x - p1.x,
C1 = A1 * p0.x + B1 * p0.y,
A2 = p3.y - p2.y,
B2 = p2.x - p3.x,
C2 = A2 * p2.x + B2 * p2.y,
denominator = A1 * B2 - A2 * B1;
if (denominator == 0) {
return null;
}
var intersectX = (B2 * C1 - B1 * C2) / denominator,
intersectY = (A1 * C2 - A2 * C1) / denominator,
rx0 = (intersectX - p0.x) / (p1.x - p0.x),
ry0 = (intersectY - p0.y) / (p1.y - p0.y),
rx1 = (intersectX - p2.x) / (p3.x - p2.x),
ry1 = (intersectY - p2.y) / (p3.y - p2.y);
if (((rx0 >= 0 && rx0 <= 1) || (ry0 >= 0 && ry0 <= 1)) &&
((rx1 >= 0 && rx1 <= 1) || (ry1 >= 0 && ry1 <= 1))) {
return {
x: intersectX,
y: intersectY
};
}
else {
return null;
}
}
// mousedown ***************************
canvas.addEventListener('mousedown', function (evt) {
isDragging = true;
var mousePos = oMousePos(canvas, evt);
for (var i = 0; i < list.length; i++) {
drawPoligon(list[i]);
if (ctx.isPointInPath(mousePos.x, mousePos.y)) {
list[i].bool = true;
delta.x = list[i].x - mousePos.x;
delta.y = list[i].y - mousePos.y;
break;
} else {
list[i].bool = false;
}
}
ctx.clearRect(0, 0, canvas.width, canvas.height);
drawPoligons();
}, false);
// mousemove ***************************
canvas.addEventListener('mousemove', function (evt) {
if (isDragging) {
var mousePos = oMousePos(canvas, evt),
selectPoligon;
for (var i = 0; i < list.length; i++) {
if (list[i].bool) {
ctx.clearRect(0, 0, width, height);
list[i].x = mousePos.x + delta.x;
list[i].y = mousePos.y + delta.y;
selectPoligon = list[i];
}
updatePoligon(list[i]);
if (checkStarCollision(selectPoligon, list[i])) {
ctx.fillStyle = "red";
}
else {
ctx.fillStyle = "black";
}
drawPoligon(list[i]);
}
}
}, false);
// mouseup ***************************
canvas.addEventListener('mouseup', function (evt) {
isDragging = false;
for (var i = 0; i < list.length; i++) { list[i].bool = false }
ctx.clearRect(0, 0, canvas.width, canvas.height);
drawPoligons();
}, false);
// mouseout ***************************
canvas.addEventListener('mouseout', function (evt) {
isDragging = false;
for (var i = 0; i < list.length; i++) { list[i].bool = false }
ctx.clearRect(0, 0, canvas.width, canvas.height);
drawPoligons();
}, false);
}
}
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Canvas Figures</title>
<style>
html,
body {
width: 100%;
margin: 0;
background-color: #78909C;
}
#lienzo {
width: 100%;
background-color: #37474F;
}
</style>
</head>
<body>
<canvas id="lienzo"></canvas>
<script src="Javascript/app.js"></script>
</body>
</html>
|
|
26.03.2018, 23:05
|
|
Профессор
|
|
Регистрация: 27.05.2010
Сообщений: 33,124
|
|
ar4ipers,
со строки 190
сначала определить selectPoligon и только потом им оперировать, вынести строки 192 - 197 в отдельный цикл, перед строкой 191.
|
|
26.03.2018, 23:21
|
|
Профессор
|
|
Регистрация: 27.05.2010
Сообщений: 33,124
|
|
ar4ipers,
строку 169 перенести на 174
|
|
27.03.2018, 14:50
|
Интересующийся
|
|
Регистрация: 26.03.2018
Сообщений: 25
|
|
Спасибо, разобрался с этим, был невнимателен. Далее пытаюсь сделать чтобы объект обновлял свое состояние после drop'а. Если после drop'а два
объекта пересекаются они должны поменять цвет заливки фигуры. Изменил метод mousemove. Получил вот такое
canvas.addEventListener('mousemove', function (evt) {
if (isDragging) {
var mousePos = oMousePos(canvas, evt);
for (var i = 0; i < list.length; i++) {
if (list[i].bool) {
updatePoligon(list[i]);
ctx.clearRect(0, 0, width, height);
var X = mousePos.x + delta.x, Y = mousePos.y + delta.y
list[i].x = X;
list[i].y = Y;
selectPoligon = list[i];
break;
}
}
drawPoligons();
}
}, false);
и изменил метод mouseup, получилось вот такое
canvas.addEventListener('mouseup', function (evt) {
isDragging = false;
for (var i = 0; i < list.length; i++) {
list[i].bool = false
}
ctx.clearRect(0, 0, canvas.width, canvas.height);
for (var i = 0; i < list.length; i++) {
if (checkStarCollision(selectPoligon, list[i])) {
ctx.fillStyle = "red";
}
else{
ctx.fillStyle = "black";
}
drawPoligon(list[i]);
}
}, false);
Но цвета прыгают, т.е. после дропа если два полигона пересекаются, они красными становятся, но так же если не пересекаются, то полигон который двигал, становится красным, а если двигаю 3-ю фигуру, то во время mousemove, становятся красными и все остальные, моет поскажет кто где косяк?
|
|
27.03.2018, 14:55
|
|
Профессор
|
|
Регистрация: 27.05.2010
Сообщений: 33,124
|
|
пересечение полигонов
ar4ipers,
код нуждается в оптимизации ...
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Canvas Figures</title>
<style>
html,
body {
width: 100%;
margin: 0;
background-color: #78909C;
}
#lienzo {
width: 100%;
background-color: #37474F;
}
</style>
</head>
<body>
<canvas id="lienzo"></canvas>
<script>window.onload = function () {
var canvas = document.getElementById('lienzo');
if (canvas && canvas.getContext) {
var ctx = canvas.getContext('2d');
if (ctx) {
width = canvas.width = window.innerWidth - 5;
height = canvas.height = window.innerHeight - 5;
var isDragging = false;
var delta = new Object();
function drawPoligon(poligon) {
ctx.beginPath();
ctx.moveTo(poligon.points[0].x, poligon.points[0].y);
for (var i = 1; i < poligon.points.length; i++) {
ctx.lineTo(poligon.points[i].x, poligon.points[i].y);
}
ctx.closePath();
ctx.fill();
}
function updatePoligon(star) {
for (var i = 0; i < star.points.length; i++) {
star.points[i].x = star.x + star.offset[i].x;
star.points[i].y = star.y + star.offset[i].y;
}
}
function updatePoligons() {
for (var i = 0; i < list.length; i++) {
updatePoligon(list[i]);
}
}
function drawPoligons() {
for (var i = 0; i < list.length; i++) {
drawPoligon(list[i]);
}
}
var list = [
{
'x': 50,
'y': 100,
'color': '#3F51B5',
'points': [
{ 'x': 0, 'y': 0 },
{ 'x': 0, 'y': 0 },
{ 'x': 0, 'y': 0 },
{ 'x': 0, 'y': 0 },
],
'offset': [
{ 'x': 50, 'y': 0 },
{ 'x': 5, 'y': -48 },
{ 'x': -40, 'y': 0 },
{ 'x': 5, 'y': 48 },
],
'bool': false
},
{
'x': 50,
'y': 200,
'color': '#3F51B5',
'points': [
{ 'x': 0, 'y': 0 },
{ 'x': 0, 'y': 0 },
{ 'x': 0, 'y': 0 },
{ 'x': 0, 'y': 0 },
{ 'x': 0, 'y': 0 },
{ 'x': 0, 'y': 0 },
],
'offset': [
{ 'x': 25, 'y': -48 },
{ 'x': -15, 'y': -48 },
{ 'x': -40, 'y': 0 },
{ 'x': -15, 'y': 48 },
{ 'x': 25, 'y': 48 },
{ 'x': 50, 'y': 0 },
],
'bool': false
},
{
'x': 50,
'y': 300,
'color': '#3F51B5',
'points': [
{ 'x': 0, 'y': 0 },
{ 'x': 0, 'y': 0 },
{ 'x': 0, 'y': 0 },
{ 'x': 0, 'y': 0 },
{ 'x': 0, 'y': 0 },
{ 'x': 0, 'y': 0 },
{ 'x': 0, 'y': 0 },
{ 'x': 0, 'y': 0 },
{ 'x': 0, 'y': 0 },
{ 'x': 0, 'y': 0 }
],
'offset': [
{ 'x': 50, 'y': 0 },
{ 'x': 20, 'y': 14 },
{ 'x': 15, 'y': 48 },
{ 'x': -8, 'y': 24 },
{ 'x': -40, 'y': 29 },
{ 'x': -25, 'y': 0 },
{ 'x': -40, 'y': -29 },
{ 'x': -8, 'y': -24 },
{ 'x': 15, 'y': -48 },
{ 'x': 20, 'y': -14 }
],
'bool': false
}
];
updatePoligons()
drawPoligons();
function oMousePos(canvas, evt) {
var rect = canvas.getBoundingClientRect();
return {
x: parseInt(evt.clientX - rect.left),
y: parseInt(evt.clientY - rect.top)
};
}
function checkStarCollision(starA, starB) {
for (var i = 0; i < starA.points.length; i++) {
var p0 = starA.points[i],
p1 = starA.points[(i + 1) % starA.points.length];
for (var j = 0; j < starB.points.length; j++) {
var p2 = starB.points[j],
p3 = starB.points[(j + 1) % starB.points.length];
if (segmentIntersect(p0, p1, p2, p3)) {
return true;
}
}
}
return false;
}
function segmentIntersect(p0, p1, p2, p3) {
var A1 = p1.y - p0.y,
B1 = p0.x - p1.x,
C1 = A1 * p0.x + B1 * p0.y,
A2 = p3.y - p2.y,
B2 = p2.x - p3.x,
C2 = A2 * p2.x + B2 * p2.y,
denominator = A1 * B2 - A2 * B1;
if (denominator == 0) {
return null;
}
var intersectX = (B2 * C1 - B1 * C2) / denominator,
intersectY = (A1 * C2 - A2 * C1) / denominator,
rx0 = (intersectX - p0.x) / (p1.x - p0.x),
ry0 = (intersectY - p0.y) / (p1.y - p0.y),
rx1 = (intersectX - p2.x) / (p3.x - p2.x),
ry1 = (intersectY - p2.y) / (p3.y - p2.y);
if (((rx0 >= 0 && rx0 <= 1) || (ry0 >= 0 && ry0 <= 1)) &&
((rx1 >= 0 && rx1 <= 1) || (ry1 >= 0 && ry1 <= 1))) {
return {
x: intersectX,
y: intersectY
};
}
else {
return null;
}
}
// mousedown ***************************
canvas.addEventListener('mousedown', function (evt) {
var mousePos = oMousePos(canvas, evt);
for (var i = 0; i < list.length; i++) {
drawPoligon(list[i]);
if (ctx.isPointInPath(mousePos.x, mousePos.y)) {
isDragging = true;
list[i].bool = true;
delta.x = list[i].x - mousePos.x;
delta.y = list[i].y - mousePos.y;
break;
} else {
list[i].bool = false;
}
}
ctx.clearRect(0, 0, canvas.width, canvas.height);
drawPoligons();
}, false);
// mousemove ***************************
canvas.addEventListener('mousemove', function (evt) {
if (isDragging) {
var mousePos = oMousePos(canvas, evt),
selectPoligon;
for (var i = 0; i < list.length; i++) {
if (list[i].bool) {
ctx.clearRect(0, 0, width, height);
list[i].x = mousePos.x + delta.x;
list[i].y = mousePos.y + delta.y;
updatePoligon(list[i]);
selectPoligon = list[i];
}
}
for (var i = 0; i < list.length; i++) {
if (checkStarCollision(selectPoligon, list[i])) {
ctx.fillStyle = "red";
}
else {
ctx.fillStyle = "black";
}
drawPoligon(list[i]);
}
}
}, false);
// mouseup ***************************
canvas.addEventListener('mouseup', function (evt) {
isDragging = false;ctx.fillStyle = "black";
for (var i = 0; i < list.length; i++) { list[i].bool = false }
ctx.clearRect(0, 0, canvas.width, canvas.height);
drawPoligons();
}, false);
// mouseout ***************************
canvas.addEventListener('mouseout', function (evt) {
isDragging = false;
for (var i = 0; i < list.length; i++) { list[i].bool = false }
ctx.clearRect(0, 0, canvas.width, canvas.height);
drawPoligons();
}, false);
}
}
}
</script>
</body>
</html>
Последний раз редактировалось рони, 12.05.2019 в 14:23.
|
|
27.03.2018, 15:18
|
Интересующийся
|
|
Регистрация: 26.03.2018
Сообщений: 25
|
|
Спасибо, я так понимаю нужно drawPoligon переделать
|
|
27.03.2018, 15:23
|
|
Профессор
|
|
Регистрация: 27.05.2010
Сообщений: 33,124
|
|
Сообщение от ar4ipers
|
я так понимаю нужно drawPoligon переделать
|
сейчас что - то не так?
|
|
27.03.2018, 15:33
|
|
Профессор
|
|
Регистрация: 27.05.2010
Сообщений: 33,124
|
|
ar4ipers,
мысли вслух ...
if (checkStarCollision(selectPoligon, list[i])) {
ctx.fillStyle = "red";
}
else {
ctx.fillStyle = "black";
}
if (checkStarCollision(selectPoligon, list[i])) {
list[i].color = "red";
}
else {
list[i].color = "black";
}
function drawPoligon(poligon) {
ctx.beginPath();
*!*
ctx.fillStyle = poligon.color ? poligon.color : curentColor;
*/!*
ctx.moveTo(poligon.points[0].x, poligon.points[0].y);
for (var i = 1; i < poligon.points.length; i++) {
ctx.lineTo(poligon.points[i].x, poligon.points[i].y);
}
ctx.closePath();
ctx.fill();
}
if (ctx.isPointInPath(mousePos.x, mousePos.y)) {
isDragging = true;
list[i].bool = true;
*!*
selectPoligon = list[i];
*/!*
delta.x = list[i].x - mousePos.x;
delta.y = list[i].y - mousePos.y;
break;
}
|
|
27.03.2018, 15:49
|
Интересующийся
|
|
Регистрация: 26.03.2018
Сообщений: 25
|
|
Спасибо, тот вариант который вы подсказали вчера, я разобрался, понял в чем была ошибка, а теперь подумал как сделать чтобы цвета менялись после drop'a именно, спасибо за решение, а не подскажете как вообще мне лучше оптимизировать код, может вообще лучше создать класс Poligon и непосредственно работать уже с ним или же данная реализация тоже вполне себе корректна?
|
|
27.03.2018, 16:42
|
|
Профессор
|
|
Регистрация: 27.05.2010
Сообщений: 33,124
|
|
Сообщение от ar4ipers
|
лучше создать класс Poligon
|
как вам удобнее, на сколько позволяет опыт абстрагировать ...
|
|
|
|