<!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;
width: 620px;
height: 420px;
}
.item{
position: absolute;
left: 0;
top: 0;
width: 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>