版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/cc_fys/article/details/77842360
做题做到了这样一道题,设用邻接矩阵A表示图G的存储结构,G的顶点为V0,V1,V2,V3,V4,V5,V6,则关于图G的说法正确的是
这道题比较简单,基本思路是:
不对称矩阵是有向图
有向图才会有入度和出度
学习JS做练习,刚好使用对象这一块内容,用JavaScript,canvas,prototype将数据结构中邻接矩阵的图做一个直观表示。
/**
* Created by CC on 2017/9/4.
*/
var Gra=function(){
this.elem=arguments[0];
this.options=arguments[1];
this.width=this.elem.width;
this.height=this.elem.height;
this.context=this.elem.getContext('2d');
this.deName=false;
this.isSymmetric=true;
this.pointSize=15;
this.pointData=[];
this.init();
}
Gra.prototype.init=function()
{
var name=this.options.name;
this.num=this.options.data.length;
if(name&&name.length!=0)
{
this.deName=true;
}
this.drawPoint();
this.drawEdge();
this.initaction();
}
//绘顶点
Gra.prototype.drawPoint=function()
{
var ctx=this.context;
var num=this.num;
var dia=(this.width<this.height) ? this.width : this.height;
var centerx=this.width/2;
var centery=this.height/2;
var rad=2*Math.PI/num;
for(var i=0;i<num;i++) {
var y = (dia / 2 - 30) * Math.sin(rad * i) + centery;
var x = (dia / 2 - 30) * Math.cos(rad * i) + centerx;
ctx.beginPath();
ctx.strokeStyle='#000';
ctx.lineWidth=1;
ctx.arc(x, y, this.pointSize, 0, 2 * Math.PI, false);
ctx.stroke();
this.pointData.push({x:x,y:y})
}
}
//绘边
Gra.prototype.drawEdge=function()
{
//判断是无向图和有向图
var gra=this;
var ctx=this.context;
var data=this.options.data;
var mydata=this.pointData;
for(var i=0;i<data.length;i++)
{
for(j=0;j<data.length;j++){
if(data[i][j]!=data[j][i])
{
this.isSymmetric=false;
}
}
}
ctx.save();
ctx.strokeStyle='#000';
ctx.lineWidth=1;
ctx.font='12px 微软雅黑';
ctx.textAlign='left';
if(this.isSymmetric)
{
ctx.fillText('无向图', 14, 14);
for(var i=0;i<data.length;i++)
{
for(j=0;j<i;j++){
if(data[i][j]!=0&&data[i][j]!=Number.POSITIVE_INFINITY)
{
ctx.moveTo(mydata[i].x,mydata[i].y);
ctx.lineTo(mydata[j].x,mydata[j].y);
ctx.stroke();
}
}
}
}
else
{
ctx.fillText('有向图', 14, 14);
for(var i=0;i<data.length;i++) {
for (j = 0; j < data.length; j++) {
if (data[i][j] != 0 && data[i][j] != Number.POSITIVE_INFINITY && i != j) {
//比例
//console.log(i + '> ' + j)
var rat = Math.atan((mydata[j].y - mydata[i].y) / (mydata[j].x - mydata[i].x));
var dex = Math.cos(rat + (Math.PI / 6)) * this.pointSize;
var dey = Math.sin(rat + (Math.PI / 6)) * this.pointSize;
var dex1 = Math.cos(rat - (Math.PI / 6)) * this.pointSize;
var dey1 = Math.sin(rat - (Math.PI / 6)) * this.pointSize;
if (j < i) {
ctx.strokeStyle=' #2F4F4F';
ctx.moveTo(mydata[j].x - dex, mydata[j].y - dey);
ctx.lineTo(mydata[i].x + dex1, mydata[i].y + dey1);
ctx.stroke();
//箭头
this.drawArrow(mydata[i].x + dex1, mydata[i].y + dey1,mydata[j].x - dex, mydata[j].y - dey);
}
else {
ctx.strokeStyle='#800000 ';
ctx.moveTo(mydata[i].x - dex1, mydata[i].y - dey1);
ctx.lineTo(mydata[j].x + dex, mydata[j].y + dey);
ctx.stroke();
//箭头
this.drawArrow(mydata[i].x - dex1, mydata[i].y - dey1, mydata[j].x + dex, mydata[j].y + dey);
}
}
}
}
}
ctx.textAlign='center';
ctx.textBaseline='middle';
mydata.forEach(function (item, index) {
//console.log(item.x);
ctx.fillStyle='#fff';
ctx.beginPath();
ctx.arc(item.x, item.y, gra.pointSize-1, 0, 2 * Math.PI, true);
ctx.closePath();
ctx.fill();
ctx.fillStyle='#000';
if(gra.deName) {
ctx.fillText(gra.options.name[index], item.x, item.y);
}
else
{
ctx.fillText(index.toString(), item.x, item.y);
}
});
ctx.restore();
}
Gra.prototype.drawArrow=function(x,y,x1,y1)
{
var ctx=this.context;
ctx.save();
ctx.translate(x/2+x1/2,y/2+y1/2)
if(x1-x>0)
ctx.rotate(Math.atan((y1-y)/(x1-x))+Math.PI);
else
ctx.rotate(Math.atan((y1-y)/(x1-x)));
ctx.fillStyle='#000';
ctx.beginPath();
ctx.moveTo(0,0);
ctx.lineTo(10,5);
ctx.lineTo(10,-5);
ctx.closePath();
ctx.fill();
ctx.restore();
}
//拖动事件
Gra.prototype.initaction=function()
{
var gra=this;
var canvas=gra.elem;
var ctx=gra.context;
var mydata=gra.pointData;
canvas.onmousedown=function(ev)
{
var moveIndex=-1;
for(var i=0;i<mydata.length;i++){
if(ev.x<(mydata[i].x+gra.pointSize)&&ev.x>(mydata[i].x-gra.pointSize)&&ev.y<(mydata[i].y+gra.pointSize)&&ev.y>(mydata[i].y-gra.pointSize)) {
moveIndex = i;
break;
}
}
document.onmousemove=function (event)
{
if(moveIndex!=-1)
{
ctx.clearRect(0,0,gra.width,gra.height);
mydata[moveIndex].x=event.pageX;
mydata[moveIndex].y=event.pageY;
for(var i=0;i<mydata.length;i++) {
ctx.beginPath();
ctx.strokeStyle='#000';
ctx.lineWidth=1;
ctx.arc(mydata[i].x,mydata[i].y, gra.pointSize, 0, 2 * Math.PI, false);
ctx.stroke();
}
gra.drawEdge();
}
}
document.onmouseup=function()
{
document.onmousemove=null;
document.onmouseup=null;
}
}
}
HTML
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title></title>
<script type="text/javascript" src="gra.js"></script>
<style type="text/css">
#gra
{
border:1px solid black;
}
</style>
</head>
<body>
<div>
<canvas id="gra" width="500" height="500"></canvas>
</div>
<script>
var option={
name:['v0','v1','v2','v3','v4','v5','v6'],
data:[ [0,1,1,1,1,0,1],
[1,0,0,1,0,0,1],
[1,0,0,0,1,0,0],
[1,1,0,0,1,1,0],
[1,0,1,1,0,1,0],
[0,0,0,1,1,0,1],
[1,1,0,0,0,1,0]]
};
var gra = new Gra(document.getElementById('gra'),option);
</script>
</body>
</html>
调整后的效果,每一个节点都可以拖动调整:
传其他值时:
var option={
name:['v0','v1','v2','v3','v4','v5','v6'],
data:[ [0,1,1,0,0,1,0],
[0,0,0,1,0,0,0],
[1,0,0,0,0,0,1],
[0,0,0,0,0,1,0],
[1,0,0,0,0,0,1],
[0,0,0,0,1,0,0],
[1,0,1,0,0,0,0]]
};
var gra = new Gra(document.getElementById('gra'),option);