@@ -6,8 +6,8 @@ var lineWidth=3.0*canvasScale;
66var PI = Math . PI ;
77
88var allCircles = [ ] ,
9- mainCircles = [ ] ,
10- currentCircle , //points to a mainCircle which contains selectedCircle
9+ wordCircles = [ ] ,
10+ currentCircle , //points to a wordCircle which contains selectedCircle
1111 selectedCircle = - 1 , //points to selected circle
1212 snapMode = true ; //disabling this disables some rule checking; can't be toggled for now
1313
@@ -18,19 +18,26 @@ var lines=[],
1818var dirtyRender = true ; //whether GUI and red dots will be drawn
1919
2020Array . prototype . contains = function ( k ) {
21- for ( var p in this )
22- if ( this [ p ] === k )
23- return true ;
24- return false ;
21+ return ( this . indexOf ( k ) != - 1 ) ;
2522}
2623
27- Array . prototype . remove = function ( from , to ) {
24+ Array . prototype . remove = function ( from , to ) { //based on http://ejohn.org/blog/javascript-array-remove/
2825 var rest = this . slice ( ( to || from ) + 1 || this . length ) ;
2926 this . length = from < 0 ? this . length + from : from ;
3027 return this . push . apply ( this , rest ) ;
3128} ;
29+
30+ //these functions are meant to reduce the clutter in the actual code
3231function dist ( a , b , x , y ) { return Math . sqrt ( Math . pow ( ( a - x ) , 2 ) + Math . pow ( ( b - y ) , 2 ) ) }
3332
33+ //since we are drawing mostly circles, it's not like we need control over beginPath() and stroke() anyway
34+ function drawCircle ( x , y , r ) { ctx . beginPath ( ) ; ctx . arc ( x , y , r , 0 , PI * 2 ) ; ctx . stroke ( ) ; }
35+ function drawArc ( x , y , r , a1 , a2 ) { ctx . beginPath ( ) ; ctx . arc ( x , y , r , a1 , a2 ) ; ctx . stroke ( ) ; }
36+ function drawDot ( x , y , r ) { ctx . beginPath ( ) ; ctx . arc ( x , y , r , 0 , PI * 2 ) ; ctx . fill ( ) ; }
37+
38+ //draws a red dot in a given location, signifying a circle you can select
39+ function drawRedDot ( x , y ) { ctx . fillStyle = "red" ; drawDot ( x , y , 3 + lineWidth / 3 ) ; ctx . fillStyle = "black" ; }
40+
3441$ ( document ) . ready ( function ( ) {
3542 $ ( 'input' ) . val ( localStorage . getItem ( "input" ) ) ;
3643
@@ -45,7 +52,7 @@ $(document).ready(function(){
4552function updateText ( ) {
4653 resetZoom ( ) ;
4754
48- mainCircles = [ ] ; allCircles = [ ] ; lines = [ ] ; currentCircle = 0 ; selectedCircle = - 1 ; selectedLine = - 1 ;
55+ wordCircles = [ ] ; allCircles = [ ] ; lines = [ ] ; currentCircle = 0 ; selectedCircle = - 1 ; selectedLine = - 1 ;
4956
5057 var t = $ ( 'input' ) . val ( ) . trim ( ) . toLowerCase ( ) . split ( " " ) ;
5158 localStorage . setItem ( "input" , $ ( 'input' ) . val ( ) ) ;
@@ -66,12 +73,12 @@ function updateText(){
6673//thus, it will always be connected to the circles' borders.
6774function Line ( circle1 , a1 , circle2 , a2 ) {
6875 this . draw = function ( ) {
69- if ( selectedLine == this ) ctx . strokeStyle = "grey" ;
76+ if ( selectedLine == this ) ctx . strokeStyle = "grey" ;
77+ else ctx . strokeStyle = "black" ;
7078 ctx . beginPath ( ) ; ctx . moveTo ( this . points [ 0 ] . x , this . points [ 0 ] . y ) ; ctx . lineTo ( this . points [ 1 ] . x , this . points [ 1 ] . y ) ; ctx . stroke ( ) ;
71- ctx . strokeStyle = "black" ;
72- if ( dirtyRender && this . selectable ) { ctx . fillStyle = "red" ;
73- ctx . beginPath ( ) ; ctx . arc ( this . points [ 0 ] . x , this . points [ 0 ] . y , lineWidth , 0 , PI * 2 ) ; ctx . fill ( ) ;
74- ctx . beginPath ( ) ; ctx . arc ( this . points [ 1 ] . x , this . points [ 1 ] . y , lineWidth , 0 , PI * 2 ) ; ctx . fill ( ) ;
79+ if ( dirtyRender && this . selectable ) {
80+ drawRedDot ( this . points [ 0 ] . x , this . points [ 0 ] . y )
81+ drawRedDot ( this . points [ 1 ] . x , this . points [ 1 ] . y )
7582 }
7683 }
7784 this . update = function ( ) {
@@ -105,9 +112,10 @@ function Line(circle1, a1, circle2, a2){
105112//a list of other circles and lines connected to it, so they can easily updated in a cascading style
106113function Circle ( owner , type , subtype , d , r , a ) {
107114 this . draw = function ( ) {
108- if ( selectedCircle == this ) ctx . strokeStyle = "grey" ;
115+ if ( selectedCircle == this ) ctx . strokeStyle = "grey" ;
116+ else ctx . strokeStyle = "black" ;
109117
110- if ( mainCircles . contains ( this ) ) { //it's a mainCircle so we need to make a gap for B- and T- row letters
118+ if ( wordCircles . contains ( this ) ) { //it's a wordCircle so we need to make a gap for B- and T- row letters
111119 var angles = [ ] ; //a list of intersections with these letters
112120 for ( var i = 0 ; i < this . children . length ; ++ i ) {
113121 var child = this . children [ i ] ;
@@ -120,37 +128,36 @@ function Circle(owner,type,subtype, d, r, a){
120128 }
121129 if ( angles . length == 0 ) angles = [ 0 , 2 * PI ] ;
122130 for ( var i = angles . length ; i > 0 ; i -= 2 ) { //we're going in the oppposite direction as that's how arc() draws
123- ctx . beginPath ( ) ; ctx . arc ( this . x , this . y , this . r , angles [ i % angles . length ] , angles [ i - 1 ] ) ; ctx . stroke ( ) ;
131+ drawArc ( this . x , this . y , this . r , angles [ i % angles . length ] , angles [ i - 1 ] ) ;
124132 }
125133 }
126- else if ( this . type == 3 || this . type == 1 ) { //so it's not a mainCircle ; not let's check if it's a B- or T- row letter
134+ else if ( this . type == 3 || this . type == 1 ) { //so it's not a wordCircle ; not let's check if it's a B- or T- row letter
127135 var d , an ;
128136 d = dist ( this . x , this . y , this . owner . x , this . owner . y ) ;
129137 an = Math . acos ( ( this . owner . r * this . owner . r - d * d - this . r * this . r ) / ( - 2 * d * this . r ) ) ; an = ( PI / 2 - an )
130- ctx . beginPath ( ) ; ctx . arc ( this . x , this . y , this . r , this . a + PI / 2 + an , this . a + 3 / 2 * PI - an ) ; ctx . stroke ( ) ;
138+ drawArc ( this . x , this . y , this . r , this . a + PI / 2 + an , this . a + 3 / 2 * PI - an ) ;
131139 }
132140 else { //if not, we can just draw a circle there
133- ctx . beginPath ( ) ; ctx . arc ( this . x , this . y , this . r , 0 , 2 * PI ) ; ctx . stroke ( ) ;
141+ drawCircle ( this . x , this . y , this . r ) ;
134142 }
135143
136144 if ( this . type < 5 && ( this . subtype == 2 || this . subtype == 3 ) ) { //drawing the dots
137- var dotR , r , delta ;
138- for ( var i = - 1 ; i < this . subtype - 1 ; i ++ ) {
139- dotR = 3 + lineWidth / 2 , r = this . r - 3 * dotR , delta = ( 0.2 * this . owner . r / this . r ) * i ;
140- ctx . beginPath ( ) ; ctx . arc ( this . x - Math . cos ( this . a + delta ) * r , this . y - Math . sin ( this . a + delta ) * r , dotR , 0 , PI * 2 ) ; ctx . fillStyle = "black" ; ctx . fill ( ) ;
141- }
145+ var dotR = 3 + lineWidth / 2 , r = this . r - 1 - 3 * dotR , delta = ( 0.2 * this . owner . r / this . r ) ;
146+ for ( var i = - 1 ; i < this . subtype - 1 ; i ++ )
147+ drawDot ( this . x - Math . cos ( this . a + delta * i ) * r , this . y - Math . sin ( this . a + delta * i ) * r , dotR ) ;
142148 }
143- ctx . strokeStyle = "black" ;
144- if ( dirtyRender && this . selectable ) { ctx . beginPath ( ) ; ctx . arc ( this . x , this . y , lineWidth , 0 , PI * 2 ) ; ctx . fillStyle = "red" ; ctx . fill ( ) ; }
149+ if ( dirtyRender && this . selectable )
150+ drawRedDot ( this . x , this . y ) ;
145151 }
152+
146153 this . update = function ( d , a ) { //recalculates the position, forces other circles/lines connected to it to update too
147154 var dx , dy ;
148155 var oldA = this . a ;
149156 dx = Math . cos ( a ) * ( d ) , dy = Math . sin ( a ) * ( d ) ;
150157 this . x = this . owner . x + dx ; this . y = this . owner . y + dy ; this . d = d ;
151158 if ( a < - PI ) this . a = a + 2 * PI ; else if ( a > PI ) this . a = a - 2 * PI ; else this . a = a ;
152159 for ( var i = 0 ; i < this . children . length ; i ++ ) {
153- if ( mainCircles . contains ( this ) )
160+ if ( wordCircles . contains ( this ) )
154161 this . children [ i ] . update ( this . children [ i ] . d , this . children [ i ] . a ) ;
155162 else
156163 this . children [ i ] . update ( this . children [ i ] . d , this . children [ i ] . a - oldA + this . a ) ;
@@ -205,24 +212,24 @@ function doClick(e){
205212} ;
206213
207214//makes sure that the correct distance from the base circle is kept according to language rules
208- function updateLocation ( selected , d , a ) {
215+ function correctCircleLocation ( selected , d , a ) {
209216 if ( ! snapMode ) { selected . update ( d , a ) ; return ; }
210217 switch ( selected . type ) {
211- case 1 :
218+ case 1 : //B-row
212219 if ( d > selected . owner . r - selected . r * 0.5 ) d = selected . owner . r - selected . r * 0.5 ;
213- if ( d < selected . owner . r - selected . r + 1.5 + lineWidth ) d = selected . owner . r - selected . r + 1.5 + lineWidth ;
220+ if ( d < selected . owner . r - selected . r + 1 ) d = selected . owner . r - selected . r + 1 ;
214221 break ;
215- case 2 :
222+ case 2 : //J-row
216223 if ( d > selected . owner . r - selected . r - 5 ) d = selected . owner . r - selected . r - 5 ;
217224 break ;
218- case 3 :
225+ case 3 : //T-row
219226 if ( d > selected . owner . r + selected . r * 0.8 ) d = selected . owner . r + selected . r * 0.8 ;
220227 if ( d < selected . owner . r ) d = selected . owner . r ;
221228 break ;
222- case 4 :
229+ case 4 : //TH-row
223230 d = selected . owner . r ;
224231 break ;
225- case 5 :
232+ case 5 : //vowels, laying on a wordCircle
226233 switch ( selected . subtype ) {
227234 case 1 :if ( d < selected . owner . r + selected . r ) d = selected . owner . r + selected . r ; break ;
228235 case 2 :
@@ -231,8 +238,8 @@ function updateLocation(selected, d, a){
231238 d = selected . owner . r ; break ;
232239 case 4 :if ( d > selected . owner . r - selected . r ) d = selected . owner . r - selected . r ; break ;
233240 } break ;
234- case 6 :
235- switch ( selected . subtype ) { //TODO
241+ case 6 : //vowels, connected to consonants
242+ switch ( selected . subtype ) {
236243 case 1 :
237244 if ( selected . owner . type == 1 ) { if ( d < selected . r * 2 ) d = selected . r * 2 ; a = selected . owner . a ; }
238245 if ( selected . owner . type == 2 ) { if ( d < selected . owner . r + selected . r ) d = selected . owner . r + selected . r ; a = selected . owner . a ; }
@@ -251,10 +258,10 @@ function updateLocation(selected, d, a){
251258 } break ;
252259 }
253260 selected . update ( d , a ) ;
254- for ( var i = 0 ; i < selected . children . length ; i ++ ) updateLocation ( selected . children [ i ] , selected . children [ i ] . d , selected . children [ i ] . a ) ;
261+ for ( var i = 0 ; i < selected . children . length ; i ++ ) correctCircleLocation ( selected . children [ i ] , selected . children [ i ] . d , selected . children [ i ] . a ) ;
255262}
256263
257- //manages the movement of circles and lines. In case of circles, updateLocation () is called to enforce language rules
264+ //manages the movement of circles and lines. In case of circles, correctCircleLocation () is called to enforce language rules
258265$ ( 'canvas' ) . mousemove ( function ( e ) {
259266 var mouse = getMouse ( e ) ;
260267 if ( selectedCircle != - 1 ) {
@@ -272,7 +279,7 @@ $('canvas').mousemove(function(e){
272279 if ( a - aplus > 2 * PI || a - aminus > 2 * PI ) a -= 2 * PI ; if ( a - aplus < - 2 * PI || a - aminus < - 2 * PI ) a += 2 * PI ;
273280 if ( a < aplus ) a = aplus ; else if ( a > aminus ) a = aminus ;
274281 }
275- updateLocation ( selected , d , a ) ;
282+ correctCircleLocation ( selected , d , a ) ;
276283 redraw ( ) ;
277284 return ;
278285 }
@@ -310,7 +317,7 @@ $('canvas').mousewheel(function(event, delta, deltaX, deltaY){
310317 selected . children [ i ] . r *= ( selected . r / oldR ) ;
311318 selected . children [ i ] . update ( selected . children [ i ] . d * ( selected . r / oldR ) , selected . children [ i ] . a ) ;
312319 }
313- updateLocation ( selected , selected . d , selected . a ) ;
320+ correctCircleLocation ( selected , selected . d , selected . a ) ;
314321 redraw ( ) ;
315322 }
316323 return false ;
@@ -377,7 +384,7 @@ function generateWord(word, wordL, mcR, dist, mainAngle){
377384
378385 var newMainCircle = new Circle ( allCircles [ 0 ] , 2 , 0 , dist , mcR , mainAngle ) ;
379386
380- mainCircles . push ( newMainCircle ) ;
387+ wordCircles . push ( newMainCircle ) ;
381388 allCircles . push ( newMainCircle ) ;
382389 allCircles [ 0 ] . children . push ( newMainCircle ) ;
383390
@@ -431,7 +438,7 @@ function generateWord(word, wordL, mcR, dist, mainAngle){
431438 }
432439 }
433440 newCircle . nLines = nLines ;
434- updateLocation ( newCircle , newCircle . d , newCircle . a ) ;
441+ correctCircleLocation ( newCircle , newCircle . d , newCircle . a ) ;
435442 owner . children . push ( newCircle ) ;
436443
437444 allCircles . push ( newCircle ) ;
@@ -517,7 +524,7 @@ function createLines(){
517524//checks whether all the circles have a correct amount of lines connected
518525function checkLines ( ) {
519526 for ( var i = 1 ; i < allCircles . length ; ++ i ) { //we don't check the first circle
520- if ( mainCircles . indexOf ( allCircles [ i ] ) != - 1 ) continue ; //also skip mainCircles
527+ if ( wordCircles . indexOf ( allCircles [ i ] ) != - 1 ) continue ; //also skip wordCircles
521528 if ( allCircles [ i ] . nLines != allCircles [ i ] . lines . length ) return 0 ;
522529 }
523530 return 1 ;
0 commit comments