将一段染色体可视化为一个圆环,根据一段基因的起始点和终止点绘画,根据基因的方向绘画箭头,可以任意确定染色体哪个位置在哪个角度上,例如染色体的1700点位在180上,默认是顺时针方向从起始点向终止点绘画。
1.将一段染色体的基因数组加上极坐标绘画属性
function computePolar(n,drawStartLocus,drawStartPolar){
var length = n[n.length-1]["End"]-n[0]["Start"]
n.forEach(d=>{
var start = d["Start"]
var end = d["End"]
if(start<drawStartLocus){
d["polarStart"]=(drawStartPolar-(drawStartLocus-start)/length*360)
}else{
d["polarStart"]=(drawStartPolar+(start-drawStartLocus)/length*360)
}
if(end<drawStartLocus){
d["polarEnd"]=(drawStartPolar-(drawStartLocus-end)/length*360)
}else{
d["polarEnd"]=(drawStartPolar+(end-drawStartLocus)/length*360)
}
var fraction = d["Strand"]=="+"? 0.95:0.05
d["polarArrowStart"]=(d["polarEnd"]-d["polarStart"])*fraction+d["polarStart"]
var arrowPos = []
arrowPos.push(computeArrowPos(r+10,d["polarArrowStart"],180))
arrowPos.push(computeArrowPos(r-10,d["polarArrowStart"],180))
arrowPos.push(computeArrowPos(r,d["Strand"]=="+"?d["polarEnd"]:d["polarStart"],180))
d["arrowPos"] = arrowPos
})
console.log("addPolar",n)
return n
}
2.上面还调用了一个函数,可以返回箭头的三个点坐标
function computeArrowPos(r1,angle,drawStartPolar){
// r0,angle
// 判断象限用极坐标计算cartesian笛卡尔坐标
var x
var y
angle = angle*Math.PI/180 // 角度转弧度
angle = angle<0? 360+angle:angle
angle = angle>360? angle%360:angle
if(angle<90){
x = r1*Math.sin(angle)
y = -r1*Math.cos(angle)
}else if(angle<180){
x = r1*Math.sin(drawStartPolar-angle)
y = r1*Math.cos(drawStartPolar-angle)
}else if(angle<270){
x = -r1*Math.sin(angle-drawStartPolar)
y = r1*Math.cos(angle-drawStartPolar)
const g = angle-drawStartPolar
//console.log(x,y,Math.sin(angle-drawStartPolar),Math.cos(angle-drawStartPolar),angle,g,Math.cos(78))
}else{
x = -r1*Math.sin(360-angle)
y = -r1*Math.cos(360-angle)
}
return [x,y]
}
computePolar(donor1,deleteMid,180)
computePolar(receptor1,insert_locus,0)
圆上的刻度text旋转角度以及刻度转换
// 刻度转换,K,M,G
function scailNum(num){
if (num/1000000000>1){
return (num/1000000000).toFixed(2)+"G"
}else if(num/1000000>1){
return (num/1000000).toFixed(2)+"M"
}else if(num/1000){
return (num/1000).toFixed(2)+"K"
}else{
return ""+num
}
}
function computeTextPolar(startLocus,drawStartLocus,l,drawStartPolar){
const degreeArr = Array(9).fill(0)
var startPolar = drawStartPolar-(drawStartLocus-startLocus)/l*360 // [-360,0]
startPolar = startPolar>0?startPolar:360+startPolar
degreeArr[0] = {"text":startLocus,"rotation1":startPolar}
var subQuadrant = Math.ceil(startPolar/45)
degreeArr[1] = {"text":scailNum(Math.round(startLocus+(45*subQuadrant-startPolar)/360*l)),"rotation1":45*subQuadrant}
var unit = l/8
for(let i=2;i<9;i++){
degreeArr[i] = {"text":scailNum(Math.round(startLocus+(45*subQuadrant-startPolar)/360*l+unit*(i-1))),"rotation1":(degreeArr[i-1]["rotation1"]+45)%360}
console.log("degreeArr",degreeArr)
}
// 旋转到刻度位后,旋转文本使文本以便于阅读的方式显示
degreeArr.forEach((d,i)=>{
switch(d["rotation1"]){
case 0:
case 45:
case 90:
case 270:
case 315:
d["rotation2"] = 90
break
case 135:
case 180:
case 225:
d["rotation2"] = -90
break
}
})
return degreeArr
}
圆上的范围框怎么通过移动的x,y去移动范围框的极坐标值
onDrag = ((ev,el,delta) => {
donorDragLC.value = computeCartesianPos(r,donorDragL.value)
donorDragLB.value = [donorDragLC.value[0]+delta[0],donorDragLC.value[1]+delta[1]]
console.log("donorDragLC.value,donorDragLB",donorDragLC.value,donorDragLB.value)
a = Math.sqrt((donorDragLB.value[0]-donorDragLC.value[0])**2+(donorDragLB.value[1]-donorDragLC.value[1])**2)
b = Math.sqrt((donorDragLC.value[0])**2+(donorDragLC.value[1])**2)
c = Math.sqrt((donorDragLB.value[0])**2+(donorDragLB.value[1])**2)
console.log((b**2+c**2-a**2),(b**2+c**2-a**2)/(2*b*c)*180,Math.acos((b**2+c**2-a**2)/(2*b*c))*180/Math.PI)
console.log("deltaDegree",Math.acos((b**2+c**2-a**2)/(2*b*c))*180/Math.PI)
donorDragL.value = donorDragL.value-Math.acos((b**2+c**2-a**2)/(2*b*c))*180/Math.PI
console.log(el)
el.$parent.redraw()
})