<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title></title> <style type="text/css"> html, body { margin: 0; padding: 0; border: none; width: 100%; height: 100%; } </style> <script type="text/javascript"> onload = function () { demoCanvas.height = document.body.clientHeight - paramsPanel.clientHeight; demoCanvas.width = document.body.clientWidth; } </script> </head> <body> <div id="paramsPanel"> <label for="radius">radius</label><input id="radius" type="range" value="5" max="111" min="1" /> <label for="density">density</label><input id="density" type="range" value="5" max="111" min="1" /> <label for="areaRange">areaRange</label><input id="areaRange" type="range" value="32" max="111" min="1" /> </div> <canvas id="demoCanvas"></canvas> <script type="text/javascript"> onkeydown = function (e) { switch (e.keyCode) { case 49: radius.focus(); break; case 50: density.focus(); break; case 51: areaRange.focus(); break; } }; function dropDots() { var ctx = demoCanvas.getContext("2d"); var ps = []; function drop(e) { ctx.beginPath(); ctx.arc(e.x, e.y, .5, 0, Math.PI * 2); ps.push([e.x, e.y]); ctx.fillStyle = "#000"; ctx.fill(); } demoCanvas.onmousedown = function (e) { demoCanvas.getContext("2d").clearRect(0, 0, 12344, 12344); ps = []; drop(e); addEventListener("mousemove", drop); }; onmouseup = onblur = function () { if (!ps.length) { return; } removeEventListener("mousemove", drop); var radius = parseFloat(document.getElementById("radius").value); var density = parseInt(document.getElementById("density").value); var areaRange = parseInt(document.getElementById("areaRange").value); var areas = getAreas(ps, radius, density, areaRange); for (var i = 0; i < areas.length; i++) { var e = areas[i][0][0]; ctx.beginPath(); ctx.arc(e[0], e[1], areaRange / 2, 0, Math.PI * 2); ctx.strokeStyle = "#00a"; ctx.stroke(); ctx.closePath(); } } } dropDots(); function getAreas(ps, radius, density, areaRange) { var vps = [];//所有符合条件的点与附近点集,格式为[point,[points]] for (var i = 0; i < ps.length; i++) { var nps = [];//遍历附近的点,找出附近点的点集 for (var j = 0; j < ps.length; j++) {// if (i === j) { continue; } if (xy2(ps[i], ps[j]) > radius) { continue; } nps.push(ps[j]); } if (nps.length > density) {//检查附近的点的密度 vps.push([ps[i], nps]); } } var idxs = []; for (var i = 0; i < vps.length; i++) {//生成所有符合条件的点集的坐标集 idxs.push(i); } vps.sort(function (np0, np1) {//附近点集 return np1[1].length - np0[1].length; }); var areas = [];//返回值 while (idxs.length) { var nps0 = vps[idxs[0]]; var g = [nps0]; var new_idxs = [];//不符合条件点集,如有元素将重新开始判断 for (var i = 1; i < idxs.length; i++) { var idxi = idxs[i]; var npsi = vps[idxi]; if (xy2(nps0[0], npsi[0]) > areaRange * areaRange) { new_idxs.push(idxi); } else { g.push(npsi);//一个区域 } } g.sort(function (g0, g1) {//找出附近点集数量最大的点 return g1[1].length - g0[1].length; }); areas.push(g); idxs = new_idxs;//不符合条件点集,如存在将重新开始判断 } return areas; } function xy2(p0, p1) {//算距离 return (p0[0] - p1[0]) * (p0[0] - p1[0]) + (p0[1] - p1[1]) * (p0[1] - p1[1]); } </script> </body> </html>