D3
OG
Old school D3 from simpler times
All examples
By author
By category
About
pmariac
Full window
Github gist
line of sight
Built with
blockbuilder.org
<!DOCTYPE html> <head> <meta charset="utf-8"> <script src="https://d3js.org/d3.v4.js"></script> <style> body { margin:0;position:fixed;top:0;right:0;bottom:0;left:0; } </style> </head> <body> <script> let width = 800 let height = 400 var intersects = []; var svg = d3.select("body").append("svg") .attr("width", width) .attr("height", height) function randomPoint() { return {x:(Math.random()*(width - 100)) + 50, y:(Math.random()*(height - 100)) + 50} } function randomCentered(point) { return {x:(Math.random() * 100) - 50 + point.x, y:(Math.random() * 100) - 50 + point.y} } function randomPoly(point) { return {p1:randomCentered(point), p2:randomCentered(point), p3:randomCentered(point)} } var polygons = [] for (i=0; i<4; i++) { let point = randomPoint() polygons.push(randomPoly(point)) } let polygonEdges = [ {x:0, y:0}, {x:0, y:height}, {x:width, y:height}, {x:width, y:0} ]; let polygonSegments = [ {pa: polygonEdges[0], pb: polygonEdges[1], xab: 0, yab: -height}, {pa: polygonEdges[1], pb: polygonEdges[2], xab: -width, yab: 0}, {pa: polygonEdges[2], pb: polygonEdges[3], xab: 0, yab: height}, {pa: polygonEdges[3], pb: polygonEdges[0], xab: width, yab: 0}, ] polygons.forEach(function(p) { svg.append("line").style("stroke", "black") .attr("x1", p.p1.x) .attr("x2", p.p2.x) .attr("y1", p.p1.y) .attr("y2", p.p2.y); svg.append("line").style("stroke", "black") .attr("x1", p.p2.x) .attr("x2", p.p3.x) .attr("y1", p.p2.y) .attr("y2", p.p3.y); svg.append("line").style("stroke", "black") .attr("x1", p.p3.x) .attr("x2", p.p1.x) .attr("y1", p.p3.y) .attr("y2", p.p1.y); polygonEdges.push(p.p1); polygonEdges.push(p.p2); polygonEdges.push(p.p3); var xab = p.p2.x-p.p1.x; var yab = p.p2.y-p.p1.y; var a = yab/xab; var b = p.p1.y - (a * p.p1.x); polygonSegments.push({pa: p.p1, pb: p.p2, xab: xab, yab: yab, a:a, b:b}); xab = p.p3.x-p.p2.x; yab = p.p3.y-p.p2.y; a = yab/xab; b = p.p2.y - (a * p.p2.x); polygonSegments.push({pa: p.p2, pb: p.p3, xab: xab, yab: yab, a:a, b:b}); xab = p.p1.x-p.p3.x; yab = p.p1.y-p.p3.y; a = yab/xab; b = p.p3.y - (a * p.p3.x); polygonSegments.push({pa: p.p3, pb: p.p1, xab: xab, yab: yab, a:a, b:b}); }) let visor = svg.append("circle") .attr("r", 5) .attr("fill", "red") .attr("class", "visor"); var w = d3.select(window).on("mousemove", mouseMove); function getIntersection(ray,segment){ // RAY in parametric: Point + Delta*T1 var r_px = ray.pa.x; var r_py = ray.pa.y; var r_dx = ray.xab; var r_dy = ray.yab; // SEGMENT in parametric: Point + Delta*T2 var s_px = segment.pa.x; var s_py = segment.pa.y; var s_dx = segment.xab; var s_dy = segment.yab; console.log(r_px+" "+r_py+" "+r_dx+" "+r_dy+" "+s_px+" "+s_py+" "+s_dx+" "+s_dy) // Are they parallel? If so, no intersect var r_mag = Math.sqrt(r_dx*r_dx+r_dy*r_dy); var s_mag = Math.sqrt(s_dx*s_dx+s_dy*s_dy); if(r_dx/r_mag==s_dx/s_mag && r_dy/r_mag==s_dy/s_mag){ // Unit vectors are the same. return null; } var T2 = (r_dx*(s_py-r_py) + r_dy*(r_px-s_px))/(s_dx*r_dy - s_dy*r_dx); var T1 = (s_px+s_dx*T2-r_px)/r_dx; // Must be within parametic whatevers for RAY/SEGMENT if(T1<0) return null; if(T2<0 || T2>1) return null; // Return the POINT OF INTERSECTION return { x: r_px+r_dx*T1, y: r_py+r_dy*T1, param: T1 }; } function mouseMove() { var x = d3.event.x; var y = d3.event.y; intersects = []; for(var i=0;i<polygonEdges.length;i++){ var p = polygonEdges[i] var xab = p.x-x; var yab = p.y-y; var a = yab/xab; var b = p.y - (a * p.x); var angle = Math.atan2(yab,xab); var ray = {pa: {x:x, y:y}, pb: {x:p.x, y:p.y}, xab: xab, yab: yab, a:a, b:b, angle:angle} angle += 0.00001; var dx = Math.cos(angle); var dy = Math.sin(angle); a = dy/dx; b = y - (a * x); var ray2 = {pa:{x:x,y:y},pb:{x:x+dx,y:y+dy}, xab:dx, yab:dy, a:a, b:b, angle:angle}; angle -= 0.00002; var dx = Math.cos(angle); var dy = Math.sin(angle); a = dy/dx; b = y - (a * x); var ray3 = {pa:{x:x,y:y},pb:{x:x+dx,y:y+dy}, xab:dx, yab:dy, a:a, b:b, angle:angle}; var closestIntersect1 = null; var closestIntersect2 = null; var closestIntersect3 = null; for(var j=0;j<polygonSegments.length;j++){ var intersect = getIntersection(ray,polygonSegments[j]); if(!intersect) continue; if(!closestIntersect1 || intersect.param<closestIntersect1.param) { closestIntersect1=intersect; } intersect = getIntersection(ray2,polygonSegments[j]); if(!intersect) continue; if(!closestIntersect2 || intersect.param<closestIntersect2.param) { closestIntersect2=intersect; } intersect = getIntersection(ray3,polygonSegments[j]); if(!intersect) continue; if(!closestIntersect3 || intersect.param<closestIntersect3.param) { closestIntersect3=intersect; } } if(closestIntersect1) intersects.push(closestIntersect1); if(closestIntersect2) intersects.push(closestIntersect2); if(closestIntersect3) intersects.push(closestIntersect3); } svg.select(".visor") .attr("cx", x) .attr("cy", y); drawLinesOfSight(d3.event.x, d3.event.y); } let linesOfSight = svg.selectAll(".lineOfSight").data(polygonEdges) linesOfSight.enter() .append("line") .attr("class", "lineOfSight") .style("stroke", "red") .attr("x1", 0) .attr("x2", function(d) { return d.x; }) .attr("y1", 0) .attr("y2", function(d) { return d.y; }); function drawLinesOfSight(x, y) { svg.selectAll(".lineOfSight").data(intersects) .enter().append("line") .attr("class", "lineOfSight") .style("stroke", "red") .attr("x1", x) .attr("x2", function(d) { return d.x; if (d.x >= width || d.x <= 0) return d.x; var diff = x - d.x; let limit = (diff > 0) ? 0 : width; return limit }) .attr("y1", y) .attr("y2", function(d) { return d.y; if (d.x >= width || d.x <= 0) return d.y; var diff = x - d.x; let limit = (diff > 0) ? 0 : width; var xab = d.x-x; var yab = d.y-y; var a = yab/xab; var b = d.y - (a * d.x); return (a * limit + b) //return d.y; }); svg.selectAll(".lineOfSight").data(intersects) .attr("x1", x) .attr("x2", function(d) { return d.x; if (d.x >= width || d.x <= 0) return d.x; var diff = x - d.x; let limit = (diff > 0) ? 0 : width; return limit }) .attr("y1", y) .attr("y2", function(d) { return d.y; if (d.x >= width || d.x <= 0) return d.y; var diff = x - d.x; let limit = (diff > 0) ? 0 : width; var xab = d.x-x; var yab = d.y-y; var a = yab/xab; var b = d.y - (a * d.x); return (a * limit + b) //return d.y; }); svg.selectAll(".lineOfSight").data(intersects).exit().remove() } </script> </body>
https://d3js.org/d3.v4.js