<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>数据分类器demo</title> </head> <body> <button onclick="splitArr()">分类</button> <div id="app"></div> </body> <script> function getDis(key1,key2) { const x=Math.abs(key1.x-key2.x) const y=Math.abs(key1.y-key2.y) return Math.sqrt(x*x+y*y); } Array.prototype.pushOnly=function(one){ if(this.indexOf(one)===-1){ this.push(one) } } /* * 分类器*/ class ArraySplit { constructor(getDis,sArr) { this.getDis=getDis; this.sArr=sArr; this.tagMap={}; this.dataMap={}; const indexArr=sArr.map(function (item,i) { return i; }) this.splitByIndex(indexArr,'') console.log(this.tagMap) console.log(this.dataMap) } //计算元素key的最大长度dis、最大长度对应的元素arr getMaxKey(key1,indexArr) { const sArr=this.sArr const getDis=this.getDis let maxDis=0; let allDis=0; let arr=[] indexArr.forEach(function (key2) { const dis=getDis(sArr[key1],sArr[key2]) allDis=allDis+dis; if(dis>maxDis){ arr=[key2] maxDis=dis }else if(dis===maxDis){ arr.push(key2) } }) return { key:key1, dis:maxDis, allDis:allDis, arr } } //获取数据分割线(两个风格点) getSplitLine(indexArr) { const sArr=this.sArr //找到对边的点 let line=this.getMaxKey(indexArr[0],indexArr,sArr) let isMax=false; let moreKey; let maxDis=0; while (!isMax){ taskArr.push(line.key) isMax=true; maxDis=0; for(let i=0;i<line.arr.length;i++){ const key=line.arr[i] if(key!==line.key){ const m2=this.getMaxKey(key,indexArr,sArr) const dis=m2.allDis; if(m2.dis>line.dis||m2.dis===line.dis&&m2.arr.length>line.arr.length||m2.dis===line.dis&&m2.arr.length===line.arr.length&&m2.allDis>line.allDis){ line=m2 isMax=false; break }else if(dis>maxDis){ maxDis=dis moreKey=key } } } } let lessKey=line.key; return [lessKey,moreKey,parseInt(line.dis)] } getTags(ele,line){ const sArr=this.sArr const getDis=this.getDis const tags=[] const left=getDis(sArr[line[0]],ele); const right=getDis(sArr[line[1]],ele); if(left*2<line[2]){ tags.push(0) if(left*8>3*line[2]){ tags.push(2) } }else if(right*2<line[2]){ tags.push(1) if(right*8>3*line[2]){ tags.push(2) } }else{ tags.push(2) } return tags; } splitByIndex(indexArr,deep){ const sArr=this.sArr const line=this.getSplitLine(indexArr) const data=[[],[],[]] indexArr.forEach( (key) =>{ const tags=this.getTags(sArr[key],line); tags.forEach(function (tag) { data[tag].push(key) }) }) data.forEach( (arr0,i)=> { const tag0=deep+String(i) if(arr0.length>2){ this.splitByIndex(arr0,tag0) }else if(arr0.length){ this.dataMap[tag0]=arr0; } }) if(data[2].length===0){ this.dataMap[deep]=indexArr }else{ this.tagMap[deep]=line; } } getNearTags(ele){ let t0Arr=[''] let t1Arr=[] let lock=false; while (!lock){ const cArr=[] t0Arr.forEach((path)=> { const line=this.tagMap[path] if(line){ const tags=this.getTags(ele,line) tags.forEach(function (tag) { cArr.pushOnly(path+tag) }) }else{ t1Arr.pushOnly(path) } }) if(cArr.length>0){ t0Arr=cArr; }else{ lock=true; t0Arr.forEach(function (path) { t1Arr.pushOnly(path) }) } } return t1Arr.reverse(); } //对数组分类,成2部分 getNearEles(ele){ const tags=this.getNearTags(ele) console.log(tags) const eles=[] tags.forEach((tag)=> { this.dataMap[tag].forEach((i)=>{ eles.pushOnly(i) }) }) return eles } } let taskArr=[] const room=document.querySelector('#app') const arr=[] for(let i=0;i<500;i++){ // const r=0|Math.random()*10+3 const r=5 const x=0|Math.random()*600 const y=0|Math.random()*400 arr.push({ x,y,r }) } const eleArr=[] arr.forEach(function ({x,y,r}) { const ele=document.createElement('div') ele.className='item' ele.style.top=(y-r/2)+'px' ele.style.left=(x-r/2)+'px' ele.style.width=r+'px' ele.style.height=r+'px' room.appendChild(ele) eleArr.push(ele) }) const testArr=[{x: 92, y: 217, r: 2}] testArr.forEach(function ({x,y,r}) { const ele=document.createElement('div') ele.className='item test' ele.style.top=(y-r/2)+'px' ele.style.left=(x-r/2)+'px' ele.style.width=r+'px' ele.style.height=r+'px' room.appendChild(ele) }) function sleep(time) { return new Promise(function (resolve) { setTimeout(resolve,time) }) } let preTag; let running=false; async function splitArr(){ if(running){return;} running=true; taskArr.forEach(function (num) { eleArr[num].classList.remove('task') }) taskArr=[] if(preTag){ eleArr[preTag.line[0]].classList.remove('top') eleArr[preTag.line[1]].classList.remove('bottom') preTag.data[0].forEach(function (num) { eleArr[num].classList.remove('top2') }) preTag.data[1].forEach(function (num) { eleArr[num].classList.remove('bottom2') }) preTag.data[2].forEach(function (num) { eleArr[num].classList.remove('middle2') }) await sleep(1000) } const splitObj=new ArraySplit(getDis,arr) const tag1= splitObj.getNearEles(testArr[0]) console.log(JSON.stringify(tag1)) for(let i=0;i<tag1.length;i++){ const num=tag1[i] eleArr[num].classList.add('task') await sleep(100) } return for(let i=0;i<taskArr.length;i++){ const num=taskArr[i] eleArr[num].classList.add('task') await sleep(100) } preTag=tag1; eleArr[tag1.line[0]].classList.remove('task') eleArr[tag1.line[0]].classList.add('top') await sleep(100) eleArr[tag1.line[1]].classList.remove('task') eleArr[tag1.line[1]].classList.add('bottom') await sleep(100) for(let i=0;i<tag1.data[0].length;i++){ const num=tag1.data[0][i] if(num!==tag1.line[0]&&taskArr.indexOf(num)===-1){ eleArr[num].classList.add('top2') } } await sleep(1000) for(let i=0;i<tag1.data[1].length;i++){ const num=tag1.data[1][i] if(num!==tag1.line[1]&&taskArr.indexOf(num)===-1){ eleArr[num].classList.add('bottom2') } } await sleep(1000) for(let i=0;i<tag1.data[2].length;i++){ const num=tag1.data[2][i] if(num!==tag1.line[1]&&taskArr.indexOf(num)===-1){ eleArr[num].classList.add('middle2') } } running=false } </script> <style> #app{ position: relative; border: 1px saddlebrown solid; 620px; height: 420px; } .item{ position: absolute; left: 0; top: 0; 20px; height: 20px; border-radius: 50%; background: black; } .test{ background: #f422ff; } .task{ background: red; } .top{ background: red; } .bottom{ background: #121bff; } .top2{ background: #7cff97; } .bottom2{ background: #ffb148; } .middle2{ background: #ff38d2; } </style> </html>