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> |
ar4ipers,
со строки 190 сначала определить selectPoligon и только потом им оперировать, вынести строки 192 - 197 в отдельный цикл, перед строкой 191. |
ar4ipers,
строку 169 перенести на 174 |
Спасибо, разобрался с этим, был невнимателен. Далее пытаюсь сделать чтобы объект обновлял свое состояние после 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, становятся красными и все остальные, моет поскажет кто где косяк? |
пересечение полигонов
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> |
Спасибо, я так понимаю нужно drawPoligon переделать
|
Цитата:
|
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; } |
Спасибо, тот вариант который вы подсказали вчера, я разобрался, понял в чем была ошибка, а теперь подумал как сделать чтобы цвета менялись после drop'a именно, спасибо за решение, а не подскажете как вообще мне лучше оптимизировать код, может вообще лучше создать класс Poligon и непосредственно работать уже с ним или же данная реализация тоже вполне себе корректна?
|
Цитата:
|
Часовой пояс GMT +3, время: 15:04. |