OLD | NEW |
| (Empty) |
1 // Copyright (c) 2011 The Native Client Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be found | |
3 // in the LICENSE file. | |
4 | |
5 /** | |
6 * @fileoverview This file contains the JavaScript required for the WebGTT | |
7 * application, specifically, the implementation of the Graph class. This | |
8 * implementation provides functions for creating, directing and drawing a | |
9 * graph, adding/deleting vertices/edges, checking whether an edge exists, | |
10 * obtaining the vertex that is nearest to a given point on the canvas, and | |
11 * obtaining the adjacency matrix. | |
12 * | |
13 * @author ragad@google.com (Raga Gopalakrishnan) | |
14 */ | |
15 | |
16 /** | |
17 * This class is used to represent a graph. | |
18 * @constructor | |
19 */ | |
20 Graph = function () { | |
21 /** | |
22 * These variables are arrays that hold references to the vertices and edges | |
23 * that make up the graph. | |
24 */ | |
25 this.listOfVertices = new Array(); | |
26 this.listOfEdges = new Array(); | |
27 | |
28 /** | |
29 * This boolean variable indicates whether the graph is directed or not. | |
30 */ | |
31 this.isDirected = false; | |
32 }; | |
33 | |
34 /** | |
35 * This function sets the value of Graph.isDirected. | |
36 * | |
37 * If the graph is being converted from a directed to an undirected graph, then | |
38 * possible duplicate edges should be deleted. | |
39 * | |
40 * @param {boolean} isDirected The value to be assigned to Graph.isDirected. | |
41 */ | |
42 Graph.prototype.setDirected = function (isDirected) { | |
43 if (isDirected) { | |
44 this.isDirected = true; | |
45 } else if(this.isDirected) { | |
46 this.isDirected = false; | |
47 for (var i = 0 ; i < this.listOfEdges.length - 1 ; i++) { | |
48 for (var j = i+1 ; j < this.listOfEdges.length ; j++) { | |
49 if (this.listOfEdges[i].start == this.listOfEdges[j].end && | |
50 this.listOfEdges[i].end == this.listOfEdges[j].start) { | |
51 this.deleteEdgeByIndex(j); | |
52 break; | |
53 } | |
54 } | |
55 } | |
56 } | |
57 }; | |
58 | |
59 /** | |
60 * This function adds a vertex to the graph. | |
61 * | |
62 * @param {object} newVertex Reference to the new vertex to be added. | |
63 */ | |
64 Graph.prototype.addVertex = function (newVertex) { | |
65 this.listOfVertices.push(newVertex); | |
66 }; | |
67 | |
68 /** | |
69 * This function deletes a vertex from the graph, given its index in | |
70 * Graph.listOfVertices. | |
71 * | |
72 * @param {number} vertexIndex The index of the vertex to be deleted. | |
73 */ | |
74 Graph.prototype.deleteVertexByIndex = function (vertexIndex) { | |
75 // First, delete all edges from/to this vertex | |
76 for (var i = 0 ; i < this.listOfEdges.length ; i++) { | |
77 if (this.listOfEdges[i].start == this.listOfVertices[vertexIndex] || | |
78 this.listOfEdges[i].end == this.listOfVertices[vertexIndex]) { | |
79 this.deleteEdgeByIndex(i); | |
80 i--; | |
81 } | |
82 } | |
83 | |
84 for (var i = vertexIndex ; i < this.listOfVertices.length - 1 ; i++) { | |
85 this.listOfVertices[i] = this.listOfVertices[i+1]; | |
86 } | |
87 this.listOfVertices.pop(); | |
88 }; | |
89 | |
90 /** | |
91 * This function returns the vertex nearest to the given coordinates. | |
92 * | |
93 * @param {number} x The given x-coordinate. | |
94 * @param {number} y The given y-coordinate. | |
95 * @return {object} Reference to the nearest vertex (undefined if none). | |
96 */ | |
97 Graph.prototype.getNearestVertex = function (x, y) { | |
98 var closestVertex = undefined; | |
99 var closestDistance = 0; | |
100 if (graph1.listOfVertices.length != 0) { | |
101 closestVertex = graph1.listOfVertices[0]; | |
102 closestDistance = Math.sqrt(Math.pow(x-closestVertex.x,2) + | |
103 Math.pow(y-closestVertex.y,2)); | |
104 for (var i = 1 ; i < graph1.listOfVertices.length ; i++) { | |
105 var tempVertex = graph1.listOfVertices[i]; | |
106 var tempDistance = Math.sqrt(Math.pow(x-tempVertex.x,2) + | |
107 Math.pow(y-tempVertex.y,2)); | |
108 if (tempDistance < closestDistance) { | |
109 closestVertex = tempVertex; | |
110 closestDistance = tempDistance; | |
111 } | |
112 } | |
113 } | |
114 return closestVertex; | |
115 }; | |
116 | |
117 /** | |
118 * This function adds an edge to the graph. | |
119 * | |
120 * @param {object} newEdge Reference to the new edge to be added. | |
121 */ | |
122 Graph.prototype.addEdge = function (newEdge) { | |
123 this.listOfEdges.push(newEdge); | |
124 }; | |
125 | |
126 /** | |
127 * This function deletes an edge from the graph, given its index in | |
128 * Graph.listOfEdges. | |
129 * | |
130 * @param {number} edgeIndex The index of the edge to be deleted. | |
131 */ | |
132 Graph.prototype.deleteEdgeByIndex = function (edgeIndex) { | |
133 for (var i = edgeIndex ; i < this.listOfEdges.length - 1 ; i++) { | |
134 this.listOfEdges[i] = this.listOfEdges[i+1]; | |
135 } | |
136 this.listOfEdges.pop(); | |
137 }; | |
138 | |
139 /** | |
140 * This function returns a reference to the edge that is adjacent to the given | |
141 * vertices. | |
142 * | |
143 * @param {object} start Reference to the start vertex. | |
144 * @param {object} end Reference to the end vertex. | |
145 * @return {object} Reference to the adjacent edge (undefined if none). | |
146 */ | |
147 Graph.prototype.getEdge = function (start, end) { | |
148 var returnEdge = undefined; | |
149 | |
150 // This is slightly complex, since the graph could be directed or undirected. | |
151 for (var i = 0 ; i < this.listOfEdges.length ; i++) { | |
152 if (this.listOfEdges[i].start == start && this.listOfEdges[i].end == end) { | |
153 returnEdge = this.listOfEdges[i]; | |
154 break; | |
155 } | |
156 if (this.listOfEdges[i].start == end && this.listOfEdges[i].end == start) { | |
157 if (!this.isDirected) { | |
158 returnEdge = this.listOfEdges[i]; | |
159 break; | |
160 } | |
161 } | |
162 } | |
163 return returnEdge; | |
164 }; | |
165 | |
166 /** | |
167 * This function draws the given list of elements (vertices or edges) on the | |
168 * canvas. | |
169 * | |
170 * @param {object} drawingContext The handle to the drawing surface of the | |
171 * canvas. | |
172 * @param {object} listOfElements The list of elements (vertices or edges) to be | |
173 * drawn on to the canvas. | |
174 */ | |
175 Graph.prototype.drawSpecific = function (drawingContext, listOfElements) { | |
176 for (var i = 0 ; i < listOfElements.length ; i++) { | |
177 listOfElements[i].draw(drawingContext); | |
178 } | |
179 }; | |
180 | |
181 /** | |
182 * This function draws the graph on the canvas. | |
183 * | |
184 * @param {object} drawingContext The handle to the drawing surface of the | |
185 * canvas. | |
186 */ | |
187 Graph.prototype.draw = function (drawingContext) { | |
188 drawingContext.globalCompositeOperation = 'destination-over'; | |
189 this.drawSpecific(drawingContext, this.listOfVertices); | |
190 this.drawSpecific(drawingContext, this.listOfEdges); | |
191 }; | |
192 | |
193 /** This function returns the adjacency matrix of the graph. | |
194 * | |
195 * @return {object} The adjacency matrix of the graph. | |
196 */ | |
197 Graph.prototype.getAdjacencyMatrix = function () { | |
198 var adjacencyMatrix = new Array(); | |
199 for (var i = 0 ; i < this.listOfVertices.length ; i++) { | |
200 adjacencyMatrix.push(new Array()); | |
201 } | |
202 | |
203 for (var i = 0 ; i < this.listOfVertices.length ; i++) { | |
204 for (var j = 0 ; j < this.listOfVertices.length ; j++) { | |
205 adjacencyMatrix[i][j] = 0; | |
206 } | |
207 } | |
208 | |
209 for (var i = 0 ; i < this.listOfEdges.length ; i++) { | |
210 var indexOfStart = this.listOfVertices.indexOf(this.listOfEdges[i].start); | |
211 var indexOfEnd = this.listOfVertices.indexOf(this.listOfEdges[i].end); | |
212 adjacencyMatrix[indexOfStart][indexOfEnd] = 1; | |
213 if (!this.isDirected) { | |
214 adjacencyMatrix[indexOfEnd][indexOfStart] = 1; | |
215 } | |
216 } | |
217 | |
218 return adjacencyMatrix; | |
219 }; | |
OLD | NEW |